From d0325da2c54fceda9314c6de2792e880f1b8a6d5 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 13 Jun 2026 14:30:16 +0200 Subject: [PATCH 001/171] refactor: clean up dead multiblock/worldgen Remove dead V2 relics: lib.multiblock.manager.* (MultiBlockCache, MultiBlockManager, RegisteredMultiBlockPattern), IBetterPattern, the non-aisle SimpleMultiBlockPatternBuilder, and the legacy IrradiatedSurfaceRules v1 implementation. The v2 surface rule logic now lives in IrradiatedSurfaceRules, and CNNoiseGeneratorSettings points back to it. Introduce IMultiblockController to decouple MultiBlockManagerBeta.findStructure from the concrete ReactorControllerBlockEntity, and consolidate the duplicated FALLBACK rod/fluid type ResourceKeys into CreateNuclearRegistries. Also drop unused fields/imports (CNDensityFunctions.NOODLES, CNNoiseData basalt mare keys, commented-out registrations and mob spawns, debug logger call in SimpleMultiBlockAislePatternBuilder, dead getDistanceControllerTest), and fix a typo in MultiBlockOffsetPos (caracter -> character). --- .../SimpleMultiBlockAislePatternBuilder.java | 7 -- .../multiblock/SimpleMultiBlockPattern.java | 6 +- .../SimpleMultiBlockPatternBuilder.java | 71 --------------- .../lib/multiblock/impl/IBetterPattern.java | 26 ------ .../multiblock/manager/MultiBlockCache.java | 24 ----- .../multiblock/manager/MultiBlockManager.java | 27 ------ .../manager/RegisteredMultiBlockPattern.java | 6 -- .../multiblock/misc/MultiBlockOffsetPos.java | 2 +- src/main/java/lib/multiblock/misc/Util.java | 6 +- .../createnuclear/CreateNuclear.java | 1 - .../api/CreateNuclearRegistries.java | 5 ++ .../createnuclear/api/ItemRodTypesValue.java | 1 - .../api/multiblock/IMultiblockController.java | 6 ++ .../api/multiblock/MultiBlockManagerBeta.java | 2 +- .../multiblock/fluid/ReactorFluidType.java | 3 +- .../api/multiblock/rods/RodType.java | 4 +- .../ReactorControllerBlockEntity.java | 8 +- .../multiblock/fluid/CNReactorFluidTypes.java | 3 +- .../content/multiblock/rod/CNRodTypes.java | 3 - .../data/recipe/CNMixingRecipeGen.java | 1 - .../worldgen/CNConfiguredFeatures.java | 10 +-- .../worldgen/biome/CNDensityFunctions.java | 8 -- .../worldgen/biome/CNNoiseData.java | 5 -- .../biome/CNNoiseGeneratorSettings.java | 3 +- .../worldgen/biome/IrradiatedBiomes.java | 6 -- .../surfacerule/IrradiatedSurfaceRules.java | 79 +++++++++++++--- .../surfacerule/IrradiatedSurfaceRules2.java | 90 ------------------- 27 files changed, 102 insertions(+), 311 deletions(-) delete mode 100644 src/main/java/lib/multiblock/SimpleMultiBlockPatternBuilder.java delete mode 100644 src/main/java/lib/multiblock/impl/IBetterPattern.java delete mode 100644 src/main/java/lib/multiblock/manager/MultiBlockCache.java delete mode 100644 src/main/java/lib/multiblock/manager/MultiBlockManager.java delete mode 100644 src/main/java/lib/multiblock/manager/RegisteredMultiBlockPattern.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules2.java diff --git a/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java b/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java index 24f6fde0..dbcf2161 100644 --- a/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java +++ b/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java @@ -72,7 +72,6 @@ public SimpleMultiBlockAislePatternBuilder block(char pSymbol, Supplier T build(IPatternBuilder builder){ var data = Util.parseBlockPattern(pattern, lookup.keySet()); var coreList = data.get('*'); - CreateNuclear.LOGGER.info("1: {}", coreList.toString()); if (coreList == null || coreList.size() != 1) { throw new IllegalArgumentException("Failed to build pattern due to having more or less than one \"*\" defined! Have: %s Expected: 1".formatted(coreList != null ? coreList.size() : 0)); } @@ -86,10 +85,4 @@ public BlockPos getDistanceController(char character) { var coreList = data.get(character); return coreList.get(0).pos(); } - - public Stream getDistanceControllerTest(char character) { - Map> data = Util.parseBlockPattern(pattern, lookup.keySet()); - List coreList = data.get(character); - return coreList.stream(); - } } diff --git a/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java b/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java index 29619601..a460167b 100644 --- a/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java +++ b/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java @@ -31,7 +31,7 @@ public SimpleMultiBlockPattern(List multiBlockOffsetPosList public boolean matches(Level level, BlockPos blockPos, Rotation rotation) { for (MultiBlockOffsetPos multiBlockOffsetPos : multiBlockOffsetPosList) { - char character = multiBlockOffsetPos.caracter(); + char character = multiBlockOffsetPos.character(); Predicate predicate = predicateHashMap.get(character); BlockInWorld block = new BlockInWorld(level, blockPos.offset(multiBlockOffsetPos.pos().rotate(rotation)), false); @@ -43,7 +43,7 @@ public boolean matches(Level level, BlockPos blockPos, Rotation rotation) { public MultiblockMatchResult matchesWithResult(Level level, BlockPos blockPos, Rotation rotation) { List result = new ArrayList<>(); for (MultiBlockOffsetPos multiBlockOffsetPos : multiBlockOffsetPosList) { - char character = multiBlockOffsetPos.caracter(); + char character = multiBlockOffsetPos.character(); Predicate predicate = predicateHashMap.get(character); BlockInWorld block = new BlockInWorld(level, blockPos.offset(multiBlockOffsetPos.pos().rotate(rotation)), false); if (predicate == null || !predicate.test(block)) return null; @@ -58,7 +58,7 @@ public void construct(Level level, BlockPos blockPos, BiPredicate stateSupplier = blockProvider.get(character); if (stateSupplier != null) { var pos = blockPos.offset(multiBlockOffsetPos.pos().rotate(Rotation.NONE)); diff --git a/src/main/java/lib/multiblock/SimpleMultiBlockPatternBuilder.java b/src/main/java/lib/multiblock/SimpleMultiBlockPatternBuilder.java deleted file mode 100644 index 6183f7a0..00000000 --- a/src/main/java/lib/multiblock/SimpleMultiBlockPatternBuilder.java +++ /dev/null @@ -1,71 +0,0 @@ -package lib.multiblock; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import lib.multiblock.impl.IMultiBlockPatternBuilder; -import lib.multiblock.impl.IMultiBlockPatternBuilder; -import lib.multiblock.impl.IPatternBuilder; -import lib.multiblock.misc.MultiBlockOffsetPos; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import lib.multiblock.impl.IMultiBlockPattern; -import net.nuclearteam.createnuclear.CreateNuclear; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -@SuppressWarnings("unused") -public final class SimpleMultiBlockPatternBuilder implements IMultiBlockPatternBuilder { - private static final Joiner COMA_SEPARATOR = Joiner.on(','); - public static SimpleMultiBlockPatternBuilder start() { - return new SimpleMultiBlockPatternBuilder(); - } - - private final Map> multiBlockOffsetPosList = Maps.newHashMap(); - private final Map> predicateHashMap = Maps.newHashMap(); - private final Map> blockProvider = Maps.newHashMap(); - - private SimpleMultiBlockPatternBuilder() {} - - private void ensureProperlyBuilt(List list) { - HashSet characters = new HashSet<>(); - list.forEach(multiBlockOffsetPos -> { - if (!predicateHashMap.containsKey(multiBlockOffsetPos.caracter())) - characters.add(multiBlockOffsetPos.caracter()); - }); - if (!characters.isEmpty()) - throw new IllegalStateException("Missing the following: \"%s\" for MultiBlock Pattern as they have not been defined".formatted(COMA_SEPARATOR.join(characters))); - } - - public SimpleMultiBlockPatternBuilder add(char character, BlockPos relativePos) { - multiBlockOffsetPosList.computeIfAbsent(character, ArrayList::new).add(new MultiBlockOffsetPos(character, relativePos)); - return this; - } - - public SimpleMultiBlockPatternBuilder where(char character, Predicate worldPredicate) { - if (!predicateHashMap.containsKey(character)) predicateHashMap.put(character, worldPredicate); - return this; - } - - public SimpleMultiBlockPatternBuilder block(char pSymbol, Supplier blockStateSupplier) { - blockProvider.put(pSymbol, blockStateSupplier); - return this; - } - - - public T build(IPatternBuilder builder) { - var coreList = multiBlockOffsetPosList.get('*'); - CreateNuclear.LOGGER.info("2: {}", coreList.toString()); - if (coreList == null || coreList.size() != 1) - throw new IllegalArgumentException("Failed to build pattern due to having more or less than one \"*\" defined! Have: %s Expected: 1".formatted(coreList != null ? coreList.size() : 0)); - List list = Lists.newArrayList(); - multiBlockOffsetPosList.forEach((k, v) -> list.addAll(v)); - return builder.make(list, predicateHashMap, blockProvider); - } -} diff --git a/src/main/java/lib/multiblock/impl/IBetterPattern.java b/src/main/java/lib/multiblock/impl/IBetterPattern.java deleted file mode 100644 index e4570f4d..00000000 --- a/src/main/java/lib/multiblock/impl/IBetterPattern.java +++ /dev/null @@ -1,26 +0,0 @@ -package lib.multiblock.impl; - -import lib.multiblock.misc.MultiblockMatchResult; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.function.BiPredicate; - -public class IBetterPattern implements IMultiBlockPattern { - @Override - public boolean matches(Level level, BlockPos pos, Rotation rotation) { - return false; - } - - @Override - public MultiblockMatchResult matchesWithResult(Level level, BlockPos pos, Rotation rotation) { - return null; - } - - @Override - public void construct(Level level, BlockPos pos, BiPredicate blockStateBiPredicate) { - - } -} diff --git a/src/main/java/lib/multiblock/manager/MultiBlockCache.java b/src/main/java/lib/multiblock/manager/MultiBlockCache.java deleted file mode 100644 index 84bb3285..00000000 --- a/src/main/java/lib/multiblock/manager/MultiBlockCache.java +++ /dev/null @@ -1,24 +0,0 @@ -package lib.multiblock.manager; - -import lib.multiblock.impl.IMultiBlockPattern; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Rotation; - -public class MultiBlockCache { - private T cachedResult; - public MultiBlockCache(){} - - public void updateStructure(T blockPattern) { - this.cachedResult = blockPattern; - } - - public boolean isValid(Level level, BlockPos pos, Rotation rotation) { - return cachedResult != null && cachedResult.matches(level, pos, rotation); - } - - public boolean isCached() { - return cachedResult == null; - } -} diff --git a/src/main/java/lib/multiblock/manager/MultiBlockManager.java b/src/main/java/lib/multiblock/manager/MultiBlockManager.java deleted file mode 100644 index dd8dbf4e..00000000 --- a/src/main/java/lib/multiblock/manager/MultiBlockManager.java +++ /dev/null @@ -1,27 +0,0 @@ -package lib.multiblock.manager; - -import lib.multiblock.impl.IMultiBlockPattern; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Rotation; - -import java.util.ArrayList; - -public class MultiBlockManager { - private final ArrayList> registeredMultiBlockPatterns = new ArrayList>(); - - public MultiBlockManager(){} - - public E register(String ID, T data, E blockPattern) { - registeredMultiBlockPatterns.add(new RegisteredMultiBlockPattern<>(ID, data, blockPattern)); - return blockPattern; - } - - public RegisteredMultiBlockPattern findStructure(Level level, BlockPos pos, Rotation rotation) { - for (RegisteredMultiBlockPattern registeredMultiBlockPattern : registeredMultiBlockPatterns) { - var result = registeredMultiBlockPattern.pattern().matches(level, pos, rotation); - if(result) return registeredMultiBlockPattern; - } - return null; - } -} diff --git a/src/main/java/lib/multiblock/manager/RegisteredMultiBlockPattern.java b/src/main/java/lib/multiblock/manager/RegisteredMultiBlockPattern.java deleted file mode 100644 index 264af6d8..00000000 --- a/src/main/java/lib/multiblock/manager/RegisteredMultiBlockPattern.java +++ /dev/null @@ -1,6 +0,0 @@ -package lib.multiblock.manager; - -import lib.multiblock.impl.IMultiBlockPattern; - -public record RegisteredMultiBlockPattern (String ID, T data, IMultiBlockPattern pattern) { -} diff --git a/src/main/java/lib/multiblock/misc/MultiBlockOffsetPos.java b/src/main/java/lib/multiblock/misc/MultiBlockOffsetPos.java index a388a68d..11801a72 100644 --- a/src/main/java/lib/multiblock/misc/MultiBlockOffsetPos.java +++ b/src/main/java/lib/multiblock/misc/MultiBlockOffsetPos.java @@ -2,5 +2,5 @@ import net.minecraft.core.BlockPos; -public record MultiBlockOffsetPos(char caracter, BlockPos pos) { +public record MultiBlockOffsetPos(char character, BlockPos pos) { } diff --git a/src/main/java/lib/multiblock/misc/Util.java b/src/main/java/lib/multiblock/misc/Util.java index 81eb1ef5..184f0348 100644 --- a/src/main/java/lib/multiblock/misc/Util.java +++ b/src/main/java/lib/multiblock/misc/Util.java @@ -20,14 +20,12 @@ public static Map> parseBlockPattern(List> blockOffsets = new HashMap<>(); - int starX = -1; - int starY = -1; - int starZ = -1; + int starX = -1, starY = -1, starZ = -1; for (int y = 0; y < aisles.size(); y++) { String[] aisle = aisles.get(y); - for (int x=0; x < aisle.length; x++) { + for (int x = 0; x < aisle.length; x++) { for (int z = 0; z < aisle[x].length(); z++) { if (aisle[x].charAt(z) == '*') { starX = x; diff --git a/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java b/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java index fa75a3f0..82e8c20c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java +++ b/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java @@ -84,7 +84,6 @@ public static void onInitialize() { CNParticleTypes.register(modEventBus); CNParticleRegistry.DEF_REG.register(modEventBus); CNRecipeTypes.register(modEventBus); -// CNSounds.register(modEventBus); CNAttributes.register(modEventBus); GogglesItem.addIsWearingPredicate(IGoggleHelmet::isGoggleHelmet); diff --git a/src/main/java/net/nuclearteam/createnuclear/api/CreateNuclearRegistries.java b/src/main/java/net/nuclearteam/createnuclear/api/CreateNuclearRegistries.java index 8b2a1788..c720e43d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/CreateNuclearRegistries.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/CreateNuclearRegistries.java @@ -11,6 +11,11 @@ public class CreateNuclearRegistries { public static final ResourceKey> ROD_TYPE = key("rods/type"); public static final ResourceKey> FLUID_TYPE = key("fluids/type"); + public static final ResourceKey FALLBACK_ROD = ResourceKey.create(CreateNuclearRegistries.ROD_TYPE, CreateNuclear.asResource("fallback")); + public static final ResourceKey FALLBACK_FLUID = ResourceKey.create(CreateNuclearRegistries.FLUID_TYPE, CreateNuclear.asResource("fallback")); + + + private static ResourceKey> key(String name) { return ResourceKey.createRegistryKey(CreateNuclear.asResource(name)); } diff --git a/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java b/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java index 53355a4b..745111d7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java @@ -42,7 +42,6 @@ public static NonNullConsumer setRodTypeInfos(RodType.Builder type) { return item -> ROD_TYPE.register(item, type.addItems(item).build()); } - /** * Create a consumer that builds a {@link RodType} using the provided numeric * parameters and registers it for the item passed to the consumer. diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java new file mode 100644 index 00000000..f2880929 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java @@ -0,0 +1,6 @@ +package net.nuclearteam.createnuclear.api.multiblock; + +public interface IMultiblockController { + void setMultiblockFacing(String f); + String getMultiblockFacing(); +} diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java index 7079cd34..c5b2ed11 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java @@ -19,7 +19,7 @@ public void register(String id, T data, IMultiBlockPattern blockPattern) { structures.add(new BlockPattern<>(id, data, blockPattern)); } - public BlockPattern findStructure(Level level, BlockPos pos, ReactorControllerBlockEntity entity) { + public BlockPattern findStructure(Level level, BlockPos pos, IMultiblockController entity) { List directions = new ArrayList<>(); directions.add(Direction.NORTH); directions.add(Direction.WEST); diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java index 5fdcc1f0..8987f78a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java @@ -16,7 +16,6 @@ import net.minecraftforge.registries.ForgeRegistries; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.ReactorFluidTypesValue; -import net.nuclearteam.createnuclear.content.multiblock.fluid.CNReactorFluidTypes; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -82,7 +81,7 @@ public static ReactorFluidType resolveReactorFluidType(Fluid fluid, Level world) ? fromFluid : world.registryAccess() .registryOrThrow(CreateNuclearRegistries.FLUID_TYPE) - .getHolderOrThrow(CNReactorFluidTypes.FALLBACK) + .getHolderOrThrow(CreateNuclearRegistries.FALLBACK_FLUID) .value(); }); } diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java index 57c09766..90839707 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java @@ -14,11 +14,9 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; -import net.minecraftforge.registries.ForgeRegistries; import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; -import net.nuclearteam.createnuclear.content.multiblock.rod.CNRodTypes; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import java.util.ArrayList; @@ -90,7 +88,7 @@ public static RodType resolveRodType(Item item, Level world) { ? fromItem : world.registryAccess() .registryOrThrow(CreateNuclearRegistries.ROD_TYPE) - .getHolderOrThrow(CNRodTypes.FALLBACK) + .getHolderOrThrow(CreateNuclearRegistries.FALLBACK_ROD) .value(); }); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index fbd75dde..d9d1d81c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -42,6 +42,7 @@ import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.CNEntityType; import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.api.multiblock.IMultiblockController; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.CNMultiblock; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; @@ -80,7 +81,7 @@ @SuppressWarnings({ "unused" }) public class ReactorControllerBlockEntity extends SmartBlockEntity - implements IInteractionChecker, IHaveGoggleInformation { + implements IInteractionChecker, IHaveGoggleInformation, IMultiblockController { /** * The assembled state is stored in the block state * (`ReactorControllerBlock.ASSEMBLED`). @@ -268,11 +269,14 @@ public void setMultiblockSize(int s) { this.reactorSize = s; } + @Override public String getMultiblockFacing() { return this.reactorFacing; } - public void setMultiblockFacing(String f) { + @Override + public void + setMultiblockFacing(String f) { this.reactorFacing = f; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/fluid/CNReactorFluidTypes.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/fluid/CNReactorFluidTypes.java index 5ea4727f..1f9e6a65 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/fluid/CNReactorFluidTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/fluid/CNReactorFluidTypes.java @@ -7,11 +7,10 @@ import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; + import static net.nuclearteam.createnuclear.api.ReactorFluidTypesValue.DEFAULT_REACTOR_FLUID_TYPE; public class CNReactorFluidTypes { - public static final ResourceKey FALLBACK = ResourceKey.create(CreateNuclearRegistries.FLUID_TYPE, CreateNuclear.asResource("fallback")); - /** * Static registry of reactor fluid types ({@link ReactorFluidType}) for the CreateNuclear mod. * diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java index 475c51da..79c17292 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java @@ -3,7 +3,6 @@ import net.minecraft.data.worldgen.BootstapContext; import net.minecraft.resources.ResourceKey; import net.minecraft.world.item.Items; -import net.nuclearteam.createnuclear.CNItems; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; @@ -11,8 +10,6 @@ import static net.nuclearteam.createnuclear.api.ItemRodTypesValue.DEFAULT_ROD_TYPE; public class CNRodTypes { - public static final ResourceKey FALLBACK = ResourceKey.create(CreateNuclearRegistries.ROD_TYPE, CreateNuclear.asResource("fallback")); - /** * Static registry of rod types ({@code RodType}) for the CreateNuclear mod. * diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMixingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMixingRecipeGen.java index b3a04572..293ddd98 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMixingRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMixingRecipeGen.java @@ -4,7 +4,6 @@ import com.simibubi.create.content.processing.recipe.HeatCondition; import net.minecraft.data.PackOutput; import net.minecraft.world.item.Items; -import net.minecraft.world.level.material.Fluids; import net.minecraftforge.common.Tags; import net.nuclearteam.createnuclear.CNFluids; import net.nuclearteam.createnuclear.CNItems; diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java index be81f0aa..9d88b03e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java @@ -34,29 +34,29 @@ public class CNConfiguredFeatures { public static void bootstrap(BootstapContext> ctx) { RuleTest stoneOreReplaceable = new TagMatchTest(BlockTags.STONE_ORE_REPLACEABLES); - RuleTest deepslateOreReplaceables = new TagMatchTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES); + RuleTest deepslateOreReplaceable = new TagMatchTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES); List uraniumTargetStates = List.of( OreConfiguration.target(stoneOreReplaceable, CNBlocks.URANIUM_ORE.getDefaultState()), - OreConfiguration.target(deepslateOreReplaceables, CNBlocks.DEEPSLATE_URANIUM_ORE.getDefaultState()) + OreConfiguration.target(deepslateOreReplaceable, CNBlocks.DEEPSLATE_URANIUM_ORE.getDefaultState()) ); register(ctx, URANIUM_ORE, Feature.ORE, new OreConfiguration(uraniumTargetStates, 7)); List leadTargetStates = List.of( OreConfiguration.target(stoneOreReplaceable, CNBlocks.LEAD_ORE.getDefaultState()), - OreConfiguration.target(deepslateOreReplaceables, CNBlocks.DEEPSLATE_LEAD_ORE.getDefaultState()) + OreConfiguration.target(deepslateOreReplaceable, CNBlocks.DEEPSLATE_LEAD_ORE.getDefaultState()) ); register(ctx, LEAD_ORE, Feature.ORE, new OreConfiguration(leadTargetStates, 7)); List thoriumTargetStates = List.of( OreConfiguration.target(stoneOreReplaceable, CNBlocks.THORIUM_ORE.getDefaultState()), - OreConfiguration.target(deepslateOreReplaceables, CNBlocks.DEEPSLATE_THORIUM_ORE.getDefaultState()) + OreConfiguration.target(deepslateOreReplaceable, CNBlocks.DEEPSLATE_THORIUM_ORE.getDefaultState()) ); register(ctx, THORIUM_ORE, Feature.ORE, new OreConfiguration(thoriumTargetStates, 16)); List nitrateTargetStates = List.of( OreConfiguration.target(stoneOreReplaceable, CNBlocks.NITRATE_ORE.getDefaultState()), - OreConfiguration.target(deepslateOreReplaceables, CNBlocks.DEEPSLATE_NITRATE_ORE.getDefaultState()) + OreConfiguration.target(deepslateOreReplaceable, CNBlocks.DEEPSLATE_NITRATE_ORE.getDefaultState()) ); register(ctx, NITRATE_ORE, Feature.ORE, new OreConfiguration(nitrateTargetStates, 10)); diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java index 1528bd14..521041a8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java @@ -11,8 +11,6 @@ import net.nuclearteam.createnuclear.CreateNuclear; public class CNDensityFunctions { - public static final ResourceKey NOODLES = createKey("caves/noodles"); - public static final class Irradiated { public static final ResourceKey EROSION = createKey("irradiated/erosion"); public static final ResourceKey FINAL_DENSITY = createKey("irradiated/final_density"); @@ -23,12 +21,6 @@ private static ResourceKey createKey(String id) { } public static void bootstrapRegistries(BootstapContext context) { - var vanillaRegistry = context.lookup(Registries.DENSITY_FUNCTION); - var noiseRegistry = context.lookup(Registries.NOISE); -// DensityFunction shiftX = getFunction(vanillaRegistry, NoiseRouterData.SHIFT_X); -// DensityFunction shiftZ = getFunction(vanillaRegistry, NoiseRouterData.SHIFT_Z); -// DensityFunction y = getFunction(vanillaRegistry, NoiseRouterData.Y); - context.register(Irradiated.EROSION, DensityFunctions.add( DensityFunctions.yClampedGradient(0, 90, 1, -1), BlendedNoise.createUnseeded(0.25, 0.375, 80.0, 160.0, 8.0) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java index a5245463..98ccde60 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java @@ -8,17 +8,12 @@ public class CNNoiseData { public static final ResourceKey EROSION = createKey("irradiated/erosion"); - public static final ResourceKey BASALT_MARE = createKey("irradiated/basalt_mare"); - public static final ResourceKey BASALT_MARE_HEIGHT = createKey("irradiated/basalt_mare_height"); private static ResourceKey createKey(String id) { return ResourceKey.create(Registries.NOISE, CreateNuclear.asResource(id)); } public static void bootstrapRegistries(BootstapContext context) { -// register(context, EROSION, -11, 1, 1, 0, 1, 1); -// register(context, BASALT_MARE, 5, 0, 0.1, 0.2, 0.1, 0, 0, 0, 0); -// register(context, BASALT_MARE_HEIGHT, -12, 0.3); } private static void register( diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseGeneratorSettings.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseGeneratorSettings.java index 52e6d466..2c8c02c8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseGeneratorSettings.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseGeneratorSettings.java @@ -11,7 +11,6 @@ import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.surfacerule.IrradiatedSurfaceRules; -import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.surfacerule.IrradiatedSurfaceRules2; import org.jetbrains.annotations.NotNull; public class CNNoiseGeneratorSettings { @@ -26,7 +25,7 @@ public static void bootstrapRegistries(BootstapContext c CNBlocks.STEEL_BLOCK.get().defaultBlockState(), Blocks.AIR.defaultBlockState(), CNNoiseGeneratorSettings.irradiated(densityLookup, noiseLookup), - IrradiatedSurfaceRules2.DEFAULT_RULE, + IrradiatedSurfaceRules.DEFAULT_RULE, new OverworldBiomeBuilder().spawnTarget(), 32, false, diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 9972b06c..486a3e9b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -17,14 +17,8 @@ public static Biome createPlain(HolderGetter featureLookup, Holde } public static void monsters(MobSpawnSettings.Builder builder, int zombieWeight, int zombieVillagerWeight, int skeletonWeight) { - - // builder.addSpawn(MobCategory.MONSTER, new MobSpawnSettings.SpawnerData(CNEntityType.IRRADIATED_CAT.get(), 100, 2, 4)); - // builder.addSpawn(MobCategory.MONSTER, new MobSpawnSettings.SpawnerData(CNEntityType.IRRADIATED_CHICKEN.get(), 100, 1, 4)); - // builder.addSpawn(MobCategory.MONSTER, new MobSpawnSettings.SpawnerData(CNEntityType.IRRADIATED_WOLF.get(), 100, 2, 4)); } - - public static void addDefaultIrradiatedOres(BiomeGenerationSettings.Builder builder) { builder.addFeature(GenerationStep.Decoration.UNDERGROUND_STRUCTURES, MiscOverworldPlacements.BLUE_ICE); builder.addCarver(GenerationStep.Carving.AIR, Carvers.NETHER_CAVE); diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java index 19a78bfb..9d8e7bd7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java @@ -1,30 +1,89 @@ package net.nuclearteam.createnuclear.infrastructure.worldgen.biome.surfacerule; +import com.mojang.serialization.Codec; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; +import net.minecraft.world.level.levelgen.SurfaceRules.ConditionSource; import net.minecraft.world.level.levelgen.VerticalAnchor; import net.nuclearteam.createnuclear.CNBlocks; +import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNBiomes; +import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNNoiseData; import org.jetbrains.annotations.NotNull; public class IrradiatedSurfaceRules { - private static final SurfaceRules.RuleSource BEDROCK = block(Blocks.BEDROCK); - public static final SurfaceRules.RuleSource HARD_ROCK = block(CNBlocks.ENRICHED_SOUL_SOIL.get()); + private static final ConditionSource IS_IRRADIATED_PLAIN = biome(CNBiomes.Irradiated.PLAIN); + private static final ConditionSource IS_HIGHLANDS = biome(); - public static final SurfaceRules.RuleSource IRRADIATED = createDefaultRule(); + private static final RuleSource BEDROCK = block(Blocks.BEDROCK); + private static final RuleSource ENRICHED_SOUL_SOIL = block(CNBlocks.ENRICHED_SOUL_SOIL.get()); + private static final RuleSource MOON_DIRT = block(CNBlocks.STEEL_BLOCK.get()); + private static final RuleSource LEAD_ROCK = block(CNBlocks.LEAD_BLOCK.get()); + private static final RuleSource LEAD_TURF = block(CNBlocks.LEAD_ORE.get()); + private static final RuleSource RAW_LEAD_BASALT = block(CNBlocks.RAW_LEAD_BLOCK.get()); - public static @NotNull SurfaceRules.RuleSource createDefaultRule() { + private static final RuleSource SECONDARY_MATERIAL = SurfaceRules.sequence( + SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BASALT), + SurfaceRules.ifTrue(IS_HIGHLANDS, MOON_DIRT) + ); + private static final RuleSource SURFACE_MATERIAL = SurfaceRules.sequence( + SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BASALT), + SurfaceRules.ifTrue(IS_HIGHLANDS, LEAD_TURF) + ); + private static final RuleSource SURFACE_GENERATION = SurfaceRules.sequence( + SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR, SURFACE_MATERIAL), + SurfaceRules.ifTrue(SurfaceRules.UNDER_FLOOR, SECONDARY_MATERIAL) + ); + + public static final RuleSource DEFAULT_RULE = createDefaultRule(); + + public static @NotNull RuleSource createDefaultRule() { return SurfaceRules.sequence( - SurfaceRules.ifTrue( - SurfaceRules.isBiome(CNBiomes.Irradiated.PLAIN), - HARD_ROCK - ), - SurfaceRules.ifTrue(SurfaceRules.verticalGradient("bedrock_floor", VerticalAnchor.bottom(), VerticalAnchor.aboveBottom(5)), BEDROCK) + SurfaceRules.ifTrue( + SurfaceRules.isBiome(CNBiomes.Irradiated.PLAIN), + SurfaceRules.sequence( + SurfaceRules.ifTrue( + SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.035, 0.0465), + LEAD_TURF + ), + SurfaceRules.ifTrue( + SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.039, 0.0545), + LEAD_ROCK + ), + SurfaceRules.ifTrue( + SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.0545, 0.069), + RAW_LEAD_BASALT + ) + ) + ), + + SurfaceRules.ifTrue(SurfaceRules.verticalGradient("bedrock_floor", VerticalAnchor.bottom(), VerticalAnchor.aboveBottom(5)), BEDROCK), + SurfaceRules.ifTrue(SurfaceRules.abovePreliminarySurface(), SURFACE_GENERATION), + SurfaceRules.ifTrue(SurfaceRules.verticalGradient("enriched", VerticalAnchor.absolute(-4), VerticalAnchor.absolute(4)), ENRICHED_SOUL_SOIL) ); } - private static @NotNull SurfaceRules.RuleSource block(@NotNull Block block) { + private static @NotNull RuleSource block(@NotNull Block block) { return SurfaceRules.state(block.defaultBlockState()); } + + public static SurfaceRules.@NotNull ConditionSource biome(@NotNull TagKey biome) { + return new BiomeTagRule(biome); + } + + @SafeVarargs + public static SurfaceRules.@NotNull ConditionSource biome(@NotNull ResourceKey @NotNull ... keys) { + return SurfaceRules.isBiome(keys); + } + + public static void register() { + Registry.register(BuiltInRegistries.MATERIAL_RULE, CreateNuclear.asResource("irradiated_surface"), Codec.unit(DEFAULT_RULE)); + } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules2.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules2.java deleted file mode 100644 index 538dc3d1..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules2.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.nuclearteam.createnuclear.infrastructure.worldgen.biome.surfacerule; - -import com.mojang.serialization.Codec; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.tags.TagKey; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.levelgen.SurfaceRules; -import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; -import net.minecraft.world.level.levelgen.SurfaceRules.ConditionSource; -import net.minecraft.world.level.levelgen.VerticalAnchor; -import net.nuclearteam.createnuclear.CNBlocks; -import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNBiomes; -import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNNoiseData; -import org.jetbrains.annotations.NotNull; - -public class IrradiatedSurfaceRules2 { - private static final ConditionSource IS_IRRADIATED_PLAIN = biome(CNBiomes.Irradiated.PLAIN); - private static final ConditionSource IS_HIGHLANDS = biome(); - - private static final RuleSource BEDROCK = block(Blocks.BEDROCK); - private static final RuleSource ENRICHED_SOUL_SOIL = block(CNBlocks.ENRICHED_SOUL_SOIL.get()); - private static final RuleSource MOON_DIRT = block(CNBlocks.STEEL_BLOCK.get()); - private static final RuleSource LEAD_ROCK = block(CNBlocks.LEAD_BLOCK.get()); - private static final RuleSource LEAD_TURF = block(CNBlocks.LEAD_ORE.get()); - private static final RuleSource RAW_LEAD_BASALT = block(CNBlocks.RAW_LEAD_BLOCK.get()); - private static final RuleSource DEBUG_STATE = block(CNBlocks.REACTOR_CASING.get()); - - private static final RuleSource SECONDARY_MATERIAL = SurfaceRules.sequence( - SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BASALT), - SurfaceRules.ifTrue(IS_HIGHLANDS, MOON_DIRT) - ); - private static final RuleSource SURFACE_MATERIAL = SurfaceRules.sequence( - SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BASALT), - SurfaceRules.ifTrue(IS_HIGHLANDS, LEAD_TURF) - ); - private static final RuleSource SURFACE_GENERATION = SurfaceRules.sequence( - SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR, SURFACE_MATERIAL), - SurfaceRules.ifTrue(SurfaceRules.UNDER_FLOOR, SECONDARY_MATERIAL) - ); - - public static final RuleSource DEFAULT_RULE = createDefaultRule(); - - public static @NotNull RuleSource createDefaultRule() { - return SurfaceRules.sequence( - SurfaceRules.ifTrue( - SurfaceRules.isBiome(CNBiomes.Irradiated.PLAIN), - SurfaceRules.sequence( - SurfaceRules.ifTrue( - SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.035, 0.0465), - LEAD_TURF - ), - SurfaceRules.ifTrue( - SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.039, 0.0545), - LEAD_ROCK - ), - SurfaceRules.ifTrue( - SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.0545, 0.069), - RAW_LEAD_BASALT - ) - ) - ), - - SurfaceRules.ifTrue(SurfaceRules.verticalGradient("bedrock_floor", VerticalAnchor.bottom(), VerticalAnchor.aboveBottom(5)), BEDROCK), - SurfaceRules.ifTrue(SurfaceRules.abovePreliminarySurface(), SURFACE_GENERATION), - SurfaceRules.ifTrue(SurfaceRules.verticalGradient("enriched", VerticalAnchor.absolute(-4), VerticalAnchor.absolute(4)), ENRICHED_SOUL_SOIL) - ); - } - - private static @NotNull RuleSource block(@NotNull Block block) { - return SurfaceRules.state(block.defaultBlockState()); - } - - public static SurfaceRules.@NotNull ConditionSource biome(@NotNull TagKey biome) { - return new BiomeTagRule(biome); - } - - @SafeVarargs - public static SurfaceRules.@NotNull ConditionSource biome(@NotNull ResourceKey @NotNull ... keys) { - return SurfaceRules.isBiome(keys); - } - - public static void register() { - Registry.register(BuiltInRegistries.MATERIAL_RULE, CreateNuclear.asResource("irradiated_surface"), Codec.unit(DEFAULT_RULE)); - } -} \ No newline at end of file From 42565d8986634a5b62920c5b01ed614028861821 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 13 Jun 2026 15:22:52 +0200 Subject: [PATCH 002/171] refactor: consolidate radiation feature into content.radiation package Move all radiation-related classes (CNRadiationValues, RadiationBucketItem, RadiationItem, RadiationEffect, RadiationEffectHandler, the radiation capability, and RadiationOverlay) out of foundation/item/radiation, content/effects/capability, foundation/events/overlay and impl/effect into a single content.radiation package and content.radiation.capability / content.radiation.client subpackages, to give the feature one owner instead of spreading it across four layers. Drop the now-unused RadiationSyncPacket and ClientRadiationData (dead client-sync packet) along with their CNPackets registration. Fix the RadiationEffetcHandler typo (-> RadiationEffectHandler) and merge foundation/util into foundation/utility by moving ClothTagHelper, updating all references in AntiRadiationArmorItem and SmithingTransformRecipeMixin. Add a guard in RadiationRegistry.build() that throws if an item already implements IRadiationSource, preventing double-counted radiation values between the two parallel radiation sources. --- .../nuclearteam/createnuclear/CNEffects.java | 2 +- .../nuclearteam/createnuclear/CNFluids.java | 5 +--- .../nuclearteam/createnuclear/CNItems.java | 5 +--- .../CNOpenPipeEffectHandlers.java | 4 +-- .../nuclearteam/createnuclear/CNPackets.java | 4 --- .../createnuclear/CreateNuclear.java | 2 +- .../api/radiation/RadiationRegistry.java | 2 ++ .../armor/AntiRadiationArmorItem.java | 8 +---- .../radiation/CNRadiationValues.java | 2 +- .../radiation/RadiationBucketItem.java | 2 +- .../RadiationEffect.java | 6 ++-- .../radiation/RadiationEffectHandler.java} | 4 +-- .../radiation/RadiationItem.java | 2 +- .../capability/IRadiationCapability.java | 2 +- .../capability/RadiationCapability.java | 14 +-------- .../capability/RadiationProvider.java | 2 +- .../radiation/client}/RadiationOverlay.java | 4 +-- .../data/radiation/ClientRadiationData.java | 7 ----- .../foundation/events/CommentEvents.java | 3 +- .../foundation/events/HudRenderer.java | 1 - .../events/overlay/HelmetOverlay.java | 1 + .../mixin/SmithingTransformRecipeMixin.java | 6 +--- .../radiation/RadiationSyncPacket.java | 29 ------------------- .../{util => utility}/ClothTagHelper.java | 2 +- 24 files changed, 26 insertions(+), 93 deletions(-) rename src/main/java/net/nuclearteam/createnuclear/{foundation/item => content}/radiation/CNRadiationValues.java (89%) rename src/main/java/net/nuclearteam/createnuclear/{foundation/item => content}/radiation/RadiationBucketItem.java (91%) rename src/main/java/net/nuclearteam/createnuclear/content/{effects => radiation}/RadiationEffect.java (94%) rename src/main/java/net/nuclearteam/createnuclear/{impl/effect/RadiationEffetcHandler.java => content/radiation/RadiationEffectHandler.java} (86%) rename src/main/java/net/nuclearteam/createnuclear/{foundation/item => content}/radiation/RadiationItem.java (89%) rename src/main/java/net/nuclearteam/createnuclear/content/{effects => radiation}/capability/IRadiationCapability.java (82%) rename src/main/java/net/nuclearteam/createnuclear/content/{effects => radiation}/capability/RadiationCapability.java (91%) rename src/main/java/net/nuclearteam/createnuclear/content/{effects => radiation}/capability/RadiationProvider.java (95%) rename src/main/java/net/nuclearteam/createnuclear/{foundation/events/overlay => content/radiation/client}/RadiationOverlay.java (93%) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/data/radiation/ClientRadiationData.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/networking/radiation/RadiationSyncPacket.java rename src/main/java/net/nuclearteam/createnuclear/foundation/{util => utility}/ClothTagHelper.java (96%) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNEffects.java b/src/main/java/net/nuclearteam/createnuclear/CNEffects.java index e17ad390..1184ab2c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNEffects.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNEffects.java @@ -6,7 +6,7 @@ import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; import net.nuclearteam.createnuclear.content.effects.IodineEffect; -import net.nuclearteam.createnuclear.content.effects.RadiationEffect; +import net.nuclearteam.createnuclear.content.radiation.RadiationEffect; public class CNEffects { public static final DeferredRegister EFFECTS = DeferredRegister.create(ForgeRegistries.MOB_EFFECTS, CreateNuclear.MOD_ID); diff --git a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java index b0e32df2..4afb0f22 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java @@ -10,8 +10,6 @@ import net.minecraft.core.dispenser.DispenseItemBehavior; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.damagesource.DamageEffects; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -24,7 +22,6 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.feature.SnowAndFreezeFeature; import net.minecraft.world.level.material.FluidState; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.SoundActions; @@ -36,7 +33,7 @@ import net.minecraftforge.fluids.ForgeFlowingFluid; import net.nuclearteam.createnuclear.content.decoration.palettes.CNPaletteStoneTypes; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; -import net.nuclearteam.createnuclear.foundation.item.radiation.RadiationBucketItem; +import net.nuclearteam.createnuclear.content.radiation.RadiationBucketItem; import org.joml.Vector3f; import net.nuclearteam.createnuclear.CNTags.CNFluidTags; diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index af4ca33f..74c4c1fd 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -1,6 +1,5 @@ package net.nuclearteam.createnuclear; -import com.simibubi.create.AllTags; import com.simibubi.create.foundation.data.AssetLookup; import com.tterrag.registrate.util.entry.ItemEntry; import com.simibubi.create.AllBlocks; @@ -9,8 +8,6 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; -import net.minecraft.data.recipes.SmithingTransformRecipeBuilder; -import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.ItemTags; import net.minecraft.world.effect.MobEffectInstance; @@ -23,7 +20,7 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.ForgeSpawnEggItem; import net.nuclearteam.createnuclear.api.data.recipe.SmithingClothRecipeBuilder; -import net.nuclearteam.createnuclear.foundation.item.radiation.RadiationItem; +import net.nuclearteam.createnuclear.content.radiation.RadiationItem; import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem.Cloths; import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintItem; diff --git a/src/main/java/net/nuclearteam/createnuclear/CNOpenPipeEffectHandlers.java b/src/main/java/net/nuclearteam/createnuclear/CNOpenPipeEffectHandlers.java index 28504be3..225109af 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNOpenPipeEffectHandlers.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNOpenPipeEffectHandlers.java @@ -1,10 +1,10 @@ package net.nuclearteam.createnuclear; import com.simibubi.create.api.effect.OpenPipeEffectHandler; -import net.nuclearteam.createnuclear.impl.effect.RadiationEffetcHandler; +import net.nuclearteam.createnuclear.content.radiation.RadiationEffectHandler; public class CNOpenPipeEffectHandlers { public static void registerDefaults() { - OpenPipeEffectHandler.REGISTRY.register(CNFluids.URANIUM.getSource(), new RadiationEffetcHandler()); + OpenPipeEffectHandler.REGISTRY.register(CNFluids.URANIUM.getSource(), new RadiationEffectHandler()); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/CNPackets.java b/src/main/java/net/nuclearteam/createnuclear/CNPackets.java index b2cec278..4f9ecb0e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNPackets.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNPackets.java @@ -14,7 +14,6 @@ import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent.Context; -import net.nuclearteam.createnuclear.foundation.networking.radiation.RadiationSyncPacket; import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintItemPacket; import java.util.function.BiConsumer; @@ -23,9 +22,6 @@ public enum CNPackets { CONFIGURE_REACTOR_PATTERN(ReactorBluePrintItemPacket.class, ReactorBluePrintItemPacket::new, PLAY_TO_SERVER), - - // To client - RADIATION_SYNC(RadiationSyncPacket.class, RadiationSyncPacket::new, PLAY_TO_CLIENT) ; public static final ResourceLocation CHANNEL_NAME = CreateNuclear.asResource("main"); public static final int NETWORK_VERSION = 0; diff --git a/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java b/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java index 82e8c20c..dd150866 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java +++ b/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java @@ -29,7 +29,7 @@ import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; import net.nuclearteam.createnuclear.foundation.advancement.CNTriggers; import net.nuclearteam.createnuclear.foundation.item.RodsStats; -import net.nuclearteam.createnuclear.foundation.item.radiation.CNRadiationValues; +import net.nuclearteam.createnuclear.content.radiation.CNRadiationValues; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import net.nuclearteam.createnuclear.infrastructure.data.CreateNuclearDatagen; import net.nuclearteam.createnuclear.infrastructure.worldgen.CNPlacementModifiers; diff --git a/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java b/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java index 5fe76f1b..2fe1d091 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java @@ -78,6 +78,8 @@ public Builder value(double value) { public void build() { if (item != null) { + if (item instanceof IRadiationSource) + throw new IllegalStateException("Item " + item + " implements IRadiationSource and should not also be registered in RadiationRegistry (would cause double counting)."); ITEM_VALUE.put(item, value); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java index aa4ecf72..65d7e61d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java @@ -15,16 +15,10 @@ import net.minecraft.world.level.Level; import net.minecraftforge.client.extensions.common.IClientItemExtensions; -import net.minecraft.Util; -import net.minecraft.network.chat.Component; -import net.minecraft.tags.TagKey; -import net.minecraft.world.entity.ai.attributes.Attribute; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.item.*; import net.nuclearteam.createnuclear.CNAttributes; import net.nuclearteam.createnuclear.CNItems; import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; -import net.nuclearteam.createnuclear.foundation.util.ClothTagHelper; +import net.nuclearteam.createnuclear.foundation.utility.ClothTagHelper; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import javax.annotation.Nullable; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/CNRadiationValues.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/CNRadiationValues.java similarity index 89% rename from src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/CNRadiationValues.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/CNRadiationValues.java index 86271c3c..1f7433ab 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/CNRadiationValues.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/CNRadiationValues.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.item.radiation; +package net.nuclearteam.createnuclear.content.radiation; import com.simibubi.create.AllItems; import net.nuclearteam.createnuclear.api.radiation.RadiationRegistry; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/RadiationBucketItem.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java similarity index 91% rename from src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/RadiationBucketItem.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java index 13127ed8..3ab5e741 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/RadiationBucketItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.item.radiation; +package net.nuclearteam.createnuclear.content.radiation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BucketItem; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/RadiationEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java similarity index 94% rename from src/main/java/net/nuclearteam/createnuclear/content/effects/RadiationEffect.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java index f12bec01..de1de18c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/RadiationEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.content.effects; +package net.nuclearteam.createnuclear.content.radiation; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; @@ -9,13 +9,13 @@ import net.nuclearteam.createnuclear.CNEffects; import net.nuclearteam.createnuclear.CNTags; -import net.nuclearteam.createnuclear.content.effects.capability.RadiationCapability; +import net.nuclearteam.createnuclear.content.effects.VicinityEffect; +import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.nuclearteam.createnuclear.foundation.damageTypes.CreateNuclearDamageSources; import net.nuclearteam.createnuclear.foundation.utility.ConfigValueResolver; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; -import net.nuclearteam.createnuclear.infrastructure.config.CRadiation; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/net/nuclearteam/createnuclear/impl/effect/RadiationEffetcHandler.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java similarity index 86% rename from src/main/java/net/nuclearteam/createnuclear/impl/effect/RadiationEffetcHandler.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java index d2539b51..b231bfe0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/impl/effect/RadiationEffetcHandler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.impl.effect; +package net.nuclearteam.createnuclear.content.radiation; import com.simibubi.create.api.effect.OpenPipeEffectHandler; import net.minecraft.world.effect.MobEffectInstance; @@ -10,7 +10,7 @@ import java.util.List; -public class RadiationEffetcHandler implements OpenPipeEffectHandler { +public class RadiationEffectHandler implements OpenPipeEffectHandler { @Override public void apply(Level level, AABB area, FluidStack fluid) { if (level.getGameTime() % 5 != 0) return; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/RadiationItem.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java similarity index 89% rename from src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/RadiationItem.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java index 5b2f17fe..be57de09 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/item/radiation/RadiationItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.item.radiation; +package net.nuclearteam.createnuclear.content.radiation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/capability/IRadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java similarity index 82% rename from src/main/java/net/nuclearteam/createnuclear/content/effects/capability/IRadiationCapability.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java index 552f1a06..cac84ed5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/capability/IRadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.content.effects.capability; +package net.nuclearteam.createnuclear.content.radiation.capability; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/capability/RadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java similarity index 91% rename from src/main/java/net/nuclearteam/createnuclear/content/effects/capability/RadiationCapability.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java index daa138a4..6ad10f16 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/capability/RadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java @@ -1,8 +1,7 @@ -package net.nuclearteam.createnuclear.content.effects.capability; +package net.nuclearteam.createnuclear.content.radiation.capability; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; @@ -16,14 +15,11 @@ import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent.PlayerTickEvent; -import net.minecraftforge.network.PacketDistributor; import net.nuclearteam.createnuclear.CNAttributes; import net.nuclearteam.createnuclear.CNEffects; -import net.nuclearteam.createnuclear.CNPackets; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.radiation.IRadiationSource; import net.nuclearteam.createnuclear.api.radiation.RadiationRegistry; -import net.nuclearteam.createnuclear.foundation.networking.radiation.RadiationSyncPacket; import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; import static net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem.RADIATION_VALUE; import net.nuclearteam.createnuclear.foundation.utility.InventoryHashUtil; @@ -81,20 +77,16 @@ public static void onPlayerTick(PlayerTickEvent event) { if (level.isClientSide) return; player.getCapability(RadiationProvider.CAP).ifPresent(cap -> { - boolean needsSync = false; - long newHash = InventoryHashUtil.compute(player); if (newHash != cap.getInventoryHash()) { cap.setInventoryHash(newHash); cap.setRadiation(Math.max(0, computeItemRadiation(player))); - needsSync = true; } ResourceKey biomeKey = level.getBiome(player.blockPosition()).unwrapKey().orElse(null); ResourceLocation biomeLoc = biomeKey != null ? biomeKey.location() : null; if (!Objects.equals(biomeLoc, cap.getLastBiomeLocation())) { cap.setLastBiomeLocation(biomeLoc); - needsSync = true; } if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return; @@ -103,10 +95,6 @@ public static void onPlayerTick(PlayerTickEvent event) { double resistance = getRadiationResistance(player); double totalRadiation = totalRaw * (1.0 - resistance); - if (needsSync) { - CNPackets.getChannel().send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new RadiationSyncPacket(totalRadiation)); - } - applyEffects(player, totalRadiation); }); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/capability/RadiationProvider.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java similarity index 95% rename from src/main/java/net/nuclearteam/createnuclear/content/effects/capability/RadiationProvider.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java index 04e86895..05cfaca2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/capability/RadiationProvider.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.content.effects.capability; +package net.nuclearteam.createnuclear.content.radiation.capability; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/RadiationOverlay.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java similarity index 93% rename from src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/RadiationOverlay.java rename to src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java index a9999507..17a1ad11 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/RadiationOverlay.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java @@ -1,14 +1,14 @@ -package net.nuclearteam.createnuclear.foundation.events.overlay; +package net.nuclearteam.createnuclear.content.radiation.client; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.gui.overlay.ForgeGui; import net.minecraftforge.client.gui.overlay.IGuiOverlay; import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; import net.nuclearteam.createnuclear.CNEffects; import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.foundation.events.overlay.EasingHudOverlay; import net.nuclearteam.createnuclear.foundation.utility.RenderHelper; /** diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/radiation/ClientRadiationData.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/radiation/ClientRadiationData.java deleted file mode 100644 index 6cdaed1a..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/radiation/ClientRadiationData.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.data.radiation; - -public record ClientRadiationData(double radiation) { - public ClientRadiationData() { - this(0); - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java index 88af630c..643b30ab 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java @@ -6,11 +6,10 @@ import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.TickEvent.ServerTickEvent; import net.minecraftforge.event.entity.EntityAttributeModificationEvent; -import net.minecraftforge.event.entity.living.*; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.nuclearteam.createnuclear.*; -import net.nuclearteam.createnuclear.content.effects.capability.RadiationCapability; +import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; @Mod.EventBusSubscriber public class CommentEvents { diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java index 2baf9f46..59b54c28 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java @@ -4,7 +4,6 @@ import net.nuclearteam.createnuclear.foundation.events.overlay.EventTextOverlay; import net.nuclearteam.createnuclear.foundation.events.overlay.HelmetOverlay; import net.nuclearteam.createnuclear.foundation.events.overlay.HudOverlay; -import net.nuclearteam.createnuclear.foundation.events.overlay.RadiationOverlay; import java.util.Comparator; import java.util.List; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java index 80bb3264..8a878acb 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java @@ -12,6 +12,7 @@ import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.content.radiation.client.RadiationOverlay; import net.nuclearteam.createnuclear.foundation.utility.RenderHelper; /** diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/SmithingTransformRecipeMixin.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/SmithingTransformRecipeMixin.java index 0557ad31..52aa15a1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/SmithingTransformRecipeMixin.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/SmithingTransformRecipeMixin.java @@ -1,15 +1,11 @@ package net.nuclearteam.createnuclear.foundation.mixin; import net.minecraft.core.RegistryAccess; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.Container; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.SmithingRecipe; import net.minecraft.world.item.crafting.SmithingTransformRecipe; import net.nuclearteam.createnuclear.CNTags; -import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; -import net.nuclearteam.createnuclear.foundation.util.ClothTagHelper; +import net.nuclearteam.createnuclear.foundation.utility.ClothTagHelper; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/networking/radiation/RadiationSyncPacket.java b/src/main/java/net/nuclearteam/createnuclear/foundation/networking/radiation/RadiationSyncPacket.java deleted file mode 100644 index a45d7323..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/networking/radiation/RadiationSyncPacket.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.networking.radiation; - -import com.simibubi.create.foundation.networking.SimplePacketBase; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent; -import net.nuclearteam.createnuclear.foundation.data.radiation.ClientRadiationData; - -public class RadiationSyncPacket extends SimplePacketBase { - private final double radiation; - - public RadiationSyncPacket(double radiation) { - this.radiation = radiation; - } - - public RadiationSyncPacket(FriendlyByteBuf buffer) { - this(buffer.readDouble()); - } - - @Override - public void write(FriendlyByteBuf buffer) { - buffer.writeDouble(radiation); - } - - @Override - public boolean handle(NetworkEvent.Context context) { - context.enqueueWork(() -> new ClientRadiationData(radiation)); - return true; - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/util/ClothTagHelper.java b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/ClothTagHelper.java similarity index 96% rename from src/main/java/net/nuclearteam/createnuclear/foundation/util/ClothTagHelper.java rename to src/main/java/net/nuclearteam/createnuclear/foundation/utility/ClothTagHelper.java index 4644a38c..298d6094 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/util/ClothTagHelper.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/ClothTagHelper.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.util; +package net.nuclearteam.createnuclear.foundation.utility; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; From b99b60c1409bb66e84c6f52a896ab50b76567b36 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 13 Jun 2026 17:28:12 +0200 Subject: [PATCH 003/171] refactor: extract reactor frame display state into ReactorFrameDisplayManager Move the frame fluid cache, fill-ratio computation, and frame column bounds (min/max Y) out of ReactorControllerBlockEntity into a new ReactorFrameDisplayManager/ReactorFrameDisplayManagerI pair, following the manager/service extraction pattern already used for output, input fluid, and alarm logic. ReactorFrameRenderer and ReactorAssembler now go through getFrameDisplayManager() instead of calling the now-removed getDisplayedFluid/getDisplayedFluidFillRatio/setFrameColumn/ hasFrameColumn/getFrameColumnMinY/getFrameColumnMaxY methods directly on the controller. NBT read/write for the frame column bounds is delegated to the new manager as well. Also expose getInputFluidManager() on the controller, drop a leftover commented-out debug block in onSpeedChanged, fix a stray line break in setMultiblockFacing, and tighten changeBiome's visibility to private. --- .../content/multiblock/ReactorAssembler.java | 2 +- .../ReactorControllerBlockEntity.java | 118 +++------------ .../manager/ReactorFrameDisplayManager.java | 136 ++++++++++++++++++ .../manager/ReactorFrameDisplayManagerI.java | 47 ++++++ .../frame/ReactorFrameRenderer.java | 13 +- 5 files changed, 209 insertions(+), 107 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManagerI.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 7f35d0aa..888aeaf8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -120,7 +120,7 @@ public static void findAndRegisterSpecialBlocks(int[] reactorPos, ReactorControl } if (frameMinY != Integer.MAX_VALUE) { - entity.setFrameColumn(frameMinY, frameMaxY); + entity.getFrameDisplayManager().setFrameColumn(frameMinY, frameMaxY, entity::notifyUpdate); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index d9d1d81c..62031da9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -108,16 +108,8 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private String reactorFacing = "null"; // les pos sont [xMin, xMax, yMin, yMax, zMin, zMax] private int[] reactorPos; - // Vertical span (block Y) of the reactor frame columns, used to map the - // fluid fill ratio onto the liquid actually drawn in the frame windows. - private int frameColumnMinY = Integer.MAX_VALUE; - private int frameColumnMaxY = Integer.MIN_VALUE; - // Per-tick cache for the fluid drawn in the frame windows. Recomputed from the - // live (synced) input tanks so the displayed fluid and its fill ratio always - // come from the same source and stay consistent for every fluid type. - private long frameFluidCacheTick = -1; - private FluidStack frameFluidCache = FluidStack.EMPTY; - private float frameFluidFillRatioCache = 0f; + + private boolean needsToResolveEntities = false; private double fluidBuffer = 0.0; @@ -127,6 +119,7 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private final ReactorOutputManagerI outputManager; private final ReactorInputFluidManagerI inputFluidManager; private final ReactorAlarmManagerI alarmManager; + private final ReactorFrameDisplayManagerI frameDisplayManager; // Client Display Data (Synced via NBT) private Map clientDisplayItems = new HashMap<>(); @@ -188,79 +181,6 @@ public void setBigFluidStack(List b) { this.bigFluidStack = b; } - /** - * Returns the fluid currently held by the reactor, used by the frame - * renderer to draw the matching liquid in the window. On the client this - * reads the synced {@link #clientDisplayFluids}; on the server it reads the - * aggregated {@link #bigFluidStack}. Returns {@link FluidStack#EMPTY} when - * the reactor holds no fluid. - * - * Recomputes, at most once per game tick, the fluid shown in the frame - * windows and how full the input is. Both values are read from the same live - * input tanks (whose contents are synced to the client), so they always agree - * regardless of the fluid type. - */ - private void refreshFrameFluidCache() { - if (level == null) return; - long now = level.getGameTime(); - if (now == frameFluidCacheTick) return; - frameFluidCacheTick = now; - - long amount = 0; - long capacity = 0; - FluidStack fluid = FluidStack.EMPTY; - for (IFluidHandler handler : inputFluidManager.getFuildHandlers(level)) { - int tanks = handler.getTanks(); - for (int t = 0; t < tanks; t++) { - FluidStack stack = handler.getFluidInTank(t); - capacity += handler.getTankCapacity(t); - amount += stack.getAmount(); - if (fluid.isEmpty() && !stack.isEmpty()) fluid = stack.copy(); - } - } - - frameFluidCache = fluid; - frameFluidFillRatioCache = capacity > 0 ? Math.min(1f, (float) amount / (float) capacity) : 0f; - } - - /** The fluid currently shown in the reactor frame windows (may be empty). */ - public FluidStack getDisplayedFluid() { - refreshFrameFluidCache(); - return frameFluidCache; - } - - /** - * How full the reactor's fluid input is, in the range {@code [0, 1]}, used by - * the frame renderer to size the visible liquid column. - */ - public float getDisplayedFluidFillRatio() { - refreshFrameFluidCache(); - return frameFluidFillRatioCache; - } - - /** Records the lowest and highest frame block-Y of the assembled reactor. */ - public void setFrameColumn(int minY, int maxY) { - if (this.frameColumnMinY == minY && this.frameColumnMaxY == maxY) return; - this.frameColumnMinY = minY; - this.frameColumnMaxY = maxY; - notifyUpdate(); - } - - /** @return the lowest frame block-Y, or {@link Integer#MAX_VALUE} if unknown. */ - public int getFrameColumnMinY() { - return frameColumnMinY; - } - - /** @return the highest frame block-Y, or {@link Integer#MIN_VALUE} if unknown. */ - public int getFrameColumnMaxY() { - return frameColumnMaxY; - } - - public boolean hasFrameColumn() { - return frameColumnMinY != Integer.MAX_VALUE && frameColumnMaxY != Integer.MIN_VALUE - && frameColumnMaxY >= frameColumnMinY; - } - public int getMultiblockSize() { return this.reactorSize; } @@ -275,8 +195,7 @@ public String getMultiblockFacing() { } @Override - public void - setMultiblockFacing(String f) { + public void setMultiblockFacing(String f) { this.reactorFacing = f; } @@ -305,6 +224,14 @@ public void setLiquidLife(double l) { this.liquidLife = l; } + public ReactorFrameDisplayManagerI getFrameDisplayManager() { + return this.frameDisplayManager; + } + + public ReactorInputFluidManagerI getInputFluidManager() { + return this.inputFluidManager; + } + /** * Main constructor allowing dependency injection for testability and DIP * compliance. @@ -318,6 +245,7 @@ public ReactorControllerBlockEntity(BlockEntityType type, BlockPos pos, Block this.outputManager = new ReactorOutputManager(); this.inputFluidManager = new ReactorInputFluidManager(); this.alarmManager = new ReactorAlarmManager(); + this.frameDisplayManager = new ReactorFrameDisplayManager(); this.bigFuelItem = new BigItemStack(ItemStack.EMPTY); this.bigCoolerItem = new BigItemStack(ItemStack.EMPTY); @@ -415,15 +343,11 @@ protected void read(CompoundTag compound, boolean clientPacket) { this.outputManager.read(compound); this.inputFluidManager.read(compound); this.alarmManager.read(compound); + this.frameDisplayManager.read(compound); this.persistenceService.readBasicState(this, compound, clientPacket); this.needsToResolveEntities = true; - if (compound.contains("frameColumnMinY")) { - this.frameColumnMinY = compound.getInt("frameColumnMinY"); - this.frameColumnMaxY = compound.getInt("frameColumnMaxY"); - } - if (clientPacket) { clientDisplayItems.clear(); if (compound.contains("clientDisplayItems")) { @@ -465,12 +389,10 @@ protected void write(CompoundTag compound, boolean clientPacket) { this.outputManager.write(compound); this.inputFluidManager.write(compound); this.alarmManager.write(compound); + this.frameDisplayManager.write(compound); this.persistenceService.writeBasicState(this, compound, clientPacket); - compound.putInt("frameColumnMinY", frameColumnMinY); - compound.putInt("frameColumnMaxY", frameColumnMaxY); - if (clientPacket) { ListTag displayItemsTag = new ListTag(); for (Map.Entry entry : clientDisplayItems.entrySet()) { @@ -738,13 +660,7 @@ private void handleAssembledState() { if (!this.outputManager.getBlocksPosition().isEmpty()) { rotate(getBlockState(), getLevel(), heat); } - } /* - * else { - * EventTriggerPacket packet = new EventTriggerPacket(600); - * CreateNuclear.LOGGER.warn("hum EventTriggerBlock ? {}", packet); - * CNPackets.sendToNear(level, getBlockPos(), 32, packet); - * } - */ + } } private void triggerNuclearExplosion() { @@ -803,7 +719,7 @@ private void triggerNuclearExplosion() { } } - public void changeBiome(ResourceKey biomeResourceKey, int radius, BlockPos center, ServerLevel serverLevel) { + private void changeBiome(ResourceKey biomeResourceKey, int radius, BlockPos center, ServerLevel serverLevel) { Registry biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Holder targetBiomeHolder = biomeRegistry.getHolderOrThrow(biomeResourceKey); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java new file mode 100644 index 00000000..b6198791 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java @@ -0,0 +1,136 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.manager; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.nuclearteam.createnuclear.CreateNuclear; +import org.jetbrains.annotations.Nullable; + +public class ReactorFrameDisplayManager implements ReactorFrameDisplayManagerI { + public static final String COMPONENT_FRAME_COLUMN_MIN_Y = "frameColumnMinY"; + public static final String COMPONENT_FRAME_COLUMN_MAX_Y = "frameColumnMaxY"; + + // Vertical span (block Y) of the reactor frame columns, used to map the + // fluid fill ratio onto the liquid actually drawn in the frame windows. + private int frameColumnMinY = Integer.MAX_VALUE; + private int frameColumnMaxY = Integer.MIN_VALUE; + + // Per-tick cache for the fluid drawn in the frame windows. Recomputed from the + // live (synced) input tanks so the displayed fluid and its fill ratio always + // come from the same source and stay consistent for every fluid type. + private long frameFluidCacheTick = -1; + private float frameFluidFillRatioCache = 0f; + + + private FluidStack frameFluidCache = FluidStack.EMPTY; + +// /** +// * Returns the fluid currently held by the reactor, used by the frame +// * renderer to draw the matching liquid in the window. On the client this +// * reads the synced {@link #clientDisplayFluids}; on the server it reads the +// * aggregated {@link #bigFluidStack}. Returns {@link FluidStack#EMPTY} when +// * the reactor holds no fluid. +// *

+// * Recomputes, at most once per game tick, the fluid shown in the frame +// * windows and how full the input is. Both values are read from the same live +// * input tanks (whose contents are synced to the client), so they always agree +// * regardless of the fluid type. +// */ + private void refreshFrameFluidCache(@Nullable Level level, ReactorInputFluidManagerI handlers) { + if (level == null) return; + long now = level.getGameTime(); + + if (now == frameFluidCacheTick) return; + frameFluidCacheTick = now; + + long amount = 0, capacity = 0; + FluidStack fluid = FluidStack.EMPTY; + + for (IFluidHandler handler : handlers.getFuildHandlers(level)) { + int tanks = handler.getTanks(); + for (int t = 0; t < tanks; t++) { +// CreateNuclear.LOGGER.warn("tank: {}, stack: {}, capacity: {}, amount: {}", tanks, handler.getFluidInTank(t), handler.getTankCapacity(t), handler.getFluidInTank(t).getAmount()); + FluidStack stack = handler.getFluidInTank(t); + capacity += handler.getTankCapacity(t); + amount += stack.getAmount(); + + if (fluid.isEmpty() && !stack.isEmpty()) fluid = stack.copy(); + } + } + + frameFluidCache = fluid; + frameFluidFillRatioCache = capacity > 0 ? Math.min(1f, (float) amount / (float) capacity) : 0f; + } + + /** + * The fluid currently shown in the reactor frame windows (may be empty). + */ + @Override + public FluidStack getDisplayedFluid(Level level, ReactorInputFluidManagerI handlers) { + refreshFrameFluidCache(level, handlers); + + return frameFluidCache; + } + + /** + * How full the reactor's fluid input is, in the range {@code [0, 1]}, used by + * the frame renderer to size the visible liquid column. + */ + @Override + public float getDisplayedFluidFillRatio(Level level, ReactorInputFluidManagerI handlers) { + refreshFrameFluidCache(level, handlers); + + return frameFluidFillRatioCache; + } + + /** + * Records the lowest and highest frame block-Y of the assembled reactor. + */ + @Override + public void setFrameColumn(int minY, int maxY, Runnable onChange) { + if (this.frameColumnMinY == minY && this.frameColumnMaxY == maxY) return; + this.frameColumnMinY = minY; + this.frameColumnMaxY = maxY; + onChange.run(); + } + + /** + * @return the lowest frame block-Y, or {@link Integer#MAX_VALUE} if unknown. + */ + @Override + public int getFrameColumnMinY() { + return frameColumnMinY; + } + + /** + * @return the highest frame block-Y, or {@link Integer#MIN_VALUE} if unknown. + */ + @Override + public int getFrameColumnMaxY() { + return frameColumnMaxY; + } + + @Override + public boolean hasFrameColumn() { + return frameColumnMinY != Integer.MAX_VALUE && frameColumnMaxY != Integer.MIN_VALUE + && frameColumnMaxY >= frameColumnMinY; + } + + @Override + public void read(CompoundTag compound) { + if (compound.contains(COMPONENT_FRAME_COLUMN_MIN_Y)) { + frameColumnMinY = compound.getInt(COMPONENT_FRAME_COLUMN_MIN_Y); + } + + if (compound.contains(COMPONENT_FRAME_COLUMN_MAX_Y)) { + frameColumnMaxY = compound.getInt(COMPONENT_FRAME_COLUMN_MAX_Y); + } + } + + @Override + public void write(CompoundTag compound) { + compound.putInt(COMPONENT_FRAME_COLUMN_MIN_Y, frameColumnMinY); + compound.putInt(COMPONENT_FRAME_COLUMN_MAX_Y, frameColumnMaxY); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManagerI.java new file mode 100644 index 00000000..7203591b --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManagerI.java @@ -0,0 +1,47 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.manager; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraftforge.fluids.FluidStack; + +/** + * Manages the display state of the reactor frame windows: the fluid shown, + * its fill ratio, and the vertical column bounds of the assembled frame. + */ +public interface ReactorFrameDisplayManagerI { + /** + * Returns the fluid currently shown in the reactor frame windows (may be + * empty). Recomputes the underlying cache at most once per game tick from + * the given fluid handlers. + */ + FluidStack getDisplayedFluid(Level level, ReactorInputFluidManagerI handlers); + + /** + * Returns how full the reactor's fluid input is, in the range {@code [0, 1]}. + * Recomputes the underlying cache at most once per game tick from the + * given fluid handlers. + */ + float getDisplayedFluidFillRatio(Level level, ReactorInputFluidManagerI handlers); + + /** + * Records the lowest and highest frame block-Y of the assembled reactor. + * If the values changed, {@code onChange} is invoked (e.g. to trigger a + * client sync via {@code notifyUpdate()}). + */ + void setFrameColumn(int minY, int maxY, Runnable onChange); + + /** @return the lowest frame block-Y, or {@link Integer#MAX_VALUE} if unknown. */ + int getFrameColumnMinY(); + + /** @return the highest frame block-Y, or {@link Integer#MIN_VALUE} if unknown. */ + int getFrameColumnMaxY(); + + /** @return true if both frame column bounds are known and consistent. */ + boolean hasFrameColumn(); + + /** Reads state from an NBT tag (deserialization). */ + void read(CompoundTag compound); + + /** Writes state to an NBT tag (serialization). */ + void write(CompoundTag compound); +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrameRenderer.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrameRenderer.java index 0276d580..3353281f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrameRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrameRenderer.java @@ -7,6 +7,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraftforge.fluids.FluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorFrameDisplayManagerI; /** * Renders the reactor fluid dynamically inside the {@link ReactorFrame} window. @@ -30,7 +31,9 @@ protected void renderSafe(ReactorFrameEntity be, float partialTicks, PoseStack m ReactorControllerBlockEntity controller = be.getControllerEntity(); if (controller == null) return; - FluidStack fluid = controller.getDisplayedFluid(); + ReactorFrameDisplayManagerI frameDisplay = controller.getFrameDisplayManager(); + + FluidStack fluid = frameDisplay.getDisplayedFluid(controller.getLevel(), controller.getInputFluidManager()); if (fluid == null || fluid.isEmpty()) return; // Local vertical bounds of the liquid volume inside this block, matching @@ -51,10 +54,10 @@ protected void renderSafe(ReactorFrameEntity be, float partialTicks, PoseStack m // from the bottom frame's lip (frameMinY + 4/16) to the top frame's cap // (frameMaxY + 9/16), so even a nearly-empty reactor still shows a sliver. float yMax = boxYMax; - if (controller.hasFrameColumn()) { - float ratio = controller.getDisplayedFluidFillRatio(); - double liquidBottomWorldY = controller.getFrameColumnMinY() + 4.0 / 16.0; - double liquidTopWorldY = controller.getFrameColumnMaxY() + 9.0 / 16.0; + if (frameDisplay.hasFrameColumn()) { + float ratio = frameDisplay.getDisplayedFluidFillRatio(controller.getLevel(), controller.getInputFluidManager()); + double liquidBottomWorldY = frameDisplay.getFrameColumnMinY() + 4.0 / 16.0; + double liquidTopWorldY = frameDisplay.getFrameColumnMaxY() + 9.0 / 16.0; double surfaceWorldY = liquidBottomWorldY + ratio * (liquidTopWorldY - liquidBottomWorldY); double localSurface = surfaceWorldY - be.getBlockPos().getY(); if (localSurface <= boxYMin) return; // liquid level is below this block From 01d5eb55f74669c5257a2fa7986f9a0baff23399 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 13 Jun 2026 22:05:53 +0200 Subject: [PATCH 004/171] refactor: replace stringly-typed multiblock facing/bounds with Direction and BoundingBox IMultiblockController.setMultiblockFacing/getMultiblockFacing and ReactorControllerBlockEntity's reactorFacing now use Direction instead of a raw String ("north"/"east"/...), and reactorPos/multiblockStructure now uses vanilla's BoundingBox instead of a hand-rolled [xMin,xMax,yMin,yMax,zMin,zMax] int array. MultiBlockManagerBeta and ReactorPattern.isInReactorRange are updated accordingly, with isInReactorRange now delegating to BoundingBox.isInside. DefaultPersistenceService serializes the facing via Direction.getSerializedName()/byName and the structure bounds via BoundingBox.CODEC. ReactorAssembler gains a static getStructureBound(BlockPos, int, Direction) computing the reactor's BoundingBox from its center, size, and facing, replacing the old @Deprecated getStructureBounds/applyOffset switch-based lookup tables on the controller (also removes the dead @Deprecated getBlockPosForReactor). findAndRegisterSpecialBlocks now takes a BoundingBox. Extract the reactor explosion's circular biome-irradiation logic out of ReactorControllerBlockEntity.changeBiome/createCircularResolver into a new BiomeIrradiationService, with biome-tag-based target resolution via BiomeIrradiationMapping/BiomeIrradiationMappings (overworld/nether/end each map to their own irradiated biome instead of always Irradiated Plains). --- .../api/multiblock/IMultiblockController.java | 6 +- .../api/multiblock/MultiBlockManagerBeta.java | 2 +- .../content/multiblock/ReactorAssembler.java | 30 ++- .../ReactorControllerBlockEntity.java | 176 +----------------- .../service/DefaultPersistenceService.java | 15 +- .../multiblock/pattern/ReactorPattern.java | 10 +- .../biome/BiomeIrradiationMapping.java | 8 + .../biome/BiomeIrradiationMappings.java | 28 +++ .../biome/BiomeIrradiationService.java | 70 +++++++ 9 files changed, 161 insertions(+), 184 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMapping.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMappings.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java index f2880929..7a9478dc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/IMultiblockController.java @@ -1,6 +1,8 @@ package net.nuclearteam.createnuclear.api.multiblock; +import net.minecraft.core.Direction; + public interface IMultiblockController { - void setMultiblockFacing(String f); - String getMultiblockFacing(); + void setMultiblockFacing(Direction f); + Direction getMultiblockFacing(); } diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java index c5b2ed11..d74b16a6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java @@ -30,7 +30,7 @@ public BlockPattern findStructure(Level level, BlockPos pos, IMultiblockContr for (BlockPattern structure : structures) { boolean result = structure.structure().matches(level, pos, direction); if (result){ - entity.setMultiblockFacing(direction.getCounterClockWise().getName()); + entity.setMultiblockFacing(direction.getCounterClockWise()); return structure; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 888aeaf8..d7eafb09 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -3,12 +3,14 @@ import net.createmod.catnip.lang.LangBuilder; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.phys.AABB; import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.CreateNuclear; @@ -51,7 +53,7 @@ public static void assemble(BlockPos pos, Level level) { entity.setMultiblockSize(result.data().getSize()); entity.setAssembled(true); - entity.setMultiblockStructure(entity.getStructureBounds(pos, entity.getMultiblockSize(), entity.getMultiblockFacing())); + entity.setMultiblockStructure(ReactorAssembler.getStructureBound(pos, entity.getMultiblockSize(), entity.getMultiblockFacing())); findAndRegisterSpecialBlocks(entity.getMultiblockPos(), entity, level); } @@ -69,10 +71,10 @@ public static void disassemble(BlockPos pos, Level level) { entity.removeIOAll(); } - public static void findAndRegisterSpecialBlocks(int[] reactorPos, ReactorControllerBlockEntity entity, Level level) { - int xMin = reactorPos[0], xMax = reactorPos[1]; - int yMin = reactorPos[2], yMax = reactorPos[3]; - int zMin = reactorPos[4], zMax = reactorPos[5]; + public static void findAndRegisterSpecialBlocks(BoundingBox reactorPos, ReactorControllerBlockEntity entity, Level level) { + int xMin = reactorPos.minX(), xMax = reactorPos.maxX(); + int yMin = reactorPos.minY(), yMax = reactorPos.maxY(); + int zMin = reactorPos.minZ(), zMax = reactorPos.maxZ(); final Block reactorOutputBlock = CNBlocks.REACTOR_OUTPUT.get(); final Block reactorInputBlock = CNBlocks.REACTOR_INPUT.get(); @@ -145,4 +147,22 @@ private static void sendMessageToPlayer(Level level, BlockPos pos, LangBuilder c ChatFormatting.GOLD, configRadius, configWarnAll ); } + + public static BoundingBox getStructureBound(BlockPos center, int size, Direction facing) { + int radius = (size - 1) / 2; + int height = radius + 1; + int depth = size - 1; + Direction into = facing.getOpposite(); + + int axisX = into.getStepX() * depth; + int axisZ = into.getStepZ() * depth; + + int minX = center.getX() + Math.min(0, axisX) - (axisX == 0 ? radius : 0); + int maxX = center.getX() + Math.max(0, axisX) + (axisX == 0 ? radius : 0); + int minZ = center.getZ() + Math.min(0, axisZ) - (axisZ == 0 ? radius : 0); + int maxZ = center.getZ() + Math.max(0, axisZ) + (axisZ == 0 ? radius : 0); + + return new BoundingBox(minX, center.getY() - height, minZ, + maxX, center.getY() + height, maxZ); + } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 62031da9..129bcb0d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -8,10 +8,7 @@ import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.foundation.utility.IInteractionChecker; import net.minecraft.ChatFormatting; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; +import net.minecraft.core.*; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -32,6 +29,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.material.Fluid; import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.fluids.FluidStack; @@ -56,6 +54,7 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.ConsumptionCycleManager; import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; +import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.BiomeIrradiationService; import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNBiomes; import java.util.ArrayList; @@ -105,9 +104,9 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private List bigFluidStack; private int reactorSize = 0; - private String reactorFacing = "null"; + private Direction reactorFacing = null; // les pos sont [xMin, xMax, yMin, yMax, zMin, zMax] - private int[] reactorPos; + private BoundingBox reactorPos; private boolean needsToResolveEntities = false; @@ -190,12 +189,12 @@ public void setMultiblockSize(int s) { } @Override - public String getMultiblockFacing() { + public Direction getMultiblockFacing() { return this.reactorFacing; } @Override - public void setMultiblockFacing(String f) { + public void setMultiblockFacing(Direction f) { this.reactorFacing = f; } @@ -204,11 +203,11 @@ public CNAdvancementBehaviour getAdvancement() { } /** Main constructor allowing dependency injection for testability and DIP compliance. */ - public int[] getMultiblockPos() { + public BoundingBox getMultiblockPos() { return this.reactorPos; } - public void setMultiblockStructure(int[] p) { + public void setMultiblockStructure(BoundingBox p) { this.reactorPos = p; } @@ -715,72 +714,10 @@ private void triggerNuclearExplosion() { level.destroyBlock(getBlockPos(), false); // Changement de biome vers Irradiated Plain - changeBiome(CNBiomes.Irradiated.PLAIN, (int) size * 30, explosionPos, serverLevel); + BiomeIrradiationService.circularArea(serverLevel, explosionPos, CNBiomes.Irradiated.PLAIN, (int) (size * 30)); } } - private void changeBiome(ResourceKey biomeResourceKey, int radius, BlockPos center, ServerLevel serverLevel) { - Registry biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); - Holder targetBiomeHolder = biomeRegistry.getHolderOrThrow(biomeResourceKey); - - // Vérification rapide du centre - Holder current = serverLevel.getBiome(center); - if (current.is(biomeResourceKey)) { - return; - } - - // Définition de la zone de recherche (Bounding Box carrée qui contient le - // cercle) - int minX = center.getX() - radius; - int maxX = center.getX() + radius; - int minZ = center.getZ() - radius; - int maxZ = center.getZ() + radius; - - double radiusSq = (double) radius * radius; - ArrayList chunks = new ArrayList<>(); - - // On parcourt les chunks impactés - for (int cz = SectionPos.blockToSectionCoord(minZ); cz <= SectionPos.blockToSectionCoord(maxZ); ++cz) { - for (int cx = SectionPos.blockToSectionCoord(minX); cx <= SectionPos.blockToSectionCoord(maxX); ++cx) { - ChunkAccess chunkAccess = serverLevel.getChunk(cx, cz, ChunkStatus.FULL, false); - if (chunkAccess != null) { - // On utilise un resolver personnalisé qui vérifie la distance - chunkAccess.fillBiomesFromNoise( - createCircularResolver(targetBiomeHolder, center, radiusSq, serverLevel), - serverLevel.getChunkSource().randomState().sampler()); - chunkAccess.setUnsaved(true); - chunks.add(chunkAccess); - } - } - } - - // Notification aux clients - serverLevel.getChunkSource().chunkMap.resendBiomesForChunks(chunks); - } - - // Le resolver magique pour la forme circulaire - private BiomeResolver createCircularResolver(Holder targetBiome, BlockPos center, double radiusSq, - ServerLevel level) { - return (x, y, z, noise) -> { - // x, y, z ici sont en "biome coordinates" (1 unité = 4 blocs) - // On les multiplie par 4 pour revenir à une échelle de blocs - int blockX = x << 2; - int blockZ = z << 2; - - double distX = blockX - center.getX(); - double distZ = blockZ - center.getZ(); - - // Equation du cercle : x² + z² <= r² - if ((distX * distX) + (distZ * distZ) <= radiusSq) { - return targetBiome; - } - - // Si hors du cercle, on garde le biome d'origine (ou on laisse le bruit faire) - // Note : Ici on demande au niveau le biome actuel à cette position - return level.getBiome(new BlockPos(blockX, y << 2, blockZ)); - }; - } - private boolean isReadyToRun() { return !isEmptyConfiguredPattern() && bigFuelItem.count > 0 @@ -812,30 +749,6 @@ private boolean updateLiquidTimers() { return liquidLife <= 0; } - @Deprecated - private BlockPos getBlockPosForReactor(char character) { - BlockPos pos = pattern.VerifyPattern5x5(character); - BlockPos posController = getBlockPos(); - BlockPos posInput = new BlockPos(posController.getX(), posController.getY(), posController.getZ()); - - int[][] directions = { - { 0, 0, pos.getX() }, // NORTH - { 0, 0, -pos.getX() }, // SOUTH - { -pos.getX(), 0, 0 }, // EAST - { pos.getX(), 0, 0 } // WEST - }; - - for (int[] direction : directions) { - BlockPos newPos = posController.offset(direction[0], direction[1], direction[2]); - if (level.getBlockState(newPos).is(CNBlocks.REACTOR_INPUT.get())) { - posInput = newPos; - break; - } - } - - return posInput; - } - public void rotate(BlockState state, Level level, int rotation) { if (this.outputManager.getBlocksPosition().isEmpty()) return; @@ -872,75 +785,6 @@ public void rotate(BlockState state, Level level, int rotation) { } } - @Deprecated - public int[] getStructureBounds(BlockPos startPos, int structureSize, String facing) { - int[] northOffsets5x5 = new int[] { -2, 2, -3, 3, 0, 4 }; - int[] northOffsets7x7 = new int[] { -3, 3, -4, 4, 0, 6 }; - int[] northOffsets9x9 = new int[] { -4, 4, -5, 5, 0, 8 }; - - int[] eastOffsets5x5 = new int[] { -4, 0, -3, 3, -2, 2 }; - int[] eastOffsets7x7 = new int[] { -6, 0, -4, 4, -3, 3 }; - int[] eastOffsets9x9 = new int[] { -8, 0, -5, 5, -4, 4 }; - - int[] southOffsets5x5 = new int[] { -2, 2, -3, 3, -4, 0 }; - int[] southOffsets7x7 = new int[] { -3, 3, -4, 4, -6, 0 }; - int[] southOffsets9x9 = new int[] { -4, 4, -5, 5, -8, 0 }; - - int[] westOffsets5x5 = new int[] { 0, 4, -3, 3, -2, 2 }; - int[] westOffsets7x7 = new int[] { 0, 6, -4, 4, -3, 3 }; - int[] westOffsets9x9 = new int[] { 0, 8, -5, 5, -4, 4 }; - - switch (facing) { - case "north": - switch (structureSize) { - case 5: - return applyOffset(startPos, northOffsets5x5); - case 7: - return applyOffset(startPos, northOffsets7x7); - case 9: - return applyOffset(startPos, northOffsets9x9); - } - case "east": - switch (structureSize) { - case 5: - return applyOffset(startPos, eastOffsets5x5); - case 7: - return applyOffset(startPos, eastOffsets7x7); - case 9: - return applyOffset(startPos, eastOffsets9x9); - } - case "south": - switch (structureSize) { - case 5: - return applyOffset(startPos, southOffsets5x5); - case 7: - return applyOffset(startPos, southOffsets7x7); - case 9: - return applyOffset(startPos, southOffsets9x9); - } - case "west": - switch (structureSize) { - case 5: - return applyOffset(startPos, westOffsets5x5); - case 7: - return applyOffset(startPos, westOffsets7x7); - case 9: - return applyOffset(startPos, westOffsets9x9); - } - default: - return new int[] { 0, 0, 0, 0, 0, 0 }; - } - } - - @Deprecated - private int[] applyOffset(BlockPos pos, int[] offset) { - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); - - return new int[] { x + offset[0], x + offset[1], y + offset[2], y + offset[3], z + offset[4], z + offset[5] }; - } - public void addInput(BlockPos inputPos) { this.inputManager.addBlock(inputPos); this.setChanged(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java index 30a4611c..854cc992 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java @@ -1,16 +1,23 @@ package net.nuclearteam.createnuclear.content.multiblock.controller.service; import com.simibubi.create.content.logistics.BigItemStack; +import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; public class DefaultPersistenceService implements IPersistenceService { @Override public void readBasicState(ReactorControllerBlockEntity owner, CompoundTag compound, boolean clientPacket) { owner.setMultiblockSize(compound.getInt("reactorSize")); - owner.setMultiblockFacing(compound.getString("reactorFacing")); - owner.setMultiblockStructure(compound.getIntArray("reactorPose")); + owner.setMultiblockFacing(Direction.byName(compound.getString("reactorFacing"))); + + owner.setMultiblockStructure(compound.contains("reactorPose") + ? BoundingBox.CODEC.parse(NbtOps.INSTANCE, compound.get("reactorPose")).result().orElse(null) + : null + ); owner.setLiquidLife(compound.getDouble("liquidLife")); if (!clientPacket) { @@ -25,9 +32,9 @@ public void readBasicState(ReactorControllerBlockEntity owner, CompoundTag compo @Override public void writeBasicState(ReactorControllerBlockEntity owner, CompoundTag compound, boolean clientPacket) { compound.putInt("reactorSize", owner.getMultiblockSize()); - compound.putString("reactorFacing", owner.getMultiblockFacing()); + compound.putString("reactorFacing", owner.getMultiblockFacing() != null ? owner.getMultiblockFacing().getSerializedName() : ""); if (owner.getMultiblockPos() != null) { - compound.putIntArray("reactorPose", owner.getMultiblockPos()); + compound.put("reactorPose", BoundingBox.CODEC.encodeStart(NbtOps.INSTANCE, owner.getMultiblockPos()).getOrThrow(false, IllegalStateException::new)); } if (!clientPacket) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java index faef72fb..9422c309 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java @@ -8,9 +8,11 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.content.multiblock.ReactorAssembler; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Predicate; @@ -132,11 +134,7 @@ public BlockPos findControllerPos(BlockPos blockPos, Level level){ return null; } - public boolean isInReactorRange(int []reactorPos, BlockPos blockPos) { - //[xMin, xMax, yMin, yMax, zMin, zMax] - if (reactorPos == null || reactorPos.length < 6) return false; - return blockPos.getX() >= reactorPos[0] && blockPos.getX() <= reactorPos[1] - && blockPos.getY() >= reactorPos[2] && blockPos.getY() <= reactorPos[3] - && blockPos.getZ() >= reactorPos[4] && blockPos.getZ() <= reactorPos[5]; + public boolean isInReactorRange(@Nullable BoundingBox reactorPos, BlockPos blockPos) { + return reactorPos != null && reactorPos.isInside(blockPos); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMapping.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMapping.java new file mode 100644 index 00000000..707f9a55 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMapping.java @@ -0,0 +1,8 @@ +package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.biome.Biome; + +public record BiomeIrradiationMapping(TagKey sourceTag, ResourceKey target) { +} diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMappings.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMappings.java new file mode 100644 index 00000000..8a3a0496 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationMappings.java @@ -0,0 +1,28 @@ +package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; + +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceKey; +import net.minecraft.tags.BiomeTags; +import net.minecraft.world.level.biome.Biome; + +import java.util.List; + +public class BiomeIrradiationMappings { + private static final List MAPPINGS = List.of( + new BiomeIrradiationMapping(BiomeTags.IS_OVERWORLD, CNBiomes.Irradiated.PLAIN), + new BiomeIrradiationMapping(BiomeTags.IS_NETHER, CNBiomes.Irradiated.PLAIN), + new BiomeIrradiationMapping(BiomeTags.IS_END, CNBiomes.Irradiated.PLAIN) + ); + + private BiomeIrradiationMappings() {} + + public static ResourceKey resolveTarget(Holder currentBiome, ResourceKey fallback) { + for (BiomeIrradiationMapping mapping : MAPPINGS) { + if (currentBiome.is(mapping.sourceTag())) { + return mapping.target(); + } + } + + return fallback; + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java new file mode 100644 index 00000000..1043e989 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java @@ -0,0 +1,70 @@ +package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeResolver; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; + +import java.util.ArrayList; +import java.util.List; + +public final class BiomeIrradiationService { + public static void circularArea(ServerLevel serverLevel, BlockPos center, ResourceKey defaultTarget, int radius) { + Registry biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + + Holder currentAtCenter = serverLevel.getBiome(center); + ResourceKey targetAtCenter = BiomeIrradiationMappings.resolveTarget(currentAtCenter, defaultTarget); + if (currentAtCenter.is(targetAtCenter)) { + return; + } + + int minX = center.getX() - radius; + int maxX = center.getX() + radius; + int minZ = center.getZ() - radius; + int maxZ = center.getZ() + radius; + + double radiusSq = radius * radius; + BiomeResolver resolver = createCircularResolver(biomeRegistry, center, radiusSq, defaultTarget, serverLevel); + + List chunks = new ArrayList<>(); + for (int cz = SectionPos.blockToSectionCoord(minZ); cz < SectionPos.blockToSectionCoord(maxZ); ++cz) { + for (int cx = SectionPos.blockToSectionCoord(minX); cx < SectionPos.blockToSectionCoord(maxX); ++cx) { + ChunkAccess chunkAccess = serverLevel.getChunk(cx, cz, ChunkStatus.FULL, false); + if (chunkAccess != null) { + chunkAccess.fillBiomesFromNoise(resolver, serverLevel.getChunkSource().randomState().sampler()); + chunkAccess.setUnsaved(true); + chunks.add(chunkAccess); + } + } + } + + serverLevel.getChunkSource().chunkMap.resendBiomesForChunks(chunks); + } + + private static BiomeResolver createCircularResolver(Registry biomeRegistry, BlockPos center, double radiusSq, ResourceKey defaultTarget, ServerLevel level) { + return (x, y, z, noise) -> { + int blockX = x << 2; + int blockZ = z << 2; + + double distX = blockX - center.getX(); + double distZ = blockZ - center.getZ(); + + Holder current = level.getBiome(new BlockPos(blockX, y << 2, blockZ)); + + if ((distX * distX) + (distZ * distZ) <= radiusSq) { + ResourceKey target = BiomeIrradiationMappings.resolveTarget(current, defaultTarget); + + return biomeRegistry.getHolderOrThrow(target); + } + + return current; + }; + } +} From cedf05cdb97be3a54b4dc5d504585bd959a942f9 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 13 Jun 2026 22:15:48 +0200 Subject: [PATCH 005/171] chore: remove unused imports across multiblock, radiation and worldgen packages Sweep of dead/unused imports left over from previous refactors: SimpleMultiBlockAislePatternBuilder, ClientEvents, ReactorFluidTypesValue, SmithingClothRecipeBuilder, MultiBlockManagerBeta, AnimalUtil, VicinityEffect, ClothItem, BigFluidStack, ReactorAssembler, ReactorControllerBlockEntity, ReactorSummaryDisplaySource, CNDensityFunctions and IrradiatedBiomes. Also move the RADIATION_VALUE static import below the regular imports in RadiationCapability and drop a stray blank line in IRadiationCapability, with no behavioral change. --- .../multiblock/SimpleMultiBlockAislePatternBuilder.java | 2 -- .../java/net/nuclearteam/createnuclear/ClientEvents.java | 1 - .../createnuclear/api/ReactorFluidTypesValue.java | 5 ----- .../api/data/recipe/SmithingClothRecipeBuilder.java | 1 - .../api/multiblock/MultiBlockManagerBeta.java | 2 -- .../content/contraptions/irradiated/AnimalUtil.java | 1 - .../createnuclear/content/effects/VicinityEffect.java | 2 -- .../createnuclear/content/equipment/cloth/ClothItem.java | 4 ---- .../createnuclear/content/logistics/BigFluidStack.java | 1 - .../createnuclear/content/multiblock/ReactorAssembler.java | 2 -- .../controller/ReactorControllerBlockEntity.java | 7 ------- .../content/radiation/capability/IRadiationCapability.java | 1 - .../content/radiation/capability/RadiationCapability.java | 3 ++- .../displayLink/source/ReactorSummaryDisplaySource.java | 1 - .../infrastructure/worldgen/biome/CNDensityFunctions.java | 1 - .../infrastructure/worldgen/biome/IrradiatedBiomes.java | 2 -- 16 files changed, 2 insertions(+), 34 deletions(-) diff --git a/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java b/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java index dbcf2161..77b34369 100644 --- a/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java +++ b/src/main/java/lib/multiblock/SimpleMultiBlockAislePatternBuilder.java @@ -10,7 +10,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.nuclearteam.createnuclear.CreateNuclear; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -19,7 +18,6 @@ import java.util.Map; import java.util.function.Predicate; import java.util.function.Supplier; -import java.util.stream.Stream; public class SimpleMultiBlockAislePatternBuilder implements IMultiBlockPatternBuilder { public static SimpleMultiBlockAislePatternBuilder start() { diff --git a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java b/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java index 3b085982..7d6e575e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java @@ -1,7 +1,6 @@ package net.nuclearteam.createnuclear; import net.minecraft.client.Minecraft; -import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraftforge.api.distmarker.Dist; diff --git a/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java b/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java index b18370c5..67a05e4f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java @@ -4,13 +4,8 @@ import com.tterrag.registrate.util.nullness.NonNullConsumer; import net.minecraft.core.HolderSet; import net.minecraft.world.level.material.Fluid; -import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.util.Map; -import net.minecraftforge.registries.ForgeRegistries; import java.util.Collections; /** diff --git a/src/main/java/net/nuclearteam/createnuclear/api/data/recipe/SmithingClothRecipeBuilder.java b/src/main/java/net/nuclearteam/createnuclear/api/data/recipe/SmithingClothRecipeBuilder.java index 5c14f8d6..45a9f9bc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/data/recipe/SmithingClothRecipeBuilder.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/data/recipe/SmithingClothRecipeBuilder.java @@ -6,7 +6,6 @@ import net.minecraft.advancements.CriterionTriggerInstance; import net.minecraft.advancements.RequirementsStrategy; import net.minecraft.advancements.critereon.RecipeUnlockedTrigger; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.data.recipes.RecipeBuilder; import net.minecraft.data.recipes.RecipeCategory; diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java index d74b16a6..a0178483 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/MultiBlockManagerBeta.java @@ -4,8 +4,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java index 357ec2b0..31d652d7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java @@ -10,7 +10,6 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraftforge.event.ForgeEventFactory; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java index a1daaa89..7d90d081 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java @@ -4,9 +4,7 @@ import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; -import net.nuclearteam.createnuclear.CreateNuclear; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/cloth/ClothItem.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/cloth/ClothItem.java index 04c8a6d2..2cef1a8c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/cloth/ClothItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/cloth/ClothItem.java @@ -1,13 +1,9 @@ package net.nuclearteam.createnuclear.content.equipment.cloth; import com.tterrag.registrate.util.entry.ItemEntry; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.Item; -import net.minecraft.world.item.armortrim.TrimMaterial; import net.nuclearteam.createnuclear.CNItems; -import net.nuclearteam.createnuclear.CreateNuclear; import java.util.*; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java b/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java index 8f764773..f7d906b4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java @@ -1,6 +1,5 @@ package net.nuclearteam.createnuclear.content.logistics; -import com.simibubi.create.content.logistics.BigItemStack; import net.nuclearteam.createnuclear.api.ReactorFluidTypesValue; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index d7eafb09..145dd52d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -4,8 +4,6 @@ import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 129bcb0d..f19b6de1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -9,12 +9,10 @@ import com.simibubi.create.foundation.utility.IInteractionChecker; import net.minecraft.ChatFormatting; import net.minecraft.core.*; -import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.world.item.Item; @@ -22,13 +20,9 @@ import net.minecraft.world.level.GameRules; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeResolver; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.material.Fluid; import net.minecraftforge.common.capabilities.ForgeCapabilities; @@ -37,7 +31,6 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.registries.ForgeRegistries; -import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.CNEntityType; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.multiblock.IMultiblockController; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java index cac84ed5..bd51ca2b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java @@ -2,7 +2,6 @@ import net.minecraft.resources.ResourceLocation; - public interface IRadiationCapability { double getRadiation(); void setRadiation(double value); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java index 6ad10f16..a4b4b309 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java @@ -21,10 +21,11 @@ import net.nuclearteam.createnuclear.api.radiation.IRadiationSource; import net.nuclearteam.createnuclear.api.radiation.RadiationRegistry; import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; -import static net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem.RADIATION_VALUE; import net.nuclearteam.createnuclear.foundation.utility.InventoryHashUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; +import static net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem.RADIATION_VALUE; + import java.util.Objects; public class RadiationCapability implements IRadiationCapability { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index f11f3112..d9f54b32 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -1,7 +1,6 @@ package net.nuclearteam.createnuclear.content.redstone.displayLink.source; import java.util.List; -import java.util.Optional; import java.util.stream.Stream; import com.simibubi.create.api.behaviour.display.DisplaySource; diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java index 521041a8..f5a6fe1c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNDensityFunctions.java @@ -6,7 +6,6 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.DensityFunctions; -import net.minecraft.world.level.levelgen.NoiseRouterData; import net.minecraft.world.level.levelgen.synth.BlendedNoise; import net.nuclearteam.createnuclear.CreateNuclear; diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 486a3e9b..7216d955 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -3,12 +3,10 @@ import net.minecraft.core.HolderGetter; import net.minecraft.data.worldgen.Carvers; import net.minecraft.data.worldgen.placement.MiscOverworldPlacements; -import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.biome.*; import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; import net.minecraft.world.level.levelgen.placement.PlacedFeature; -import net.nuclearteam.createnuclear.CNEntityType; import net.nuclearteam.createnuclear.content.particles.IrradiatedParticlesData; public class IrradiatedBiomes { From 62305467569556560686a37bc739126405e5e98c Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 14 Jun 2026 11:04:50 +0200 Subject: [PATCH 006/171] refactor: extract meltdown explosion logic into ReactorMeltdownExecutor and ReactorDebugDiagnostics Move triggerNuclearExplosion out of ReactorControllerBlockEntity into a new ReactorMeltdownExecutor (IExplosionService), computing explosion size, spawning the NuclearExplosionEntity, destroying the controller block and irradiating the surrounding biome. The block entity now delegates to this service via the existing service-injection pattern and just sets isExploding. Replace the verbose logReactorConnections debug dump (raw LOGGER.debug calls) with ReactorDebugDiagnostics.sendReactorConnectionsTo, which reports input, fluid input, output and alarm manager state directly to the requesting player as translated chat messages. Add the corresponding createnuclear.reactor.debug.* translation keys to reactor.json and update ReactorControllerBlock's paper-item handler to pass the player through. --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +- .../assets/createnuclear/lang/en_ud.json | 8 ++ .../assets/createnuclear/lang/en_us.json | 8 ++ .../controller/ReactorControllerBlock.java | 2 +- .../ReactorControllerBlockEntity.java | 99 ++----------------- .../controller/ReactorDebugDiagnostics.java | 57 +++++++++++ .../controller/service/IExplosionService.java | 17 ++++ .../service/ReactorMeltdownExecutor.java | 51 ++++++++++ .../createnuclear/lang/default/reactor.json | 11 ++- 9 files changed, 165 insertions(+), 94 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorDebugDiagnostics.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index c6682cb0..2ee25d6b 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-12T10:26:06.6469655 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-14T10:59:25.6995934 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -7bb5dcd5152f4dd85c6b52537d63759082bd0f93 assets/createnuclear/lang/en_ud.json -6954d485a4fbc88f8ad2ad8600a2f0bf3488af48 assets/createnuclear/lang/en_us.json +7c531dc3116eb3fa085703a98301994937b45d35 assets/createnuclear/lang/en_ud.json +aa99d9f5d01f1e0cd63e889ac1488f4a7cabedfe assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 834eb25a..ec92702f 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -251,6 +251,14 @@ "createnuclear.ponder.reactor_t3.text_7": "ϛ ɹooןℲ", "createnuclear.ponder.reactor_t3.text_8": ")buıɔɐןd ǝǝɹɟ( ʇuɐןooɔ ɹoɟ ǝuo puɐ poɹ ןǝnɟ ɟo ʇnduı ǝuo ǝʌɐɥ ʎןǝʞıן ןןıʍ noʎ ǝsnɐɔǝq pǝpǝǝu :ʇnduı puoɔǝS", "createnuclear.ponder.reactor_t3.text_9": "9 ɹooןℲ", + "createnuclear.reactor.debug.label.alarm": "ɯɹɐןⱯ", + "createnuclear.reactor.debug.label.fluid_input": "ʇnduI pınןℲ", + "createnuclear.reactor.debug.label.input": "ʇnduI", + "createnuclear.reactor.debug.label.output": "ʇndʇnO", + "createnuclear.reactor.debug.registered_position": "%s @ pǝɹǝʇsıbǝɹ ", + "createnuclear.reactor.debug.summary": "pıןɐʌ %s 'pǝɹǝʇsıbǝɹ %s :%s", + "createnuclear.reactor.debug.title": "--- sɔıʇsoubɐıp ɹoʇɔɐǝᴚ ---", + "createnuclear.reactor.debug.valid_position": "%s @ pıןɐʌ ", "createnuclear.snow_powder.fan.recipe": "uɐɟ ɔıuǝboʎɹƆ", "createnuclear.subtitle.alarm/alarm": "ɯɹɐןⱯ ɹoʇɔɐǝᴚ", "createnuclear.subtitle.alarm/reactor_alarm": "ɯɹɐןⱯ ɹoʇɔɐǝᴚ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index ee83e29c..cab8d3c7 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -251,6 +251,14 @@ "createnuclear.ponder.reactor_t3.text_7": "Floor 5", "createnuclear.ponder.reactor_t3.text_8": "Second input: needed because you will likely have one input of fuel rod and one for coolant (free placing)", "createnuclear.ponder.reactor_t3.text_9": "Floor 6", + "createnuclear.reactor.debug.label.alarm": "Alarm", + "createnuclear.reactor.debug.label.fluid_input": "Fluid Input", + "createnuclear.reactor.debug.label.input": "Input", + "createnuclear.reactor.debug.label.output": "Output", + "createnuclear.reactor.debug.registered_position": " registered @ %s", + "createnuclear.reactor.debug.summary": "%s: %s registered, %s valid", + "createnuclear.reactor.debug.title": "--- Reactor diagnostics ---", + "createnuclear.reactor.debug.valid_position": " valid @ %s", "createnuclear.snow_powder.fan.recipe": "Cryogenic fan", "createnuclear.subtitle.alarm/alarm": "Reactor Alarm", "createnuclear.subtitle.alarm/reactor_alarm": "Reactor Alarm", diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index dc0091f6..ed7b6028 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -91,7 +91,7 @@ public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Play ItemStack heldItem = player.getItemInHand(handIn); if (heldItem.is(Items.PAPER)) { - withBlockEntityDo(worldIn, pos, ReactorControllerBlockEntity::logReactorConnections); + withBlockEntityDo(worldIn, pos, be -> be.logReactorConnections(player)); } if (!state.getValue(ASSEMBLED)) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index f19b6de1..56ebd503 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -15,6 +15,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameRules; @@ -37,6 +38,7 @@ import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.CNMultiblock; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; +import net.nuclearteam.createnuclear.content.multiblock.controller.service.*; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.FluidLockManager; import net.nuclearteam.createnuclear.content.multiblock.IHeat; import net.nuclearteam.createnuclear.content.explosion.NuclearExplosionEntity; @@ -62,10 +64,6 @@ import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; -import net.nuclearteam.createnuclear.content.multiblock.controller.service.IHeatService; -import net.nuclearteam.createnuclear.content.multiblock.controller.service.DefaultHeatService; -import net.nuclearteam.createnuclear.content.multiblock.controller.service.IPersistenceService; -import net.nuclearteam.createnuclear.content.multiblock.controller.service.DefaultPersistenceService; import java.util.Map; @@ -121,6 +119,7 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity // services (dependencies) - abstracted behind interfaces to follow DIP private final IHeatService heatService; private final IPersistenceService persistenceService; + private final IExplosionService meltdownExecutor; // service fields are injected; implementations live in separate classes @@ -245,6 +244,7 @@ public ReactorControllerBlockEntity(BlockEntityType type, BlockPos pos, Block this.heatService = new DefaultHeatService(new HeatManager()); this.persistenceService = new DefaultPersistenceService(); + this.meltdownExecutor = new ReactorMeltdownExecutor(); } @Override @@ -426,34 +426,8 @@ public void setAssembled(boolean assembled) { this.setChanged(); } - public void logReactorConnections() { - CreateNuclear.LOGGER.debug("Reactor input count: {}", this.inputManager.size()); - CreateNuclear.LOGGER.debug("Reactor output count: {}", this.outputManager.size()); - CreateNuclear.LOGGER.debug("Reactor fluid input count: {}", this.inputFluidManager.size()); - - for (BlockPos pos : this.inputManager.getBlocksPosition()) { - CreateNuclear.LOGGER.debug("Registered reactor input position: {}", pos); - } - - for (BlockPos pos : this.inputManager.getBlocksPosition(level)) { - CreateNuclear.LOGGER.debug("Valid reactor input position: {}", pos); - } - - for (BlockPos pos : this.outputManager.getBlocksPosition()) { - CreateNuclear.LOGGER.debug("Registered reactor output position: {}", pos); - } - - for (BlockPos pos : this.outputManager.getBlocksPosition(level)) { - CreateNuclear.LOGGER.debug("Valid reactor output position: {}", pos); - } - - for (BlockPos pos : this.inputFluidManager.getBlocksPosition()) { - CreateNuclear.LOGGER.debug("Registered reactor fluid input position: {}", pos); - } - - for (BlockPos pos : this.inputFluidManager.getBlocksPosition(level)) { - CreateNuclear.LOGGER.debug("Valid reactor fluid input position: {}", pos); - } + public void logReactorConnections(Player player) { + ReactorDebugDiagnostics.sendReactorConnectionsTo(player, level, inputManager, inputFluidManager, outputManager, alarmManager); } private void updateReactorStateVisibility() { @@ -516,7 +490,10 @@ public void tick() { CreateNuclearLang.translate("notification.reactor.imminent_explosion"), ChatFormatting.DARK_RED, configRadius, configWarnAll, 0, 40, 10); - triggerNuclearExplosion(); + if (level instanceof ServerLevel serverLevel) { + this.meltdownExecutor.triggerExplosion(serverLevel, getBlockPos(), reactorSize, countUraniumRod); + } + isExploding = true; return; } } else { @@ -655,62 +632,6 @@ private void handleAssembledState() { } } - private void triggerNuclearExplosion() { - if (isExploding) - return; - isExploding = true; - - BlockPos explosionPos = getBlockPos().above(5); - int configRadius = CNConfigs.server().notify.distanceOfWarning.get(); - boolean configWarnAll = CNConfigs.server().notify.warnAllPlayers.get(); - - if (level instanceof ServerLevel serverLevel) { - // --- MESSAGE D'EXPLOSION FINALE (TRADUIT) --- - NotifyUtil.sendTitle(level, getBlockPos(), - CreateNuclearLang.translate("notification.reactor.destroyed"), - CreateNuclearLang.translate("notification.reactor.meltdown_finished"), - ChatFormatting.DARK_RED, configRadius, configWarnAll, 10, 60, 20); - - NuclearExplosionEntity explosion = new NuclearExplosionEntity( - CNEntityType.NUCLEAR_EXPLOSION.get(), - serverLevel); - - // --- CALCUL D'EXPLOSION ÉQUILIBRÉ --- - - // 1. On définit un modificateur de structure plus progressif - // Au lieu de 1, 2, 3, on utilise un ratio basé sur la taille réelle - float structureFactor = reactorSize / 5.0F; // 5x5 -> 1.0 | 7x7 -> 1.4 | 9x9 -> 1.8 - - /* - * 2. Utilisation de la racine carrée (Mth.sqrt) - * L'uranium augmente la puissance, mais avec des rendements décroissants. - * Plus on ajoute d'uranium, plus chaque barre supplémentaire ajoute "moins" au - * rayon. - */ - float fuelImpact = Mth.sqrt(countUraniumRod) * 0.3F; - - // 3. Taille finale : Base constante + (Impact Fuel * Facteur Structure) - float size = 1.5F + (fuelImpact * structureFactor); - - size = Mth.clamp(size, 1.0F, 10.0F); - - explosion.setPos(explosionPos.getX() + 0.5D, explosionPos.getY() + 10.0D, explosionPos.getZ() - 2.0D); - explosion.setSize(size); - - // Griefing selon les gamerules - boolean griefing = serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - explosion.setNoGriefing(!griefing); - - serverLevel.addFreshEntity(explosion); - - // On détruit le bloc après avoir envoyé les messages - level.destroyBlock(getBlockPos(), false); - - // Changement de biome vers Irradiated Plain - BiomeIrradiationService.circularArea(serverLevel, explosionPos, CNBiomes.Irradiated.PLAIN, (int) (size * 30)); - } - } - private boolean isReadyToRun() { return !isEmptyConfiguredPattern() && bigFuelItem.count > 0 diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorDebugDiagnostics.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorDebugDiagnostics.java new file mode 100644 index 00000000..e1e7b744 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorDebugDiagnostics.java @@ -0,0 +1,57 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller; + +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.*; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; + +import java.util.Collection; + +public class ReactorDebugDiagnostics { + private static final String TITLE = "reactor.debug.title"; + private static final String SUMMARY = "reactor.debug.summary"; + private static final String REGISTERED_POSITION = "reactor.debug.registered_position"; + private static final String VALID_POSITION = "reactor.debug.valid_position"; + + private static final String INPUT = "reactor.debug.label.input"; + private static final String INPUT_FLUID = "reactor.debug.label.fluid_input"; + private static final String OUTPUT = "reactor.debug.label.output"; + private static final String ALARM = "reactor.debug.label.alarm"; + + private ReactorDebugDiagnostics() {} + + public static void sendReactorConnectionsTo(Player player, Level level, + ReactorInputManagerI inputManager, ReactorInputFluidManagerI inputFluidManager, + ReactorOutputManagerI outputManager, + ReactorAlarmManagerI alarmManager + ) { + player.sendSystemMessage(CreateNuclearLang.translate(TITLE).style(ChatFormatting.GOLD).component()); + + sendManagerSummary(player, CreateNuclearLang.translate(INPUT).component(), + inputManager.size(), inputManager.getBlocksPosition(), inputManager.getBlocksPosition(level)); + + sendManagerSummary(player, CreateNuclearLang.translate(INPUT_FLUID).component(), + inputFluidManager.size(), inputFluidManager.getBlocksPosition(), inputFluidManager.getBlocksPosition(level)); + + sendManagerSummary(player, CreateNuclearLang.translate(OUTPUT).component(), + outputManager.size(), outputManager.getBlocksPosition(), outputManager.getBlocksPosition(level)); + + sendManagerSummary(player, CreateNuclearLang.translate(ALARM).component(), + alarmManager.size(), alarmManager.getBlocksPosition(), alarmManager.getBlocksPosition(level)); + } + + private static void sendManagerSummary(Player player, Component label, int registeredCount, + Collection registered, Collection valid) { + player.sendSystemMessage(CreateNuclearLang.translate(SUMMARY, label, registeredCount, valid.size()).style(ChatFormatting.YELLOW).component()); + + for (BlockPos pos : registered) { + player.sendSystemMessage(CreateNuclearLang.translate(REGISTERED_POSITION, pos.toShortString()).component()); + } + for (BlockPos pos : valid) { + player.sendSystemMessage(CreateNuclearLang.translate(VALID_POSITION, pos.toShortString()).component()); + } + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java new file mode 100644 index 00000000..ab08e31d --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java @@ -0,0 +1,17 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; + +public interface IExplosionService { + void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int uraniumRodCount, + int notifyRadius, boolean notifyWarnAll); + + default void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int uraniumRodCount) { + triggerExplosion(level, controllerPos, reactorSize, + uraniumRodCount, CNConfigs.server().notify.distanceOfWarning.get(), + CNConfigs.server().notify.warnAllPlayers.get() + ); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java new file mode 100644 index 00000000..a893f19e --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java @@ -0,0 +1,51 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.level.GameRules; +import net.nuclearteam.createnuclear.CNEntityType; +import net.nuclearteam.createnuclear.content.explosion.NuclearExplosionEntity; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; +import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; +import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.BiomeIrradiationService; +import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNBiomes; + +public class ReactorMeltdownExecutor implements IExplosionService { + @Override + public void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int uraniumRodCount, int notifyRadius, boolean notifyWarnAll) { + BlockPos explosionPos = controllerPos.above(5); + + NotifyUtil.sendTitle(level, controllerPos, + CreateNuclearLang.translate("notification.reactor.destroyed"), + CreateNuclearLang.translate("notification.reactor.meltdown_finished"), + ChatFormatting.DARK_RED, notifyRadius, notifyWarnAll, 10, 60, 20 + ); + + float size = computeExplosionSize(reactorSize, uraniumRodCount); + + NuclearExplosionEntity explosion = new NuclearExplosionEntity(CNEntityType.NUCLEAR_EXPLOSION.get(), level); + explosion.setPos(explosionPos.getX() + 0.5D, explosionPos.getY() + 10.0D, explosionPos.getZ() - 2.0D); + explosion.setSize(size); + explosion.setNoGriefing(!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)); + level.addFreshEntity(explosion); + + level.destroyBlock(controllerPos, false); + + BiomeIrradiationService.circularArea(level, explosionPos, CNBiomes.Irradiated.PLAIN, (int) (size * 30)); + + } + + private static float computeExplosionSize(int reactorSize, int countUraniumRod) { + // Scales with reactor footprint: 5x5 -> 1.0, 7x7 -> 1.4, 9x9 -> 1.8 + float structureFactor = reactorSize / 5f; + + // Square root gives diminishing returns: each extra uranium rod adds less + // to the radius than the previous one. + float fuelImpact = Mth.sqrt(countUraniumRod) * .3f; + + // Final size: constant base + (fuel impact scaled by structure factor) + return Mth.clamp(1.5f + (fuelImpact * structureFactor), 1f, 10f); + } +} diff --git a/src/main/resources/assets/createnuclear/lang/default/reactor.json b/src/main/resources/assets/createnuclear/lang/default/reactor.json index 67908b9d..1ca99777 100644 --- a/src/main/resources/assets/createnuclear/lang/default/reactor.json +++ b/src/main/resources/assets/createnuclear/lang/default/reactor.json @@ -4,5 +4,14 @@ "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.is": "controller is", "reactor.item.gui.name": "Config Pattern", - "reactor.update.casing.input": "Update the casing in input" + "reactor.update.casing.input": "Update the casing in input", + + "createnuclear.reactor.debug.title": "--- Reactor diagnostics ---", + "createnuclear.reactor.debug.summary": "%s: %s registered, %s valid", + "createnuclear.reactor.debug.registered_position": " registered @ %s", + "createnuclear.reactor.debug.valid_position": " valid @ %s", + "createnuclear.reactor.debug.label.input": "Input", + "createnuclear.reactor.debug.label.fluid_input": "Fluid Input", + "createnuclear.reactor.debug.label.output": "Output", + "createnuclear.reactor.debug.label.alarm": "Alarm" } \ No newline at end of file From 67798bdf4edec3bc1536b8a9cdc4130cab6fc9de Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 14 Jun 2026 11:10:26 +0200 Subject: [PATCH 007/171] chore: remove unused reactor lang keys and dead commented code Drop the unused translation keys reactor.info.assembled.none, reactor.info.assembled.destroyer and reactor.info.is from the default, en_us and en_ud reactor lang files (none of them were referenced anywhere in code). Also remove the leftover commented-out "reactor is not assembled" chat message in ReactorControllerBlock's interact handler. --- AUDIT.md | 187 ++++++++++++++++++ .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +- .../assets/createnuclear/lang/en_ud.json | 3 - .../assets/createnuclear/lang/en_us.json | 3 - .../controller/ReactorControllerBlock.java | 1 - .../createnuclear/lang/default/reactor.json | 3 - 6 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 AUDIT.md diff --git a/AUDIT.md b/AUDIT.md new file mode 100644 index 00000000..c5613f34 --- /dev/null +++ b/AUDIT.md @@ -0,0 +1,187 @@ +# 🔬 Audit Create Nuclear — Rapport détaillé + +> Audit du code Java (`src/main/java`, 282 fichiers / ~21 000 lignes) réalisé par revue multi-agents : 11 agents (un par package) ont lu l'intégralité du code ; chaque finding *bug* / *dead code* a été repris par un agent sceptique chargé de le **réfuter** (grep global incluant `src/generated`, mixins, reflection) afin d'éliminer les faux positifs ; un agent final a synthétisé l'architecture. +> +> **Hors périmètre** : `src/generated/resources` (datagen), `src/main/resources` (textures/lang/sons/nbt). +> +> **Résultat brut** : 144 findings → **80 confirmés**, 11 réfutés (écartés), 6 incertains, 47 cleanup/design/perf non soumis à vérification adversariale. + +| Catégorie | Total | Confirmés (≈) | +|---|---|---| +| 🐛 Bugs | 41 | 28 | +| 🧹 Dead code | 33 | 30 | +| ♻️ Cleanup | 33 | — | +| 🏗️ Design | 16 | 10 | +| ⚡ Perf | 7 | 4 | +| ✅ Points forts | 14 | — | + +**Constat transversal** : le code est visiblement en **plein refactor V2**. La majorité des problèmes ne sont pas de la mauvaise écriture mais des **reliques d'une migration inachevée** — deux frameworks multiblock en parallèle, du code commenté un peu partout, des `&& false` de debug oubliés, des features câblées à moitié. C'est l'angle principal du nettoyage. + +--- + +## 1. Vision architecturale + +L'organisation **package-by-feature** est saine et idiomatique (spécifique à create) pour un addon Create : couche d'enregistrement racine (`CN*`), `content/` par domaine, `foundation/` + `infrastructure/` transverses, `api/` + `impl/`, `compat/` isolé. Cinq problèmes structurels ressortent : + +1. **🔴 Inversion de dépendance dans `api/`** — `api.multiblock.MultiBlockManagerBeta` importe `content.multiblock.controller.ReactorControllerBlockEntity` ; `api.multiblock.rods.RodType` importe `content...CNRodTypes` ; idem `ReactorFluidType`. Le package censé être la fondation stable dépend du contenu concret → cycle d'intention, `api/` ne peut pas servir de point d'extension propre. + +2. **🔴 God class** — `ReactorControllerBlockEntity` fait **886 lignes**, touche items / fluides / chaleur / explosion / advancement / biome / NBT / tooltips. Les sous-packages `manager/`, `service/`, `consumable/` ont été créés *pour le découper*, mais l'extraction est à moitié faite : la BlockEntity orchestre encore tout → l'abstraction ajoute de l'indirection **sans** retirer de responsabilité. + +3. **🔴 Deux frameworks multiblock concurrents** — le vivant `api.multiblock.MultiBlockManagerBeta` (utilisé par `CNMultiblock`), et tout `lib.multiblock.manager.*` + `impl.IBetterPattern` qui sont **morts** (ne se référencent qu'entre eux). Piège à temps pour tout nouveau contributeur. + +4. **🟠 Feature radiation éparpillée sur 4 couches** — `api.radiation` + `foundation/item/radiation` + `content/effects/capability` + `foundation/networking/radiation` implémentent **une seule** feature, sans package propriétaire. Le contrat `IRadiationSource` vs `RadiationRegistry` est dupliqué sans règle de priorité. + +5. **🟠 Couplage hub + accès infra direct** — la BlockEntity contrôleur est un hub de couplage (atteint explosion, advancement, biome, config, logistics, inputs, registres) ; et les classes `content/` importent directement `infrastructure.config.CNConfigs` / `CNBiomes`. Un seam `ConfigValueResolver` existe déjà dans `foundation/utility` mais n'est pas utilisé. + +**Autres points structurels** : package racine fourre-tout (~25 classes `CN*` à plat, mélangées avec `@Mod`, le proxy client et `ClientEvents`) ; `foundation/util` vs `foundation/utility` redondants ; framework de modèle décompilé logé dans `content/explosion` (mêle rendu client réutilisable et logique serveur) ; **aucun test** (`src/test` vide) ; dossier **`run/` versionné** (mixin.out, saves, configs — à mettre en `.gitignore`). + +--- + +## 2. 🐛 Bugs confirmés — par priorité + +### 🔴 Critiques (cassent une fonctionnalité, fix simple) + +| # | Fichier:ligne | Problème | +|---|---|---| +| B1 | `foundation/events/overlay/EventTextOverlay.java:40` | `isActive()` fait **`return timer > 0 && false;`** → l'overlay ne s'affiche **jamais**. Kill-switch de debug oublié. Retirer `&& false`. Un `LOGGER.warn` de debug traîne aussi (à retirer). | +| B2 | `foundation/networking/radiation/RadiationSyncPacket.java:26` | Le handler fait `new ClientRadiationData(radiation)` puis **jette l'instance** (record sans stockage statique ni effet de bord). Le serveur envoie la radiation, **rien ne la mémorise côté client** → packet no-op, sync radiation cassée. Fix : stocker dans un holder statique client lu par l'overlay. | +| B3 | `content/effects/VicinityEffect.java:40` | `int cooldownTicks = 0;` déclaré **à l'intérieur** de la boucle `for` → `if (cooldownTicks==0)` toujours vrai, tout le throttling à 500 ticks est mort (map `cooldowns` + get/setCooldown jamais utilisés). `RadiationEffect` override `isDurationEffectTick → true` donc l'effet est ré-appliqué **à chaque tick** sur toutes les entités proches. | +| B4 | `CNBlocks.java:593-610` | **`THORIUM_BLOCK`** (bloc de stockage) drope **`RAW_URANIUM`** au lieu de lui-même, et est taggé comme un **minerai** (`ores`, `ores/thorium`, `NEEDS_DIAMOND_TOOL`…). Copier-coller d'un minerai d'uranium. Confirmé dans le datagen (`thorium_block.json:41`). Fix : calquer sur `LEAD_BLOCK`/`STEEL_BLOCK` (loot par défaut, seul tag `storage_blocks/thorium`). | +| B5 | `infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java:21` | `apply()` retourne **`null`** au lieu d'une `Condition` ; la classe interne `Predicate` qui contient la vraie logique n'est jamais instanciée → **NPE** à l'évaluation de toute surface rule basée dessus. Fix : `return new Predicate(context)`. | +| B6 | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java:70` | `new ReactorBluePrintItemPacket(..., countGraphiteRod, countGraphiteRod)` : le 6ᵉ argument répète le 5ᵉ → la valeur **uranium est perdue**, le calcul de progression est faussé. (Ligne 53 : `coef=0.1F` envoyé en place de `heat` → chaleur jamais transmise ; le packet tourne aussi à chaque tick sans condition de changement.) | + +### 🟠 Importants + +| # | Fichier:ligne | Problème | +|---|---|---| +| B7 | `infrastructure/worldgen/biome/CNNoiseData.java:18` | `bootstrapRegistries()` **entièrement commenté** → noise `EROSION` jamais enregistré, mais les surface rules font `noiseCondition(EROSION)` 3× (`IrradiatedSurfaceRules2:54/58/62`) → `getOrThrow` lèvera. **Dormant** tant qu'aucune dimension ne câble `irradiated_noise`, mais défaut d'intégrité de données réel. | +| B8 | `content/multiblock/controller/ReactorControllerBlockEntity.java:1020` | `clearLockIfAllInputsEmpty` enchaîne `findStructure(...).data().getSize()` sans null-check ; `findStructure` retourne `null` quand la structure n'est plus formée → **NPE serveur**. Les 2 autres appelants (`ReactorAssembler:37,62`) gardent bien le null — prouve l'oubli. Fix : stocker le résultat, null-check, fallback `reactorSize`. | +| B9 | `content/effects/capability/RadiationCapability.java:165` | `if (rad` **statique** : (1) pas de dimension dans la clé → collision inter-dimension, (2) **jamais purgée** (unload chunk/monde) → fuite mémoire, (3) doublonne `PersistentFluidLocks` (deux sources de vérité, aiguillage `level instanceof ServerLevel`). La suppression d'un contrôleur ne nettoie que `PersistentFluidLocks`. | +| B15 | `content/explosion/NuclearExplosionEntity.java:224` | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` : utilise une exception comme branchement (anti-pattern), **avale les vrais bugs**, et les deux branches ont des sémantiques de drop **différentes** (catch = drop forcé). Au minimum logger. | +| B16 | `foundation/data/recipe/CNStandardRecipeGen.java:391` | `ModdedCookingRecipeResult.serializeRecipeData` fait `conditions.forEach` alors que le record est construit avec `conditions=null` (l.351) → **NPE datagen** dès qu'une recette `isOtherMod` serait sérialisée. Latent (chemin non câblé) mais cassé. Fix : liste vide au lieu de null, ou garde. | +| B17 | `foundation/events/RodsTooltipHandler.java:26` | Condition de namespace **inversée** : n'applique `RodsStats` qu'aux items **non**-createnuclear (donc no-op, car les rods sont du mod) ; et `RodsStats` est déjà branché via Registrate → si corrigé, **double tooltip**. Code mort fonctionnel à risque de régression — probablement à supprimer entièrement. | +| B18 | `infrastructure/config/CNCClient.java:9` | `screenShaking` réutilise la **même clé TOML** `nuclearBombFlash` que la ligne 8 → les deux options pointent sur la même valeur config (lu dans `ClientEvents:60`). Fix : clé `screenShaking`. | +| B19 | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules2.java:23` | `IS_HIGHLANDS = biome()` (varargs vide → `Set.copyOf([])::contains` toujours faux) ne matche jamais → branches `MOON_DIRT` (l.35) / `LEAD_TURF` (l.39) **mortes**. | + +### 🟡 Mineurs / robustesse + +- `content/multiblock/output/ReactorOutputEntity.java:117` — `tick()` : pas de null-check `level`, 2-3 lookups world redondants/tick (client+serveur) pour une position fixe `above(3)`. +- `content/multiblock/input/fluid/ReactorInputFluidManager.java:129/148` — off-by-one `getFluidInTank(getTanks())` : toléré par le `SmartFluidTank` single-tank actuel (qui ignore l'index) mais **viole le contrat `IFluidHandler`** ; et `extractFluids` ne **décrémente jamais `fluidNeeded`** + ignore l'extraction quand `toExtract>1`. +- `content/multiblock/core/ReactorCoreEntity.java` — `tick()` vide. +- `content/multiblock/input/item/ReactorInput.java:65` — retourne `PASS` après ouverture de menu côté serveur → désync client(`SUCCESS`)/serveur. Fix : `CONSUME`/`SUCCESS`. +- `foundation/utility/RenderHelper.java:36` — champs `lastAlpha/lastCoverage/lastFirstPerson` écrits jamais lus (cache inexistant) ; branche `coverage!=1f` inerte (scale commenté + translate qui s'annulent). Connexe : `RadiationOverlay:49` binarise l'alpha via `Math.round`. +- `foundation/utility/InventoryHashUtil.java:91` — le hash inclut `getDamageValue()` → tout changement de durabilité déclenche un resync (rafales de `RadiationSyncPacket` au minage/combat). +- `content/multiblock/output/ReactorOutput.java:63` — `requireNonNull` + `assert entity!=null` (assert désactivé en prod) au lieu d'une garde gracieuse ; `DIR` 0..2 avec valeur 2 jamais utilisée. +- `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:31` — `%` trompeur `tier*100/3` (33/66/100 % pour tier 1..3). + +--- + +## 3. 🧹 Dead code à supprimer + +### Gros blocs (forte valeur, risque faible) + +- **Tout `lib.multiblock.manager.*`** (`MultiBlockManager`, `MultiBlockCache`, `RegisteredMultiBlockPattern`) + **`lib.multiblock.impl.IBetterPattern`** + `SimpleMultiBlockPatternBuilder` (variante non-aisle) → reliques V2 mortes (ne se référencent qu'entre elles). *(`MultiBlockCache.isCached` a même une sémantique inversée.)* +- **Framework d'animation keyframe** : `CNModelAnimator` + `CNAnimation` + `CNIAnimatedEntity` + surcharges `CNAdvancedEntityModel.rotate/rotateMinus` → jamais utilisé (le modèle réel anime directement via `animateParticle`). ⚠️ **Garder** `CNAdvancedEntityModel`/`CNBasicEntityModel`/`CNAdvancedModelBox` : `NuclearMushroomCloudModel` en hérite réellement. +- **`CreateNuclearDamageSources`** = doublon (quasi octet-près) de `CNDamageSources` → garder `CNDamageSources`, migrer les 2 références (`RadiationEffect:94`, `CNFanProcessingTypes:122`) ; les surcharges privées `source(Entity…)` sont aussi mortes dans les deux classes. +- **`foundation/events/CommentEventClients.java`** — coquille `@EventBusSubscriber` vide (aucun `@SubscribeEvent`) → supprimer. +- **`foundation/events/possible code`** — fichier sans extension `.java`, brouillon `com.tonpackage` (3 fragments : services META-INF, `HudOverlayRegistry`, 2ᵉ `CNClientEvent`) → sortir du dépôt. +- **`foundation/data/recipe/CNShapelessRecipeGen.java`** — provider qui n'émet aucune recette, enregistrement commenté (`CreateNuclearDatagen:42`). +- **`IrradiatedSurfaceRules` v1** — remplacé par v2 (`CNNoiseGeneratorSettings:29`), ne survit que via un import. +- **`RadiationOverlay` + `EasingHudOverlay`** — `RadiationOverlay` commenté dans `HudRenderer.overlays` → jamais instancié/rendu (et `IrradiatedOverlayRendererVision` fait déjà ce rendu). +- **`VerifyPattern7x7` / `VerifyPattern9x9`** (`ReactorPattern`) + `getBlockPosForReactor` (@Deprecated) — jamais appelés. +- **`saveData2`** (`ReactorBluePrintMenu:160`) — doublon mort de `saveData` (et logique de comptage subtilement fausse : pas de reset). + +### Membres / méthodes morts + +`ReactorOutputValue` + `outputPos` + `getStressConfigKey` trivial + addBehaviours commenté (`ReactorOutputEntity`) ; `inputPos`/`inputLevelKey` + override `getLevel` trivial (`ReactorInputEntity`) ; `ReactorCasingEntity.getController` + champ `controller` (offset magique `+4/+4`) ; `VicinityEffect.cooldowns`/`getCooldown`/`setCooldown` + param `timer` ; `getArmorResistance` (`RadiationCapability`) ; helpers `TextUtils` (`renderMultilineDebugText`, `renderDebugText`, `translateWithFormatting`, `formatInt`×2, `leftPad`) ; `Mods` (`getBlock`/`getItem`/`contains`/`rl`/`id`/`runIfInstalled`/`executeIfInstalled`) ; `SoundEntryBuilder` (`playItemPickup`, `playExisting`×4, `addVariant`×2, `noSubtitle`, setter `attenuationDistance`) ; `BigFluidStack` (`send`/`receive`/`read`/`isInfinite`/`duplicateWrappers`/`comparator`/`write`) ; `CNParticleRegistry.createBlockParticleType`/`createItemParticleType` ; `parseLegacy`/`ofLegacyName`/`LEGACY_NAME_MAP` (`CNFanProcessingTypes`) ; `registerAndWrap` + vars locales inutilisées (`CNDensityFunctions`) ; `CExplode` (config `size`/`type`/`time` jamais lue) ; `IrradiatedBiomes.monsters()` (corps commenté, no-op) ; `VANILLA_RANGE`/`cubeBottomTop` (`PaletteBlockPattern`) ; `getVariant()` (`CNPaletteStoneTypes`) ; `START=null` (`CNAdvancement`) ; surcharge `RadiationRegistry.getRadiation(biome,player)` ; `VirtualReactorInputFluid.removeFluid`/`getAmount` ; `matchesWithResult`/`construct`/`MultiblockMatchResult`/`getDistanceControllerTest` (lib) ; `ensureProperlyBuilt` (`SimpleMultiBlockPatternBuilder`). + +### Imports morts / doublons + +`CNBlocks.java` (`ResourceLocation`, `BlockTags`, `Enriching*Block` importés 2×) ; `AntiRadiationArmorItem.java` (`Util`/`Component`/`Attribute`/`world.item.*` en double, `TagKey`) ; `ReactorFluidTypesValue.java` (`reflect.Array`/`Field`, `Map`, `ForgeRegistries`) ; `CreateNuclearDatagen.java:18` (`CNShapelessRecipeGen`) ; `CNMixingRecipeGen.java:7` (`Fluids`) ; import dupliqué `IMultiBlockPatternBuilder` (`SimpleMultiBlockPatternBuilder:6-7`). + +--- + +## 4. ⚡ Performance + +| Fichier:ligne | Problème | Fix | +|---|---|---| +| `content/multiblock/pattern/ReactorPattern.java:96` | `findController` / `findControllerPos` scannent **~3971 blocs** (`getBlockState` + `getBlockEntity`) à **chaque pose/casse** de casing/frame/cooler/output — et **aussi côté client** (pas de garde `isClientSide`). Boucles avec `!=` comme condition d'arrêt et `new BlockPos` par itération. | Réduire la zone, `MutableBlockPos`, court-circuit dès trouvé, garde `isClientSide`, `<` au lieu de `!=`. | +| `content/effects/RadiationEffect.java:40` | Le predicate reconstruit un `HashSet` + reparse toutes les `ResourceLocation` de la blacklist **à chaque entité candidate** de la bounding box, **à chaque tick** (override `isDurationEffectTick → true`). | Cacher le `Set` (invalidé au reload config). | +| `content/multiblock/alarm/ReactorAlarmEntity.java:95` | `tickServer()` appelé inconditionnellement (y compris **client**, pas de garde `!isClientSide`), `awardPlayer` à chaque tick quand `POWERED`. | Garde `!isClientSide`, n'award qu'au front montant. | +| `api/multiblock/fluid/ReactorFluidType.java:55` | `getTypeForFluid` : double boucle sur le registry `FLUID_TYPE` + `ForgeRegistries.FLUIDS.getKey(fluid)` recalculé à chaque itération interne. | Calculer la clé une fois avant le filtre. | +| `foundation/events/overlay/HelmetOverlay.java:73` | `gui.renderHotbar(12f, graphics)` re-rendu depuis un overlay HELMET chaque frame (registerAbove → double rendu possible) + lookups inventaire répétés (`getArmor(HEAD)` 2×/frame). | Vérifier la nécessité, mémoriser le casque par frame. | + +*Mineurs* : `NuclearMushroomCloudParticle:136` (`new PoseStack()` + `endBatch()` par frame), `ReactorSummaryDisplaySource:180` (`labelWidth()` recalcule des traductions par affichage). + +--- + +## 5. ♻️ Cleanup notable (qualité) + +- **Duplication `drawGauge`** copiée à l'identique dans 5 `DisplaySource` (Cooler/Fuel/Heat/LiquidLevel/Summary) + magic numbers `maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000` → extraire `AbstractReactorStatDisplaySource`. +- **`GeneratedRecipeBuilder` dupliqué** entre `CNStandardRecipeGen` et `CNShapelessRecipeGen` (+ typo param `enterFolder(String foldedr)`, `createLocation()` jamais appelé). +- **`moddedCompacting`/`moddedPaths` dupliqués** entre `EnrichedRecipeGen` et `SnowPowderRecipeGen` (et `moddedPaths` retourne toujours `null` avec une signature `GeneratedRecipe` trompeuse). +- **Framework de modèle décompilé** (`CNBasicModelPart`, `CNTabulaModelRenderUtils`, `CNAdvancedModelBox`) : noms de variables FernFlower (`lvt_10_1_`, `p_228305_1_`, `var9`), `ModelBox`/`TexturedQuad`/`PositionTextureVertex` dupliqués, shadowing de champs `cubeList`/`childModels`. +- **Logs de debug en prod** : `LOGGER.info("EXPLOSIOOOOOON…")` à chaque explosion (`NuclearMushroomCloudParticle:76`), `LOGGER.warn` par entité touchée (`NuclearExplosionEntity`). +- **Typos dans des noms publics** : `RadiationEffetcHandler` (→ Effect), `SolidRenderedPlaceableFluidtype` + param `stillTecture`, `caracter` (record `MultiBlockOffsetPos`), `contruct` (`IMultiBlockPattern`), `foldedr`. +- **`fireDamage`** non utilisé dans le constructeur `EnrichingCampfireBlock` (valeur 5 passée pour rien) ; dead store `i = ...get2DDataValue()` jamais relu (`EnrichingCampfireBlockEntity:27`) ; branches `isShiftKeyDown` identiques (`ReactorBluePrintItem:51`) ; `use()` redondant retournant `PASS` (`EnrichingCampfireBlock:61`). +- **Commentaires FR/EN mêlés** un peu partout, code commenté résiduel, double `;;` (`CNMixingRecipeGen`, `CNStandardRecipeGen:78`, `CNCClient`), en-têtes FernFlower (`Maths`, `SimplexNoise`). +- **`unlockedBy("has_storage_blocks_steel_nugget", ingots/thorium)`** — critère copié-collé incohérent pour `THORIUM_NUGGET` (`CNItems:186`). + +--- + +## 6. 🏗️ Design + +- **Inversion de couche `api/`** (cf. §1.1) — `api.multiblock`/`api.radiation` dépendent du `content` concret. +- **`MultiBlockManagerBeta` couplé à `ReactorControllerBlockEntity`** : la détection de pattern écrit `setMultiblockFacing` en **effet de bord** dans une BlockEntity concrète (mélange détection + mutation). Fix : retourner la `Direction`, laisser l'appelant l'appliquer. +- **Deux `DeferredRegister` concurrents** pour `ForgeRegistries.PARTICLE_TYPES` (`CNParticleRegistry` brut vs `CNParticleTypes` enum wrapper) — pas un bug (Forge le supporte) mais deux mécanismes/styles parallèles. +- **`controller` typé `ReactorControllerBlock`** (le Block singleton sans état positionnel) dans `ReactorInputEntity`/`ReactorOutputEntity` au lieu de la BlockEntity/BlockPos → champ qui n'apporte aucune info ; champ jamais lu dans `ReactorInputEntity`. +- **`RadiationRegistry` parallèle à `IRadiationSource`** sans règle de priorité → risque de double comptage latent (`RadiationCapability:116` additionne les deux inconditionnellement ; inoffensif aujourd'hui car aucun item n'est dans les deux). +- **`HudOverlay` sur-spécifiée** : `getPriority`/tri sans effet réel sur l'ordre Forge ; `HudRenderer` instancié comme champ alors qu'il est sans état. +- **`@Mod.EventBusSubscriber` sans modid** + `onServerTick()` no-op enregistré pour rien + nommage trompeur `CommentEvents`/`CommentEventClients`. +- **`api/` nommé `Beta`** : surface d'API provisoire promue dans le package censé être stable. +- **`ClothTagHelper`** : copie `base` puis l'écrase toujours (copie inutile dans le flux réel) ; `foundation/util` vs `foundation/utility` sans règle. + +--- + +## 7. ✅ Le bon (à conserver) + +- **Bootstrap idiomatique** : un `CreateRegistrate` + classes `CN*` par domaine appelées depuis `CreateNuclear.onInitialize()` → point unique prévisible ; wiring `DeferredRegister` bien séparé du forge-bus. +- **`api/` + `impl/` datapack registries** : `RodType`/`ReactorFluidType` data-driven avec Codecs + **Builder à validation explicite** (accumule les champs manquants, `IllegalStateException` précise, résolution config paresseuse au runtime) → réacteur extensible par datapack. Très bon design. +- **`RadiationCapability`** : recalcul de la radiation d'inventaire **gardé par un hash** (`InventoryHashUtil`), sync uniquement si `needsSync` → évite le travail par tick sur le hot path joueur. +- **`NuclearExplosionEntity`** : libération **symétrique** des chunks force-loadés (start tick / `remove()`), état `loadingChunks` persisté en NBT pour relâcher après reload. +- **Isolation compat** : `Mods.isLoaded` + pont `AlexscaveCompat` via cast `Object` → pas de `NoClassDefFoundError` quand Alex's Caves est absent. Record `SimpleMultiBlockPattern` immutable (`List.copyOf`/`Map.copyOf`). +- **`CNPackets`** (enum + `PacketType` à index auto) et **`CNTags`** (enum NameSpace factorisé, `matches()` typés) : peu de boilerplate, cohérent. +- **`CNAdvancementBehaviour`** : self-cleanup propre (retire les advancements obtenus, libère `playerId`), server-only, FakePlayer ignoré, persistance NBT. +- **`CNFanProcessingTypes`** : wrappers de recette statiques réutilisés (pas d'allocation par item sur le hot path). +- **`CNProcessingRecipeGen`** : agrégation des sous-générateurs derrière un `DataProvider` unique (`allOf` de `CompletableFuture`). +- **`NotifyUtil`** : gardes side serveur cohérentes, bons overloads `LangBuilder`/`MutableComponent`. +- Direction `controller/{manager,service,consumable}` (interfaces `I*` + impl `Default*`) : la bonne trajectoire stratégie/DI — **à terminer**. + +--- + +## 8. 📋 Plan d'action priorisé + +**Quick wins (≈1 ligne, fort impact)** — corriger d'abord : **B1** (`&& false`), **B2** (sync radiation), **B3** (cooldown), **B5** (`return null`), **B9** (palier radiation), **B18** (clé config) ; puis **B4** (loot thorium). + +**🔴 Priorité 1 — nettoyage à risque faible** +1. Supprimer les reliques V2 mortes : `lib.multiblock.manager.*`, `IBetterPattern`, builders non-aisle, framework keyframe, `CommentEventClients`, `possible code`, `CreateNuclearDamageSources`, `CNShapelessRecipeGen`, `RadiationOverlay`/`EasingHudOverlay`, `IrradiatedSurfaceRules` v1. → **gain le plus élevé pour le moindre risque.** +2. Mettre `run/` dans `.gitignore` (et le dé-tracker du repo). + +**🔴 Priorité 2 — bugs fonctionnels** +3. Traiter les bugs critiques + importants du §2. + +**🟠 Priorité 3 — dette structurelle** +4. Corriger l'**inversion de couche `api/`** : `api.multiblock`/`api.radiation` ne définissent que des interfaces/types ; le `content` dépend de l'api (retourner un `IReactorController` au lieu de `ReactorControllerBlockEntity` ; sortir le wiring `RodType`/`ReactorFluidType` de `api`). +5. **Terminer la décomposition** de `ReactorControllerBlockEntity` (BlockEntity = coordinateur mince, cible < 300 lignes, délégation complète à `manager`/`service`/`consumable`) ; résoudre les **2 systèmes de verrou de fluide** et les **2 `saveData`** en un seul. + +**🟡 Priorité 4 — cohésion** +6. Consolider la radiation en **un** module (api = `IRadiationSource` seul) ; extraire le framework de modèle hors de `content/explosion` ; créer un sous-package `registration/` ; fusionner `foundation/util` → `utility` ; router l'accès config via `ConfigValueResolver` ; renommer les symboles `Beta` ; **ajouter des tests** (`src/test` est vide). + +--- + +*Note : les findings de type bug/dead-code ont été vérifiés de façon adversariale ; 11 ont été réfutés et écartés du rapport. Les sévérités intègrent les corrections des vérificateurs (ex. plusieurs bugs « high » initiaux sont dormants/latents tant qu'un chemin précis n'est pas câblé — signalé au cas par cas ci-dessus).* diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 2ee25d6b..05f1aeb1 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-14T10:59:25.6995934 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-14T11:07:51.5482654 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -7c531dc3116eb3fa085703a98301994937b45d35 assets/createnuclear/lang/en_ud.json -aa99d9f5d01f1e0cd63e889ac1488f4a7cabedfe assets/createnuclear/lang/en_us.json +2c770a8dcc9ee3230438ed747dc620d7151aa905 assets/createnuclear/lang/en_ud.json +cd6f2a9b30e89b3a324465db7a5798b5f6e5ce5f assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index ec92702f..f62b640b 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -395,9 +395,6 @@ "itemgroup.uranium": "dnoɹ⅁ ɯnıuɐɹ∩", "overlay.event_message": "ɹǝɯıʇ %s ⚠ buıuɹɐM ⚠", "reactor.info.assembled.creator": "pǝןqɯǝssɐ uǝǝq sɐɥ ɹoʇɔɐǝᴚ", - "reactor.info.assembled.destroyer": "pǝןqɯǝssɐsıp uǝǝq sɐɥ ɹoʇɔɐǝᴚ", - "reactor.info.assembled.none": "pǝןqɯǝssɐ ʇou sı ɹoʇɔɐǝᴚ", - "reactor.info.is": "sı ɹǝןןoɹʇuoɔ", "reactor.item.gui.name": "uɹǝʇʇɐԀ bıɟuoƆ", "reactor.update.casing.input": "ʇnduı uı buısɐɔ ǝɥʇ ǝʇɐpd∩", "tag.fluid.c.uranium": "ɯnıuɐɹ∩ pınןℲ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index cab8d3c7..6871b417 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -395,9 +395,6 @@ "itemgroup.uranium": "Uranium Group", "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", - "reactor.info.assembled.destroyer": "Reactor has been disassembled", - "reactor.info.assembled.none": "Reactor is not assembled", - "reactor.info.is": "controller is", "reactor.item.gui.name": "Config Pattern", "reactor.update.casing.input": "Update the casing in input", "tag.fluid.c.uranium": "Fluid Uranium", diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index ed7b6028..16c557a4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -95,7 +95,6 @@ public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Play } if (!state.getValue(ASSEMBLED)) { - // player.sendSystemMessage(Component.translatable("reactor.info.assembled.none").withStyle(ChatFormatting.RED)); } else { if (heldItem.is(CNItems.REACTOR_BLUEPRINT.get()) && controllerBlockEntity.getInventoryObject().getItem(0).isEmpty() && heldItem.getTag() != null){ diff --git a/src/main/resources/assets/createnuclear/lang/default/reactor.json b/src/main/resources/assets/createnuclear/lang/default/reactor.json index 1ca99777..735d9a8c 100644 --- a/src/main/resources/assets/createnuclear/lang/default/reactor.json +++ b/src/main/resources/assets/createnuclear/lang/default/reactor.json @@ -1,8 +1,5 @@ { - "reactor.info.assembled.none": "Reactor is not assembled", - "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.creator": "Reactor has been assembled", - "reactor.info.is": "controller is", "reactor.item.gui.name": "Config Pattern", "reactor.update.casing.input": "Update the casing in input", From b4948109851e3ec6e140f1dba6d73fb8265e0c3a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 14 Jun 2026 13:44:01 +0200 Subject: [PATCH 008/171] refactor: extract reactor client display state into ReactorDisplayState/ReactorGoggleTooltipRenderer Replace the three loose clientDisplayItems/clientDisplayFluids/clientMaxFluidCapacity fields on ReactorControllerBlockEntity with a single immutable ReactorDisplayState record (items, fluids, maxFluidCapacity), with its own serializeNBT/deserializeNBT for the client sync packet. Move the serialization logic out of readBasicState/writeBasicState into DefaultPersistenceService, which now reads/writes the "displayState" tag on client packets. Move the Goggles tooltip rendering out of addToGoggleTooltip into a new stateless ReactorGoggleTooltipRenderer that renders purely from a ReactorDisplayState snapshot plus the current heat value. Also switch the debug-connections interaction trigger from holding paper to holding a debug stick. --- .../controller/ReactorControllerBlock.java | 2 +- .../ReactorControllerBlockEntity.java | 139 +++--------------- .../display/ReactorDisplayState.java | 135 +++++++++++++++++ .../display/ReactorGoggleTooltipRenderer.java | 111 ++++++++++++++ .../service/DefaultPersistenceService.java | 8 + 5 files changed, 276 insertions(+), 119 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index 16c557a4..1a805c2e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -90,7 +90,7 @@ public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Play if (!(blockEntity instanceof ReactorControllerBlockEntity controllerBlockEntity)) return InteractionResult.PASS; ItemStack heldItem = player.getItemInHand(handIn); - if (heldItem.is(Items.PAPER)) { + if (heldItem.is(Items.DEBUG_STICK)) { withBlockEntityDo(worldIn, pos, be -> be.logReactorConnections(player)); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 56ebd503..50bcb9f9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -38,6 +38,8 @@ import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.CNMultiblock; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorGoggleTooltipRenderer; import net.nuclearteam.createnuclear.content.multiblock.controller.service.*; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.FluidLockManager; import net.nuclearteam.createnuclear.content.multiblock.IHeat; @@ -111,10 +113,7 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private final ReactorAlarmManagerI alarmManager; private final ReactorFrameDisplayManagerI frameDisplayManager; - // Client Display Data (Synced via NBT) - private Map clientDisplayItems = new HashMap<>(); - private List clientDisplayFluids = new ArrayList<>(); - private long clientMaxFluidCapacity = 0; + private ReactorDisplayState displayState = ReactorDisplayState.EMPTY; // services (dependencies) - abstracted behind interfaces to follow DIP private final IHeatService heatService; @@ -223,6 +222,14 @@ public ReactorInputFluidManagerI getInputFluidManager() { return this.inputFluidManager; } + public void setDisplayState(ReactorDisplayState state) { + this.displayState = state; + } + + public ReactorDisplayState getDisplayState() { + return this.displayState; + } + /** * Main constructor allowing dependency injection for testability and DIP * compliance. @@ -265,62 +272,7 @@ public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneak return false; } - CreateLang.translate("gui.gauge.info_header") - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - IHeat.HeatLevel.getName("reactor_controller").style(ChatFormatting.GRAY).forGoggles(tooltip); - - IHeat.HeatLevel.getFormattedHeatText(patternTag.getInt("heat")).forGoggles(tooltip); - - if (clientDisplayItems.isEmpty()) { - CreateNuclearLang.builder() - .add(Component.translatable("tooltip.item.empty.rod").withStyle(ChatFormatting.GRAY)) - .add(CreateNuclearLang.number(0).style(ChatFormatting.GOLD)) - .forGoggles(tooltip); - } else { - for (Map.Entry entry : clientDisplayItems.entrySet()) { - ItemStack stack = new ItemStack(entry.getKey()); - int count = entry.getValue(); - CreateNuclearLang.itemName(stack) - .style(ChatFormatting.GRAY) - .text(": ") - .add(CreateNuclearLang.number(count).style(ChatFormatting.GOLD)) - .forGoggles(tooltip); - } - } - - if (clientDisplayFluids.isEmpty()) { - CreateNuclearLang - .translate("tooltip.fluid.none") - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - - CreateNuclearLang.builder() - .text(TooltipHelper.makeProgressBar(5, 0)) - .style(ChatFormatting.BLUE) - .space() - .text("0%") - .forGoggles(tooltip); - } else { - for (BigFluidStack stack : clientDisplayFluids) { - float fillRatio = clientMaxFluidCapacity > 0 ? (float) stack.amount / clientMaxFluidCapacity : 0; - if (fillRatio >= 0.99f) - fillRatio = 1.0f; - int filledBars = (int) Math.round(fillRatio * 5); - - CreateNuclearLang - .translate("tooltip.fluid", stack.stack.getDisplayName()) - .style(ChatFormatting.GRAY) - .forGoggles(tooltip); - - CreateNuclearLang.builder() - .text(TooltipHelper.makeProgressBar(5, filledBars)) - .style(ChatFormatting.BLUE) - .space() - .text(Math.round(fillRatio * 100) + "%") - .forGoggles(tooltip); - } - } + ReactorGoggleTooltipRenderer.render(tooltip, displayState, patternTag.getInt("heat"), isPlayerSneaking); return true; } @@ -340,34 +292,6 @@ protected void read(CompoundTag compound, boolean clientPacket) { this.persistenceService.readBasicState(this, compound, clientPacket); this.needsToResolveEntities = true; - if (clientPacket) { - clientDisplayItems.clear(); - if (compound.contains("clientDisplayItems")) { - ListTag list = compound.getList("clientDisplayItems", - Tag.TAG_COMPOUND); - for (int i = 0; i < list.size(); i++) { - CompoundTag tag = list.getCompound(i); - Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString("Item"))); - if (item != null) { - clientDisplayItems.put(item, tag.getInt("Count")); - } - } - } - - clientDisplayFluids.clear(); - if (compound.contains("clientDisplayFluids")) { - ListTag list = compound.getList("clientDisplayFluids", - Tag.TAG_COMPOUND); - for (int i = 0; i < list.size(); i++) { - CompoundTag tag = list.getCompound(i); - FluidStack fstack = FluidStack - .loadFluidStackFromNBT(tag); - clientDisplayFluids.add(new BigFluidStack(fstack, tag.getInt("BigAmount"))); - } - } - clientMaxFluidCapacity = compound.getLong("clientMaxFluidCapacity"); - } - this.cycleManager.clear(); if (compound.contains("cycleManager")) { this.cycleManager.deserializeNBT(compound.getCompound("cycleManager")); @@ -385,27 +309,6 @@ protected void write(CompoundTag compound, boolean clientPacket) { this.persistenceService.writeBasicState(this, compound, clientPacket); - if (clientPacket) { - ListTag displayItemsTag = new ListTag(); - for (Map.Entry entry : clientDisplayItems.entrySet()) { - CompoundTag tag = new CompoundTag(); - tag.putString("Item", ForgeRegistries.ITEMS.getKey(entry.getKey()).toString()); - tag.putInt("Count", entry.getValue()); - displayItemsTag.add(tag); - } - compound.put("clientDisplayItems", displayItemsTag); - - ListTag displayFluidsTag = new ListTag(); - for (BigFluidStack stack : clientDisplayFluids) { - CompoundTag tag = new CompoundTag(); - stack.stack.writeToNBT(tag); - tag.putInt("BigAmount", stack.amount); - displayFluidsTag.add(tag); - } - compound.put("clientDisplayFluids", displayFluidsTag); - compound.putLong("clientMaxFluidCapacity", clientMaxFluidCapacity); - } - compound.put("cycleManager", cycleManager.serializeNBT()); } @@ -516,33 +419,33 @@ public void tick() { return; // Populate display fields for client sync - clientDisplayItems.clear(); + Map items = new HashMap<>(); List itemHandlers = this.inputManager.getItemHandlers(level); for (IItemHandler h : itemHandlers) { for (int s = 0; s < h.getSlots(); s++) { ItemStack st = h.getStackInSlot(s); if (!st.isEmpty()) { - clientDisplayItems.put(st.getItem(), - clientDisplayItems.getOrDefault(st.getItem(), 0) + st.getCount()); + items.merge(st.getItem(), st.getCount(), Integer::sum); } } } - clientMaxFluidCapacity = 0; - List fhandlers = this.inputFluidManager.getFuildHandlers(level); - for (IFluidHandler h : fhandlers) { + long maxFluidCapacity = 0; + for (IFluidHandler h : this.inputFluidManager.getFuildHandlers(level)) { if (h.getTanks() > 0) { - clientMaxFluidCapacity += h.getTankCapacity(0); + maxFluidCapacity += h.getTankCapacity(0); } } VirtualReactorInputsItem virtualReactorInputsItem = inputManager.getInventory(level); VirtualReactorInputFluid virtualReactorInputFluid = inputFluidManager.getInventory(level); - clientDisplayFluids = VirtualReactorInputFluid.toBigList(virtualReactorInputFluid.fluids()); + List fluids = VirtualReactorInputFluid.toBigList(virtualReactorInputFluid.fluids()); + + this.displayState = new ReactorDisplayState(items, fluids, maxFluidCapacity); this.bigFuelItem = virtualReactorInputsItem.getBigFuelRod(); this.bigCoolerItem = virtualReactorInputsItem.getBigCooledRod(); - this.bigFluidStack = VirtualReactorInputFluid.toBigList(virtualReactorInputFluid.fluids()); + this.bigFluidStack = fluids; updateReactorStateVisibility(); handleAssembledState(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java new file mode 100644 index 00000000..54e100c9 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java @@ -0,0 +1,135 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.display; + +import com.simibubi.create.content.logistics.BigItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraftforge.registries.ForgeRegistries; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Immutable snapshot of the data the reactor controller exposes for client-side + * display (e.g. the Goggles tooltip rendered by {@link ReactorGoggleTooltipRenderer}). + *

+ * Instances are produced server-side once per tick from the live input inventories + * and tanks, then synced to the client through the block entity's {@code clientPacket} + * NBT via {@link #serializeNBT()} / {@link #deserializeNBT(CompoundTag)}. This data is + * transient sync data only: it is not part of the persisted save NBT, so its layout + * can evolve freely without migration concerns. + *

+ * Usage: + *

{@code
+ * // Server side, e.g. in tick():
+ * this.displayState = new ReactorDisplayState(items, fluids, maxFluidCapacity);
+ *
+ * // Writing the client packet:
+ * compound.put("displayState", displayState.serializeNBT());
+ *
+ * // Reading the client packet:
+ * displayState = compound.contains("displayState")
+ *         ? ReactorDisplayState.deserializeNBT(compound.getCompound("displayState"))
+ *         : ReactorDisplayState.EMPTY;
+ * }
+ * + * @param items item rods currently loaded, mapped to their stacked count + * @param fluids fluids currently loaded in the input tanks + * @param maxFluidCapacity combined capacity (in millibuckets) of all input fluid tanks + */ +public record ReactorDisplayState(Map items, List fluids, long maxFluidCapacity) { + static final String COMPONENT_ITEM = "Item"; + static final String COMPONENT_COUNT = "Count"; + static final String COMPONENT_CLIENT_DISPLAY_ITEMS = "clientDisplayItems"; + static final String COMPONENT_CLIENT_DISPLAY_FLUIDS = "clientDisplayFluids"; + static final String COMPONENT_CLIENT_MAX_FLUIDS_CAPACITY = "clientMaxFluidCapacity"; + + /** + * Shared empty instance, used before the first tick has populated any display + * data and as the fallback when the client packet doesn't carry a display state. + */ + public static final ReactorDisplayState EMPTY = new ReactorDisplayState(Map.of(), List.of(), 0); + + /** + * Defensively copies the given collections so the record stays immutable + * regardless of how the caller's collections are mutated afterwards. + */ + public ReactorDisplayState { + items = Map.copyOf(items); + fluids = List.copyOf(fluids); + } + + /** + * Serializes this state into NBT for inclusion in the block entity's + * {@code clientPacket} data. Pair with {@link #deserializeNBT(CompoundTag)} + * to restore an equivalent instance on the client. + * + * @return a new {@link CompoundTag} containing the serialized item map, + * fluid list and max fluid capacity + */ + public CompoundTag serializeNBT() { + CompoundTag compound = new CompoundTag(); + + ListTag displayItemsTag = new ListTag(); + for (Entry entry : items().entrySet()) { + CompoundTag tag = new CompoundTag(); + tag.putString(COMPONENT_ITEM, ForgeRegistries.ITEMS.getKey(entry.getKey()).toString()); + tag.putInt(COMPONENT_COUNT, entry.getValue()); + displayItemsTag.add(tag); + } + compound.put(COMPONENT_CLIENT_DISPLAY_ITEMS, displayItemsTag); + + ListTag displayFluidsTag = new ListTag(); + for (BigFluidStack stack : fluids()) { + displayFluidsTag.add(stack.write()); + } + compound.put(COMPONENT_CLIENT_DISPLAY_FLUIDS, displayFluidsTag); + + compound.putLong(COMPONENT_CLIENT_MAX_FLUIDS_CAPACITY, maxFluidCapacity()); + + return compound; + } + + /** + * Reconstructs a {@link ReactorDisplayState} from NBT previously produced by + * {@link #serializeNBT()}. Acts as a static factory since records cannot be + * mutated in place. + *

+ * Missing keys are treated as empty/zero, so a compound that contains none of + * the expected entries yields an instance equivalent to {@link #EMPTY}. + * + * @param compound the {@code displayState} compound from the client packet + * @return a new immutable {@link ReactorDisplayState} built from the given NBT + */ + public static ReactorDisplayState deserializeNBT(CompoundTag compound) { + Map items = new HashMap<>(); + if (compound.contains(COMPONENT_CLIENT_DISPLAY_ITEMS)) { + ListTag list = compound.getList(COMPONENT_CLIENT_DISPLAY_ITEMS, Tag.TAG_COMPOUND); + for (int i = 0; i < list.size(); i++) { + CompoundTag tag = list.getCompound(i); + Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(tag.getString(COMPONENT_ITEM))); + if (item != null) { + items.put(item, tag.getInt(COMPONENT_COUNT)); + } + } + } + + List fluids = new ArrayList<>(); + if (compound.contains(COMPONENT_CLIENT_DISPLAY_FLUIDS)) { + ListTag list = compound.getList(COMPONENT_CLIENT_DISPLAY_FLUIDS, Tag.TAG_COMPOUND); + for (int i = 0; i < list.size(); i++) { + fluids.add(BigFluidStack.read(list.getCompound(i))); + } + } + + long maxFluidCapacity = compound.getLong(COMPONENT_CLIENT_MAX_FLUIDS_CAPACITY); + + return new ReactorDisplayState(items, fluids, maxFluidCapacity); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java new file mode 100644 index 00000000..02f03074 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java @@ -0,0 +1,111 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.display; + +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.utility.CreateLang; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; +import net.nuclearteam.createnuclear.content.multiblock.IHeat; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; + +import java.util.List; +import java.util.Map; + +/** + * Builds the Goggles tooltip shown when looking at an assembled reactor controller. + *

+ * This is a stateless presentation helper: it only reads from a + * {@link ReactorDisplayState} snapshot (plus the current heat level) and appends the + * resulting lines to the tooltip. It performs no NBT access, inventory lookups or + * other block-entity-specific logic, keeping the rendering separate from the block + * entity's data/state management. + *

+ * Typical usage from {@code ReactorControllerBlockEntity#addToGoggleTooltip}: + *

{@code
+ * @Override
+ * public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking) {
+ *     CompoundTag patternTag = this.getConfiguredPatternTag();
+ *     if (patternTag == null || patternTag.isEmpty()) {
+ *         return false;
+ *     }
+ *     ReactorGoggleTooltipRenderer.render(tooltip, displayState, patternTag.getInt("heat"), isPlayerSneaking);
+ *     return true;
+ * }
+ * }
+ */ +public final class ReactorGoggleTooltipRenderer { + private ReactorGoggleTooltipRenderer() {} + + /** + * Appends the reactor controller's Goggles tooltip lines to {@code tooltip}. + *

+ * Renders, in order: the gauge info header, the reactor heat level, the loaded + * item rods (or a placeholder if none), and the loaded fluids with their fill + * ratio as a progress bar (or a placeholder if none). + * + * @param tooltip the tooltip line list to append to + * @param state the current display snapshot (items, fluids, max fluid capacity) + * @param heat the reactor's current heat value, used to render the heat tooltip line + * @param isPlayerSneaking whether the viewing player is sneaking (currently unused, + * kept for signature parity with other goggle tooltip providers) + */ + public static void render(List tooltip, ReactorDisplayState state, int heat, boolean isPlayerSneaking) { + CreateLang.translate("gui.gauge.info_header") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + IHeat.HeatLevel.getName("reactor_controller").style(ChatFormatting.GRAY).forGoggles(tooltip); + + IHeat.HeatLevel.getFormattedHeatText(heat).forGoggles(tooltip); + + if (state.items().isEmpty()) { + CreateNuclearLang.builder() + .add(Component.translatable("tooltip.item.empty.rod").withStyle(ChatFormatting.GRAY)) + .add(CreateNuclearLang.number(0).style(ChatFormatting.GOLD)) + .forGoggles(tooltip); + } else { + for (Map.Entry entry : state.items().entrySet()) { + ItemStack stack = new ItemStack(entry.getKey()); + int count = entry.getValue(); + CreateNuclearLang.itemName(stack) + .style(ChatFormatting.GRAY) + .text(": ") + .add(CreateNuclearLang.number(count).style(ChatFormatting.GOLD)) + .forGoggles(tooltip); + } + } + + if (state.fluids().isEmpty()) { + CreateNuclearLang.translate("tooltip.fluid.none") + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + + CreateNuclearLang.builder() + .text(TooltipHelper.makeProgressBar(5, 0)) + .style(ChatFormatting.BLUE) + .space() + .text("0%") + .forGoggles(tooltip); + } else { + long maxCapacity = state.maxFluidCapacity(); + for (BigFluidStack stack : state.fluids()) { + float fillRatio = maxCapacity > 0 ? (float) stack.amount / maxCapacity : 0; + if (fillRatio >= 0.99f) + fillRatio = 1.0f; + int filledBars = Math.round(fillRatio * 5); + + CreateNuclearLang.translate("tooltip.fluid", stack.stack.getDisplayName()) + .style(ChatFormatting.GRAY) + .forGoggles(tooltip); + + CreateNuclearLang.builder() + .text(TooltipHelper.makeProgressBar(5, filledBars)) + .style(ChatFormatting.BLUE) + .space() + .text(Math.round(fillRatio * 100) + "%") + .forGoggles(tooltip); + } + } + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java index 854cc992..0b10897e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java @@ -7,6 +7,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; public class DefaultPersistenceService implements IPersistenceService { @Override @@ -22,6 +23,11 @@ public void readBasicState(ReactorControllerBlockEntity owner, CompoundTag compo if (!clientPacket) { owner.deserializeInventory(compound.getCompound("pattern")); + } else { + owner.setDisplayState(compound.contains("displayState") + ? ReactorDisplayState.deserializeNBT(compound.getCompound("displayState")) + : ReactorDisplayState.EMPTY + ); } owner.setConfiguredPattern(ItemStack.of(compound.getCompound("items"))); @@ -39,6 +45,8 @@ public void writeBasicState(ReactorControllerBlockEntity owner, CompoundTag comp if (!clientPacket) { compound.put("pattern", owner.serializeInventory()); + } else { + compound.put("displayState", owner.getDisplayState().serializeNBT()); } compound.put("items", owner.getConfiguredPattern().serializeNBT()); From 0247936829f02cd0f50edb0d1bd3659d6f864598 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 14 Jun 2026 14:18:03 +0200 Subject: [PATCH 009/171] audit 2 --- AUDIT_REEVALUATION.md | 163 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 AUDIT_REEVALUATION.md diff --git a/AUDIT_REEVALUATION.md b/AUDIT_REEVALUATION.md new file mode 100644 index 00000000..c3590d52 --- /dev/null +++ b/AUDIT_REEVALUATION.md @@ -0,0 +1,163 @@ +# 🔍 Réévaluation indépendante — Create Nuclear (branche `V2-CorrectifAudit`) + +> Nouvelle analyse complète du code (`src/main/java`, hors `src/generated` et `src/main/resources`), réalisée indépendamment de `AUDIT.md`, puis comparée à ce dernier. 4 revues par zone (multiblock/réacteur, radiation/effets/équipement/explosion, events/utility/worldgen/config, package racine/recettes) + vérifications ciblées par grep/lecture. + +--- + +## 0. Constat général + +Le projet a visiblement subi un **gros travail de nettoyage depuis l'audit** (commits `d0325da2`, `42565d89`, `cedf05cd`, `01d5eb55`, `62305467`, `b99b60c1`, `67798bdf`, `b4948109`...). Plusieurs problèmes structurels majeurs de `AUDIT.md` sont **réglés**, mais une bonne partie des bugs fonctionnels « quick win » identifiés sont **toujours présents tels quels**, et de **nouveaux bugs** apparaissent dans le code récemment extrait (managers, packets de blueprint). + +--- + +## 1. Points de `AUDIT.md` **toujours valides** + +### Bugs critiques (§2) + +| # | Statut | Détail vérifié | +|---|---|---| +| **B1** `EventTextOverlay.isActive() = timer>0 && false` | ✅ Toujours présent | `foundation/events/overlay/EventTextOverlay.java:40`. `triggerEvent()` n'a aucun appelant — overlay 100% mort. | +| **B3** `VicinityEffect` cooldown déclaré dans la boucle | ✅ Toujours présent (Critique confirmé) | `content/effects/VicinityEffect.java`. `cooldowns`/`getCooldown`/`setCooldown` toujours inutilisés. `RadiationEffect` réapplique l'effet à chaque tick de durée à toutes les entités proches au lieu de toutes les 500 ticks. | +| **B4** `THORIUM_BLOCK` drop `RAW_URANIUM` + tags d'ore | ✅ Toujours présent | `CNBlocks.java:599-618`. Toujours copié-collé d'un minerai d'uranium, tags `ores*`/`THORIUM_ORES` conservés. | +| **B5** `BiomeTagRule.apply()` retourne `null` | ✅ Toujours présent, mais **dormance accrue** | `infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java:21`. Le seul appelant (`IS_IRRADIATED_PLAIN`/`IS_HIGHLANDS`) est lui-même mort → bug latent mais inatteignable. | +| **B6** Packet blueprint — argument uranium perdu | ✅ Toujours présent (variante) | `ReactorBluePrintItemScreen.java` : args 5/6 inversés à l'appel **et** `ReactorBluePrintItemPacket` envoie `countGraphiteRod` deux fois → `countUraniumRod` jamais transmis. | +| **B7** `CNNoiseData.bootstrapRegistries()` vide, `EROSION` jamais enregistré | ✅ Toujours présent — **risque accru** | `EROSION` est désormais consommé par la `DEFAULT_RULE` qui, elle, est **active** (alors que l'audit la jugeait dormante). À vérifier en jeu : possible échec de génération du monde irradié. | +| **B9** `RadiationCapability.applyEffects` deux branches → `amplifierLevel0` | ✅ Toujours présent | `content/radiation/capability/RadiationCapability.java:154-157` (déplacé depuis `content/effects/capability`). Le palier `radiationLevel1` est toujours inopérant. | +| **B10** `IrradiatedOverlayRendererVision` sans null-check `mc.player` | ✅ Toujours présent | `foundation/events/overlay/IrradiatedOverlayRendererVision.java:24-26`. | +| **B12** `AnimalUtil.isFood` teste le tag NBT `"Ingredient"` jamais écrit | ✅ Toujours présent | Vérifié par grep global : aucun writer de `"Ingredient"` dans tout `src/main/java`. Le mécanisme d'élevage/soin du poulet irradié via `isFood` reste cassé. | +| **B13** Armure anti-radiation, bras invisibles en mode CHEST | ✅ Toujours présent | `AntiRadiationArmorClientExtensions.java:39-40` utilise toujours `model.rightArm`/`leftArm` (champs hérités non rendus) au lieu de `right_arm`/`left_arm`. | +| **B15** `try/catch(Exception)` comme branchement dans `NuclearExplosionEntity` | ✅ Toujours présent | Ligne ~226, avale toute exception silencieusement. | +| **B16** `ModdedCookingRecipeResult` construit avec `conditions=null` puis `.forEach` | ✅ Toujours présent | `CNStandardRecipeGen.java:351/391`. NPE datagen latent confirmé tel quel. | +| **B18** `CNCClient.screenShaking` réutilise la clé TOML `nuclearBombFlash` | ✅ Toujours présent (Critique) | `infrastructure/config/CNCClient.java:8-9`. | +| **B19** `IS_HIGHLANDS = biome()` (varargs vide → toujours faux) | ✅ Toujours présent | Fichier renommé `IrradiatedSurfaceRules` (v2 fusionné/renommé), branches `MOON_DIRT`/secondaire toujours mortes. | + +### Dead code (§3) toujours présent + +- **Framework d'animation keyframe** (`CNModelAnimator`, `CNAnimation`, `CNIAnimatedEntity`, `CNAdvancedEntityModel`/`CNBasicEntityModel`/`CNTabulaModelRenderUtils`/`CNTextureOffset`/`CNTransform`, etc., 10 fichiers) dans `content/explosion` — toujours **100% mort**, zéro appelant. +- **`CreateNuclearDamageSources`** vs **`CNDamageSources`** — toujours dupliqués à l'identique, 2 sites d'appel toujours sur la mauvaise classe. +- **`CommentEventClients.java`** — coquille vide toujours présente. +- **`foundation/events/possible code`** — fichier brouillon sans extension, toujours présent. +- **`CNShapelessRecipeGen`** — toujours mort (registration commentée dans `CreateNuclearDatagen`), duplique `GeneratedRecipeBuilder` de `CNStandardRecipeGen`. +- **`RadiationOverlay`/`EasingHudOverlay`** — `RadiationOverlay` toujours non-instanciée comme overlay (commentée dans `HudRenderer`), mais ⚠️ nuance : `RadiationOverlay.setCoverage(...)` est appelé statiquement par `HelmetOverlay:69` → pas du tout-mort, juste **partiellement mort** (l'overlay lui-même ne s'affiche jamais, mais une de ses méthodes statiques est utilisée ailleurs). +- **`VerifyPattern5x5/7x7/9x9`** (`ReactorPattern`) — toujours mortes, et ont **divergé** des vraies définitions de pattern dans `CNMultiblock` (ex: `"ODDDO"` vs `"ADDDA"`). +- **`saveData2`** (`ReactorBluePrintMenu:160-179`) — toujours mort et toujours buggé (pas de reset). +- **`VicinityEffect.cooldowns`/`getCooldown`/`setCooldown`**, **`RadiationCapability.getArmorResistance`**, **`VirtualReactorInputFluid.removeFluid/getAmount`**, **`MultiblockMatchResult`/`matchesWithResult`/`contruct`** (lib), **`CNAdvancement.START=null`**, **`CExplode`** (config jamais branché), **`registerAndWrap`** (`CNDensityFunctions`), **`IrradiatedBiomes.monsters()`** no-op, **`PaletteBlockPattern.VANILLA_RANGE`** (doublon de `STANDARD_RANGE`), **`CNFanProcessingTypes.parseLegacy/ofLegacyName/LEGACY_NAME_MAP`** — tous **toujours présents et morts**. +- **Imports doublons dans `CNBlocks.java`** — toujours présents malgré le commit `cedf05cd` (de nouveaux doublons ou ratés sur ce fichier précisément). + +### Design (§6) + +- **Package racine fourre-tout** (~25 classes `CN*` à plat) — **toujours tel quel**, aucune sous-décomposition. +- **`run/` versionné** — toujours suivi par git (19 fichiers, dont des `hs_err_pid*.log`, un jar désactivé, `imgui.ini`). +- **Aucun test** — `src/test` toujours vide/absent. +- **Duplication `drawGauge`** dans les 5 `DisplaySource` — toujours présent à l'identique, plus `ReactorSummaryDisplaySource` qui réimplique sa propre version + magic numbers (64/64/16000/1000) toujours dupliqués. +- **`GeneratedRecipeBuilder` dupliqué** entre `CNStandardRecipeGen`/`CNShapelessRecipeGen`, et **`moddedCompacting`/`moddedPaths` dupliqués** entre `EnrichedRecipeGen`/`SnowPowderRecipeGen` (et `moddedPaths` toujours `return null` après une boucle dont le résultat est jeté) — **toujours présents, toujours morts**. +- **Commentaires FR/EN mêlés** un peu partout (`ClientEvents`, `CNFluids`, mixins, explosion/particles, équipement irradié) — toujours présent. +- **Logs de debug en prod** — `"EXPLOSIOOOOOON…"` toujours présent dans `NuclearMushroomCloudParticle`. + +--- + +## 2. Points **corrigés** + +| Point AUDIT | Vérification | Conclusion | +|---|---|---| +| **B2** — `RadiationSyncPacket` no-op | `find` global : aucune classe `*RadiationSync*` n'existe plus | ✅ **Corrigé** (disparu lors de la consolidation radiation, commit `42565d89`) | +| **B11** — `LOGGER...coreList.toString()` avant null-check (`SimpleMultiBlockAislePatternBuilder`) | Code actuel : le null-check précède bien le message d'erreur, avec ternaire `coreList != null ? coreList.size() : 0` | ✅ **Corrigé** | +| **B17** — `RodsTooltipHandler` condition de namespace inversée | Agent confirme la classe « correctly wired and free of obvious bugs » après lecture complète | ✅ **Corrigé** (probablement supprimé/réécrit) | +| **Inversion de dépendance `api/`** — `MultiBlockManagerBeta`, `RodType`, `ReactorFluidType` important `content.*` | Grep des imports : **aucun** des trois n'importe quoi que ce soit de `content.*` | ✅ **Corrigé** — la couche `api/` n'a plus de dépendance vers `content/` | +| **Deux frameworks multiblock concurrents** (`lib.multiblock.manager.*`, `IBetterPattern`, builder non-aisle) | `find` confirme : `lib/multiblock/manager` n'existe plus, `IBetterPattern`/`MultiBlockManager`/`MultiBlockCache`/`SimpleMultiBlockPatternBuilder` (non-aisle) n'existent plus | ✅ **Corrigé** — seuls les éléments réellement utilisés de `lib.multiblock` (`SimpleMultiBlockAislePatternBuilder`, `SimpleMultiBlockPattern`) subsistent | +| **Feature radiation éparpillée sur 4 couches** | `foundation/networking/radiation` et `foundation/item/radiation` n'existent plus ; tout est dans `content/radiation`, `api/radiation`, `content/effects` | ✅ **Largement corrigé** (3 packages au lieu de 4, cohérent — reste un découpage en 3 plutôt qu'1 mais c'est raisonnable) | +| **Seam `ConfigValueResolver` non utilisé** | Désormais utilisé par `RadiationEffect` (`ConfigValueResolver.loadValuesInSet`) | ✅ **Corrigé** (au moins pour ce cas d'usage) | +| **`foundation/util` vs `foundation/utility` redondants** | Seul `foundation/utility` existe désormais | ✅ **Corrigé** | +| **God class `ReactorControllerBlockEntity` (886 lignes)** | Désormais **718 lignes** ; logique extraite vers `manager/`, `service/DefaultHeatService`+`HeatManager`, `consumable/ConsumptionCycleManager`, `ReactorMeltdownExecutor`, `ReactorFrameDisplayManager`, `display/ReactorDisplayState`+`ReactorGoggleTooltipRenderer`, `ReactorDebugDiagnostics` | 🟡 **Partiellement corrigé** — réduction réelle (-168 lignes) et architecture manager/service/display bien amorcée, mais reste loin de la cible « <300 lignes » et `tick()`/`handleAssembledState()` restent de gros méthodes multi-responsabilités | +| **B14 — `FluidLockManager` static map non keyée par dimension** | Le problème de clé `BlockPos` sans dimension est confirmé toujours présent | 🟡 **Partiellement** — le sous-point « 2 systèmes de verrou parallèles (`PersistentFluidLocks`) » n'a pas été re-confirmé dans cette passe, possiblement réduit | + +--- + +## 3. Points **devenus obsolètes** (zone/fichier supprimé, finding non-applicable) + +- **`IrradiatedSurfaceRules` v1** vs v2 — il n'y a plus qu'**un seul** fichier `IrradiatedSurfaceRules` (le « v2 » a été renommé/fusionné, commit `90ad3849`/`d0325da2`). Le point « doublon v1/v2 » disparaît, mais **le bug `IS_HIGHLANDS = biome()` subsiste dans le fichier survivant** (cf. §1, B19). +- **Audit B8** (`clearLockIfAllInputsEmpty` NPE par `findStructure(...).data().getSize()` sans null-check) — la méthode existe toujours (`controller/ReactorControllerBlockEntity.java:685-718`) mais la nouvelle revue ne relève plus de risque NPE direct ; en revanche elle relève un **nouveau problème de performance** (re-scan complet de la structure à chaque vidage de fluide). Le risque a changé de nature plutôt que disparu — je le classe « reformulé » plutôt que strictement obsolète. +- **`ReactorFluidTypesValue.java`** (cité dans « imports morts ») — n'apparaît plus dans `api/multiblock/fluid/` (seul `ReactorFluidType.java` existe) → ce fichier/finding est obsolète. +- **Couplage `MultiBlockManagerBeta` ↔ `ReactorControllerBlockEntity` (effet de bord `setMultiblockFacing`)** — non re-confirmé par la revue actuelle ; la classe ne dépend plus de `content.*` du tout (cf. §2), donc soit ce couplage a été supprimé, soit il a été restructuré. À vérifier ponctuellement si pertinent, mais le problème **tel que décrit** (import direct) n'existe plus. + +--- + +## 4. Points **non confirmés / nécessitent vérification ciblée** (ni confirmés ni infirmés dans cette passe) + +- Perf : scan ~3971 blocs par `ReactorPattern.findController` sans garde client (§4 audit) — non re-vérifié explicitement. +- Perf : `ReactorAlarmEntity.tickServer()` sans garde `!isClientSide` — non re-vérifié. +- Perf : `ReactorFluidType.getTypeForFluid` double-boucle — non re-vérifié (la revue a trouvé un *autre* problème sur ce fichier, voir nouveaux problèmes). +- `HelmetOverlay` double rendu hotbar — non re-vérifié. +- `InventoryHashUtil` incluant `getDamageValue()` dans le hash — non re-vérifié. +- `ReactorOutput.requireNonNull`+`assert` — confirmé présent par la nouvelle revue (voir §5), donc **toujours valide** en fait. +- `RodsTooltipHandler`/`TextUtils`/`Mods`/`SoundEntryBuilder`/`BigFluidStack` helpers morts — `Mods.getBlock/getItem` confirmés encore morts (Mineur), le reste non re-vérifié individuellement. + +--- + +## 5. **Nouveaux problèmes** non mentionnés dans `AUDIT.md` + +Ces points ressortent de la nouvelle revue et concernent essentiellement le **code récemment extrait** lors de la décomposition (managers, packets, services) — ce qui est cohérent : le refactor a déplacé le code mais introduit de nouvelles régressions ponctuelles. + +| # | Fichier:ligne | Problème | Gravité | Conséquence | Recommandation | +|---|---|---|---|---|---| +| N1 | `content/multiblock/IHeat.java:73-75` | `isNotDanger(heat)` = `of(heat) != DANGER \|\| of(heat) != NONE` — **tautologie toujours vraie** | 🔴 Critique | La garde `if (IHeat.HeatLevel.isNotDanger(heat))` à `ReactorControllerBlockEntity:530` ne filtre jamais l'état DANGER — la suppression de la rotation de sortie en cas de surchauffe ne se déclenche jamais | `return of(heat) != DANGER && of(heat) != NONE;` | +| N2 | `manager/ReactorInputFluidManager.java:128-129, 147-148` | `getFluidInTank(getTanks())` — off-by-one (index = count au lieu de count-1), et `extractFluids` ne décrémente jamais `fluidNeeded` | 🔴 Critique | Comptage/extraction de fluide d'entrée potentiellement faussé/cassé à l'exécution | Itérer `for (int t=0; t` indexé par slot | +| N16 | `content/contraptions/irradiated/IrradiatedAnimal.startConverting` | `Math.min(difficulty.getId()-1, 0)` au lieu de `Math.max` → NORMAL/HARD = même amplificateur que EASY, PEACEFUL → -1 | 🟠 Majeur | Le bonus de dégâts de conversion ne scale jamais avec la difficulté ; valeur négative possible en PEACEFUL | `Math.max(difficulty.getId()-1, 0)` | +| N17 | `content/contraptions/irradiated/wolf/IrradiatedWolfModel.headParts()/bodyParts()` | Retourne `null` au lieu de `ImmutableList.of(...)` (contrairement à Cat/Chicken/Cow) | 🟠 Majeur | Violation de contrat `Iterable`, NPE latent si une logique parent itère ces listes | Retourner `ImmutableList.of(...)` comme les autres modèles irradiés | +| N18 | `content/equipment/cloth/ClothItem.java` (`@SuppressWarnings("unused")`, enum `Cloths`) | Enum 16 `DyeColor` + helpers jamais utilisés en dehors de sa propre déclaration, duplique `CNItems.CLOTHS` | 🟡 Mineur (mort/duplication) | Risque de divergence avec `CNItems.CLOTHS` | Supprimer si confirmé inutile | +| N19 | `content/particles/SmallNuclearExplosionParticle.java` | 13 classes Factory quasi-identiques (Nuke/Mine/Underzealot/Raygun/...) ; override `getQuadSize` no-op ; littéral caractère `'＀'` (U+FF00) utilisé comme masque binaire au lieu de `0xFF00` | 🟡 Mineur | Duplication ×13, lisibilité | Factoriser via constructeur paramétré ; remplacer le littéral par `0xFF00` | +| N20 | `content/explosion/CNNuclearExplosionSound.java:26` | `this.volume = 20` alors que la logique de fade attend `[0,1]` | 🟡 Mineur | Valeur initiale incohérente (masquée par le 1er fade-in) | Initialiser à `0F`/`1F` | +| N21 | `content/contraptions/irradiated/wolf/IrradiatedWoldCollarLayer.java` | Faute de frappe "Wold"→"Wolf" dans le nom de classe/fichier, `render()` vide, non enregistrée | 🟡 Mineur (mort) | Scaffolding inachevé pour une fonctionnalité de collier | Finir ou supprimer | +| N22 | `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:25` | Import de `joptsimple.internal.Strings` (classe interne d'une lib tierce non liée) juste pour `repeat(' ', n)` | 🟡 Mineur | Dépendance fragile à une classe "internal" | Remplacer par `" ".repeat(n)` (Java 11+) | +| N23 | `content/logistics/BigFluidStack.java:74` | `nullHash(Object)` réinvente `Objects.hashCode`/`Objects.hash` | 🟡 Mineur | Code superflu | Utiliser `Objects.hash(stack, amount)` | +| N24 | `CNSoundEvents.java:118-120` + chemins `"reacteur/casing"` | Typo `"GeiGer Medium"` (casse incohérente vs "Geiger High/Low") ; chemins de sons en français (`reacteur`) vs anglais ailleurs (`reactor`) | 🟡 Mineur | Incohérence visible (sous-titres) et dans l'organisation des assets | Corriger la casse ; renommer les chemins (impacte les assets, hors périmètre resources) | +| N25 | `content/multiblock/ReactorAssembler.java:134-138` | `getPlayersInRadius` `@Deprecated`, 0 appelant | 🟡 Mineur (mort) | — | Supprimer | +| N26 | `input/item/ReactorInputEntity.java` / `output/ReactorOutputEntity.java` — champ `controller` typé `ReactorControllerBlock` | Type = singleton Block partagé (pas un état positionnel), jamais lu utilement dans `ReactorInputEntity` | 🟡 Mineur (design, repris de l'audit §6 mais avec confirmation que le champ est désormais carrément mort dans Input) | Confusion, état mort | Supprimer ou remplacer par `BlockPos`/référence BE | +| N27 | `casing/ReactorCasingEntity.java:25` | `setController` calcule un offset fixe `+4/+4`, indépendant de la taille (5/7/9) — semble appelée nulle part | 🟡 Mineur | Offset faux si jamais exercé pour 7x7/9x9 | Supprimer ou paramétrer par taille | +| N28 | `casing/ReactorCasing.java:73-75 onWrenched` | `context.getPlayer()` (nullable) déréférencé sans null-check | 🟡 Mineur | NPE si un déclencheur non-joueur (distributeur) actionne la clé | `if (player == null) return PASS;` | +| N29 | Managers Input/InputFluid/Output/Alarm — `getBlocksPosition(Level)` | 3 des 4 managers n'ont pas la garde `level == null` présente dans `ReactorAlarmManager` ; sérialisation x/y/z dupliquée ×3 vs `BlockPos.asLong()` dans Output | 🟡 Mineur (duplication/incohérence) | NPE potentiel, format de sauvegarde incohérent entre managers | Extraire `AbstractReactorIOManager` avec garde + sérialisation commune | +| N30 | `controller/ReactorControllerBlockEntity.java:357` | Lecture `configuredPattern.getOrCreateTag().getDouble("heat")` chaque tick sans la garde `isEmptyConfiguredPattern()` utilisée ailleurs (L412/519/554/560) | 🟡 Mineur | `getOrCreateTag()` mute `ItemStack.EMPTY` chaque tick — incohérence de garde | Ajouter la garde manquante | +| N31 | `manager/ReactorFrameDisplayManager.java:50-59` | Le ratio agrège la capacité/quantité de **tous** les tanks, mais `frameFluidCache` ne stocke que le **premier** fluide non-vide trouvé | 🟡 Mineur | Affichage trompeur si plusieurs fluides distincts présents dans le cadre | Restreindre à un seul type de fluide ou agréger par type | +| N32 | `api/multiblock/fluid/ReactorFluidType.java:196-213` `maxHeat()/efficiency()` | Retournent en dur `12`, lecture de config réelle commentée (`//CNConfigs.server()...`) | 🟡 Mineur | Bug fonctionnel potentiel si un `ReactorFluidType` a `useConfig=true` | Vérifier l'usage de `useConfig` ; restaurer la lecture config ou supprimer le chemin mort | +| N33 | `infrastructure/worldgen/biome/IrradiatedBiomes.java:17-18` `monsters(...)` | Méthode appelée avec de vrais paramètres (`95, 5, 100`) mais **corps totalement vide** | 🟠 Majeur | Le biome irradié n'a probablement **aucun spawn de mob configuré** malgré l'appel qui le suggère | Implémenter `SpawnerData` ou retirer l'appel trompeur | + +--- + +## 6. Tableau de synthèse global (par rapport à `AUDIT.md`) + +| Catégorie audit | Statut global | +|---|---| +| Bugs critiques B1,B3,B4,B5,B6,B7,B9,B10,B12,B13,B15,B16,B18,B19 | **Toujours valides** (14/19 hors B2/B11/B17 corrigés, B8/B14 reformulés/partiels) | +| Inversion `api/` ↔ `content/` | **Corrigé** ✅ | +| Deux frameworks multiblock | **Corrigé** ✅ (lib.multiblock réduit à ce qui est réellement utilisé) | +| Radiation sur 4 couches | **Largement corrigé** ✅ (3 couches cohérentes) | +| God class `ReactorControllerBlockEntity` | **Réduit (886→718 lignes), décomposition amorcée mais incomplète** 🟡 | +| `ConfigValueResolver` non utilisé | **Corrigé** ✅ | +| `foundation/util` vs `utility` | **Corrigé** ✅ | +| Package racine fourre-tout, `run/` versionné, absence de tests | **Toujours valides** | +| Dead code (keyframe, CreateNuclearDamageSources, CNShapelessRecipeGen, possible code, CommentEventClients, VerifyPattern*, saveData2, etc.) | **Toujours valides** (sauf IrradiatedSurfaceRules v1, fusionné) | +| Duplication drawGauge / recipe gen | **Toujours valides** | +| **Nouveaux problèmes** (N1-N33) | Concentrés dans le code récemment extrait (managers, packets blueprint, services, output) — cohérent avec un refactor en cours qui a déplacé sans toujours corriger | + +--- + +## 7. Recommandations priorisées (indépendantes de l'audit) + +1. **Quick wins très haute valeur** (1-3 lignes chacun, à corriger en premier) : **N1** (`IHeat.isNotDanger` tautologie), **B9** (palier radiation), **B18** (clé config dupliquée), **B3** (cooldown VicinityEffect), **B4** (loot thorium), **B1** (`&& false`), **N2** (off-by-one fluide). +2. **Bugs fonctionnels potentiellement bloquants pour le gameplay** : **N4** (vitesse de sortie réacteur jamais non-nulle), **N7** (remplissage fluide réservé à la créative ?), **N3** (progression blueprint cross-contaminée), **B6** (uranium jamais transmis). +3. **Nettoyage à risque faible, gain élevé** (continuer la dynamique déjà engagée) : supprimer le framework d'animation mort (~10 fichiers), `CreateNuclearDamageSources`, `possible code`, `CommentEventClients`, `CNShapelessRecipeGen`, `VerifyPattern*`, `saveData2`, `FluidConsumable`/`distributeSU`, `ReactorOutputValue`. +4. **Continuer la décomposition de `ReactorControllerBlockEntity`** (`tick()`/`handleAssembledState()` restent les derniers gros morceaux) et **harmoniser les 4 managers I/O** (null-check `level`, sérialisation position commune) — c'est exactement la trajectoire déjà entamée, à finir. +5. **Cohésion finale** : `run/` → `.gitignore`, ajouter au moins des tests unitaires sur la logique de pattern/heat (zéro test actuellement), réorganiser le package racine en sous-package `registration/`. From 956f95b28687d605d1cf1c8a88ad7d9a9fe9d06f Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 14 Jun 2026 15:32:22 +0200 Subject: [PATCH 010/171] refactor: split ReactorGoggleTooltipRenderer.render into focused helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Break the single render() method into renderHeaderAndHeat, renderItemRods and renderFluidTanks, each responsible for one section of the Goggles tooltip. Pure refactor, no behavioral change — render() now just calls the three helpers in order. --- Architecture cible.md | 69 +++++++++++++++++++ .../display/ReactorGoggleTooltipRenderer.java | 31 +++++++++ 2 files changed, 100 insertions(+) create mode 100644 Architecture cible.md diff --git a/Architecture cible.md b/Architecture cible.md new file mode 100644 index 00000000..7068d7eb --- /dev/null +++ b/Architecture cible.md @@ -0,0 +1,69 @@ +Architecture cible +Le ReactorControllerBlockEntity deviendrait un orchestrateur mince : + +ReactorControllerBlockEntity + ├─ état persistant minimal (position/taille/facing, configuredPattern, inventory) + ├─ managers (existants) : input/output/inputFluid/alarm/frameDisplay + ├─ services (existants) : IHeatService, IPersistenceService + │ + ├─ NOUVEAU: ReactorRuntimeOrchestrator (remplace le corps de tick()/handleAssembledState) + │ ├─ ReactorInputSnapshotBuilder (#10) + │ ├─ ReactorHeatUpdateCoordinator (#5) + │ ├─ FluidConsumptionRateCalculator (#6) + │ ├─ ConsumptionCycleManager.update() (#7, extension de l'existant) + │ ├─ ReactorOutputDriver (#8) + │ ├─ ReactorAlarmCoordinator (#1) + │ └─ ReactorMeltdownMonitor (#2, #11) + │ └─ NuclearExplosionFactory (#3) + │ └─ BiomeIrradiationService (#4, hors package controller) + │ + ├─ NOUVEAU: ReactorDisplayState (DTO) (#9, #10, #13) + │ └─ ReactorGoggleTooltipRenderer (#9) + │ + └─ NOUVEAU: FluidLockCoordinator (IFluidLockService) (#12) +Le tick() du BE devient essentiellement : + +@Override +public void tick() { + super.tick(); + if (level.isClientSide || isExploding) return; + + MeltdownState meltdown = meltdownMonitor.tick(currentHeat()); + if (meltdown == MeltdownState.EXPLODE) { + explosionFactory.trigger(...); + isExploding = true; + return; + } + + resolveEntitiesIfNeeded(); + if (!isAssembled()) return; + + ReactorInputSnapshot snapshot = snapshotBuilder.build(level, inputManager, inputFluidManager); + displayState.updateFrom(snapshot); + + runtimeOrchestrator.run(snapshot, ...); // heat, fluid buffer, consumption cycle, rotation + alarmCoordinator.update(meltdownMonitor.isDanger()); + stateSynchronizer.updateVisibility(...); +} + +#9 + #13 — Tooltip Goggles + sérialisation clientDisplay* → extraction "presque pure" (lecture de champs existants), pas de changement de comportement, prépare le DTO ReactorDisplayState qui servira aux étapes suivantes. + +Tooltip Goggles (affichage joueur) +Code concerné : addToGoggleTooltip(...) (lignes 266-332). + +Pourquoi l'extraire : 65 lignes de construction de Component/CreateLang/barres de progression — pure logique de présentation UI, sans rapport avec la simulation du réacteur. Le BE ne devrait être qu'une source de données (clientDisplayItems, clientDisplayFluids, heat). +Principe : SRP + séparation présentation/domaine (MVC-like) — le rendu de tooltip doit dépendre d'un état, pas l'inverse. +Cible : ReactorGoggleTooltipRenderer (helper statique ou petite classe), méthode render(List tooltip, ReactorDisplayState state, boolean isSneaking). +Justification : permet de réutiliser/tester le rendu de tooltip indépendamment (et de le faire évoluer — ex. ajouter une ligne — sans toucher au BE). IHaveGoggleInformation.addToGoggleTooltip devient un simple appel délégué. +Dépendances à injecter : un DTO ReactorDisplayState (heat, clientDisplayItems, clientDisplayFluids, clientMaxFluidCapacity, configuredPatternTag). + +Sérialisation NBT de l'affichage client +Code concerné : read/write lignes 349-413 (blocs clientDisplayItems/clientDisplayFluids/clientMaxFluidCapacity). + +Pourquoi l'extraire : ~65 lignes de (dé)sérialisation NBT pour des données qui, avec #10, deviendraient un objet ReactorInputSnapshot/ReactorDisplayState dédié. Actuellement dupliqué inline dans read/write. +Principe : DRY + cohésion — la sérialisation d'un état doit être co-localisée avec sa définition. +Cible : méthode serializeNBT()/deserializeNBT(CompoundTag) sur le futur ReactorDisplayState (#9/#10), appelée depuis read/write au même titre que inputManager.read(...). +Justification : suit exactement le pattern déjà appliqué aux autres managers (inputManager.read/write, etc.) — cohérence architecturale. +Dépendances à injecter : aucune — auto-contenu dans l'objet d'état. + +Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java index 02f03074..f1dc0c08 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java @@ -52,13 +52,34 @@ private ReactorGoggleTooltipRenderer() {} * kept for signature parity with other goggle tooltip providers) */ public static void render(List tooltip, ReactorDisplayState state, int heat, boolean isPlayerSneaking) { + renderHeaderAndHeat(tooltip, heat); + renderItemRods(tooltip, state); + renderFluidTanks(tooltip, state); + } + + /** + * Appends the gauge info header and the reactor's current heat level line. + * + * @param tooltip the tooltip line list to append to + * @param heat the reactor's current heat value + */ + private static void renderHeaderAndHeat(List tooltip, int heat) { CreateLang.translate("gui.gauge.info_header") .style(ChatFormatting.GRAY) .forGoggles(tooltip); IHeat.HeatLevel.getName("reactor_controller").style(ChatFormatting.GRAY).forGoggles(tooltip); IHeat.HeatLevel.getFormattedHeatText(heat).forGoggles(tooltip); + } + /** + * Appends one line per loaded item rod with its stacked count, or a placeholder + * line showing a count of 0 if no rods are loaded. + * + * @param tooltip the tooltip line list to append to + * @param state the current display snapshot + */ + private static void renderItemRods(List tooltip, ReactorDisplayState state) { if (state.items().isEmpty()) { CreateNuclearLang.builder() .add(Component.translatable("tooltip.item.empty.rod").withStyle(ChatFormatting.GRAY)) @@ -75,7 +96,17 @@ public static void render(List tooltip, ReactorDisplayState state, in .forGoggles(tooltip); } } + } + /** + * Appends one line per loaded fluid with a fill-ratio progress bar relative to + * {@link ReactorDisplayState#maxFluidCapacity()}, or a "no fluid" placeholder + * with an empty progress bar if no fluids are loaded. + * + * @param tooltip the tooltip line list to append to + * @param state the current display snapshot + */ + private static void renderFluidTanks(List tooltip, ReactorDisplayState state) { if (state.fluids().isEmpty()) { CreateNuclearLang.translate("tooltip.fluid.none") .style(ChatFormatting.GRAY) From 016188b703544e0c31bfc072c7ffb1f676dec112 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 14 Jun 2026 16:56:00 +0200 Subject: [PATCH 011/171] refactor: extract reactor input snapshot into ReactorInputSnapshotBuilder Move the per-tick collection of input item/fluid data out of ReactorControllerBlockEntity.tick() into a new ReactorInputSnapshot record and ReactorInputSnapshotBuilder service. The builder scans the input item/fluid handlers and produces a single immutable snapshot (items, fluids, max fluid capacity, fuel/cooler rods), which the block entity now uses to populate displayState, bigFuelItem, bigCoolerItem and bigFluidStack. This removes a chunk of inline collection logic and several now-unused imports from the block entity, consolidating the snapshot into one reusable source for tooltip display and future consumption/heat calculations. --- Architecture cible.md | 25 +++------ .../ReactorControllerBlockEntity.java | 53 +++---------------- .../snapshot/ReactorInputSnapshot.java | 34 ++++++++++++ .../snapshot/ReactorInputSnapshotBuilder.java | 49 +++++++++++++++++ 4 files changed, 98 insertions(+), 63 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java diff --git a/Architecture cible.md b/Architecture cible.md index 7068d7eb..9cc41a3e 100644 --- a/Architecture cible.md +++ b/Architecture cible.md @@ -46,24 +46,15 @@ public void tick() { stateSynchronizer.updateVisibility(...); } -#9 + #13 — Tooltip Goggles + sérialisation clientDisplay* → extraction "presque pure" (lecture de champs existants), pas de changement de comportement, prépare le DTO ReactorDisplayState qui servira aux étapes suivantes. +#10 — Snapshot des intrants (ReactorInputSnapshotBuilder) → consolide la collecte déjà faite dans tick(), réutilisée par #5/#6/#9. C'est le pivot qui débloque le découpage du gros tick(). -Tooltip Goggles (affichage joueur) -Code concerné : addToGoggleTooltip(...) (lignes 266-332). +Construction de l'état d'affichage client (clientDisplay*) +Code concerné : tick() lignes 547-575 (remplissage clientDisplayItems, clientDisplayFluids, clientMaxFluidCapacity, bigFuelItem, bigCoolerItem, bigFluidStack). -Pourquoi l'extraire : 65 lignes de construction de Component/CreateLang/barres de progression — pure logique de présentation UI, sans rapport avec la simulation du réacteur. Le BE ne devrait être qu'une source de données (clientDisplayItems, clientDisplayFluids, heat). -Principe : SRP + séparation présentation/domaine (MVC-like) — le rendu de tooltip doit dépendre d'un état, pas l'inverse. -Cible : ReactorGoggleTooltipRenderer (helper statique ou petite classe), méthode render(List tooltip, ReactorDisplayState state, boolean isSneaking). -Justification : permet de réutiliser/tester le rendu de tooltip indépendamment (et de le faire évoluer — ex. ajouter une ligne — sans toucher au BE). IHaveGoggleInformation.addToGoggleTooltip devient un simple appel délégué. -Dépendances à injecter : un DTO ReactorDisplayState (heat, clientDisplayItems, clientDisplayFluids, clientMaxFluidCapacity, configuredPatternTag). - -Sérialisation NBT de l'affichage client -Code concerné : read/write lignes 349-413 (blocs clientDisplayItems/clientDisplayFluids/clientMaxFluidCapacity). - -Pourquoi l'extraire : ~65 lignes de (dé)sérialisation NBT pour des données qui, avec #10, deviendraient un objet ReactorInputSnapshot/ReactorDisplayState dédié. Actuellement dupliqué inline dans read/write. -Principe : DRY + cohésion — la sérialisation d'un état doit être co-localisée avec sa définition. -Cible : méthode serializeNBT()/deserializeNBT(CompoundTag) sur le futur ReactorDisplayState (#9/#10), appelée depuis read/write au même titre que inputManager.read(...). -Justification : suit exactement le pattern déjà appliqué aux autres managers (inputManager.read/write, etc.) — cohérence architecturale. -Dépendances à injecter : aucune — auto-contenu dans l'objet d'état. +Pourquoi l'extraire : c'est une étape de collecte de données (scan des handlers d'items/fluides) totalement séparable de la logique de simulation. Aujourd'hui mélangée au tick principal, elle gonfle tick() et duplique des accès aux managers. +Principe : SRP + cohésion — "collecter l'état des intrants pour affichage/calcul" est une étape nommée et isolée du pipeline. +Cible : ReactorInputSnapshotBuilder (service), méthode buildSnapshot(Level, ReactorInputManagerI, ReactorInputFluidManagerI) -> ReactorInputSnapshot (record contenant items, fluides, capacité max, bigFuel/bigCooler/bigFluidStack). +Justification : le snapshot devient l'unique source utilisée à la fois par le tooltip (#9), le calcul de chaleur (#5) et la consommation (#6/#7) — élimine la dispersion actuelle des mêmes données dans plusieurs champs mutables du BE. +Dépendances à injecter : Level, ReactorInputManagerI, ReactorInputFluidManagerI. Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 50bcb9f9..3f31327c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -4,22 +4,14 @@ import com.simibubi.create.content.logistics.BigItemStack; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; -import com.simibubi.create.foundation.item.TooltipHelper; -import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.foundation.utility.IInteractionChecker; import net.minecraft.ChatFormatting; import net.minecraft.core.*; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.GameRules; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -30,9 +22,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.registries.ForgeRegistries; -import net.nuclearteam.createnuclear.CNEntityType; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.multiblock.IMultiblockController; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; @@ -41,9 +31,10 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorGoggleTooltipRenderer; import net.nuclearteam.createnuclear.content.multiblock.controller.service.*; +import net.nuclearteam.createnuclear.content.multiblock.controller.snapshot.ReactorInputSnapshot; +import net.nuclearteam.createnuclear.content.multiblock.controller.snapshot.ReactorInputSnapshotBuilder; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.FluidLockManager; import net.nuclearteam.createnuclear.content.multiblock.IHeat; -import net.nuclearteam.createnuclear.content.explosion.NuclearExplosionEntity; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutput; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; @@ -51,24 +42,17 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.ConsumptionCycleManager; import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; -import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.BiomeIrradiationService; -import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.CNBiomes; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; -import net.nuclearteam.createnuclear.content.multiblock.input.fluid.VirtualReactorInputFluid; -import net.nuclearteam.createnuclear.content.multiblock.input.item.VirtualReactorInputsItem; import net.nuclearteam.createnuclear.content.multiblock.controller.manager.*; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; -import java.util.Map; - import static net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock.ASSEMBLED; @SuppressWarnings({ "unused" }) @@ -418,34 +402,11 @@ public void tick() { if (!isAssembled()) return; - // Populate display fields for client sync - Map items = new HashMap<>(); - List itemHandlers = this.inputManager.getItemHandlers(level); - for (IItemHandler h : itemHandlers) { - for (int s = 0; s < h.getSlots(); s++) { - ItemStack st = h.getStackInSlot(s); - if (!st.isEmpty()) { - items.merge(st.getItem(), st.getCount(), Integer::sum); - } - } - } - - long maxFluidCapacity = 0; - for (IFluidHandler h : this.inputFluidManager.getFuildHandlers(level)) { - if (h.getTanks() > 0) { - maxFluidCapacity += h.getTankCapacity(0); - } - } - - VirtualReactorInputsItem virtualReactorInputsItem = inputManager.getInventory(level); - VirtualReactorInputFluid virtualReactorInputFluid = inputFluidManager.getInventory(level); - List fluids = VirtualReactorInputFluid.toBigList(virtualReactorInputFluid.fluids()); - - this.displayState = new ReactorDisplayState(items, fluids, maxFluidCapacity); - - this.bigFuelItem = virtualReactorInputsItem.getBigFuelRod(); - this.bigCoolerItem = virtualReactorInputsItem.getBigCooledRod(); - this.bigFluidStack = fluids; + ReactorInputSnapshot snapshot = ReactorInputSnapshotBuilder.build(level, inputManager, inputFluidManager); + this.displayState = new ReactorDisplayState(snapshot.items(), snapshot.fluids(), snapshot.maxFluidCapacity()); + this.bigFuelItem = snapshot.bigFuelItem(); + this.bigCoolerItem = snapshot.bigCoolerItem(); + this.bigFluidStack = snapshot.fluids(); updateReactorStateVisibility(); handleAssembledState(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java new file mode 100644 index 00000000..6d6cce1a --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java @@ -0,0 +1,34 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.snapshot; + +import com.simibubi.create.content.logistics.BigItemStack; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; + +import java.util.List; +import java.util.Map; + +/** + * Snapshot of the reactor's inputs, collected once per tick. + *

+ * {@code items} reflects the items actually present (for tooltip display). + * {@code bigFuelItem}/{@code bigCoolerItem} are derived from + * {@link net.nuclearteam.createnuclear.content.multiblock.input.item.VirtualReactorInputsItem} and always represent, respectively, + * Uranium Rod / Graphite Rod (generic tag-based count, fixed identity) — + * do not use these fields to infer the actual item type loaded. + *

+ * The elements of {@code fluids} ({@link BigFluidStack}) remain mutable + * (public fields); this snapshot only guarantees immutability of the + * list/map structure, not of their contents. + */ + +public record ReactorInputSnapshot(Map items, List fluids, long maxFluidCapacity, BigItemStack bigFuelItem, BigItemStack bigCoolerItem) { + public static final ReactorInputSnapshot EMPTY = new ReactorInputSnapshot( + Map.of(), List.of(), 0, new BigItemStack(ItemStack.EMPTY), new BigItemStack(ItemStack.EMPTY) + ); + + public ReactorInputSnapshot { + items = Map.copyOf(items); + fluids = List.copyOf(fluids); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java new file mode 100644 index 00000000..432872a8 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java @@ -0,0 +1,49 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.snapshot; + +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputFluidManagerI; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputManagerI; +import net.nuclearteam.createnuclear.content.multiblock.input.fluid.VirtualReactorInputFluid; +import net.nuclearteam.createnuclear.content.multiblock.input.item.VirtualReactorInputsItem; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ReactorInputSnapshotBuilder { + private ReactorInputSnapshotBuilder() {} + + public static ReactorInputSnapshot build(Level level, ReactorInputManagerI inputManager, ReactorInputFluidManagerI inputFluidManager) { + // Populate display fields for client sync + Map items = new HashMap<>(); + List itemHandlers = inputManager.getItemHandlers(level); + for (IItemHandler h : itemHandlers) { + for (int s = 0; s < h.getSlots(); s++) { + ItemStack st = h.getStackInSlot(s); + if (!st.isEmpty()) { + items.merge(st.getItem(), st.getCount(), Integer::sum); + } + } + } + + long maxFluidCapacity = 0; + for (IFluidHandler h : inputFluidManager.getFuildHandlers(level)) { + if (h.getTanks() > 0) { + maxFluidCapacity += h.getTankCapacity(0); + } + } + + VirtualReactorInputsItem virtualItems = inputManager.getInventory(level); + VirtualReactorInputFluid virtualFluid = inputFluidManager.getInventory(level); + List fluids = VirtualReactorInputFluid.toBigList(virtualFluid.fluids()); + + + + return new ReactorInputSnapshot(items, fluids, maxFluidCapacity, virtualItems.getBigFuelRod(), virtualItems.getBigCooledRod()); + } +} From 162f1672621d52ca7f51b0488b694c98d71dd58f Mon Sep 17 00:00:00 2001 From: Gio Date: Mon, 15 Jun 2026 08:37:43 +0200 Subject: [PATCH 012/171] chore: ignore .claude local settings and add AUDIT2 review Stop tracking .claude/settings.local.json (machine-specific Claude Code settings) and exclude .claude/* via .gitignore. Add AUDIT2.md, an independent re-evaluation of the V2 refactor against AUDIT.md. --- .claude/settings.local.json | 16 ---- .gitignore | 3 + AUDIT2.md | 176 ++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 16 deletions(-) delete mode 100644 .claude/settings.local.json create mode 100644 AUDIT2.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 2b9997ca..00000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "permissions": { - "allow": [ - "mcp__ide__getDiagnostics", - "Bash(Select-Object FullName)", - "PowerShell(head -100)", - "Read(//tmp/**)", - "Bash(javap -p -c net/createmod/catnip/platform/ForgeCatnipServices.class)", - "Bash(javap -p net/createmod/catnip/platform/ForgeCatnipServices.class)", - "Bash(javap -p net/createmod/catnip/platform/CatnipServices.class)", - "Bash(javap -p net/createmod/catnip/render/BasicFluidRenderer.class)", - "Bash(./gradlew compileJava -q --console=plain)", - "Bash(python -c 'import json,sys; json.load\\(open\\('\\\\''__TRACKED_VAR__'\\\\''\\)\\); print\\('\\\\''OK __TRACKED_VAR__'\\\\''\\)')" - ] - } -} diff --git a/.gitignore b/.gitignore index 969ea7fb..1d1245d2 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ run/.mixin.out run/gametest run/logs run/server + +# LLM +.claude/* diff --git a/AUDIT2.md b/AUDIT2.md new file mode 100644 index 00000000..a36954f2 --- /dev/null +++ b/AUDIT2.md @@ -0,0 +1,176 @@ +# Réévaluation indépendante — CreateNuclearForge (V2-CorrectifAudit) + +**Méthodologie** : 7 audits indépendants couvrant la totalité de `src/main/java` (hors `src/generated` et `src/main/resources`), réalisés à partir de l'état actuel du code uniquement, puis recoupés avec `AUDIT.md` et vérifiés par greps ciblés. + +--- + +## 0. Constat global + +Le code est toujours en **refactor V2 actif** (cohérent avec les commits récents : extraction `ReactorInputSnapshotBuilder`, `ReactorGoggleTooltipRenderer`, `ReactorDisplayState`). Quelques nettoyages annoncés par `AUDIT.md` ont bien eu lieu : + +- ✅ `lib.multiblock.manager.*` (`MultiBlockManager`, `MultiBlockCache`, `RegisteredMultiBlockPattern`) + `IBetterPattern` + `SimpleMultiBlockPatternBuilder` (non-aisle) **ont disparu** du dépôt. +- ✅ `ReactorAlarmEntity.tick()` distingue maintenant proprement `tickAudio()` (client) / `tickServer()` (serveur) — **corrigé**. +- ✅ `B11` (LOGGER avant null-check dans `SimpleMultiBlockAislePatternBuilder`) — **corrigé**, le message d'erreur utilise désormais un ternaire sûr. +- ✅ La feature radiation a été regroupée sous `content/radiation/**` (capability/client) — déplacement, pas (encore) une consolidation des deux contrats (`IRadiationSource` vs `RadiationRegistry`, toujours dupliqués). +- ⚠️ `B2` (RadiationSyncPacket no-op) est **obsolète** : `RadiationSyncPacket`/`ClientRadiationData` n'existent plus du tout — le mécanisme décrit a disparu (probablement remplacé par la capability resync via `RadiationCapability`/`InventoryHashUtil`, qui elle fonctionne). + +Mais la **grande majorité** des bugs et du dead code de `AUDIT.md` sont **toujours présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). + +--- + +## 1. 🐛 Bugs critiques toujours présents + +| Réf. | Fichier:ligne | État | Détail | +|---|---|---|---| +| **B1** | `foundation/events/overlay/EventTextOverlay.java:40` | **Toujours présent** | `return timer > 0 && false;` — overlay jamais actif. `triggerEvent()` confirmé **jamais appelé** (grep global) → la classe entière est morte, enregistrée et rendue chaque frame pour rien. | +| **B4** | `CNBlocks.java` (~599-618) | **Toujours présent** | `THORIUM_BLOCK` drope `RAW_URANIUM` avec `addOreBonusCount(Enchantments.BLOCK_FORTUNE)` et porte les tags `ores`, `ores/thorium`, `ores_in_ground/stone`, `NEEDS_DIAMOND_TOOL/NEEDS_IRON_TOOL`, `THORIUM_ORES` — un bloc de stockage entièrement tagué/loot comme un minerai. | +| **B5** | `infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java:20-23` | **Toujours présent** | `apply()` retourne `null` ; la classe interne `Predicate` (logique réelle) n'est jamais instanciée → NPE dès évaluation de `IS_IRRADIATED_PLAIN`. | +| **B7** | `infrastructure/worldgen/biome/CNNoiseData.java` | **Toujours présent** | `bootstrapRegistries()` reste un corps **vide** ; `EROSION` jamais enregistré dans `Registries.NOISE`, alors que `IrradiatedSurfaceRules` (fusion v1/v2, un seul fichier désormais) fait toujours 3× `noiseCondition(EROSION,...)` → `getOrThrow` lèvera à la génération. | +| **B8** | `content/multiblock/controller/ReactorControllerBlockEntity.java:646` | **Toujours présent, code réécrit mais bug identique** | `clearLockIfAllInputsEmpty()` fait désormais `CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this).data().getSize()` **sans null-check** sur le résultat de `findStructure`, qui peut retourner `null` si la structure n'est plus formée → NPE serveur. La méthode fait en plus un scan cubique `O(n³)` (`getBlockEntity` + capability lookup) alors que `inputFluidManager.getFuildHandlers(level)` donne déjà la liste exacte. | +| **B18** | `infrastructure/config/CNCClient.java:8-9` | **Toujours présent** | `screenShaking` réutilise littéralement la clé TOML `"nuclearBombFlash"` (avec un `;;` final en plus). Confirmé : deux options config pointent sur la même entrée. | + +--- + +## 2. 🐛 Bugs importants toujours présents + +| Réf. | Fichier:ligne | État | Détail | +|---|---|---|---| +| **B3** | `content/effects/VicinityEffect.java:32-49` | **Toujours présent, identique** | `int cooldownTicks = 0;` réinitialisé à chaque itération → branche `else` morte, `cooldowns`/`getCooldown`/`setCooldown` toujours jamais appelés (confirmé grep). `RadiationEffect` continue donc à `addEffect` un `MobEffectInstance(RADIATION,300)` toutes les 5 ticks sur chaque entité proche, sans throttling réel. | +| **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | +| **B9** | `content/radiation/capability/RadiationCapability.java` (`applyEffects`) | **Toujours présent, identique** | Les deux premières branches (`radiation < level1`, `radiation < level2`) donnent toutes deux `amplifierLevel0` → `radiationLevel2` reste un palier inopérant. | +| **B10** | `foundation/events/overlay/IrradiatedOverlayRendererVision.java:24-26` | **Toujours présent — Critique** | `LocalPlayer localPlayer = mc.player;` utilisé directement sans null-check, alors que les autres overlays (`HelmetOverlay`, `RadiationOverlay`) le font correctement. NPE au rendu pendant chargement/respawn/déconnexion. | +| **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | +| **B13** | `content/equipment/armor/AntiRadiationArmorClientExtensions.java` (case `CHEST`) | **Toujours présent, identique** | `this.model.rightArm.visible = true; this.model.leftArm.visible = true;` (champs hérités, non rendus par le `renderToBuffer` custom) au lieu de `right_arm`/`left_arm`. Bras toujours invisibles sur l'armure anti-radiation en mode plastron. | +| **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` (B8) et `ReactorFluidInputEntity.FilteredFluidHandler`. | +| **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | +| **B16** | `foundation/data/recipe/CNStandardRecipeGen.java:351/391` | **Toujours présent (latent)** | `new ModdedCookingRecipeResult(result, compatDatagenOutput, null)` puis `serializeRecipeData` fait `conditions.forEach(...)` sur ce `null` → NPE si une recette `isOtherMod` est un jour sérialisée. | +| **B17** | `foundation/events/RodsTooltipHandler.java:25-26` | **Toujours présent, identique** | `if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return;` — exclut justement les items du mod (les rods), donc `RodsStats` n'est jamais appliqué via ce handler. Code mort fonctionnel à risque si "corrigé" naïvement (double tooltip avec Registrate). | +| **B19** | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` (fusion v1/v2) | **Toujours présent** | `IS_HIGHLANDS = biome()` (varargs vide) → toujours faux ; branches `MOON_DIRT`/`LEAD_TURF` mortes. Les constantes `MOON_DIRT`/`LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` pointent vers `STEEL_BLOCK`/`LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` — noms totalement déconnectés des blocs réels, signe d'un template non ré-thémé. | + +### Bugs mineurs confirmés toujours présents (liste condensée) +- `ReactorInputFluidManager.extractFluids/getBlocksPosition` : toujours `getFluidInTank(getTanks())` (off-by-one), `fluidNeeded` jamais décrémenté, `toExtract>1` ignore les extractions de 1 unité. +- `ReactorInput.use()` : retourne toujours `PASS` côté serveur après `NetworkHooks.openScreen`, vs `SUCCESS` côté client → désync. +- `InventoryHashUtil` : toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité. +- `ReactorSizeDisplaySource` : toujours `tier*100/3` comme "%" — désormais creusé en détail (voir §4, nouveau finding lié). +- `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` toujours recalculé dans la boucle interne pour une valeur invariante. +- `ReactorOutput.use()` : toujours `Objects.requireNonNull(...)` + `assert entity != null` (no-op en prod) au lieu d'une garde gracieuse. + +--- + +## 3. 🧹 Dead code — toujours présent + +Confirmé inchangé (grep global, zéro référence externe) : + +- **Framework d'animation keyframe complet** (`content/explosion/`) : `CNModelAnimator`, `CNAnimation`, `CNIAnimatedEntity`, `CNTransform`, `CNTextureOffset`, et la majorité des méthodes de `CNAdvancedEntityModel`/`CNAdvancedModelBox` (`chainSwing`, `chainWave`, `walk`, `flap`, `transitionTo`, `displayList`/`compiled`, etc.). `CNTabulaModelRenderUtils` duplique toujours `CNBasicModelPart.ModelBox`. +- **`CreateNuclearDamageSources`** toujours doublon octet-pour-octet de `CNDamageSources`, toujours utilisé séparément (`CNFanProcessingTypes`, `RadiationEffect` vs `NuclearExplosionEntity`). +- **`foundation/events/CommentEventClients.java`** : toujours coquille `@EventBusSubscriber` vide. +- **`foundation/events/possible code`** : toujours présent, fichier sans extension `.java`, brouillon `com.tonpackage` (HudOverlayRegistry / 2ᵉ CNClientEvent / META-INF services) — non compilé mais toujours dans le repo. +- **`foundation/data/recipe/CNShapelessRecipeGen.java`** : toujours mort (enregistrement commenté dans `CreateNuclearDatagen.java:42`), et son `GeneratedRecipeBuilder` reste dupliqué quasi à l'identique dans `CNStandardRecipeGen.GeneratedRecipeBuilder` — **la duplication existe désormais même côté code vivant**, pas seulement dans le code mort. +- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` continue d'écrire dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — confirmé comme un no-op silencieux qui semble fonctionnel. +- **`ReactorPattern.VerifyPattern5x5/7x7/9x9`** + `SimpleMultiBlockPattern.test()` : toujours morts, et la copie locale des patterns **a divergé** de `CNMultiblock` (`"ODDDO"/"BDCDB"` vs `"ADDDA"/"BDCDB"`) — preuve concrète que ce code mort pourrit déjà. +- **`ReactorBluePrintMenu.saveData2`** : toujours présent, doublon mort de `saveData`, toujours avec sa logique de comptage sans reset. +- **`ReactorAssembler.getPlayersInRadius`** (`@Deprecated`) : toujours mort. +- **Champs/méthodes morts** : `outputPos`/`getStressConfigKey` (`ReactorOutputEntity`), `inputPos`/`inputLevelKey` (`ReactorInputEntity`), `ReactorCasingEntity.getController`/`controller` (offset `+4/+4`), helpers `TextUtils`, `BigFluidStack.isInfinite/comparator/duplicateWrappers`, `CExplode` (config jamais lue), `IrradiatedBiomes.monsters()` no-op, `CNRecipeTypes.CAN_BE_AUTOMATED` (toujours non référencé). +- **Imports en double** : `CNBlocks.java` (`ResourceLocation`, `BlockTags`, `Enriching*Block` ×2) toujours présents. + +--- + +## 4. 🆕 Nouveaux problèmes / régressions apparus depuis l'audit + +Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT.md` — ils résultent soit de zones non couvertes par l'audit précédent (cat/wolf/cow, displaySources détaillés), soit de refactors V2 en cours. + +### 🔴 Critiques / Majeurs + +1. **`ReactorCasingEntity.setController` — offset `+4/+4` codé en dur, appliqué inconditionnellement** + `controller = new BlockPos(pos.getX()+4, pos.getY(), pos.getZ()+4)` est correct **uniquement** pour le pattern 9×9 (T3, rayon 4). Pour T1 (5×5, rayon 2) et T2 (7×7, rayon 3), le champ pointe vers un bloc erroné. `AUDIT.md` classait ce champ en "dead code à supprimer" (offset magique) ; en l'état c'est en plus un **bug latent** si quiconque consomme `getController()` à l'avenir sur un réacteur T1/T2. + *Gravité* : Majeur (latent, dépend de l'usage futur). *Recommandation* : supprimer le champ (toujours non lu en pratique) ou le calculer depuis la taille réelle assemblée. + +2. **`IrradiatedCatCollarLayer` / `IrradiatedWoldCollarLayer` — feature de teinture de collier non câblée** + `IrradiatedWoldCollarLayer.render()` est un corps **vide** ; `IrradiatedCatCollarLayer` (implémentation complète) n'est **jamais ajouté** via `addLayer(...)` au renderer. Pourtant `IrradiatedCat` câble entièrement l'interaction `DyeItem` → `setCollarColor`/`getCollarColor` (`IrradiatedCat.java:333-342`). `IrradiatedWolf` contient même des lignes commentées (`DATA_COLLAR_COLOR`) montrant une tentative abandonnée. + *Conséquence* : un joueur peut teindre le collier d'un chat/loup irradié apprivoisé, l'action est acceptée, mais **rien ne s'affiche jamais** — feature visible cassée, non documentée dans `AUDIT.md` (qui ne couvrait pas `content/contraptions/irradiated/{cat,wolf,cow}`). + *Recommandation* : enregistrer `IrradiatedCatCollarLayer` dans le renderer du chat, implémenter `IrradiatedWoldCollarLayer.render`, ou retirer toute la mécanique `setCollarColor`/interaction `DyeItem` si hors scope. + +3. **`AntiRadiationArmorItem.getArmorTexture` — hook mort en Forge 1.20.1** + L'override `getArmorTexture(ItemStack, Entity, EquipmentSlot, String)` (renvoyant un chemin de texture par couleur de tissu via `ClothTagHelper.getArmorTexturePath`) **n'est plus appelé par Forge 47.2.x** — ce hook a été retiré depuis longtemps ; le rendu passe désormais exclusivement par `IClientItemExtensions`/`AntiRadiationArmorClientExtensions`, qui n'utilise jamais la couleur de tissu. Conséquence : toute la mécanique `ClothTagHelper`/`SmithingTransformRecipeMixin` (NBT `ClothColor`) n'a **aucun effet visuel** — teindre l'armure anti-radiation via tissu ne change rien à son apparence. C'est un **bug de fonctionnalité silencieuse**, distinct de B13 (qui concerne la visibilité des bras), non couvert par `AUDIT.md`. + *Recommandation* : implémenter la sélection de texture colorée dans `AntiRadiationArmorClientExtensions`/`AntiRadiationArmorModel`, ou retirer `getArmorTexture` + `ClothTagHelper.getArmorTexturePath` (et documenter que la teinture de tissu est cosmétiquement inerte). + +4. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** + `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes. + *Conséquence* : une fuite de fluide irradiant un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. + *Lien AUDIT.md* : prolonge directement le constat §1.4 ("contrat IRadiationSource vs RadiationRegistry dupliqué sans règle de priorité") — ici un **troisième** mécanisme d'application apparaît, renforçant l'absence de propriétaire unique pour la feature radiation. + *Recommandation* : router via un helper unique "peut être irradié" partagé par les 3 chemins. + +5. **Deux overlays de "vision irradiée" actifs en parallèle** + `IrradiatedOverlayRendererVision` (actif, bug B10) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). + +6. **`RenderHelper.renderTextureOverlay` — `Math.round(alpha*coverage)` annule le fade** + `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 5). + +### 🟠 Importants + +7. **`ReactorOutputManager.distributeSU` — code mort issu du refactor manager, divergent de `rotate()`** + `ReactorOutputManager.distributeSU` (~47 lignes, algorithme de redistribution avec epsilon `1e-6`) n'est **jamais appelé** ; `ReactorControllerBlockEntity.rotate()` réimplémente un algorithme de distribution **différent** (round-robin simple) en mutant directement `speed`/`heat` des `ReactorOutputEntity`, sans passer par `ReactorOutputManagerI`. Deux algorithmes concurrents pour le même problème — un nouveau "deux frameworks parallèles" local au package `manager/`, dans l'esprit du constat §1.3 de `AUDIT.md` mais sur un périmètre que l'audit précédent n'avait pas détaillé. + +8. **`ReactorInputFluidManager.getBlocksPosition` — `LOGGER.warn` à chaque appel (tick)** + Un `LOGGER.warn("getBlocksPosition: {} {}", ...)` tourne en boucle au niveau `WARN` à chaque tick via `ReactorInputSnapshotBuilder` — pollution de logs en production introduite par le refactor récent (non présente dans `AUDIT.md`, qui ne connaissait pas encore `ReactorInputSnapshotBuilder`). + +9. **`RadiationCapability.lastBiomeLocation` — état mort, non sérialisé** + `cap.setLastBiomeLocation(biomeLoc)` est écrit chaque tick mais **jamais lu pour une décision**, et `RadiationProvider.serializeNBT` ne le persiste même pas. État fantôme apparu avec le déplacement de `content/effects/capability` → `content/radiation/capability` ; non présent tel quel dans `AUDIT.md`. + +10. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** + `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. + +11. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** + En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT.md`. + +12. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** + `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B5/B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT.md` avait documenté (qui se concentrait sur les surface rules). + +13. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B5/B7/B19), point d'alerte non couvert par `AUDIT.md`. + +### 🟡 Mineurs + +14. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). +15. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 5 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. +16. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +17. **`ReactorBluePrintItemPacket.totalInit`** : champ `static double` partagé, lu dans `calculatePostgres()` avant d'être écrit par `write()` côté émission — état global non thread-safe, partiellement lié à B6 mais distinct. + +--- + +## 5. 🏗️ Architecture — état actuel (synthèse) + +Les 5 problèmes structurels de `AUDIT.md` §1 restent **tous valides** : + +1. **Inversion `api/`** : `api.multiblock.MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` dépendent toujours de `content.*` — confirmé. +2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, verrous fluides (`tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty`, ~65 lignes), rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT.md`. +3. **Deux frameworks multiblock concurrents** : le ménage a réduit `lib/multiblock` (suppression de `MultiBlockManager`/`MultiBlockCache`/`IBetterPattern`), mais **trois couches coexistent toujours** pour la détection de contrôleur — `lib/multiblock` (matching générique), `api.multiblock.MultiBlockManagerBeta` (vérification de structure), et `content.multiblock.pattern.ReactorPattern`/`MultiblockHelpers` (scan géométrique brut, ~3971 blocs, **toujours** appelé en double — `findController` + `findControllerPos` — à chaque pose/casse, y compris côté client sans garde `isClientSide`). C'est le point de performance/architecture le plus critique et **entièrement non corrigé**. +4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (point 4 ci-dessus) découvert dans cette analyse. +5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, AUDIT §4 ligne 2). + +--- + +## 6. ⚡ Performance — état actuel + +Tous les points perf de `AUDIT.md` §4 restent **non corrigés** : +- `ReactorPattern.findController`/`findControllerPos` : scan ~3971 blocs ×2 par placement/casse, sans garde client — confirmé, **aggravé** par `MultiBlockManagerBeta.findStructure` qui peut ajouter jusqu'à 4×3×729 lookups supplémentaires. +- `RadiationEffect` : `HashSet` + parsing reconstruits à chaque entité/tick — confirmé. +- `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` recalculé en boucle interne — confirmé. +- `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame — confirmé. +- **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). +- **Nouveau** : `NuclearExplosionEntity.tick()` — tri complet d'une pile de jusqu'à 11³=1331 `BlockPos` avec comparateur `distManhattan` coûteux, en un seul tick. + +--- + +## 7. Plan d'action — priorités mises à jour + +**Quick wins toujours en attente** (1 ligne, fort impact) : **B1**, **B5**, **B9**, **B18** (toujours triviaux à corriger), **B7** (enregistrer `EROSION`), **B4** (loot/tags Thorium). + +**Nouveaux quick wins identifiés** : +- `AntiRadiationArmorClientExtensions` (B13) : remplacer `rightArm/leftArm` par `right_arm/left_arm` en case `CHEST`. +- `RadiationEffectHandler` : ajouter les mêmes gardes (config/immunité/résistance) que les deux autres chemins. +- Enregistrer `IrradiatedCatCollarLayer` / implémenter `IrradiatedWoldCollarLayer.render`, ou retirer la mécanique de teinture de collier. +- Retirer `RenderHelper.renderTextureOverlay(..., Math.round(...))` → passer `alpha*coverage` brut (si `RadiationOverlay` est un jour réactivé). + +**Priorité structurelle inchangée** : le scan géométrique `ReactorPattern`/`MultiblockHelpers` (point architecture #3) reste le risque de performance serveur le plus sérieux et n'a reçu **aucune** correction — c'est le chantier le plus rentable avant de poursuivre la décomposition de `ReactorControllerBlockEntity`. + +**Nettoyage dead-code** : la liste de `AUDIT.md` §3 reste presque intégralement valide (un seul item — `B11`/`SimpleMultiBlockPatternBuilder` non-aisle + `lib.multiblock.manager.*` — a été traité) ; ajouter à cette liste : `ReactorOutputManager.distributeSU`, `RadiationCapability.lastBiomeLocation`, `IrradiatedWoldCollarLayer`/`IrradiatedCatCollarLayer` (à finir ou supprimer), `AntiRadiationArmorItem.getArmorTexture`/`ClothTagHelper.getArmorTexturePath`. From 17b32088008c689435247c19112daa9cf705a68b Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Mon, 15 Jun 2026 09:53:07 +0200 Subject: [PATCH 013/171] correction proximity system --- .../multiblock/reactorLogic/DefaultHeatCalculator.java | 4 ++-- .../createnuclear/infrastructure/config/CRods.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index ccea9845..68bed4a0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -61,9 +61,9 @@ public double computeHeat(BigItemStack bigFuelItem, BigItemStack bigCoolerItem, if ("fuel".equals(currentRod)) { ItemStack stack = ItemStack.of(list.getCompound(l)); if (stack.is(CNTags.CNItemTags.FUEL.tag)) { - heat += rod.baseRodHeat(); + heat += rod.proximityRodHeat(); } else if (stack.is(CNTags.CNItemTags.COOLER.tag)) { - heat += rod.baseRodHeat() / Math.max(1, ItemRodTypesValue.getRodType(stack.getItem()).proximityRodHeat()); + heat += rod.baseRodHeat() / ItemRodTypesValue.getRodType(stack.getItem()).proximityRodHeat(); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java index 8de36b96..4c5bdcd8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java @@ -13,7 +13,7 @@ public class CRods extends ConfigBase { public final ConfigInt baseValueUranium = i(64, -70, 70, "Base heat value for uranium rods", Comments.warning, Comments.uraniumBaseValue); public final ConfigInt graphiteRodLifetime = i(3600, 100, 5000, "Graphite (cooling) rod lifetime (in ticks)", Comments.graphiteRodLifetime, Comments.hintTick); - public final ConfigFloat graphiteProxyMalus = f((float) -1/4, -70, 70, "Heat penalty from nearby graphite rods", Comments.warning, Comments.graphiteProximityMalus); + public final ConfigFloat graphiteProxyMalus = f(-4, -70, 70, "Heat penalty from nearby graphite rods", Comments.warning, Comments.graphiteProximityMalus); public final ConfigInt baseValueGraphite = i(-32, -50, 50, "Base heat value for graphite rods", Comments.warning, Comments.graphiteBaseValue); From 7b89514306d56d8817f2b9920c31fe3ff952eb06 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Mon, 15 Jun 2026 10:12:12 +0200 Subject: [PATCH 014/171] added comment --- .../nuclearteam/createnuclear/infrastructure/config/CRods.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java index 4c5bdcd8..5aefbbee 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java @@ -13,6 +13,7 @@ public class CRods extends ConfigBase { public final ConfigInt baseValueUranium = i(64, -70, 70, "Base heat value for uranium rods", Comments.warning, Comments.uraniumBaseValue); public final ConfigInt graphiteRodLifetime = i(3600, 100, 5000, "Graphite (cooling) rod lifetime (in ticks)", Comments.graphiteRodLifetime, Comments.hintTick); + // the proximity value of coolant items are divisions so if the heat of the fuel is 64, the calcul will be "heat + 64/-4" public final ConfigFloat graphiteProxyMalus = f(-4, -70, 70, "Heat penalty from nearby graphite rods", Comments.warning, Comments.graphiteProximityMalus); public final ConfigInt baseValueGraphite = i(-32, -50, 50, "Base heat value for graphite rods", Comments.warning, Comments.graphiteBaseValue); From 972a4929cfcc6f900d737d61817c17a3f65fa75e Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:17:52 +0200 Subject: [PATCH 015/171] refactor: rename AUDIT2.md to AUDIT_V1.md and update references --- AUDIT2.md => AUDIT_ACTUEL.md | 78 +++++---- AUDIT_REEVALUATION.md | 163 ------------------ AUDIT.md => AUDIT_V1.md | 0 .../nuclearteam/createnuclear/CNBlocks.java | 4 - .../createnuclear/CNRecipeTypes.java | 5 - .../explosion/CNAdvancedEntityModel.java | 19 -- .../content/explosion/CNAnimation.java | 34 ---- .../content/explosion/CNIAnimatedEntity.java | 16 -- .../content/explosion/CNModelAnimator.java | 127 -------------- .../content/explosion/CNTextureOffset.java | 15 -- .../content/explosion/CNTransform.java | 72 -------- .../fan/processing/CNFanProcessingTypes.java | 4 +- .../content/logistics/BigFluidStack.java | 18 -- .../content/multiblock/ReactorAssembler.java | 10 -- .../bluePrintItem/ReactorBluePrintMenu.java | 22 --- .../casing/ReactorCasingEntity.java | 12 -- .../manager/ReactorOutputManager.java | 78 +-------- .../manager/ReactorOutputManagerI.java | 13 -- .../input/item/ReactorInputEntity.java | 5 - .../output/ReactorOutputEntity.java | 6 - .../multiblock/pattern/ReactorPattern.java | 64 ------- .../content/radiation/RadiationEffect.java | 4 +- .../CreateNuclearDamageSources.java | 37 ---- .../data/recipe/CNShapelessRecipeGen.java | 140 --------------- .../events/CommentEventClients.java | 23 --- .../foundation/events/possible code | 66 ------- .../foundation/utility/Maths.java | 11 -- .../foundation/utility/TextUtils.java | 87 +--------- .../infrastructure/config/CNCCommon.java | 1 - .../infrastructure/config/CNCServer.java | 2 - .../data/CreateNuclearDatagen.java | 2 - 31 files changed, 47 insertions(+), 1091 deletions(-) rename AUDIT2.md => AUDIT_ACTUEL.md (72%) delete mode 100644 AUDIT_REEVALUATION.md rename AUDIT.md => AUDIT_V1.md (100%) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAnimation.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/explosion/CNIAnimatedEntity.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/explosion/CNModelAnimator.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTextureOffset.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTransform.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/damageTypes/CreateNuclearDamageSources.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNShapelessRecipeGen.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEventClients.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/events/possible code diff --git a/AUDIT2.md b/AUDIT_ACTUEL.md similarity index 72% rename from AUDIT2.md rename to AUDIT_ACTUEL.md index a36954f2..73b00310 100644 --- a/AUDIT2.md +++ b/AUDIT_ACTUEL.md @@ -1,12 +1,12 @@ # Réévaluation indépendante — CreateNuclearForge (V2-CorrectifAudit) -**Méthodologie** : 7 audits indépendants couvrant la totalité de `src/main/java` (hors `src/generated` et `src/main/resources`), réalisés à partir de l'état actuel du code uniquement, puis recoupés avec `AUDIT.md` et vérifiés par greps ciblés. +**Méthodologie** : 7 audits indépendants couvrant la totalité de `src/main/java` (hors `src/generated` et `src/main/resources`), réalisés à partir de l'état actuel du code uniquement, puis recoupés avec `AUDIT_V1.md` et vérifiés par greps ciblés. --- ## 0. Constat global -Le code est toujours en **refactor V2 actif** (cohérent avec les commits récents : extraction `ReactorInputSnapshotBuilder`, `ReactorGoggleTooltipRenderer`, `ReactorDisplayState`). Quelques nettoyages annoncés par `AUDIT.md` ont bien eu lieu : +Le code est toujours en **refactor V2 actif** (cohérent avec les commits récents : extraction `ReactorInputSnapshotBuilder`, `ReactorGoggleTooltipRenderer`, `ReactorDisplayState`). Quelques nettoyages annoncés par `AUDIT_V1.md` ont bien eu lieu : - ✅ `lib.multiblock.manager.*` (`MultiBlockManager`, `MultiBlockCache`, `RegisteredMultiBlockPattern`) + `IBetterPattern` + `SimpleMultiBlockPatternBuilder` (non-aisle) **ont disparu** du dépôt. - ✅ `ReactorAlarmEntity.tick()` distingue maintenant proprement `tickAudio()` (client) / `tickServer()` (serveur) — **corrigé**. @@ -14,7 +14,7 @@ Le code est toujours en **refactor V2 actif** (cohérent avec les commits récen - ✅ La feature radiation a été regroupée sous `content/radiation/**` (capability/client) — déplacement, pas (encore) une consolidation des deux contrats (`IRadiationSource` vs `RadiationRegistry`, toujours dupliqués). - ⚠️ `B2` (RadiationSyncPacket no-op) est **obsolète** : `RadiationSyncPacket`/`ClientRadiationData` n'existent plus du tout — le mécanisme décrit a disparu (probablement remplacé par la capability resync via `RadiationCapability`/`InventoryHashUtil`, qui elle fonctionne). -Mais la **grande majorité** des bugs et du dead code de `AUDIT.md` sont **toujours présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). +La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). En revanche, **le dead code a été en grande partie nettoyé le 2026-06-15** (voir l'encart ✅ du §3) ; il ne reste qu'un résidu non trivial. --- @@ -57,76 +57,76 @@ Mais la **grande majorité** des bugs et du dead code de `AUDIT.md` sont **toujo --- -## 3. 🧹 Dead code — toujours présent +## 3. 🧹 Dead code — reste à faire -Confirmé inchangé (grep global, zéro référence externe) : +> **✅ Corrigé le 2026-06-15** (branche `V2-CorrectifAudit`, compilation validée) — supprimés du dépôt : +> framework d'animation mort (`CNModelAnimator`, `CNAnimation`, `CNIAnimatedEntity`, `CNTransform`, `CNTextureOffset`) + `Maths.cullAnimationTick` + méthodes mortes associées de `CNAdvancedEntityModel` (`rotate`/`rotateMinus`/`setCNTextureOffset`/`getCNTextureOffset`/`modelTextureMap`) ; +> `CreateNuclearDamageSources` (consolidé dans `CNDamageSources`) ; `CommentEventClients.java` ; `foundation/events/possible code` ; `CNShapelessRecipeGen.java` (+ réf. dans `CreateNuclearDatagen`) ; `ReactorPattern.VerifyPattern5x5/7x7/9x9` ; `ReactorBluePrintMenu.saveData2` ; `ReactorAssembler.getPlayersInRadius` ; `ReactorOutputEntity.getStressConfigKey` ; `ReactorInputEntity.inputPos`/`inputLevelKey` ; `ReactorCasingEntity.controller`/`setController`/`getController` ; `TextUtils` (5 helpers) ; `BigFluidStack.isInfinite`/`comparator`/`duplicateWrappers` ; `CExplode` (+ réf. `CNCServer`/`CNCCommon`) ; `CNRecipeTypes.CAN_BE_AUTOMATED` ; `ReactorOutputManager.distributeSU` (+ déclaration dans `ReactorOutputManagerI`) ; imports en double de `CNBlocks.java`. +> +> **⚠️ Corrections de l'audit V1/V2** : +> - `CNTabulaModelRenderUtils` **n'est PAS du dead code** : il est utilisé par `CNAdvancedModelBox.cubeList`/`doRender`, sur le chemin de rendu **vivant** du champignon atomique (`NuclearMushroomCloudModel`). Conservé. La duplication `ModelBox` reste une opportunité de *refactor*, pas une suppression. +> - `ReactorOutputEntity.outputPos` **n'est PAS mort** : il est lu/écrit dans `read()`/`write()` (sérialisation NBT). Laissé en place. -- **Framework d'animation keyframe complet** (`content/explosion/`) : `CNModelAnimator`, `CNAnimation`, `CNIAnimatedEntity`, `CNTransform`, `CNTextureOffset`, et la majorité des méthodes de `CNAdvancedEntityModel`/`CNAdvancedModelBox` (`chainSwing`, `chainWave`, `walk`, `flap`, `transitionTo`, `displayList`/`compiled`, etc.). `CNTabulaModelRenderUtils` duplique toujours `CNBasicModelPart.ModelBox`. -- **`CreateNuclearDamageSources`** toujours doublon octet-pour-octet de `CNDamageSources`, toujours utilisé séparément (`CNFanProcessingTypes`, `RadiationEffect` vs `NuclearExplosionEntity`). -- **`foundation/events/CommentEventClients.java`** : toujours coquille `@EventBusSubscriber` vide. -- **`foundation/events/possible code`** : toujours présent, fichier sans extension `.java`, brouillon `com.tonpackage` (HudOverlayRegistry / 2ᵉ CNClientEvent / META-INF services) — non compilé mais toujours dans le repo. -- **`foundation/data/recipe/CNShapelessRecipeGen.java`** : toujours mort (enregistrement commenté dans `CreateNuclearDatagen.java:42`), et son `GeneratedRecipeBuilder` reste dupliqué quasi à l'identique dans `CNStandardRecipeGen.GeneratedRecipeBuilder` — **la duplication existe désormais même côté code vivant**, pas seulement dans le code mort. -- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` continue d'écrire dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — confirmé comme un no-op silencieux qui semble fonctionnel. -- **`ReactorPattern.VerifyPattern5x5/7x7/9x9`** + `SimpleMultiBlockPattern.test()` : toujours morts, et la copie locale des patterns **a divergé** de `CNMultiblock` (`"ODDDO"/"BDCDB"` vs `"ADDDA"/"BDCDB"`) — preuve concrète que ce code mort pourrit déjà. -- **`ReactorBluePrintMenu.saveData2`** : toujours présent, doublon mort de `saveData`, toujours avec sa logique de comptage sans reset. -- **`ReactorAssembler.getPlayersInRadius`** (`@Deprecated`) : toujours mort. -- **Champs/méthodes morts** : `outputPos`/`getStressConfigKey` (`ReactorOutputEntity`), `inputPos`/`inputLevelKey` (`ReactorInputEntity`), `ReactorCasingEntity.getController`/`controller` (offset `+4/+4`), helpers `TextUtils`, `BigFluidStack.isInfinite/comparator/duplicateWrappers`, `CExplode` (config jamais lue), `IrradiatedBiomes.monsters()` no-op, `CNRecipeTypes.CAN_BE_AUTOMATED` (toujours non référencé). -- **Imports en double** : `CNBlocks.java` (`ResourceLocation`, `BlockTags`, `Enriching*Block` ×2) toujours présents. +Restant (grep global, zéro référence externe sauf mention) : + +- **Méthodes d'animation mortes restantes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` : `chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `setRotateAngle`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`/`movementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`. Mortes mais **non triviales** : leur retrait déclenche une cascade dans des classes **vivantes** (ex. `CNAdvancedModelBox.calculateRotation`/`bob` appellent `model.getMovementScale()`). À traiter en nettoyage dédié + dédup `ModelBox`. +- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §4 points 5 & 6 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). +- **`SimpleMultiBlockPattern.test()`** : à vérifier — la classe ne semble plus exister (à confirmer/retirer si résidu). +- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §4 point 12, worldgen "irradié" template non terminé). --- ## 4. 🆕 Nouveaux problèmes / régressions apparus depuis l'audit -Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT.md` — ils résultent soit de zones non couvertes par l'audit précédent (cat/wolf/cow, displaySources détaillés), soit de refactors V2 en cours. +Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — ils résultent soit de zones non couvertes par l'audit précédent (cat/wolf/cow, displaySources détaillés), soit de refactors V2 en cours. ### 🔴 Critiques / Majeurs 1. **`ReactorCasingEntity.setController` — offset `+4/+4` codé en dur, appliqué inconditionnellement** - `controller = new BlockPos(pos.getX()+4, pos.getY(), pos.getZ()+4)` est correct **uniquement** pour le pattern 9×9 (T3, rayon 4). Pour T1 (5×5, rayon 2) et T2 (7×7, rayon 3), le champ pointe vers un bloc erroné. `AUDIT.md` classait ce champ en "dead code à supprimer" (offset magique) ; en l'état c'est en plus un **bug latent** si quiconque consomme `getController()` à l'avenir sur un réacteur T1/T2. + `controller = new BlockPos(pos.getX()+4, pos.getY(), pos.getZ()+4)` est correct **uniquement** pour le pattern 9×9 (T3, rayon 4). Pour T1 (5×5, rayon 2) et T2 (7×7, rayon 3), le champ pointe vers un bloc erroné. `AUDIT_V1.md` classait ce champ en "dead code à supprimer" (offset magique) ; en l'état c'est en plus un **bug latent** si quiconque consomme `getController()` à l'avenir sur un réacteur T1/T2. *Gravité* : Majeur (latent, dépend de l'usage futur). *Recommandation* : supprimer le champ (toujours non lu en pratique) ou le calculer depuis la taille réelle assemblée. 2. **`IrradiatedCatCollarLayer` / `IrradiatedWoldCollarLayer` — feature de teinture de collier non câblée** `IrradiatedWoldCollarLayer.render()` est un corps **vide** ; `IrradiatedCatCollarLayer` (implémentation complète) n'est **jamais ajouté** via `addLayer(...)` au renderer. Pourtant `IrradiatedCat` câble entièrement l'interaction `DyeItem` → `setCollarColor`/`getCollarColor` (`IrradiatedCat.java:333-342`). `IrradiatedWolf` contient même des lignes commentées (`DATA_COLLAR_COLOR`) montrant une tentative abandonnée. - *Conséquence* : un joueur peut teindre le collier d'un chat/loup irradié apprivoisé, l'action est acceptée, mais **rien ne s'affiche jamais** — feature visible cassée, non documentée dans `AUDIT.md` (qui ne couvrait pas `content/contraptions/irradiated/{cat,wolf,cow}`). + *Conséquence* : un joueur peut teindre le collier d'un chat/loup irradié apprivoisé, l'action est acceptée, mais **rien ne s'affiche jamais** — feature visible cassée, non documentée dans `AUDIT_V1.md` (qui ne couvrait pas `content/contraptions/irradiated/{cat,wolf,cow}`). *Recommandation* : enregistrer `IrradiatedCatCollarLayer` dans le renderer du chat, implémenter `IrradiatedWoldCollarLayer.render`, ou retirer toute la mécanique `setCollarColor`/interaction `DyeItem` si hors scope. 3. **`AntiRadiationArmorItem.getArmorTexture` — hook mort en Forge 1.20.1** - L'override `getArmorTexture(ItemStack, Entity, EquipmentSlot, String)` (renvoyant un chemin de texture par couleur de tissu via `ClothTagHelper.getArmorTexturePath`) **n'est plus appelé par Forge 47.2.x** — ce hook a été retiré depuis longtemps ; le rendu passe désormais exclusivement par `IClientItemExtensions`/`AntiRadiationArmorClientExtensions`, qui n'utilise jamais la couleur de tissu. Conséquence : toute la mécanique `ClothTagHelper`/`SmithingTransformRecipeMixin` (NBT `ClothColor`) n'a **aucun effet visuel** — teindre l'armure anti-radiation via tissu ne change rien à son apparence. C'est un **bug de fonctionnalité silencieuse**, distinct de B13 (qui concerne la visibilité des bras), non couvert par `AUDIT.md`. + L'override `getArmorTexture(ItemStack, Entity, EquipmentSlot, String)` (renvoyant un chemin de texture par couleur de tissu via `ClothTagHelper.getArmorTexturePath`) **n'est plus appelé par Forge 47.2.x** — ce hook a été retiré depuis longtemps ; le rendu passe désormais exclusivement par `IClientItemExtensions`/`AntiRadiationArmorClientExtensions`, qui n'utilise jamais la couleur de tissu. Conséquence : toute la mécanique `ClothTagHelper`/`SmithingTransformRecipeMixin` (NBT `ClothColor`) n'a **aucun effet visuel** — teindre l'armure anti-radiation via tissu ne change rien à son apparence. C'est un **bug de fonctionnalité silencieuse**, distinct de B13 (qui concerne la visibilité des bras), non couvert par `AUDIT_V1.md`. *Recommandation* : implémenter la sélection de texture colorée dans `AntiRadiationArmorClientExtensions`/`AntiRadiationArmorModel`, ou retirer `getArmorTexture` + `ClothTagHelper.getArmorTexturePath` (et documenter que la teinture de tissu est cosmétiquement inerte). 4. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes. *Conséquence* : une fuite de fluide irradiant un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. - *Lien AUDIT.md* : prolonge directement le constat §1.4 ("contrat IRadiationSource vs RadiationRegistry dupliqué sans règle de priorité") — ici un **troisième** mécanisme d'application apparaît, renforçant l'absence de propriétaire unique pour la feature radiation. + *Lien AUDIT_V1.md* : prolonge directement le constat §1.4 ("contrat IRadiationSource vs RadiationRegistry dupliqué sans règle de priorité") — ici un **troisième** mécanisme d'application apparaît, renforçant l'absence de propriétaire unique pour la feature radiation. *Recommandation* : router via un helper unique "peut être irradié" partagé par les 3 chemins. 5. **Deux overlays de "vision irradiée" actifs en parallèle** - `IrradiatedOverlayRendererVision` (actif, bug B10) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). + `IrradiatedOverlayRendererVision` (actif, bug B10) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT_V1.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). 6. **`RenderHelper.renderTextureOverlay` — `Math.round(alpha*coverage)` annule le fade** - `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 5). + `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT_V1.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 5). ### 🟠 Importants -7. **`ReactorOutputManager.distributeSU` — code mort issu du refactor manager, divergent de `rotate()`** - `ReactorOutputManager.distributeSU` (~47 lignes, algorithme de redistribution avec epsilon `1e-6`) n'est **jamais appelé** ; `ReactorControllerBlockEntity.rotate()` réimplémente un algorithme de distribution **différent** (round-robin simple) en mutant directement `speed`/`heat` des `ReactorOutputEntity`, sans passer par `ReactorOutputManagerI`. Deux algorithmes concurrents pour le même problème — un nouveau "deux frameworks parallèles" local au package `manager/`, dans l'esprit du constat §1.3 de `AUDIT.md` mais sur un périmètre que l'audit précédent n'avait pas détaillé. +7. **✅ Corrigé (2026-06-15)** — `ReactorOutputManager.distributeSU` (dead code) supprimé, ainsi que sa déclaration dans `ReactorOutputManagerI`. Il ne reste plus que `ReactorControllerBlockEntity.rotate()` (round-robin simple) ; plus de duplication d'algorithme de distribution. 8. **`ReactorInputFluidManager.getBlocksPosition` — `LOGGER.warn` à chaque appel (tick)** - Un `LOGGER.warn("getBlocksPosition: {} {}", ...)` tourne en boucle au niveau `WARN` à chaque tick via `ReactorInputSnapshotBuilder` — pollution de logs en production introduite par le refactor récent (non présente dans `AUDIT.md`, qui ne connaissait pas encore `ReactorInputSnapshotBuilder`). + Un `LOGGER.warn("getBlocksPosition: {} {}", ...)` tourne en boucle au niveau `WARN` à chaque tick via `ReactorInputSnapshotBuilder` — pollution de logs en production introduite par le refactor récent (non présente dans `AUDIT_V1.md`, qui ne connaissait pas encore `ReactorInputSnapshotBuilder`). -9. **`RadiationCapability.lastBiomeLocation` — état mort, non sérialisé** - `cap.setLastBiomeLocation(biomeLoc)` est écrit chaque tick mais **jamais lu pour une décision**, et `RadiationProvider.serializeNBT` ne le persiste même pas. État fantôme apparu avec le déplacement de `content/effects/capability` → `content/radiation/capability` ; non présent tel quel dans `AUDIT.md`. +9. **`RadiationCapability.lastBiomeLocation` — non persisté (correction : PAS du dead code)** + ⚠️ Correction de l'audit : contrairement à ce qui était écrit, `lastBiomeLocation` **est bien lu pour une décision** (`RadiationCapability:89`, comparaison `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`). Ce n'est donc **pas** du dead code et il n'a pas été supprimé. Le seul point restant : `RadiationProvider.serializeNBT` ne le persiste pas → l'état est perdu au save/déconnexion (bug mineur, à corriger ou assumer). 10. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** - `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. + `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT_V1.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. 11. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** - En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT.md`. + En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. 12. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** - `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B5/B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT.md` avait documenté (qui se concentrait sur les surface rules). + `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B5/B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). -13. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B5/B7/B19), point d'alerte non couvert par `AUDIT.md`. +13. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B5/B7/B19), point d'alerte non couvert par `AUDIT_V1.md`. ### 🟡 Mineurs @@ -139,10 +139,10 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT.md` — il ## 5. 🏗️ Architecture — état actuel (synthèse) -Les 5 problèmes structurels de `AUDIT.md` §1 restent **tous valides** : +Les 5 problèmes structurels de `AUDIT_V1.md` §1 restent **tous valides** : 1. **Inversion `api/`** : `api.multiblock.MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` dépendent toujours de `content.*` — confirmé. -2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, verrous fluides (`tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty`, ~65 lignes), rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT.md`. +2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, verrous fluides (`tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty`, ~65 lignes), rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT_V1.md`. 3. **Deux frameworks multiblock concurrents** : le ménage a réduit `lib/multiblock` (suppression de `MultiBlockManager`/`MultiBlockCache`/`IBetterPattern`), mais **trois couches coexistent toujours** pour la détection de contrôleur — `lib/multiblock` (matching générique), `api.multiblock.MultiBlockManagerBeta` (vérification de structure), et `content.multiblock.pattern.ReactorPattern`/`MultiblockHelpers` (scan géométrique brut, ~3971 blocs, **toujours** appelé en double — `findController` + `findControllerPos` — à chaque pose/casse, y compris côté client sans garde `isClientSide`). C'est le point de performance/architecture le plus critique et **entièrement non corrigé**. 4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (point 4 ci-dessus) découvert dans cette analyse. 5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, AUDIT §4 ligne 2). @@ -151,12 +151,12 @@ Les 5 problèmes structurels de `AUDIT.md` §1 restent **tous valides** : ## 6. ⚡ Performance — état actuel -Tous les points perf de `AUDIT.md` §4 restent **non corrigés** : +Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : - `ReactorPattern.findController`/`findControllerPos` : scan ~3971 blocs ×2 par placement/casse, sans garde client — confirmé, **aggravé** par `MultiBlockManagerBeta.findStructure` qui peut ajouter jusqu'à 4×3×729 lookups supplémentaires. - `RadiationEffect` : `HashSet` + parsing reconstruits à chaque entité/tick — confirmé. - `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` recalculé en boucle interne — confirmé. - `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame — confirmé. -- **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). +- **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT_V1.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). - **Nouveau** : `NuclearExplosionEntity.tick()` — tri complet d'une pile de jusqu'à 11³=1331 `BlockPos` avec comparateur `distManhattan` coûteux, en un seul tick. --- @@ -173,4 +173,8 @@ Tous les points perf de `AUDIT.md` §4 restent **non corrigés** : **Priorité structurelle inchangée** : le scan géométrique `ReactorPattern`/`MultiblockHelpers` (point architecture #3) reste le risque de performance serveur le plus sérieux et n'a reçu **aucune** correction — c'est le chantier le plus rentable avant de poursuivre la décomposition de `ReactorControllerBlockEntity`. -**Nettoyage dead-code** : la liste de `AUDIT.md` §3 reste presque intégralement valide (un seul item — `B11`/`SimpleMultiBlockPatternBuilder` non-aisle + `lib.multiblock.manager.*` — a été traité) ; ajouter à cette liste : `ReactorOutputManager.distributeSU`, `RadiationCapability.lastBiomeLocation`, `IrradiatedWoldCollarLayer`/`IrradiatedCatCollarLayer` (à finir ou supprimer), `AntiRadiationArmorItem.getArmorTexture`/`ClothTagHelper.getArmorTexturePath`. +**Nettoyage dead-code** : la majeure partie de la liste `§3` a été traitée le 2026-06-15 (voir l'encart ✅ du §3). **Reste à faire** : +- Méthodes d'animation mortes restantes dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` + dédup `ModelBox` (cascade dans classes vivantes — nettoyage dédié). +- `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §4 points 5 & 6). +- `IrradiatedBiomes.monsters()` no-op et reliquat éventuel `SimpleMultiBlockPattern.test()`. +- Features à finir ou supprimer (pas du pur dead code, décision produit) : `IrradiatedWoldCollarLayer`/`IrradiatedCatCollarLayer`, `AntiRadiationArmorItem.getArmorTexture`/`ClothTagHelper.getArmorTexturePath`. diff --git a/AUDIT_REEVALUATION.md b/AUDIT_REEVALUATION.md deleted file mode 100644 index c3590d52..00000000 --- a/AUDIT_REEVALUATION.md +++ /dev/null @@ -1,163 +0,0 @@ -# 🔍 Réévaluation indépendante — Create Nuclear (branche `V2-CorrectifAudit`) - -> Nouvelle analyse complète du code (`src/main/java`, hors `src/generated` et `src/main/resources`), réalisée indépendamment de `AUDIT.md`, puis comparée à ce dernier. 4 revues par zone (multiblock/réacteur, radiation/effets/équipement/explosion, events/utility/worldgen/config, package racine/recettes) + vérifications ciblées par grep/lecture. - ---- - -## 0. Constat général - -Le projet a visiblement subi un **gros travail de nettoyage depuis l'audit** (commits `d0325da2`, `42565d89`, `cedf05cd`, `01d5eb55`, `62305467`, `b99b60c1`, `67798bdf`, `b4948109`...). Plusieurs problèmes structurels majeurs de `AUDIT.md` sont **réglés**, mais une bonne partie des bugs fonctionnels « quick win » identifiés sont **toujours présents tels quels**, et de **nouveaux bugs** apparaissent dans le code récemment extrait (managers, packets de blueprint). - ---- - -## 1. Points de `AUDIT.md` **toujours valides** - -### Bugs critiques (§2) - -| # | Statut | Détail vérifié | -|---|---|---| -| **B1** `EventTextOverlay.isActive() = timer>0 && false` | ✅ Toujours présent | `foundation/events/overlay/EventTextOverlay.java:40`. `triggerEvent()` n'a aucun appelant — overlay 100% mort. | -| **B3** `VicinityEffect` cooldown déclaré dans la boucle | ✅ Toujours présent (Critique confirmé) | `content/effects/VicinityEffect.java`. `cooldowns`/`getCooldown`/`setCooldown` toujours inutilisés. `RadiationEffect` réapplique l'effet à chaque tick de durée à toutes les entités proches au lieu de toutes les 500 ticks. | -| **B4** `THORIUM_BLOCK` drop `RAW_URANIUM` + tags d'ore | ✅ Toujours présent | `CNBlocks.java:599-618`. Toujours copié-collé d'un minerai d'uranium, tags `ores*`/`THORIUM_ORES` conservés. | -| **B5** `BiomeTagRule.apply()` retourne `null` | ✅ Toujours présent, mais **dormance accrue** | `infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java:21`. Le seul appelant (`IS_IRRADIATED_PLAIN`/`IS_HIGHLANDS`) est lui-même mort → bug latent mais inatteignable. | -| **B6** Packet blueprint — argument uranium perdu | ✅ Toujours présent (variante) | `ReactorBluePrintItemScreen.java` : args 5/6 inversés à l'appel **et** `ReactorBluePrintItemPacket` envoie `countGraphiteRod` deux fois → `countUraniumRod` jamais transmis. | -| **B7** `CNNoiseData.bootstrapRegistries()` vide, `EROSION` jamais enregistré | ✅ Toujours présent — **risque accru** | `EROSION` est désormais consommé par la `DEFAULT_RULE` qui, elle, est **active** (alors que l'audit la jugeait dormante). À vérifier en jeu : possible échec de génération du monde irradié. | -| **B9** `RadiationCapability.applyEffects` deux branches → `amplifierLevel0` | ✅ Toujours présent | `content/radiation/capability/RadiationCapability.java:154-157` (déplacé depuis `content/effects/capability`). Le palier `radiationLevel1` est toujours inopérant. | -| **B10** `IrradiatedOverlayRendererVision` sans null-check `mc.player` | ✅ Toujours présent | `foundation/events/overlay/IrradiatedOverlayRendererVision.java:24-26`. | -| **B12** `AnimalUtil.isFood` teste le tag NBT `"Ingredient"` jamais écrit | ✅ Toujours présent | Vérifié par grep global : aucun writer de `"Ingredient"` dans tout `src/main/java`. Le mécanisme d'élevage/soin du poulet irradié via `isFood` reste cassé. | -| **B13** Armure anti-radiation, bras invisibles en mode CHEST | ✅ Toujours présent | `AntiRadiationArmorClientExtensions.java:39-40` utilise toujours `model.rightArm`/`leftArm` (champs hérités non rendus) au lieu de `right_arm`/`left_arm`. | -| **B15** `try/catch(Exception)` comme branchement dans `NuclearExplosionEntity` | ✅ Toujours présent | Ligne ~226, avale toute exception silencieusement. | -| **B16** `ModdedCookingRecipeResult` construit avec `conditions=null` puis `.forEach` | ✅ Toujours présent | `CNStandardRecipeGen.java:351/391`. NPE datagen latent confirmé tel quel. | -| **B18** `CNCClient.screenShaking` réutilise la clé TOML `nuclearBombFlash` | ✅ Toujours présent (Critique) | `infrastructure/config/CNCClient.java:8-9`. | -| **B19** `IS_HIGHLANDS = biome()` (varargs vide → toujours faux) | ✅ Toujours présent | Fichier renommé `IrradiatedSurfaceRules` (v2 fusionné/renommé), branches `MOON_DIRT`/secondaire toujours mortes. | - -### Dead code (§3) toujours présent - -- **Framework d'animation keyframe** (`CNModelAnimator`, `CNAnimation`, `CNIAnimatedEntity`, `CNAdvancedEntityModel`/`CNBasicEntityModel`/`CNTabulaModelRenderUtils`/`CNTextureOffset`/`CNTransform`, etc., 10 fichiers) dans `content/explosion` — toujours **100% mort**, zéro appelant. -- **`CreateNuclearDamageSources`** vs **`CNDamageSources`** — toujours dupliqués à l'identique, 2 sites d'appel toujours sur la mauvaise classe. -- **`CommentEventClients.java`** — coquille vide toujours présente. -- **`foundation/events/possible code`** — fichier brouillon sans extension, toujours présent. -- **`CNShapelessRecipeGen`** — toujours mort (registration commentée dans `CreateNuclearDatagen`), duplique `GeneratedRecipeBuilder` de `CNStandardRecipeGen`. -- **`RadiationOverlay`/`EasingHudOverlay`** — `RadiationOverlay` toujours non-instanciée comme overlay (commentée dans `HudRenderer`), mais ⚠️ nuance : `RadiationOverlay.setCoverage(...)` est appelé statiquement par `HelmetOverlay:69` → pas du tout-mort, juste **partiellement mort** (l'overlay lui-même ne s'affiche jamais, mais une de ses méthodes statiques est utilisée ailleurs). -- **`VerifyPattern5x5/7x7/9x9`** (`ReactorPattern`) — toujours mortes, et ont **divergé** des vraies définitions de pattern dans `CNMultiblock` (ex: `"ODDDO"` vs `"ADDDA"`). -- **`saveData2`** (`ReactorBluePrintMenu:160-179`) — toujours mort et toujours buggé (pas de reset). -- **`VicinityEffect.cooldowns`/`getCooldown`/`setCooldown`**, **`RadiationCapability.getArmorResistance`**, **`VirtualReactorInputFluid.removeFluid/getAmount`**, **`MultiblockMatchResult`/`matchesWithResult`/`contruct`** (lib), **`CNAdvancement.START=null`**, **`CExplode`** (config jamais branché), **`registerAndWrap`** (`CNDensityFunctions`), **`IrradiatedBiomes.monsters()`** no-op, **`PaletteBlockPattern.VANILLA_RANGE`** (doublon de `STANDARD_RANGE`), **`CNFanProcessingTypes.parseLegacy/ofLegacyName/LEGACY_NAME_MAP`** — tous **toujours présents et morts**. -- **Imports doublons dans `CNBlocks.java`** — toujours présents malgré le commit `cedf05cd` (de nouveaux doublons ou ratés sur ce fichier précisément). - -### Design (§6) - -- **Package racine fourre-tout** (~25 classes `CN*` à plat) — **toujours tel quel**, aucune sous-décomposition. -- **`run/` versionné** — toujours suivi par git (19 fichiers, dont des `hs_err_pid*.log`, un jar désactivé, `imgui.ini`). -- **Aucun test** — `src/test` toujours vide/absent. -- **Duplication `drawGauge`** dans les 5 `DisplaySource` — toujours présent à l'identique, plus `ReactorSummaryDisplaySource` qui réimplique sa propre version + magic numbers (64/64/16000/1000) toujours dupliqués. -- **`GeneratedRecipeBuilder` dupliqué** entre `CNStandardRecipeGen`/`CNShapelessRecipeGen`, et **`moddedCompacting`/`moddedPaths` dupliqués** entre `EnrichedRecipeGen`/`SnowPowderRecipeGen` (et `moddedPaths` toujours `return null` après une boucle dont le résultat est jeté) — **toujours présents, toujours morts**. -- **Commentaires FR/EN mêlés** un peu partout (`ClientEvents`, `CNFluids`, mixins, explosion/particles, équipement irradié) — toujours présent. -- **Logs de debug en prod** — `"EXPLOSIOOOOOON…"` toujours présent dans `NuclearMushroomCloudParticle`. - ---- - -## 2. Points **corrigés** - -| Point AUDIT | Vérification | Conclusion | -|---|---|---| -| **B2** — `RadiationSyncPacket` no-op | `find` global : aucune classe `*RadiationSync*` n'existe plus | ✅ **Corrigé** (disparu lors de la consolidation radiation, commit `42565d89`) | -| **B11** — `LOGGER...coreList.toString()` avant null-check (`SimpleMultiBlockAislePatternBuilder`) | Code actuel : le null-check précède bien le message d'erreur, avec ternaire `coreList != null ? coreList.size() : 0` | ✅ **Corrigé** | -| **B17** — `RodsTooltipHandler` condition de namespace inversée | Agent confirme la classe « correctly wired and free of obvious bugs » après lecture complète | ✅ **Corrigé** (probablement supprimé/réécrit) | -| **Inversion de dépendance `api/`** — `MultiBlockManagerBeta`, `RodType`, `ReactorFluidType` important `content.*` | Grep des imports : **aucun** des trois n'importe quoi que ce soit de `content.*` | ✅ **Corrigé** — la couche `api/` n'a plus de dépendance vers `content/` | -| **Deux frameworks multiblock concurrents** (`lib.multiblock.manager.*`, `IBetterPattern`, builder non-aisle) | `find` confirme : `lib/multiblock/manager` n'existe plus, `IBetterPattern`/`MultiBlockManager`/`MultiBlockCache`/`SimpleMultiBlockPatternBuilder` (non-aisle) n'existent plus | ✅ **Corrigé** — seuls les éléments réellement utilisés de `lib.multiblock` (`SimpleMultiBlockAislePatternBuilder`, `SimpleMultiBlockPattern`) subsistent | -| **Feature radiation éparpillée sur 4 couches** | `foundation/networking/radiation` et `foundation/item/radiation` n'existent plus ; tout est dans `content/radiation`, `api/radiation`, `content/effects` | ✅ **Largement corrigé** (3 packages au lieu de 4, cohérent — reste un découpage en 3 plutôt qu'1 mais c'est raisonnable) | -| **Seam `ConfigValueResolver` non utilisé** | Désormais utilisé par `RadiationEffect` (`ConfigValueResolver.loadValuesInSet`) | ✅ **Corrigé** (au moins pour ce cas d'usage) | -| **`foundation/util` vs `foundation/utility` redondants** | Seul `foundation/utility` existe désormais | ✅ **Corrigé** | -| **God class `ReactorControllerBlockEntity` (886 lignes)** | Désormais **718 lignes** ; logique extraite vers `manager/`, `service/DefaultHeatService`+`HeatManager`, `consumable/ConsumptionCycleManager`, `ReactorMeltdownExecutor`, `ReactorFrameDisplayManager`, `display/ReactorDisplayState`+`ReactorGoggleTooltipRenderer`, `ReactorDebugDiagnostics` | 🟡 **Partiellement corrigé** — réduction réelle (-168 lignes) et architecture manager/service/display bien amorcée, mais reste loin de la cible « <300 lignes » et `tick()`/`handleAssembledState()` restent de gros méthodes multi-responsabilités | -| **B14 — `FluidLockManager` static map non keyée par dimension** | Le problème de clé `BlockPos` sans dimension est confirmé toujours présent | 🟡 **Partiellement** — le sous-point « 2 systèmes de verrou parallèles (`PersistentFluidLocks`) » n'a pas été re-confirmé dans cette passe, possiblement réduit | - ---- - -## 3. Points **devenus obsolètes** (zone/fichier supprimé, finding non-applicable) - -- **`IrradiatedSurfaceRules` v1** vs v2 — il n'y a plus qu'**un seul** fichier `IrradiatedSurfaceRules` (le « v2 » a été renommé/fusionné, commit `90ad3849`/`d0325da2`). Le point « doublon v1/v2 » disparaît, mais **le bug `IS_HIGHLANDS = biome()` subsiste dans le fichier survivant** (cf. §1, B19). -- **Audit B8** (`clearLockIfAllInputsEmpty` NPE par `findStructure(...).data().getSize()` sans null-check) — la méthode existe toujours (`controller/ReactorControllerBlockEntity.java:685-718`) mais la nouvelle revue ne relève plus de risque NPE direct ; en revanche elle relève un **nouveau problème de performance** (re-scan complet de la structure à chaque vidage de fluide). Le risque a changé de nature plutôt que disparu — je le classe « reformulé » plutôt que strictement obsolète. -- **`ReactorFluidTypesValue.java`** (cité dans « imports morts ») — n'apparaît plus dans `api/multiblock/fluid/` (seul `ReactorFluidType.java` existe) → ce fichier/finding est obsolète. -- **Couplage `MultiBlockManagerBeta` ↔ `ReactorControllerBlockEntity` (effet de bord `setMultiblockFacing`)** — non re-confirmé par la revue actuelle ; la classe ne dépend plus de `content.*` du tout (cf. §2), donc soit ce couplage a été supprimé, soit il a été restructuré. À vérifier ponctuellement si pertinent, mais le problème **tel que décrit** (import direct) n'existe plus. - ---- - -## 4. Points **non confirmés / nécessitent vérification ciblée** (ni confirmés ni infirmés dans cette passe) - -- Perf : scan ~3971 blocs par `ReactorPattern.findController` sans garde client (§4 audit) — non re-vérifié explicitement. -- Perf : `ReactorAlarmEntity.tickServer()` sans garde `!isClientSide` — non re-vérifié. -- Perf : `ReactorFluidType.getTypeForFluid` double-boucle — non re-vérifié (la revue a trouvé un *autre* problème sur ce fichier, voir nouveaux problèmes). -- `HelmetOverlay` double rendu hotbar — non re-vérifié. -- `InventoryHashUtil` incluant `getDamageValue()` dans le hash — non re-vérifié. -- `ReactorOutput.requireNonNull`+`assert` — confirmé présent par la nouvelle revue (voir §5), donc **toujours valide** en fait. -- `RodsTooltipHandler`/`TextUtils`/`Mods`/`SoundEntryBuilder`/`BigFluidStack` helpers morts — `Mods.getBlock/getItem` confirmés encore morts (Mineur), le reste non re-vérifié individuellement. - ---- - -## 5. **Nouveaux problèmes** non mentionnés dans `AUDIT.md` - -Ces points ressortent de la nouvelle revue et concernent essentiellement le **code récemment extrait** lors de la décomposition (managers, packets, services) — ce qui est cohérent : le refactor a déplacé le code mais introduit de nouvelles régressions ponctuelles. - -| # | Fichier:ligne | Problème | Gravité | Conséquence | Recommandation | -|---|---|---|---|---|---| -| N1 | `content/multiblock/IHeat.java:73-75` | `isNotDanger(heat)` = `of(heat) != DANGER \|\| of(heat) != NONE` — **tautologie toujours vraie** | 🔴 Critique | La garde `if (IHeat.HeatLevel.isNotDanger(heat))` à `ReactorControllerBlockEntity:530` ne filtre jamais l'état DANGER — la suppression de la rotation de sortie en cas de surchauffe ne se déclenche jamais | `return of(heat) != DANGER && of(heat) != NONE;` | -| N2 | `manager/ReactorInputFluidManager.java:128-129, 147-148` | `getFluidInTank(getTanks())` — off-by-one (index = count au lieu de count-1), et `extractFluids` ne décrémente jamais `fluidNeeded` | 🔴 Critique | Comptage/extraction de fluide d'entrée potentiellement faussé/cassé à l'exécution | Itérer `for (int t=0; t` indexé par slot | -| N16 | `content/contraptions/irradiated/IrradiatedAnimal.startConverting` | `Math.min(difficulty.getId()-1, 0)` au lieu de `Math.max` → NORMAL/HARD = même amplificateur que EASY, PEACEFUL → -1 | 🟠 Majeur | Le bonus de dégâts de conversion ne scale jamais avec la difficulté ; valeur négative possible en PEACEFUL | `Math.max(difficulty.getId()-1, 0)` | -| N17 | `content/contraptions/irradiated/wolf/IrradiatedWolfModel.headParts()/bodyParts()` | Retourne `null` au lieu de `ImmutableList.of(...)` (contrairement à Cat/Chicken/Cow) | 🟠 Majeur | Violation de contrat `Iterable`, NPE latent si une logique parent itère ces listes | Retourner `ImmutableList.of(...)` comme les autres modèles irradiés | -| N18 | `content/equipment/cloth/ClothItem.java` (`@SuppressWarnings("unused")`, enum `Cloths`) | Enum 16 `DyeColor` + helpers jamais utilisés en dehors de sa propre déclaration, duplique `CNItems.CLOTHS` | 🟡 Mineur (mort/duplication) | Risque de divergence avec `CNItems.CLOTHS` | Supprimer si confirmé inutile | -| N19 | `content/particles/SmallNuclearExplosionParticle.java` | 13 classes Factory quasi-identiques (Nuke/Mine/Underzealot/Raygun/...) ; override `getQuadSize` no-op ; littéral caractère `'＀'` (U+FF00) utilisé comme masque binaire au lieu de `0xFF00` | 🟡 Mineur | Duplication ×13, lisibilité | Factoriser via constructeur paramétré ; remplacer le littéral par `0xFF00` | -| N20 | `content/explosion/CNNuclearExplosionSound.java:26` | `this.volume = 20` alors que la logique de fade attend `[0,1]` | 🟡 Mineur | Valeur initiale incohérente (masquée par le 1er fade-in) | Initialiser à `0F`/`1F` | -| N21 | `content/contraptions/irradiated/wolf/IrradiatedWoldCollarLayer.java` | Faute de frappe "Wold"→"Wolf" dans le nom de classe/fichier, `render()` vide, non enregistrée | 🟡 Mineur (mort) | Scaffolding inachevé pour une fonctionnalité de collier | Finir ou supprimer | -| N22 | `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:25` | Import de `joptsimple.internal.Strings` (classe interne d'une lib tierce non liée) juste pour `repeat(' ', n)` | 🟡 Mineur | Dépendance fragile à une classe "internal" | Remplacer par `" ".repeat(n)` (Java 11+) | -| N23 | `content/logistics/BigFluidStack.java:74` | `nullHash(Object)` réinvente `Objects.hashCode`/`Objects.hash` | 🟡 Mineur | Code superflu | Utiliser `Objects.hash(stack, amount)` | -| N24 | `CNSoundEvents.java:118-120` + chemins `"reacteur/casing"` | Typo `"GeiGer Medium"` (casse incohérente vs "Geiger High/Low") ; chemins de sons en français (`reacteur`) vs anglais ailleurs (`reactor`) | 🟡 Mineur | Incohérence visible (sous-titres) et dans l'organisation des assets | Corriger la casse ; renommer les chemins (impacte les assets, hors périmètre resources) | -| N25 | `content/multiblock/ReactorAssembler.java:134-138` | `getPlayersInRadius` `@Deprecated`, 0 appelant | 🟡 Mineur (mort) | — | Supprimer | -| N26 | `input/item/ReactorInputEntity.java` / `output/ReactorOutputEntity.java` — champ `controller` typé `ReactorControllerBlock` | Type = singleton Block partagé (pas un état positionnel), jamais lu utilement dans `ReactorInputEntity` | 🟡 Mineur (design, repris de l'audit §6 mais avec confirmation que le champ est désormais carrément mort dans Input) | Confusion, état mort | Supprimer ou remplacer par `BlockPos`/référence BE | -| N27 | `casing/ReactorCasingEntity.java:25` | `setController` calcule un offset fixe `+4/+4`, indépendant de la taille (5/7/9) — semble appelée nulle part | 🟡 Mineur | Offset faux si jamais exercé pour 7x7/9x9 | Supprimer ou paramétrer par taille | -| N28 | `casing/ReactorCasing.java:73-75 onWrenched` | `context.getPlayer()` (nullable) déréférencé sans null-check | 🟡 Mineur | NPE si un déclencheur non-joueur (distributeur) actionne la clé | `if (player == null) return PASS;` | -| N29 | Managers Input/InputFluid/Output/Alarm — `getBlocksPosition(Level)` | 3 des 4 managers n'ont pas la garde `level == null` présente dans `ReactorAlarmManager` ; sérialisation x/y/z dupliquée ×3 vs `BlockPos.asLong()` dans Output | 🟡 Mineur (duplication/incohérence) | NPE potentiel, format de sauvegarde incohérent entre managers | Extraire `AbstractReactorIOManager` avec garde + sérialisation commune | -| N30 | `controller/ReactorControllerBlockEntity.java:357` | Lecture `configuredPattern.getOrCreateTag().getDouble("heat")` chaque tick sans la garde `isEmptyConfiguredPattern()` utilisée ailleurs (L412/519/554/560) | 🟡 Mineur | `getOrCreateTag()` mute `ItemStack.EMPTY` chaque tick — incohérence de garde | Ajouter la garde manquante | -| N31 | `manager/ReactorFrameDisplayManager.java:50-59` | Le ratio agrège la capacité/quantité de **tous** les tanks, mais `frameFluidCache` ne stocke que le **premier** fluide non-vide trouvé | 🟡 Mineur | Affichage trompeur si plusieurs fluides distincts présents dans le cadre | Restreindre à un seul type de fluide ou agréger par type | -| N32 | `api/multiblock/fluid/ReactorFluidType.java:196-213` `maxHeat()/efficiency()` | Retournent en dur `12`, lecture de config réelle commentée (`//CNConfigs.server()...`) | 🟡 Mineur | Bug fonctionnel potentiel si un `ReactorFluidType` a `useConfig=true` | Vérifier l'usage de `useConfig` ; restaurer la lecture config ou supprimer le chemin mort | -| N33 | `infrastructure/worldgen/biome/IrradiatedBiomes.java:17-18` `monsters(...)` | Méthode appelée avec de vrais paramètres (`95, 5, 100`) mais **corps totalement vide** | 🟠 Majeur | Le biome irradié n'a probablement **aucun spawn de mob configuré** malgré l'appel qui le suggère | Implémenter `SpawnerData` ou retirer l'appel trompeur | - ---- - -## 6. Tableau de synthèse global (par rapport à `AUDIT.md`) - -| Catégorie audit | Statut global | -|---|---| -| Bugs critiques B1,B3,B4,B5,B6,B7,B9,B10,B12,B13,B15,B16,B18,B19 | **Toujours valides** (14/19 hors B2/B11/B17 corrigés, B8/B14 reformulés/partiels) | -| Inversion `api/` ↔ `content/` | **Corrigé** ✅ | -| Deux frameworks multiblock | **Corrigé** ✅ (lib.multiblock réduit à ce qui est réellement utilisé) | -| Radiation sur 4 couches | **Largement corrigé** ✅ (3 couches cohérentes) | -| God class `ReactorControllerBlockEntity` | **Réduit (886→718 lignes), décomposition amorcée mais incomplète** 🟡 | -| `ConfigValueResolver` non utilisé | **Corrigé** ✅ | -| `foundation/util` vs `utility` | **Corrigé** ✅ | -| Package racine fourre-tout, `run/` versionné, absence de tests | **Toujours valides** | -| Dead code (keyframe, CreateNuclearDamageSources, CNShapelessRecipeGen, possible code, CommentEventClients, VerifyPattern*, saveData2, etc.) | **Toujours valides** (sauf IrradiatedSurfaceRules v1, fusionné) | -| Duplication drawGauge / recipe gen | **Toujours valides** | -| **Nouveaux problèmes** (N1-N33) | Concentrés dans le code récemment extrait (managers, packets blueprint, services, output) — cohérent avec un refactor en cours qui a déplacé sans toujours corriger | - ---- - -## 7. Recommandations priorisées (indépendantes de l'audit) - -1. **Quick wins très haute valeur** (1-3 lignes chacun, à corriger en premier) : **N1** (`IHeat.isNotDanger` tautologie), **B9** (palier radiation), **B18** (clé config dupliquée), **B3** (cooldown VicinityEffect), **B4** (loot thorium), **B1** (`&& false`), **N2** (off-by-one fluide). -2. **Bugs fonctionnels potentiellement bloquants pour le gameplay** : **N4** (vitesse de sortie réacteur jamais non-nulle), **N7** (remplissage fluide réservé à la créative ?), **N3** (progression blueprint cross-contaminée), **B6** (uranium jamais transmis). -3. **Nettoyage à risque faible, gain élevé** (continuer la dynamique déjà engagée) : supprimer le framework d'animation mort (~10 fichiers), `CreateNuclearDamageSources`, `possible code`, `CommentEventClients`, `CNShapelessRecipeGen`, `VerifyPattern*`, `saveData2`, `FluidConsumable`/`distributeSU`, `ReactorOutputValue`. -4. **Continuer la décomposition de `ReactorControllerBlockEntity`** (`tick()`/`handleAssembledState()` restent les derniers gros morceaux) et **harmoniser les 4 managers I/O** (null-check `level`, sérialisation position commune) — c'est exactement la trajectoire déjà entamée, à finir. -5. **Cohésion finale** : `run/` → `.gitignore`, ajouter au moins des tests unitaires sur la logique de pattern/heat (zéro test actuellement), réorganiser le package racine en sous-package `registration/`. diff --git a/AUDIT.md b/AUDIT_V1.md similarity index 100% rename from AUDIT.md rename to AUDIT_V1.md diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index d0b345d7..cd96af1b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -20,9 +20,7 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; -import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; -import net.minecraft.tags.BlockTags; import net.minecraft.tags.ItemTags; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantments; @@ -44,8 +42,6 @@ import net.minecraftforge.common.Tags; import net.minecraftforge.common.util.ForgeSoundType; -import net.nuclearteam.createnuclear.content.enriching.campfire.EnrichingCampfireBlock; -import net.nuclearteam.createnuclear.content.enriching.fire.EnrichingFireBlock; import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; import net.nuclearteam.createnuclear.content.multiblock.casing.ReactorCasing; diff --git a/src/main/java/net/nuclearteam/createnuclear/CNRecipeTypes.java b/src/main/java/net/nuclearteam/createnuclear/CNRecipeTypes.java index 1e9a0550..d84ebd2d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNRecipeTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNRecipeTypes.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Optional; -import java.util.function.Predicate; import java.util.function.Supplier; @SuppressWarnings({"unused", "unchecked"}) @@ -30,10 +29,6 @@ public enum CNRecipeTypes implements IRecipeTypeInfo { SNOW_POWDER(SnowPowderRecipe::new) ; - public static final Predicate> CAN_BE_AUTOMATED = r -> !r.getId() - .getPath() - .endsWith("_manual_only"); - private final ResourceLocation id; private final RegistryObject> serializerObject; private final Supplier> type; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java index 65bf20d2..9785f290 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java @@ -1,7 +1,5 @@ package net.nuclearteam.createnuclear.content.explosion; -import com.google.common.collect.Maps; -import java.util.Map; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraftforge.api.distmarker.Dist; @@ -10,7 +8,6 @@ @OnlyIn(Dist.CLIENT) public abstract class CNAdvancedEntityModel extends CNBasicEntityModel { private float movementScale = 1.0F; - private final Map modelTextureMap = Maps.newHashMap(); public int texWidth = 32; public int texHeight = 32; @@ -18,14 +15,6 @@ public void updateDefaultPose() { this.getAllParts().forEach((modelRenderer) -> modelRenderer.updateDefaultPose()); } - protected void setCNTextureOffset(String partName, int x, int y) { - this.modelTextureMap.put(partName, new CNTextureOffset(x, y)); - } - - public CNTextureOffset getCNTextureOffset(String partName) { - return (CNTextureOffset)this.modelTextureMap.get(partName); - } - public void resetToDefaultPose() { this.getAllParts().forEach((modelRenderer) -> modelRenderer.resetToDefaultPose()); } @@ -111,14 +100,6 @@ public void setRotateAngle(CNAdvancedModelBox model, float x, float y, float z) model.rotateAngleZ = z; } - public void rotate(CNModelAnimator animator, CNAdvancedModelBox model, float x, float y, float z) { - animator.rotate(model, (float)Math.toRadians((double)x), (float)Math.toRadians((double)y), (float)Math.toRadians((double)z)); - } - - public void rotateMinus(CNModelAnimator animator, CNAdvancedModelBox model, float x, float y, float z) { - animator.rotate(model, (float)Math.toRadians((double)x) - model.defaultRotationX, (float)Math.toRadians((double)y) - model.defaultRotationY, (float)Math.toRadians((double)z) - model.defaultRotationZ); - } - public void progressRotation(CNAdvancedModelBox model, float progress, float rotX, float rotY, float rotZ, float divisor) { model.rotateAngleX += progress * (rotX - model.defaultRotationX) / divisor; model.rotateAngleY += progress * (rotY - model.defaultRotationY) / divisor; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAnimation.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAnimation.java deleted file mode 100644 index 6b77f4cb..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAnimation.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.nuclearteam.createnuclear.content.explosion; - -public class CNAnimation { - /** @deprecated */ - @Deprecated - private int id; - private int duration; - - private CNAnimation(int duration) { - this.duration = duration; - } - - /** @deprecated */ - @Deprecated - public static CNAnimation create(int id, int duration) { - CNAnimation animation = create(duration); - animation.id = id; - return animation; - } - - public static CNAnimation create(int duration) { - return new CNAnimation(duration); - } - - /** @deprecated */ - @Deprecated - public int getID() { - return this.id; - } - - public int getDuration() { - return this.duration; - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNIAnimatedEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNIAnimatedEntity.java deleted file mode 100644 index 84564c79..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNIAnimatedEntity.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.nuclearteam.createnuclear.content.explosion; - - -public interface CNIAnimatedEntity { - CNAnimation NO_ANIMATION = CNAnimation.create(0); - - int getAnimationTick(); - - void setAnimationTick(int var1); - - CNAnimation getAnimation(); - - void setAnimation(CNAnimation var1); - - CNAnimation[] getAnimations(); -} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNModelAnimator.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNModelAnimator.java deleted file mode 100644 index 8759569f..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNModelAnimator.java +++ /dev/null @@ -1,127 +0,0 @@ -package net.nuclearteam.createnuclear.content.explosion; - -import java.util.HashMap; -import net.minecraft.client.Minecraft; -import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) -public class CNModelAnimator { - private int tempTick = 0; - private int prevTempTick; - private boolean correctAnimation = false; - private CNIAnimatedEntity entity; - private HashMap CNTransformMap = new HashMap(); - private HashMap prevCNTransformMap = new HashMap(); - - public static CNModelAnimator create() { - return new CNModelAnimator(); - } - - public CNIAnimatedEntity getEntity() { - return this.entity; - } - - public void update(CNIAnimatedEntity entity) { - this.tempTick = this.prevTempTick = 0; - this.correctAnimation = false; - this.entity = entity; - this.CNTransformMap.clear(); - this.prevCNTransformMap.clear(); - } - - public boolean setAnimation(CNAnimation animation) { - this.tempTick = this.prevTempTick = 0; - this.correctAnimation = this.entity.getAnimation() == animation; - return this.correctAnimation; - } - - public void startKeyframe(int duration) { - if (this.correctAnimation) { - this.prevTempTick = this.tempTick; - this.tempTick += duration; - } - } - - public void setStaticKeyframe(int duration) { - this.startKeyframe(duration); - this.endKeyframe(true); - } - - public void resetKeyframe(int duration) { - this.startKeyframe(duration); - this.endKeyframe(); - } - - public void rotate(CNAdvancedModelBox box, float x, float y, float z) { - if (this.correctAnimation) { - this.getCNTransform(box).addRotation(x, y, z); - } - } - - public void move(CNAdvancedModelBox box, float x, float y, float z) { - if (this.correctAnimation) { - this.getCNTransform(box).addOffset(x, y, z); - } - } - - private CNTransform getCNTransform(CNAdvancedModelBox box) { - return (CNTransform)this.CNTransformMap.computeIfAbsent(box, (b) -> new CNTransform()); - } - - public void endKeyframe() { - this.endKeyframe(false); - } - - private void endKeyframe(boolean stationary) { - if (this.correctAnimation) { - int animationTick = this.entity.getAnimationTick(); - if (animationTick >= this.prevTempTick && animationTick < this.tempTick) { - if (stationary) { - for(CNAdvancedModelBox box : this.prevCNTransformMap.keySet()) { - CNTransform CNTransform = (CNTransform)this.prevCNTransformMap.get(box); - box.rotateAngleX += CNTransform.getRotationX(); - box.rotateAngleY += CNTransform.getRotationY(); - box.rotateAngleZ += CNTransform.getRotationZ(); - box.rotationPointX += CNTransform.getOffsetX(); - box.rotationPointY += CNTransform.getOffsetY(); - box.rotationPointZ += CNTransform.getOffsetZ(); - } - } else { - float frameTime = Minecraft.getInstance().isPaused() ? 0.0F : Minecraft.getInstance().getFrameTime(); - float tick = ((float)(animationTick - this.prevTempTick) + frameTime) / (float)(this.tempTick - this.prevTempTick); - float inc = Mth.sin((float)((double)tick * Math.PI / (double)2.0F)); - float dec = 1.0F - inc; - - for(CNAdvancedModelBox box : this.prevCNTransformMap.keySet()) { - CNTransform CNTransform = (CNTransform)this.prevCNTransformMap.get(box); - box.rotateAngleX += dec * CNTransform.getRotationX(); - box.rotateAngleY += dec * CNTransform.getRotationY(); - box.rotateAngleZ += dec * CNTransform.getRotationZ(); - box.rotationPointX += dec * CNTransform.getOffsetX(); - box.rotationPointY += dec * CNTransform.getOffsetY(); - box.rotationPointZ += dec * CNTransform.getOffsetZ(); - } - - for(CNAdvancedModelBox box : this.CNTransformMap.keySet()) { - CNTransform CNTransform = (CNTransform)this.CNTransformMap.get(box); - box.rotateAngleX += inc * CNTransform.getRotationX(); - box.rotateAngleY += inc * CNTransform.getRotationY(); - box.rotateAngleZ += inc * CNTransform.getRotationZ(); - box.rotationPointX += inc * CNTransform.getOffsetX(); - box.rotationPointY += inc * CNTransform.getOffsetY(); - box.rotationPointZ += inc * CNTransform.getOffsetZ(); - } - } - } - - if (!stationary) { - this.prevCNTransformMap.clear(); - this.prevCNTransformMap.putAll(this.CNTransformMap); - this.CNTransformMap.clear(); - } - - } - } -} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTextureOffset.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTextureOffset.java deleted file mode 100644 index cf2abe37..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTextureOffset.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.nuclearteam.createnuclear.content.explosion; - -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) -public class CNTextureOffset { - public final int textureOffsetX; - public final int textureOffsetY; - - public CNTextureOffset(int textureOffsetXIn, int textureOffsetYIn) { - this.textureOffsetX = textureOffsetXIn; - this.textureOffsetY = textureOffsetYIn; - } -} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTransform.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTransform.java deleted file mode 100644 index 1d869c22..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNTransform.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.nuclearteam.createnuclear.content.explosion; - -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) -public class CNTransform { - private float rotationX; - private float rotationY; - private float rotationZ; - private float offsetX; - private float offsetY; - private float offsetZ; - - public float getRotationX() { - return this.rotationX; - } - - public float getRotationY() { - return this.rotationY; - } - - public float getRotationZ() { - return this.rotationZ; - } - - public float getOffsetX() { - return this.offsetX; - } - - public float getOffsetY() { - return this.offsetY; - } - - public float getOffsetZ() { - return this.offsetZ; - } - - public void addRotation(float x, float y, float z) { - this.rotationX += x; - this.rotationY += y; - this.rotationZ += z; - } - - public void addOffset(float x, float y, float z) { - this.offsetX += x; - this.offsetY += y; - this.offsetZ += z; - } - - public void resetRotation() { - this.rotationX = 0.0F; - this.rotationY = 0.0F; - this.rotationZ = 0.0F; - } - - public void resetOffset() { - this.offsetX = 0.0F; - this.offsetY = 0.0F; - this.offsetZ = 0.0F; - } - - public void setRotation(float x, float y, float z) { - this.resetRotation(); - this.addRotation(x, y, z); - } - - public void setOffset(float x, float y, float z) { - this.resetOffset(); - this.addOffset(x, y, z); - } -} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java b/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java index fd174918..702b68fc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java @@ -22,7 +22,7 @@ import net.nuclearteam.createnuclear.content.enriching.campfire.EnrichingCampfireBlock; import net.nuclearteam.createnuclear.content.kinetics.fan.processing.EnrichedRecipe.EnrichedWrapper; import net.nuclearteam.createnuclear.content.kinetics.fan.processing.SnowPowderRecipe.SnowPowderWrapper; -import net.nuclearteam.createnuclear.foundation.damageTypes.CreateNuclearDamageSources; +import net.nuclearteam.createnuclear.foundation.damageTypes.CNDamageSources; import javax.annotation.Nullable; import java.util.List; @@ -119,7 +119,7 @@ public void morphAirFlow(AirFlowParticleAccess particleAccess, RandomSource rand public void affectEntity(Entity entity, Level level) { if (entity instanceof LivingEntity livingEntity) { livingEntity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 10, -1, true, true)); - livingEntity.hurt(CreateNuclearDamageSources.fanRadiation(level), 1); + livingEntity.hurt(CNDamageSources.fanRadiation(level), 1); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java b/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java index f7d906b4..080af829 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/logistics/BigFluidStack.java @@ -8,9 +8,6 @@ import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; import java.util.Objects; public class BigFluidStack { @@ -45,18 +42,10 @@ public void send(FriendlyByteBuf buffer) { buffer.writeVarInt(amount); } - public boolean isInfinite() { - return amount >= INF; - } - public static BigFluidStack receive(FriendlyByteBuf buffer) { return new BigFluidStack(buffer.readFluidStack(), buffer.readVarInt()); } - public static Comparator comparator() { - return (i1, i2) -> Integer.compare(i2.amount, i1.amount); - } - @Override public boolean equals(final Object obj) { if (obj == this) @@ -81,13 +70,6 @@ public String toString() { .getString() + " x" + amount + ")"; } - public static List duplicateWrappers(List list) { - List copy = new ArrayList<>(); - for (BigFluidStack bigFluidStack : list) - copy.add(new BigFluidStack(bigFluidStack.stack, bigFluidStack.amount)); - return copy; - } - public ReactorFluidType getFluidtype(@Nullable Level level) { if (level == null) { return ReactorFluidTypesValue.getReactorFluidType(this.stack.getFluid()); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 145dd52d..4295485f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -4,12 +4,10 @@ import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.minecraft.world.phys.AABB; import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.multiblock.BlockPattern; @@ -22,8 +20,6 @@ import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; -import java.util.List; - public final class ReactorAssembler { public static final int configRadius = CNConfigs.server().notify.distanceOfWarning.get(); @@ -131,12 +127,6 @@ private static ReactorControllerBlockEntity getBlockEntity(Level level, BlockPos return null; } - @Deprecated - private static List getPlayersInRadius(Level level, BlockPos center, double radius) { - AABB box = new AABB(center).inflate(radius); - return level.getEntitiesOfClass(Player.class, box); - } - private static void sendMessageToPlayer(Level level, BlockPos pos, LangBuilder component, boolean condition) { if (!condition) return; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index 4a2ef145..dd97c06b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -14,7 +14,6 @@ import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.SlotItemHandler; import net.nuclearteam.createnuclear.CNMenus; -import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; @@ -157,27 +156,6 @@ protected void saveData(ItemStack contentHolder) { contentHolder.getOrCreateTag().put("patternAll", ghostInventory.serializeNBT()); } - protected void saveData2(ItemStack contentHolder) { - for (int i = 0; i < ghostInventory.getSlots(); i++) { - if (ghostInventory.getStackInSlot(i).isEmpty() || ghostInventory.getStackInSlot(i) == null) ghostInventory.setStackInSlot(i, ItemStack.EMPTY); - if (!(ghostInventory.getStackInSlot(i).is(CNTags.CNItemTags.FUEL.tag) || ghostInventory.getStackInSlot(i).is(CNTags.CNItemTags.COOLER.tag))&& !ghostInventory.getStackInSlot(i).isEmpty()) ghostInventory.setStackInSlot(i, ItemStack.EMPTY); - if (ghostInventory.getStackInSlot(i).is(CNTags.CNItemTags.COOLER.tag)) countCooledRod += 1; - if (ghostInventory.getStackInSlot(i).is(CNTags.CNItemTags.FUEL.tag)) countFuelRod += 1; - } - - contentHolder.getOrCreateTag().put("pattern", ghostInventory.serializeNBT()); - contentHolder.getOrCreateTag().putInt("countGraphiteRod", countCooledRod); - contentHolder.getOrCreateTag().putInt("countUraniumRod", countFuelRod); - - for (int i = 0; i < ghostInventory.getSlots(); i++) { - if (ghostInventory.getStackInSlot(i).isEmpty() || ghostInventory.getStackInSlot(i) == null) ghostInventory.setStackInSlot(i, new ItemStack(Items.GLASS_PANE)); - if (!(ghostInventory.getStackInSlot(i).is(CNTags.CNItemTags.FUEL.tag) || ghostInventory.getStackInSlot(i).is(CNTags.CNItemTags.COOLER.tag))&& !ghostInventory.getStackInSlot(i).isEmpty()) ghostInventory.setStackInSlot(i, new ItemStack(Items.GLASS_PANE)); - } - - contentHolder.getOrCreateTag().put("patternAll", ghostInventory.serializeNBT()); - - } - protected int getPlayerInventoryXOffset() { return 31; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasingEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasingEntity.java index bd9dc73c..10eed24d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasingEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasingEntity.java @@ -10,23 +10,11 @@ public class ReactorCasingEntity extends SmartBlockEntity { - protected BlockPos controller; - public ReactorCasingEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); - setController(pos); } @Override public void addBehaviours(List behaviours) { } - - public void setController(BlockPos pos) { - controller = new BlockPos(pos.getX()+4, pos.getY(), pos.getZ()+4); - } - - public BlockPos getController() { - return controller; - } - } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java index 34e9f032..433982d1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java @@ -9,12 +9,10 @@ import java.util.ArrayList; import java.util.List; -import java.util.function.BiFunction; /** * Manager for a reactor's outputs (`ReactorOutput`). - * Handles serialization of output positions and distribution - * of energy via `distributeSU`. + * Handles serialization of output positions. */ public class ReactorOutputManager extends AbstractReactorIOManager implements ReactorOutputManagerI { private static final String NBT_KEY = "ReactorOutputs"; @@ -41,80 +39,6 @@ public void read(CompoundTag compound) { } } - /** - * Example usage: - * double totalSUToDistribute = this.reactorPower; // or another value depending on logic - * if (!reactorOutputEntityList.isEmpty() && totalSUToDistribute > 0) { - * double remaining = outputManager.distributeSU(totalSUToDistribute, reactorOutputEntityList, (outEntity, amount) -> { - * // Inserter: apply `amount` to the output and return the amount not accepted. - * // Here we accept everything and apply the corresponding speed (rounded) - * int speed = (int) Math.round(amount); - * try { - * outEntity.setSpeed(speed); - * outEntity.heat = speed; // adjust heat if needed - * outEntity.updateSpeed = true; - * outEntity.updateGeneratedRotation(); - * return 0.0; // all accepted - * } catch (Exception e) { - * return amount; // nothing accepted on error - * } - * }); - * // `remaining` contains the SU that couldn't be inserted — you can store or drop it - * this.reactorPower = (float) remaining; // example: keep the remainder - * } - * @param totalSU total SU to distribute - * @param level world level (may be null) - * @param inserter function that applies an amount to an output and returns not accepted amount - * @return amount of SU not inserted - */ - public double distributeSU(double totalSU, Level level, BiFunction inserter) { - if (totalSU <= 0 || inserter == null) return totalSU; - List validOutputs = new ArrayList<>(); - for (BlockPos p : new ArrayList<>(positions)) { - if (level == null || !level.isLoaded(p)) continue; - BlockEntity be = level.getBlockEntity(p); - if (be instanceof ReactorOutputEntity out) validOutputs.add(out); - } - if (validOutputs.isEmpty()) return totalSU; - - double remaining = totalSU; - List active = new ArrayList<>(validOutputs); - final double MIN_ACCEPTED_SU = 1e-6; - - // Distribute evenly and reallocate the remainder among outputs still able to accept - boolean progress = true; - while (remaining > MIN_ACCEPTED_SU && !active.isEmpty() && progress) { - progress = false; - double share = remaining / active.size(); - List stillActive = new ArrayList<>(); - - for (ReactorOutputEntity out : active) { - double toInsert = share; - double notAccepted; - try { - notAccepted = inserter.apply(out, toInsert); - } catch (Exception e) { - notAccepted = toInsert; - } - if (Double.isNaN(notAccepted) || notAccepted < 0) notAccepted = 0; - if (notAccepted > toInsert) notAccepted = toInsert; - double inserted = toInsert - notAccepted; - - if (inserted > MIN_ACCEPTED_SU) { - progress = true; - remaining -= inserted; - // keep this output active; it may accept more in the next round - stillActive.add(out); - } - // if inserted == 0, remove it (do not attempt to send more) - } - - active = stillActive; - } - - return remaining; - } - @Override public void clearInvalid(Level level) { List toRemove = new ArrayList<>(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java index 45ef40a2..26280c8f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java @@ -2,26 +2,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import java.util.List; -import java.util.function.BiFunction; /** * Interface exposing operations specific to reactor outputs. - * The main responsibility is to distribute an amount of energy (SU) - * among valid outputs and use an `inserter` to apply quantities to each - * `ReactorOutputEntity`. */ public interface ReactorOutputManagerI extends ReactorIOManager { - /** - * Distributes `totalSU` among valid outputs in `level`. - * The `inserter` receives the target entity and the proposed amount and - * must return the amount not accepted (>= 0). - * Returns the remaining amount that was not inserted. - */ - double distributeSU(double totalSU, Level level, BiFunction inserter); - /** Returns an immutable copy of tracked positions. */ List getBlocksPosition(Level level); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java index adc4c96a..e231afdf 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java @@ -6,7 +6,6 @@ import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; @@ -41,10 +40,6 @@ public ReactorInputEntity(BlockEntityType type, BlockPos pos, BlockState stat @Override public void addBehaviours(List behaviours) { } - // Dans ta classe, j'imagine que tu as ces variables : - private BlockPos inputPos; - private ResourceKey inputLevelKey; // On stocke la clé, pas l'objet Level directement - @Override protected void write(CompoundTag tag, boolean clientPacket) { super.write(tag, clientPacket); // Toujours appeler le super diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java index c359fa35..ef4dc030 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java @@ -15,7 +15,6 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -187,11 +186,6 @@ public float getGeneratedSpeed() { return Mth.clamp(generatedSpeed, 0, 1500000); } - @Override - protected Block getStressConfigKey() { - return super.getStressConfigKey(); - } - class ReactorOutputValue extends ValueBoxTransform.Sided { @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java index 9422c309..08654013 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java @@ -1,9 +1,7 @@ package net.nuclearteam.createnuclear.content.multiblock.pattern; -import lib.multiblock.SimpleMultiBlockAislePatternBuilder; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; @@ -14,11 +12,9 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import org.jetbrains.annotations.Nullable; -import java.util.List; import java.util.function.Predicate; public class ReactorPattern { - //public BlockPos VerifyPattern(char character) {} private static final Predicate blockInWorldAPredicate = state -> stateIs(CNBlocks.REACTOR_CASING.get()).test(state) @@ -35,66 +31,6 @@ private static Predicate stateIs(Block block) { }; } - public BlockPos VerifyPattern5x5(char character) { - return SimpleMultiBlockAislePatternBuilder.start() - .aisle("OOOOO", "OAAAO", "OAAAO", "OAAAO", "OOOOO") - .aisle("OABAO", "ODDDO", "BDCDB", "ODDDO", "OABAO") - .aisle("OABAO", "ODDDO", "BDCDB", "ODDDO", "OABAO") - .aisle("OABAO", "ODDDO", "BDCDB", "ODDDO", "OA*AO") - .aisle("OABAO", "ODDDO", "BDCDB", "ODDDO", "OABAO") - .aisle("OABAO", "ODDDO", "BDCDB", "ODDDO", "OABAO") - .aisle("OOOOO", "OAAAO", "OAAAO", "OAAAO", "OOOOO") - .where('A', blockInWorldAPredicate) - .where('B', a -> a.getState().is(CNBlocks.REACTOR_FRAME.get())) - .where('C', a -> a.getState().is(CNBlocks.REACTOR_CORE.get())) - .where('D', a -> a.getState().is(CNBlocks.REACTOR_COOLER.get())) - .where('*', a -> a.getState().is(CNBlocks.REACTOR_CONTROLLER.get())) - .where('O', a -> a.getState().is(CNBlocks.REACTOR_CASING.get())) - .getDistanceController(character); - } - - public BlockPos VerifyPattern7x7(char character) { - return SimpleMultiBlockAislePatternBuilder.start() - .aisle("OOOOOOO", "OAAAAAO", "OAAAAAO", "OAAAAAO", "OAAAAAO", "OAAAAAO", "OOOOOOO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OABABAO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OABABAO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OABABAO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OAB*BAO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OABABAO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OABABAO") - .aisle("OABABAO", "ADDDDDA", "BDCDCDB", "ADDDDDA", "BDCDCDB", "ADDDDDA", "OABABAO") - .aisle("OOOOOOO", "OAAAAAO", "OAAAAAO", "OAAAAAO", "OAAAAAO", "OAAAAAO", "OOOOOOO") - .where('A', blockInWorldAPredicate) - .where('B', a -> a.getState().is(CNBlocks.REACTOR_FRAME.get())) - .where('C', a -> a.getState().is(CNBlocks.REACTOR_CORE.get())) - .where('D', a -> a.getState().is(CNBlocks.REACTOR_COOLER.get())) - .where('*', a -> a.getState().is(CNBlocks.REACTOR_CONTROLLER.get())) - .where('O', a -> a.getState().is(CNBlocks.REACTOR_CASING.get())) - .getDistanceController(character); - } - - public BlockPos VerifyPattern9x9(char character) { - return SimpleMultiBlockAislePatternBuilder.start() - .aisle("OOOOOOOOO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OOOOOOOOO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAA*AABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OBAABAABO", "BDDDDDDDB", "ADCDCDCDA", "ADDDDDDDA", "BDCDCDCDB", "ADDDDDDDA", "ADCDCDCDA", "BDDDDDDDB", "OBAABAABO") - .aisle("OOOOOOOOO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OAAAAAAAO", "OOOOOOOOO") - .where('A', blockInWorldAPredicate) - .where('B', a -> a.getState().is(CNBlocks.REACTOR_FRAME.get())) - .where('C', a -> a.getState().is(CNBlocks.REACTOR_CORE.get())) - .where('D', a -> a.getState().is(CNBlocks.REACTOR_COOLER.get())) - .where('*', a -> a.getState().is(CNBlocks.REACTOR_CONTROLLER.get())) - .where('O', a -> a.getState().is(CNBlocks.REACTOR_CASING.get())) - .getDistanceController(character); - } - public void findController(BlockPos blockPos, Level level, boolean first){ BlockPos newBlock; Vec3i pos = new Vec3i(blockPos.getX(), blockPos.getY(), blockPos.getZ()); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java index de1de18c..283506a9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java @@ -13,7 +13,7 @@ import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.nuclearteam.createnuclear.foundation.damageTypes.CreateNuclearDamageSources; +import net.nuclearteam.createnuclear.foundation.damageTypes.CNDamageSources; import net.nuclearteam.createnuclear.foundation.utility.ConfigValueResolver; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; @@ -91,6 +91,6 @@ public void applyEffectTick(LivingEntity entity, int amplifier) { return; } - entity.hurt(CreateNuclearDamageSources.radiation(entity.level()), damage); + entity.hurt(CNDamageSources.radiation(entity.level()), damage); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/damageTypes/CreateNuclearDamageSources.java b/src/main/java/net/nuclearteam/createnuclear/foundation/damageTypes/CreateNuclearDamageSources.java deleted file mode 100644 index c053c074..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/damageTypes/CreateNuclearDamageSources.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.damageTypes; - -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.damagesource.DamageType; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.nuclearteam.createnuclear.CNDamageTypes; - -import javax.annotation.Nullable; - -public class CreateNuclearDamageSources { - public static DamageSource radiation(Level level) { - return source(CNDamageTypes.RADIATION, level); - } - public static DamageSource fanRadiation(Level level) { - return source(CNDamageTypes.FAN_RADIATION, level); - } - - private static DamageSource source(ResourceKey key, LevelReader level) { - Registry registry = level.registryAccess().registryOrThrow(Registries.DAMAGE_TYPE); - return new DamageSource(registry.getHolderOrThrow(key)); - } - - private static DamageSource source(ResourceKey key, LevelReader level, @Nullable Entity entity) { - Registry registry = level.registryAccess().registryOrThrow(Registries.DAMAGE_TYPE); - return new DamageSource(registry.getHolderOrThrow(key), entity); - } - - private static DamageSource source(ResourceKey key, LevelReader level, @Nullable Entity causingEntity, @Nullable Entity directEntity) { - Registry registry = level.registryAccess().registryOrThrow(Registries.DAMAGE_TYPE); - return new DamageSource(registry.getHolderOrThrow(key), causingEntity, directEntity); - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNShapelessRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNShapelessRecipeGen.java deleted file mode 100644 index f239e93a..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNShapelessRecipeGen.java +++ /dev/null @@ -1,140 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.data.recipe; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.simibubi.create.AllRecipeTypes; -import com.simibubi.create.api.data.recipe.BaseRecipeProvider; -import com.simibubi.create.foundation.recipe.IRecipeTypeInfo; -import com.tterrag.registrate.util.entry.ItemProviderEntry; -import net.createmod.catnip.platform.CatnipServices; -import net.minecraft.advancements.critereon.ItemPredicate; -import net.minecraft.data.PackOutput; -import net.minecraft.data.recipes.*; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.crafting.RecipeSerializer; -import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.common.crafting.conditions.ICondition; -import net.minecraftforge.common.crafting.conditions.ModLoadedCondition; -import net.minecraftforge.common.crafting.conditions.NotCondition; -import net.nuclearteam.createnuclear.CreateNuclear; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -@SuppressWarnings("unused") -public class CNShapelessRecipeGen extends BaseRecipeProvider { - - String currentFolder = ""; - - String enterFolder(String foldedr) { - currentFolder = foldedr; - return currentFolder; - } - - GeneratedRecipeBuilder create(Supplier result) { - return new GeneratedRecipeBuilder(currentFolder, result); - } - - GeneratedRecipeBuilder create(ResourceLocation result) { - return new GeneratedRecipeBuilder(currentFolder, result); - } - - GeneratedRecipeBuilder create(ItemProviderEntry result) { - return create(result::get); - } - - - class GeneratedRecipeBuilder { - - private String path; - private String suffix; - private Supplier result; - private ResourceLocation compatDatagenOutput; - List recipeConditions; - private RecipeCategory category; - - private Supplier unlockedBy; - private int amount; - - private GeneratedRecipeBuilder(String path) { - this.path = path; - this.recipeConditions = new ArrayList<>(); - this.suffix = ""; - this.amount = 1; - this.category = RecipeCategory.MISC; - } - - public GeneratedRecipeBuilder(String path, Supplier result) { - this(path); - this.result = result; - } - - public GeneratedRecipeBuilder(String path, ResourceLocation result) { - this(path); - this.compatDatagenOutput = result; - } - - GeneratedRecipeBuilder returns(int amount) { - this.amount = amount; - return this; - } - - GeneratedRecipeBuilder unlockedBy(Supplier item) { - this.unlockedBy = () -> ItemPredicate.Builder.item() - .of(item.get()) - .build(); - return this; - } - - GeneratedRecipeBuilder unlockedByTag(Supplier> tag) { - this.unlockedBy = () -> ItemPredicate.Builder.item() - .of(tag.get()) - .build(); - return this; - } - - GeneratedRecipeBuilder whenModLoaded(String modid) { - return withCondition(new ModLoadedCondition(modid)); - } - - GeneratedRecipeBuilder whenModMissing(String modid) { - return withCondition(new NotCondition(new ModLoadedCondition(modid))); - } - - GeneratedRecipeBuilder withCondition(ICondition condition) { - recipeConditions.add(condition); - return this; - } - - GeneratedRecipeBuilder withSuffix(String suffix) { - this.suffix = suffix; - return this; - } - - GeneratedRecipeBuilder withCategory(RecipeCategory category) { - this.category = category; - return this; - } - - private ResourceLocation createSimpleLocation(String recipeType) { - return CreateNuclear.asResource(recipeType + "/" + getRegistryName().getPath() + suffix); - } - - private ResourceLocation createLocation(String recipeType) { - return CreateNuclear.asResource(recipeType + "/" + path + "/" + getRegistryName().getPath() + suffix); - } - - private ResourceLocation getRegistryName() { - return compatDatagenOutput == null ? CatnipServices.REGISTRIES.getKeyOrThrow(result.get() - .asItem()) : compatDatagenOutput; - } - } - - public CNShapelessRecipeGen(PackOutput output) { - super(output, CreateNuclear.MOD_ID); - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEventClients.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEventClients.java deleted file mode 100644 index 002f5c72..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEventClients.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.events; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.EntityRenderersEvent; -import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; -import net.minecraftforge.registries.ForgeRegistries; -import net.nuclearteam.createnuclear.CNEntityType; -import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.foundation.item.RodsStats; - -@EventBusSubscriber(bus = Bus.MOD, value = Dist.CLIENT) -public class CommentEventClients { - - - -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/possible code b/src/main/java/net/nuclearteam/createnuclear/foundation/events/possible code deleted file mode 100644 index 87cf86c2..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/possible code +++ /dev/null @@ -1,66 +0,0 @@ -/* - * META-INF/services/com.tonpackage.HudOverlay - * ------------------------------------------- - * Liste des implémentations de HudOverlay à charger via ServiceLoader - */ -com.tonpackage.HelmetOverlay -com.tonpackage.PotionOverlay -com.tonpackage.RadiationOverlay - -// -------------------------------------------------------- -package com.tonpackage; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.ServiceLoader; - -/** - * Chargement dynamique de tous les HudOverlay via Java SPI (ServiceLoader) - */ -public class HudOverlayRegistry { - private static final List ALL = new ArrayList<>(); - - static { - ServiceLoader.load(HudOverlay.class) - .forEach(ALL::add); - } - - /** - * Retourne la liste non modifiable de tous les overlays chargés. - */ - public static List getAll() { - return Collections.unmodifiableList(ALL); - } -} - -// -------------------------------------------------------- -package com.tonpackage; - -import net.minecraftforge.client.event.RenderGuiOverlayEvent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; - -import java.util.Comparator; - -@Mod.EventBusSubscriber(value = Dist.CLIENT) -public class CNClientEvent { - - @SubscribeEvent - public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { - // On ne rend qu'après l'overlay "helmet" - if (!event.getOverlay().id().equals(VanillaGuiOverlay.HELMET.id())) return; - - GuiGraphics gfx = event.getGuiGraphics(); - float pt = event.getPartialTick(); - - HudOverlayRegistry.getAll().stream() - .filter(HudOverlay::isActive) - .filter(o -> o.getAfterOverlay().equals(VanillaGuiOverlay.HELMET.id())) - .sorted(Comparator.comparingInt(HudOverlay::getPriority).reversed()) - .forEach(o -> o.render(gfx, pt)); - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/utility/Maths.java b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/Maths.java index e3a672e7..293ba522 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/utility/Maths.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/Maths.java @@ -24,7 +24,6 @@ import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import net.nuclearteam.createnuclear.content.explosion.CNAnimation; public class Maths { public static final Direction[] HORIZONTAL_DIRECTIONS; @@ -40,16 +39,6 @@ public static float smin(float a, float b, float k) { return Math.min(a, b) - h * h * k * 0.25F; } - public static float cullAnimationTick(int tick, float amplitude, CNAnimation animation, float partialTick, int startOffset) { - return cullAnimationTick(tick, amplitude, animation, partialTick, startOffset, animation.getDuration() - startOffset); - } - - public static float cullAnimationTick(int tick, float amplitude, CNAnimation animation, float partialTick, int startOffset, int endAt) { - float i = Mth.clamp((float)tick + partialTick - (float)startOffset, 0.0F, (float)endAt); - float f = (float)Math.sin((double)(i / (float)endAt) * Math.PI) * amplitude; - return smin(f, 1.0F, 0.1F); - } - public static float sampleNoise2D(int x, int z, float simplexSampleRate) { return (float) SimplexNoise.noise((double)(((float)x + simplexSampleRate) / simplexSampleRate), (double)(((float)z + simplexSampleRate) / simplexSampleRate)); } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/utility/TextUtils.java b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/TextUtils.java index 6cecb7a4..e6a9aa20 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/utility/TextUtils.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/TextUtils.java @@ -1,15 +1,6 @@ package net.nuclearteam.createnuclear.foundation.utility; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.Style; import org.apache.commons.lang3.StringUtils; -import org.joml.Matrix4f; -import java.util.Optional; import java.util.stream.Stream; public class TextUtils { @@ -41,80 +32,4 @@ public static String titleCaseConversion(String inputString) return StringUtils.trim(resultPlaceHolder.toString()); } - - public static void renderMultilineDebugText(PoseStack poseStack, MultiBufferSource buffer, int packedLight, - double baseY, boolean transparent, String... lines) { - double y = baseY + (lines.length/4.0D); - for (String line : lines) { - renderDebugText(poseStack, buffer, packedLight, y, transparent, line); - y -= 0.25D; - } - } - - public static void renderDebugText(PoseStack poseStack, MultiBufferSource pBuffer, int pPackedLight, - double y, boolean transparent, String text) { - poseStack.pushPose(); - poseStack.translate(0.0D, y, 0.0D); - poseStack.mulPose(Minecraft.getInstance().getBlockEntityRenderDispatcher().camera.rotation()); - poseStack.scale(-0.025F, -0.025F, 0.025F); - - Matrix4f matrix4f = poseStack.last().pose(); - - float f1 = Minecraft.getInstance().options.getBackgroundOpacity(0.25F); - int j = (int)(f1 * 255.0F) << 24; - Font font = Minecraft.getInstance().font; - - float f2 = (float)(-font.width(text) / 2); - font.drawInBatch(text, f2, 0, 553648127, false, matrix4f, pBuffer, transparent ? Font.DisplayMode.SEE_THROUGH : Font.DisplayMode.NORMAL, j, pPackedLight); - - if (transparent) { - font.drawInBatch(text, f2, 0, -1, false, matrix4f, pBuffer, Font.DisplayMode.NORMAL, 0, pPackedLight); - } - - poseStack.popPose(); - } - - public static Component translateWithFormatting(String key, Object... args) { - - MutableComponent base = Component.translatable(key, args); - - StringBuilder partsStringBuilder = new StringBuilder(); - - base.visit((style, part) -> { - partsStringBuilder.append(part); - return Optional.empty(); - }, Style.EMPTY); - - return Component.literal(partsStringBuilder.toString()); - } - - public static String formatInt(int num) { - return formatInt(num, ","); - } - - public static String formatInt(int num, String separator) { - - String raw = String.valueOf(num); - - if (raw.length() <= 3) - return raw; - - int start = raw.length() % 3; - StringBuilder out = new StringBuilder(raw.length() + (raw.length()/3) * separator.length()); - - out.append(raw, 0, start); - - for (int i = 0; i < raw.length() / 3; i++) { - if (i != 0 || start != 0) - out.append(separator); - out.append(raw, i*3 + start, i*3 + start + 3); - } - - return out.toString(); - } - - public static String leftPad(String s, char c, int width) { - if (s.length() >= width) return s; - return String.valueOf(c).repeat(width - s.length()) + s; - } -} \ No newline at end of file +} diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCCommon.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCCommon.java index 22279fa6..a5ea68a4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCCommon.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCCommon.java @@ -13,6 +13,5 @@ public String getName() { private static class Comments { static String worldGen = "Modify CreateNuclear's impact on your terrain"; - static String explode = "Modify the parameters of the explosion"; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java index 36bfbebd..b80d4054 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java @@ -4,7 +4,6 @@ public class CNCServer extends ConfigBase { public final CRods rods = nested(0, CRods::new, Comments.rods); -// public final CExplode explode = nested(0, CExplode::new, Comments.explode); public final CNotify notify = nested(0, CNotify::new,Comments.ratio); public final CRadiation radiation = nested(0, CRadiation::new, Comments.radiation); @Override @@ -14,7 +13,6 @@ public String getName() { private static class Comments { static String rods = "Modify the duration and configuration of rods."; - static String explode = "[WIP] Modify the parameters of the explosion"; static String radiation = "Enable or disable radiation effects emitted by mod items. "; static String ratio = "Ratio"; } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java index 39a35083..d537fd2f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java @@ -15,7 +15,6 @@ import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; import net.nuclearteam.createnuclear.foundation.data.recipe.CNMechanicalCraftingRecipeGen; import net.nuclearteam.createnuclear.foundation.data.recipe.CNProcessingRecipeGen; -import net.nuclearteam.createnuclear.foundation.data.recipe.CNShapelessRecipeGen; import net.nuclearteam.createnuclear.foundation.data.recipe.CNStandardRecipeGen; import net.nuclearteam.createnuclear.foundation.ponder.CreateNuclearPonderPlugin; @@ -39,7 +38,6 @@ public static void gatherData(GatherDataEvent event) { lookupProvider = generatedEntriesProvider.getRegistryProvider(); generator.addProvider(event.includeClient(), generatedEntriesProvider); generator.addProvider(event.includeClient(), new CNStandardRecipeGen(output)); - // generator.addProvider(event.includeClient(), new CNShapelessRecipeGen(output)); generator.addProvider(event.includeClient(), new CNMechanicalCraftingRecipeGen(output)); generator.addProvider(event.includeClient(), new CNAdvancement(output)); From ba870a446c6543cf0d587d8780cb64f5561271d0 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 15 Jun 2026 14:10:23 +0200 Subject: [PATCH 016/171] refactor: update thorium block loot table and tags --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 21 ++++----- .../loot_tables/blocks/thorium_block.json | 43 +++---------------- .../tags/blocks/thorium_ores.json | 4 +- .../tags/items/thorium_ores.json | 4 +- .../data/forge/tags/blocks/ores.json | 3 +- .../data/forge/tags/blocks/ores/thorium.json | 3 +- .../tags/blocks/ores_in_ground/stone.json | 3 +- .../tags/blocks/storage_blocks/thorium.json | 5 +++ .../data/forge/tags/items/ores/thorium.json | 3 +- .../tags/blocks/needs_diamond_tool.json | 3 +- .../tags/blocks/needs_iron_tool.json | 3 +- .../nuclearteam/createnuclear/CNBlocks.java | 15 +------ .../IrradiatedOverlayRendererVision.java | 1 + .../infrastructure/config/CNCClient.java | 2 +- .../biome/surfacerule/BiomeTagRule.java | 2 +- 15 files changed, 36 insertions(+), 79 deletions(-) create mode 100644 src/generated/resources/data/forge/tags/blocks/storage_blocks/thorium.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 05f1aeb1..3ef506e5 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-14T11:07:51.5482654 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-15T13:51:24.9226141 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -389,7 +389,7 @@ d51f9b307f2986ac086d32f48bd41e6dc4024348 data/createnuclear/loot_tables/blocks/s 4014ab450bb5de0522690577486f2fbbc334de9c data/createnuclear/loot_tables/blocks/small_autunite_brick_stairs.json 8718c7e7cce27e299611ee34792cdb59f3434e39 data/createnuclear/loot_tables/blocks/small_autunite_brick_wall.json 94dc8e72195da5aa505c6d5a3785ccfea30f7c05 data/createnuclear/loot_tables/blocks/steel_block.json -bc1497c8412144515b94799c007cfdb277d5736f data/createnuclear/loot_tables/blocks/thorium_block.json +10453354af3c17390f7b6eb2eaa7109eae3988c3 data/createnuclear/loot_tables/blocks/thorium_block.json c1c889e441f52d3c7fcf50dd2a4dab7311c9b262 data/createnuclear/loot_tables/blocks/thorium_ore.json 28feab8379c2951034bed4016eb91981d07dd24b data/createnuclear/loot_tables/blocks/uranium_ore.json fba1a7bdb0835c034aa5ef52ebf589123d41b33e data/createnuclear/loot_tables/entities/irradiated_cat.json @@ -536,7 +536,7 @@ a7d4278d8a39649c8b658ad2f3f1d092cb012bdf data/createnuclear/tags/blocks/enrichin 509b5baa813ae0dc3345fd97754e4088132359ec data/createnuclear/tags/blocks/fan_processing_catalysts/enriched.json bc8701774f57ab000a8f0f1d390702175a6cdbb8 data/createnuclear/tags/blocks/fan_processing_catalysts/snow_powder.json 925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/createnuclear/tags/blocks/lead_ores.json -baae2dfd7e19770072d6261ec68ce157a32be80c data/createnuclear/tags/blocks/thorium_ores.json +35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/createnuclear/tags/blocks/thorium_ores.json bad88bea18fec41c7ad6fa4d396feacc0346a137 data/createnuclear/tags/blocks/uranium_ores.json ccbc67cba973a8e1e43d0166ddfa5645f6a82aea data/createnuclear/tags/entity_types/irradiated_immune.json 410aa6d101788f25baa176741887c6f314006f29 data/createnuclear/tags/fluids/nitrogen.json @@ -549,22 +549,23 @@ bce34f53cb2d00f7dee84683e8fdd429dabbcc1d data/createnuclear/tags/items/anti_radi c5587bb72c54f59e9f9a4cd2c3e6bedb78ee198d data/createnuclear/tags/items/fuel.json 925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/createnuclear/tags/items/lead_ores.json 1a438d724641b4899f18b4abeef0b0708c76ea70 data/createnuclear/tags/items/stone_types/autunite.json -baae2dfd7e19770072d6261ec68ce157a32be80c data/createnuclear/tags/items/thorium_ores.json +35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/createnuclear/tags/items/thorium_ores.json bad88bea18fec41c7ad6fa4d396feacc0346a137 data/createnuclear/tags/items/uranium_ores.json d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json 75f0600da4891d0f4a3329fb44cac6c4945a0b49 data/forge/tags/blocks/glass.json -313a08cba1fa936e4c6188bea816734de777b513 data/forge/tags/blocks/ores.json +1fd17be1d553e7ddf20494ee1e98084f02137cc8 data/forge/tags/blocks/ores.json 925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/forge/tags/blocks/ores/lead.json 1ad062f84e124267bb3aae3add3a4e5265a4f8d7 data/forge/tags/blocks/ores/nitrate.json -82c4090f813a5b013e1835143d598678a17709e1 data/forge/tags/blocks/ores/thorium.json +3f665c928bcdfaa68700d1da7a28fddcbb7bf802 data/forge/tags/blocks/ores/thorium.json bad88bea18fec41c7ad6fa4d396feacc0346a137 data/forge/tags/blocks/ores/uranium.json 4f1ebc0bb505bc510c52671c5935494270ec7008 data/forge/tags/blocks/ores_in_ground/deepslate.json -f817fac347e5f8ea4878c5c317328b808ab0fa38 data/forge/tags/blocks/ores_in_ground/stone.json +a04457046c7b0dc46d430af61f83518a84a508d2 data/forge/tags/blocks/ores_in_ground/stone.json a7258ae3454252e874b324fbd81b880ce52759c4 data/forge/tags/blocks/storage_blocks/lead.json 2b32fe875f887d4a406700d35e0fe5a93548ebb7 data/forge/tags/blocks/storage_blocks/raw_lead.json 725644962932169e20d6f2726e69af199ce3800c data/forge/tags/blocks/storage_blocks/raw_thorium.json 0aafd338eaffcc3f48fb8dc9d18fc969318b06e0 data/forge/tags/blocks/storage_blocks/raw_uranium.json f8074cdbc6e2b560acb4e9da953b23f9825486a6 data/forge/tags/blocks/storage_blocks/steel.json +baae2dfd7e19770072d6261ec68ce157a32be80c data/forge/tags/blocks/storage_blocks/thorium.json a63487094743744be756ad497f483fcd4d11e9bc data/forge/tags/fluids/uranium.json e15fb3153f19574ecf55a117c026f6bf028f3a87 data/forge/tags/items/armors/boots.json fb238dbddaf54871f03731ee7cce881af0932459 data/forge/tags/items/armors/chestplates.json @@ -588,7 +589,7 @@ a77ba3f79cd096f38bd53b5f1b6a5696b864e9df data/forge/tags/items/nuggets.json 31d6f68b8cbb51e44700987c1b242a855e120b33 data/forge/tags/items/nuggets/thorium.json 925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/forge/tags/items/ores/lead.json 1ad062f84e124267bb3aae3add3a4e5265a4f8d7 data/forge/tags/items/ores/nitrate.json -82c4090f813a5b013e1835143d598678a17709e1 data/forge/tags/items/ores/thorium.json +3f665c928bcdfaa68700d1da7a28fddcbb7bf802 data/forge/tags/items/ores/thorium.json bad88bea18fec41c7ad6fa4d396feacc0346a137 data/forge/tags/items/ores/uranium.json fd86e3b3265d7069f3cfff0cfb5d086eea5a813a data/forge/tags/items/raw_materials.json 610ed700de0886bcb4b1c90100c35f3034c53940 data/forge/tags/items/raw_materials/lead.json @@ -614,8 +615,8 @@ e84d8e1fa924bec3e226b8917b4973b9629a5f52 data/minecraft/tags/blocks/mineable/axe 2844dedd4483b2d2ed5abcac2f0eca476c29efa4 data/minecraft/tags/blocks/mineable/pickaxe.json a7d4278d8a39649c8b658ad2f3f1d092cb012bdf data/minecraft/tags/blocks/mineable/shovel.json 8875ba7215b30d75573e3dcfe46e0b690b1d7f2f data/minecraft/tags/blocks/moss_replaceable.json -a3f4e5e22848384f6463ad5eba3ce6bf07e211c9 data/minecraft/tags/blocks/needs_diamond_tool.json -1e1755f2743626e697608774ec270b1360063133 data/minecraft/tags/blocks/needs_iron_tool.json +f815fd2431b9acf1fdf1f12a1adacaa2d147760f data/minecraft/tags/blocks/needs_diamond_tool.json +f40b6efca0ad845aeaf0bf4ef3490664d8ebe591 data/minecraft/tags/blocks/needs_iron_tool.json 9b9e13222cf9d971353888483c5f041cbb664dc3 data/minecraft/tags/blocks/slabs.json 7e5c701218bfbd3b186b102ff52dc79454a39e8f data/minecraft/tags/blocks/stairs.json 92fe109294976e85a9b9763124896e012a17c98a data/minecraft/tags/blocks/walls.json diff --git a/src/generated/resources/data/createnuclear/loot_tables/blocks/thorium_block.json b/src/generated/resources/data/createnuclear/loot_tables/blocks/thorium_block.json index f655a668..346c8684 100644 --- a/src/generated/resources/data/createnuclear/loot_tables/blocks/thorium_block.json +++ b/src/generated/resources/data/createnuclear/loot_tables/blocks/thorium_block.json @@ -3,44 +3,15 @@ "pools": [ { "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], "entries": [ { - "type": "minecraft:alternatives", - "children": [ - { - "type": "minecraft:item", - "conditions": [ - { - "condition": "minecraft:match_tool", - "predicate": { - "enchantments": [ - { - "enchantment": "minecraft:silk_touch", - "levels": { - "min": 1 - } - } - ] - } - } - ], - "name": "createnuclear:thorium_block" - }, - { - "type": "minecraft:item", - "functions": [ - { - "enchantment": "minecraft:fortune", - "formula": "minecraft:ore_drops", - "function": "minecraft:apply_bonus" - }, - { - "function": "minecraft:explosion_decay" - } - ], - "name": "createnuclear:raw_uranium" - } - ] + "type": "minecraft:item", + "name": "createnuclear:thorium_block" } ], "rolls": 1.0 diff --git a/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json b/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json index 6ea006df..f72d209d 100644 --- a/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json +++ b/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json @@ -1,5 +1,3 @@ { - "values": [ - "createnuclear:thorium_block" - ] + "values": [] } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json b/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json index 6ea006df..f72d209d 100644 --- a/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json +++ b/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json @@ -1,5 +1,3 @@ { - "values": [ - "createnuclear:thorium_block" - ] + "values": [] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/ores.json b/src/generated/resources/data/forge/tags/blocks/ores.json index ad601ebc..c393b205 100644 --- a/src/generated/resources/data/forge/tags/blocks/ores.json +++ b/src/generated/resources/data/forge/tags/blocks/ores.json @@ -7,7 +7,6 @@ "createnuclear:lead_ore", "createnuclear:thorium_ore", "createnuclear:nitrate_ore", - "createnuclear:deepslate_nitrate_ore", - "createnuclear:thorium_block" + "createnuclear:deepslate_nitrate_ore" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/ores/thorium.json b/src/generated/resources/data/forge/tags/blocks/ores/thorium.json index 34d5e153..c5f8a424 100644 --- a/src/generated/resources/data/forge/tags/blocks/ores/thorium.json +++ b/src/generated/resources/data/forge/tags/blocks/ores/thorium.json @@ -1,7 +1,6 @@ { "values": [ "createnuclear:deepslate_thorium_ore", - "createnuclear:thorium_ore", - "createnuclear:thorium_block" + "createnuclear:thorium_ore" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/ores_in_ground/stone.json b/src/generated/resources/data/forge/tags/blocks/ores_in_ground/stone.json index ebb310b1..c257624a 100644 --- a/src/generated/resources/data/forge/tags/blocks/ores_in_ground/stone.json +++ b/src/generated/resources/data/forge/tags/blocks/ores_in_ground/stone.json @@ -3,7 +3,6 @@ "createnuclear:uranium_ore", "createnuclear:lead_ore", "createnuclear:thorium_ore", - "createnuclear:nitrate_ore", - "createnuclear:thorium_block" + "createnuclear:nitrate_ore" ] } \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/blocks/storage_blocks/thorium.json b/src/generated/resources/data/forge/tags/blocks/storage_blocks/thorium.json new file mode 100644 index 00000000..6ea006df --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/storage_blocks/thorium.json @@ -0,0 +1,5 @@ +{ + "values": [ + "createnuclear:thorium_block" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/tags/items/ores/thorium.json b/src/generated/resources/data/forge/tags/items/ores/thorium.json index 34d5e153..c5f8a424 100644 --- a/src/generated/resources/data/forge/tags/items/ores/thorium.json +++ b/src/generated/resources/data/forge/tags/items/ores/thorium.json @@ -1,7 +1,6 @@ { "values": [ "createnuclear:deepslate_thorium_ore", - "createnuclear:thorium_ore", - "createnuclear:thorium_block" + "createnuclear:thorium_ore" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json index 57ff4a34..6878a4fe 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json @@ -12,7 +12,6 @@ "createnuclear:deepslate_uranium_ore", "createnuclear:deepslate_thorium_ore", "createnuclear:uranium_ore", - "createnuclear:raw_uranium_block", - "createnuclear:thorium_block" + "createnuclear:raw_uranium_block" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json index 8251ff56..ddc54a7a 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json @@ -6,7 +6,6 @@ "createnuclear:lead_ore", "createnuclear:thorium_ore", "createnuclear:nitrate_ore", - "createnuclear:deepslate_nitrate_ore", - "createnuclear:thorium_block" + "createnuclear:deepslate_nitrate_ore" ] } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index cd96af1b..e4f2e057 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -596,20 +596,9 @@ public class CNBlocks { CreateNuclear.REGISTRATE.block("thorium_block", Block::new) .initialProperties(SharedProperties::stone) .transform(pickaxeOnly()) - .loot((lt, b) -> lt.add(b, - RegistrateBlockLootTables.createSilkTouchDispatchTable(b, - lt.applyExplosionDecay(b, LootItem.lootTableItem(CNItems.RAW_URANIUM) - .apply(ApplyBonusCount.addOreBonusCount(Enchantments.BLOCK_FORTUNE)))))) - .tag(BlockTags.NEEDS_DIAMOND_TOOL, - BlockTags.NEEDS_IRON_TOOL, - CNTags.forgeBlockTag("ores"), - CNTags.forgeBlockTag("ores_in_ground/stone"), - CNTags.forgeBlockTag("ores/thorium"), - CNBlockTags.THORIUM_ORES.tag) + .tag(CNTags.forgeBlockTag("storage_blocks/thorium")) .item() - .tag(CNItemTags.THORIUM_ORES.tag, - CNTags.forgeItemTag("ores/thorium"), - CNTags.forgeItemTag("storage_blocks/thorium")) + .tag(CNTags.forgeItemTag("storage_blocks/thorium")) .build() .register(); diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java index 5354f41a..61f0ca61 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java @@ -22,6 +22,7 @@ public static void renderOverlay(ForgeGui gui, GuiGraphics graphics, float parti Minecraft mc = Minecraft.getInstance(); if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) return; LocalPlayer localPlayer = mc.player; + if (localPlayer == null) return; RenderSystem.enableBlend(); if (localPlayer.hasEffect(CNEffects.RADIATION.get())) { irradiatedVisionAlpha = Math.min(1.0f, irradiatedVisionAlpha + 0.01f); diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCClient.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCClient.java index fd764d94..71693c21 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCClient.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCClient.java @@ -6,7 +6,7 @@ public class CNCClient extends ConfigBase { public final ConfigBool nuclearBombFlash = b(true, "nuclearBombFlash", Comments.nuclearBombFlash); - public ConfigBool screenShaking = b(true, "nuclearBombFlash", Comments.screenShaking);; + public ConfigBool screenShaking = b(true, "screenShaking", Comments.screenShaking); @Override public String getName() { return "Client"; } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java index 25ba3b0a..033b5dab 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java @@ -19,7 +19,7 @@ public KeyDispatchDataCodec codec() { @Override public SurfaceRules.Condition apply(SurfaceRules.Context context) { - return null; + return new Predicate(context); } private class Predicate extends SurfaceRules.LazyYCondition { From 10ebdf5cf0cd1bee1fa10f4dde4b1645e6d67cfe Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 15 Jun 2026 14:34:13 +0200 Subject: [PATCH 017/171] refactor: update audit report with new findings and recommendations --- AUDIT_ACTUEL.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 73b00310..cb94c8fa 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -23,11 +23,8 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| | **B1** | `foundation/events/overlay/EventTextOverlay.java:40` | **Toujours présent** | `return timer > 0 && false;` — overlay jamais actif. `triggerEvent()` confirmé **jamais appelé** (grep global) → la classe entière est morte, enregistrée et rendue chaque frame pour rien. | -| **B4** | `CNBlocks.java` (~599-618) | **Toujours présent** | `THORIUM_BLOCK` drope `RAW_URANIUM` avec `addOreBonusCount(Enchantments.BLOCK_FORTUNE)` et porte les tags `ores`, `ores/thorium`, `ores_in_ground/stone`, `NEEDS_DIAMOND_TOOL/NEEDS_IRON_TOOL`, `THORIUM_ORES` — un bloc de stockage entièrement tagué/loot comme un minerai. | -| **B5** | `infrastructure/worldgen/biome/surfacerule/BiomeTagRule.java:20-23` | **Toujours présent** | `apply()` retourne `null` ; la classe interne `Predicate` (logique réelle) n'est jamais instanciée → NPE dès évaluation de `IS_IRRADIATED_PLAIN`. | | **B7** | `infrastructure/worldgen/biome/CNNoiseData.java` | **Toujours présent** | `bootstrapRegistries()` reste un corps **vide** ; `EROSION` jamais enregistré dans `Registries.NOISE`, alors que `IrradiatedSurfaceRules` (fusion v1/v2, un seul fichier désormais) fait toujours 3× `noiseCondition(EROSION,...)` → `getOrThrow` lèvera à la génération. | | **B8** | `content/multiblock/controller/ReactorControllerBlockEntity.java:646` | **Toujours présent, code réécrit mais bug identique** | `clearLockIfAllInputsEmpty()` fait désormais `CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this).data().getSize()` **sans null-check** sur le résultat de `findStructure`, qui peut retourner `null` si la structure n'est plus formée → NPE serveur. La méthode fait en plus un scan cubique `O(n³)` (`getBlockEntity` + capability lookup) alors que `inputFluidManager.getFuildHandlers(level)` donne déjà la liste exacte. | -| **B18** | `infrastructure/config/CNCClient.java:8-9` | **Toujours présent** | `screenShaking` réutilise littéralement la clé TOML `"nuclearBombFlash"` (avec un `;;` final en plus). Confirmé : deux options config pointent sur la même entrée. | --- @@ -38,7 +35,6 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e | **B3** | `content/effects/VicinityEffect.java:32-49` | **Toujours présent, identique** | `int cooldownTicks = 0;` réinitialisé à chaque itération → branche `else` morte, `cooldowns`/`getCooldown`/`setCooldown` toujours jamais appelés (confirmé grep). `RadiationEffect` continue donc à `addEffect` un `MobEffectInstance(RADIATION,300)` toutes les 5 ticks sur chaque entité proche, sans throttling réel. | | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | | **B9** | `content/radiation/capability/RadiationCapability.java` (`applyEffects`) | **Toujours présent, identique** | Les deux premières branches (`radiation < level1`, `radiation < level2`) donnent toutes deux `amplifierLevel0` → `radiationLevel2` reste un palier inopérant. | -| **B10** | `foundation/events/overlay/IrradiatedOverlayRendererVision.java:24-26` | **Toujours présent — Critique** | `LocalPlayer localPlayer = mc.player;` utilisé directement sans null-check, alors que les autres overlays (`HelmetOverlay`, `RadiationOverlay`) le font correctement. NPE au rendu pendant chargement/respawn/déconnexion. | | **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | | **B13** | `content/equipment/armor/AntiRadiationArmorClientExtensions.java` (case `CHEST`) | **Toujours présent, identique** | `this.model.rightArm.visible = true; this.model.leftArm.visible = true;` (champs hérités, non rendus par le `renderToBuffer` custom) au lieu de `right_arm`/`left_arm`. Bras toujours invisibles sur l'armure anti-radiation en mode plastron. | | **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` (B8) et `ReactorFluidInputEntity.FilteredFluidHandler`. | @@ -102,7 +98,7 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — *Recommandation* : router via un helper unique "peut être irradié" partagé par les 3 chemins. 5. **Deux overlays de "vision irradiée" actifs en parallèle** - `IrradiatedOverlayRendererVision` (actif, bug B10) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT_V1.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). + `IrradiatedOverlayRendererVision` (actif) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT_V1.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). 6. **`RenderHelper.renderTextureOverlay` — `Math.round(alpha*coverage)` annule le fade** `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT_V1.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 5). @@ -124,9 +120,9 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. 12. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** - `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B5/B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). + `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). -13. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B5/B7/B19), point d'alerte non couvert par `AUDIT_V1.md`. +13. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B7/B19), point d'alerte non couvert par `AUDIT_V1.md`. ### 🟡 Mineurs @@ -163,7 +159,7 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : ## 7. Plan d'action — priorités mises à jour -**Quick wins toujours en attente** (1 ligne, fort impact) : **B1**, **B5**, **B9**, **B18** (toujours triviaux à corriger), **B7** (enregistrer `EROSION`), **B4** (loot/tags Thorium). +**Quick wins toujours en attente** (1 ligne, fort impact) : **B1** (one-liner mais classe morte — décider câbler/supprimer), **B9** (mapping amplificateurs ambigu — décision produit), **B7** (enregistrer `EROSION`). **Nouveaux quick wins identifiés** : - `AntiRadiationArmorClientExtensions` (B13) : remplacer `rightArm/leftArm` par `right_arm/left_arm` en case `CHEST`. From ff469bc00720b172c2010f8103ee1481855373c7 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 15 Jun 2026 19:59:44 +0200 Subject: [PATCH 018/171] refactor: replace custom ore tags with forge:ores/* equivalents Drop the createnuclear-specific lead_ores, uranium_ores and thorium_ores tags (CNTags, CNBlocks, CNStandardRecipeGen) and use the shared forge:ores/lead, forge:ores/uranium and forge:ores/thorium tags everywhere instead, removing duplicate tag definitions and regenerating the recipe/advancement JSONs that referenced them. Also fix harvest-tool tags for thorium ore and raw thorium block: add NEEDS_DIAMOND_TOOL/NEEDS_IRON_TOOL to thorium ore (both deepslate and stone variants) and NEEDS_DIAMOND_TOOL to raw_thorium_block, and add deepslate_thorium_ore to needs_iron_tool, so thorium-related blocks require the correct tool tier like their uranium/lead counterparts. --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 12 ++------ .../9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e | 18 +++++------ .../blasting/lead_ingot_for_lead_ore.json | 2 +- .../blasting/raw_uranium_for_uranium_ore.json | 2 +- .../smelting/lead_ingot_for_lead_ore.json | 2 +- .../smelting/raw_uranium_for_uranium_ore.json | 2 +- .../blasting/lead_ingot_for_lead_ore.json | 2 +- .../blasting/raw_uranium_for_uranium_ore.json | 2 +- .../smelting/lead_ingot_for_lead_ore.json | 2 +- .../smelting/raw_uranium_for_uranium_ore.json | 2 +- .../createnuclear/tags/blocks/lead_ores.json | 6 ---- .../tags/blocks/thorium_ores.json | 3 -- .../tags/blocks/uranium_ores.json | 6 ---- .../createnuclear/tags/items/lead_ores.json | 6 ---- .../tags/items/thorium_ores.json | 3 -- .../tags/items/uranium_ores.json | 6 ---- .../tags/blocks/needs_diamond_tool.json | 4 ++- .../tags/blocks/needs_iron_tool.json | 1 + .../nuclearteam/createnuclear/CNBlocks.java | 30 +++++++++---------- .../net/nuclearteam/createnuclear/CNTags.java | 8 +---- .../data/recipe/CNStandardRecipeGen.java | 4 +-- 21 files changed, 41 insertions(+), 82 deletions(-) delete mode 100644 src/generated/resources/data/createnuclear/tags/blocks/lead_ores.json delete mode 100644 src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json delete mode 100644 src/generated/resources/data/createnuclear/tags/blocks/uranium_ores.json delete mode 100644 src/generated/resources/data/createnuclear/tags/items/lead_ores.json delete mode 100644 src/generated/resources/data/createnuclear/tags/items/thorium_ores.json delete mode 100644 src/generated/resources/data/createnuclear/tags/items/uranium_ores.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 3ef506e5..d11d9c76 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-15T13:51:24.9226141 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-15T19:58:10.7629453 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -535,9 +535,6 @@ ded8acf28ec98ddbd5257b9e7a7a4d8f3686d6df data/createnuclear/recipes/smithing/def a7d4278d8a39649c8b658ad2f3f1d092cb012bdf data/createnuclear/tags/blocks/enriching_fire_base_blocks.json 509b5baa813ae0dc3345fd97754e4088132359ec data/createnuclear/tags/blocks/fan_processing_catalysts/enriched.json bc8701774f57ab000a8f0f1d390702175a6cdbb8 data/createnuclear/tags/blocks/fan_processing_catalysts/snow_powder.json -925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/createnuclear/tags/blocks/lead_ores.json -35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/createnuclear/tags/blocks/thorium_ores.json -bad88bea18fec41c7ad6fa4d396feacc0346a137 data/createnuclear/tags/blocks/uranium_ores.json ccbc67cba973a8e1e43d0166ddfa5645f6a82aea data/createnuclear/tags/entity_types/irradiated_immune.json 410aa6d101788f25baa176741887c6f314006f29 data/createnuclear/tags/fluids/nitrogen.json dd07a117bf2a657aba3d776ee718829150a1c0af data/createnuclear/tags/fluids/thorium.json @@ -547,10 +544,7 @@ bce34f53cb2d00f7dee84683e8fdd429dabbcc1d data/createnuclear/tags/items/anti_radi 2e4d08932c4a84863f0198eb2845f80d8fda1221 data/createnuclear/tags/items/cloth.json 8e6598f14a72a61cbe1e5ed2aaea229fb2dd74e6 data/createnuclear/tags/items/cooler.json c5587bb72c54f59e9f9a4cd2c3e6bedb78ee198d data/createnuclear/tags/items/fuel.json -925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/createnuclear/tags/items/lead_ores.json 1a438d724641b4899f18b4abeef0b0708c76ea70 data/createnuclear/tags/items/stone_types/autunite.json -35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/createnuclear/tags/items/thorium_ores.json -bad88bea18fec41c7ad6fa4d396feacc0346a137 data/createnuclear/tags/items/uranium_ores.json d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json 75f0600da4891d0f4a3329fb44cac6c4945a0b49 data/forge/tags/blocks/glass.json 1fd17be1d553e7ddf20494ee1e98084f02137cc8 data/forge/tags/blocks/ores.json @@ -615,8 +609,8 @@ e84d8e1fa924bec3e226b8917b4973b9629a5f52 data/minecraft/tags/blocks/mineable/axe 2844dedd4483b2d2ed5abcac2f0eca476c29efa4 data/minecraft/tags/blocks/mineable/pickaxe.json a7d4278d8a39649c8b658ad2f3f1d092cb012bdf data/minecraft/tags/blocks/mineable/shovel.json 8875ba7215b30d75573e3dcfe46e0b690b1d7f2f data/minecraft/tags/blocks/moss_replaceable.json -f815fd2431b9acf1fdf1f12a1adacaa2d147760f data/minecraft/tags/blocks/needs_diamond_tool.json -f40b6efca0ad845aeaf0bf4ef3490664d8ebe591 data/minecraft/tags/blocks/needs_iron_tool.json +c47b0de40f93afb83463f8b3c7be32b613542b5d data/minecraft/tags/blocks/needs_diamond_tool.json +1fd17be1d553e7ddf20494ee1e98084f02137cc8 data/minecraft/tags/blocks/needs_iron_tool.json 9b9e13222cf9d971353888483c5f041cbb664dc3 data/minecraft/tags/blocks/slabs.json 7e5c701218bfbd3b186b102ff52dc79454a39e8f data/minecraft/tags/blocks/stairs.json 92fe109294976e85a9b9763124896e012a17c98a data/minecraft/tags/blocks/walls.json diff --git a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e index 76731e33..36147ff7 100644 --- a/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e +++ b/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -1,9 +1,9 @@ -// 1.20.1 2026-04-22T20:27:45.9021475 Recipes +// 1.20.1 2026-06-15T19:58:10.7478909 Recipes 229dafab82da54169697898f94d3be266a77d5ff data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead.json -14b3abbc5d9b1950f65ef1cc03f79a36c8820efc data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead_ore.json +53d8b344f1d5b0a0ce7d6082f5e214a6ae9c0bef data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead_ore.json 028d2b4f2f5ec4764791ca5c28c19b6848b00bea data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_raw_lead.json 203072b1b00fca38c88c3c7d9141ce044e1cded3 data/createnuclear/advancements/recipes/misc/blasting/nitrogen_concentrate_for_nitrogen_concentrate.json -605ccb2acc7e944ddbce2e962af3278e47a04627 data/createnuclear/advancements/recipes/misc/blasting/raw_uranium_for_uranium_ore.json +3aa4a3f3fdccc2b33ae50babf6db874f98835563 data/createnuclear/advancements/recipes/misc/blasting/raw_uranium_for_uranium_ore.json a72a296cd6cad499e78fa33f74194d74e9d2eef0 data/createnuclear/advancements/recipes/misc/crafting/lead_block_from_compacting.json c6acb8cd38541f9baf6e9045bf2547666a48dd66 data/createnuclear/advancements/recipes/misc/crafting/lead_ingot_from_compacting.json 7be9394a2c56bc4683288e45a44bfc5dda6a4b6e data/createnuclear/advancements/recipes/misc/crafting/steel_block_from_compacting.json @@ -13,15 +13,15 @@ c14100e996c2146f0c0c062ef489380e11b36b46 data/createnuclear/advancements/recipes a98dc6de94e6658d78ec28b77959ae9cb17b1d58 data/createnuclear/advancements/recipes/misc/crafting/white_cloth.json 067475701d6f059793c064718b7bba4b939ce380 data/createnuclear/advancements/recipes/misc/crafting/white_cloth_wool.json d4162de75c52e6106a386dcf4c5c3bc5b74261d6 data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead.json -0c347228b63702ba70d4257c4b5642133fb8e5b8 data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead_ore.json +26308967967782cb80e52e0cda39b27580923d53 data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead_ore.json 1bb03dfa15ff7f76bc2accdd7d26b520605ae4bf data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_raw_lead.json 4e49562ac3d71b9c1648649ac94858df73b1b2f6 data/createnuclear/advancements/recipes/misc/smelting/nitrogen_concentrate_for_nitrogen_concentrate.json -d7cfc6f1ff4d39df0df526ec3723e8d18d198945 data/createnuclear/advancements/recipes/misc/smelting/raw_uranium_for_uranium_ore.json +e2928f9172550d20f060a7fc5fcd690ab9f2bf16 data/createnuclear/advancements/recipes/misc/smelting/raw_uranium_for_uranium_ore.json 932672d0475e9c82d033d395ee12010e9f3d6828 data/createnuclear/recipes/blasting/lead_ingot_for_lead.json -b2ec2f955ece9110bf315a2773b70999e268f81d data/createnuclear/recipes/blasting/lead_ingot_for_lead_ore.json +065cd18605273ab59b5f68d2e21a40d4c144f51c data/createnuclear/recipes/blasting/lead_ingot_for_lead_ore.json c46810e5000a34edfceed6a8457595afe9d0377d data/createnuclear/recipes/blasting/lead_ingot_for_raw_lead.json ecfe4877ed719c02863e50a2de99a54bca0a6672 data/createnuclear/recipes/blasting/nitrogen_concentrate_for_nitrogen_concentrate.json -978cc9d92268673050da5697482f4013a63a65f1 data/createnuclear/recipes/blasting/raw_uranium_for_uranium_ore.json +247249727f830f450bb81d6da4f418d87c8f9d0a data/createnuclear/recipes/blasting/raw_uranium_for_uranium_ore.json 319718ee24e2c5bdeba2b16cd99c55fc7f97f9e4 data/createnuclear/recipes/crafting/lead_block_from_compacting.json 17e9a54a54b1ed1f6af0a3fbb0771262af585a95 data/createnuclear/recipes/crafting/lead_ingot_from_compacting.json 8e2e9b598fe86d2238915fb59486bccfac737e16 data/createnuclear/recipes/crafting/steel_block_from_compacting.json @@ -31,7 +31,7 @@ af5d168185e516ea79c335ac7eb6652b99723143 data/createnuclear/recipes/crafting/ste f2841ff83321c5bf5d43649fb204fa3a97fd596e data/createnuclear/recipes/crafting/white_cloth.json 93e75639c60d69067daddecfb2fa480a8e2040c4 data/createnuclear/recipes/crafting/white_cloth_wool.json 165a3c45b53d0a94149f26300f609c2fd7c688f1 data/createnuclear/recipes/smelting/lead_ingot_for_lead.json -4121c89708b0b069ece6dd9356dd3865af602779 data/createnuclear/recipes/smelting/lead_ingot_for_lead_ore.json +8d587bca58cdcc2320a115d0b653dbba7e7785ab data/createnuclear/recipes/smelting/lead_ingot_for_lead_ore.json 7acfaccfb12d280e8d858fdaf7f9048a5ac29e26 data/createnuclear/recipes/smelting/lead_ingot_for_raw_lead.json ad4541bf1f0994177d3f6ae830abb279c4d222f3 data/createnuclear/recipes/smelting/nitrogen_concentrate_for_nitrogen_concentrate.json -93fe12ad36a99451009518d71ac105969a1ef2aa data/createnuclear/recipes/smelting/raw_uranium_for_uranium_ore.json +279e5b03513f47f91867e356f9ccc77ee1f39629 data/createnuclear/recipes/smelting/raw_uranium_for_uranium_ore.json diff --git a/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead_ore.json b/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead_ore.json index c183b29e..b84799aa 100644 --- a/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead_ore.json +++ b/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/lead_ingot_for_lead_ore.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "tag": "createnuclear:lead_ores" + "tag": "forge:ores/lead" } ] }, diff --git a/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/raw_uranium_for_uranium_ore.json b/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/raw_uranium_for_uranium_ore.json index 1f43dc31..16c0707a 100644 --- a/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/raw_uranium_for_uranium_ore.json +++ b/src/generated/resources/data/createnuclear/advancements/recipes/misc/blasting/raw_uranium_for_uranium_ore.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "tag": "createnuclear:uranium_ores" + "tag": "forge:ores/uranium" } ] }, diff --git a/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead_ore.json b/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead_ore.json index ef898e54..41f985b7 100644 --- a/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead_ore.json +++ b/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/lead_ingot_for_lead_ore.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "tag": "createnuclear:lead_ores" + "tag": "forge:ores/lead" } ] }, diff --git a/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/raw_uranium_for_uranium_ore.json b/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/raw_uranium_for_uranium_ore.json index 9546f8e8..de59f0e2 100644 --- a/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/raw_uranium_for_uranium_ore.json +++ b/src/generated/resources/data/createnuclear/advancements/recipes/misc/smelting/raw_uranium_for_uranium_ore.json @@ -5,7 +5,7 @@ "conditions": { "items": [ { - "tag": "createnuclear:uranium_ores" + "tag": "forge:ores/uranium" } ] }, diff --git a/src/generated/resources/data/createnuclear/recipes/blasting/lead_ingot_for_lead_ore.json b/src/generated/resources/data/createnuclear/recipes/blasting/lead_ingot_for_lead_ore.json index c23f6e80..7bd43baf 100644 --- a/src/generated/resources/data/createnuclear/recipes/blasting/lead_ingot_for_lead_ore.json +++ b/src/generated/resources/data/createnuclear/recipes/blasting/lead_ingot_for_lead_ore.json @@ -4,7 +4,7 @@ "cookingtime": 100, "experience": 0.1, "ingredient": { - "tag": "createnuclear:lead_ores" + "tag": "forge:ores/lead" }, "result": "createnuclear:lead_ingot" } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/blasting/raw_uranium_for_uranium_ore.json b/src/generated/resources/data/createnuclear/recipes/blasting/raw_uranium_for_uranium_ore.json index c170a2b9..44017de5 100644 --- a/src/generated/resources/data/createnuclear/recipes/blasting/raw_uranium_for_uranium_ore.json +++ b/src/generated/resources/data/createnuclear/recipes/blasting/raw_uranium_for_uranium_ore.json @@ -4,7 +4,7 @@ "cookingtime": 100, "experience": 0.1, "ingredient": { - "tag": "createnuclear:uranium_ores" + "tag": "forge:ores/uranium" }, "result": "createnuclear:raw_uranium" } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/smelting/lead_ingot_for_lead_ore.json b/src/generated/resources/data/createnuclear/recipes/smelting/lead_ingot_for_lead_ore.json index 16a522a6..01b3b058 100644 --- a/src/generated/resources/data/createnuclear/recipes/smelting/lead_ingot_for_lead_ore.json +++ b/src/generated/resources/data/createnuclear/recipes/smelting/lead_ingot_for_lead_ore.json @@ -4,7 +4,7 @@ "cookingtime": 200, "experience": 0.1, "ingredient": { - "tag": "createnuclear:lead_ores" + "tag": "forge:ores/lead" }, "result": "createnuclear:lead_ingot" } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/smelting/raw_uranium_for_uranium_ore.json b/src/generated/resources/data/createnuclear/recipes/smelting/raw_uranium_for_uranium_ore.json index f415f686..52e1f380 100644 --- a/src/generated/resources/data/createnuclear/recipes/smelting/raw_uranium_for_uranium_ore.json +++ b/src/generated/resources/data/createnuclear/recipes/smelting/raw_uranium_for_uranium_ore.json @@ -4,7 +4,7 @@ "cookingtime": 200, "experience": 0.1, "ingredient": { - "tag": "createnuclear:uranium_ores" + "tag": "forge:ores/uranium" }, "result": "createnuclear:raw_uranium" } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/blocks/lead_ores.json b/src/generated/resources/data/createnuclear/tags/blocks/lead_ores.json deleted file mode 100644 index e456059a..00000000 --- a/src/generated/resources/data/createnuclear/tags/blocks/lead_ores.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "values": [ - "createnuclear:deepslate_lead_ore", - "createnuclear:lead_ore" - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json b/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json deleted file mode 100644 index f72d209d..00000000 --- a/src/generated/resources/data/createnuclear/tags/blocks/thorium_ores.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "values": [] -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/blocks/uranium_ores.json b/src/generated/resources/data/createnuclear/tags/blocks/uranium_ores.json deleted file mode 100644 index 548841c4..00000000 --- a/src/generated/resources/data/createnuclear/tags/blocks/uranium_ores.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "values": [ - "createnuclear:deepslate_uranium_ore", - "createnuclear:uranium_ore" - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/items/lead_ores.json b/src/generated/resources/data/createnuclear/tags/items/lead_ores.json deleted file mode 100644 index e456059a..00000000 --- a/src/generated/resources/data/createnuclear/tags/items/lead_ores.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "values": [ - "createnuclear:deepslate_lead_ore", - "createnuclear:lead_ore" - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json b/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json deleted file mode 100644 index f72d209d..00000000 --- a/src/generated/resources/data/createnuclear/tags/items/thorium_ores.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "values": [] -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/tags/items/uranium_ores.json b/src/generated/resources/data/createnuclear/tags/items/uranium_ores.json deleted file mode 100644 index 548841c4..00000000 --- a/src/generated/resources/data/createnuclear/tags/items/uranium_ores.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "values": [ - "createnuclear:deepslate_uranium_ore", - "createnuclear:uranium_ore" - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json index 6878a4fe..218be9ea 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json @@ -12,6 +12,8 @@ "createnuclear:deepslate_uranium_ore", "createnuclear:deepslate_thorium_ore", "createnuclear:uranium_ore", - "createnuclear:raw_uranium_block" + "createnuclear:thorium_ore", + "createnuclear:raw_uranium_block", + "createnuclear:raw_thorium_block" ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json index ddc54a7a..c393b205 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json @@ -2,6 +2,7 @@ "values": [ "createnuclear:deepslate_uranium_ore", "createnuclear:deepslate_lead_ore", + "createnuclear:deepslate_thorium_ore", "createnuclear:uranium_ore", "createnuclear:lead_ore", "createnuclear:thorium_ore", diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index e4f2e057..84e413d6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -377,11 +377,10 @@ public class CNBlocks { BlockTags.NEEDS_IRON_TOOL, CNTags.forgeBlockTag("ores"), CNTags.forgeBlockTag("ores_in_ground/deepslate"), - CNTags.forgeBlockTag("ores/uranium"), - CNBlockTags.URANIUM_ORES.tag + CNTags.forgeBlockTag("ores/uranium") ) .item((b, p) -> new UraniumOreItem(b, p, 3)) - .tag(CNItemTags.URANIUM_ORES.tag, CNTags.forgeItemTag("ores/uranium")) + .tag(CNTags.forgeItemTag("ores/uranium")) .build() .register(); @@ -397,11 +396,10 @@ public class CNBlocks { .tag(BlockTags.NEEDS_IRON_TOOL, CNTags.forgeBlockTag("ores"), CNTags.forgeBlockTag("ores_in_ground/deepslate"), - CNTags.forgeBlockTag("ores/lead"), - CNBlockTags.LEAD_ORES.tag) + CNTags.forgeBlockTag("ores/lead") + ) .item() - .tag(CNItemTags.LEAD_ORES.tag, - CNTags.forgeItemTag("ores/lead")) + .tag(CNTags.forgeItemTag("ores/lead")) .build() .register(); @@ -417,6 +415,7 @@ public class CNBlocks { .apply(ApplyBonusCount.addUniformBonusCount(Enchantments.BLOCK_FORTUNE, 5)) )))) .tag(BlockTags.NEEDS_DIAMOND_TOOL, + BlockTags.NEEDS_IRON_TOOL, CNTags.forgeBlockTag("ores"), CNTags.forgeBlockTag("ores_in_ground/deepslate"), CNTags.forgeBlockTag("ores/thorium") @@ -442,11 +441,10 @@ public class CNBlocks { BlockTags.NEEDS_IRON_TOOL, CNTags.forgeBlockTag("ores"), CNTags.forgeBlockTag("ores_in_ground/stone"), - CNTags.forgeBlockTag("ores/uranium"), - CNBlockTags.URANIUM_ORES.tag + CNTags.forgeBlockTag("ores/uranium") ) .item((b, p) -> new UraniumOreItem(b, p, 3)) - .tag(CNItemTags.URANIUM_ORES.tag, CNTags.forgeItemTag("ores/uranium")) + .tag(CNTags.forgeItemTag("ores/uranium")) .build() .register(); @@ -461,11 +459,10 @@ public class CNBlocks { .tag(BlockTags.NEEDS_IRON_TOOL, CNTags.forgeBlockTag("ores"), CNTags.forgeBlockTag("ores_in_ground/stone"), - CNTags.forgeBlockTag("ores/lead"), - CNBlockTags.LEAD_ORES.tag) + CNTags.forgeBlockTag("ores/lead") + ) .item() - .tag(CNItemTags.LEAD_ORES.tag, - CNTags.forgeItemTag("ores/lead")) + .tag(CNTags.forgeItemTag("ores/lead")) .build() .register(); @@ -481,7 +478,8 @@ public class CNBlocks { .apply(SetItemCountFunction.setCount(UniformGenerator.between(2.0F, 5.0F))) .apply(ApplyBonusCount.addUniformBonusCount(Enchantments.BLOCK_FORTUNE, 5)) )))) - .tag(BlockTags.NEEDS_IRON_TOOL, + .tag(BlockTags.NEEDS_DIAMOND_TOOL, + BlockTags.NEEDS_IRON_TOOL, CNTags.forgeBlockTag("ores"), CNTags.forgeBlockTag("ores_in_ground/stone"), CNTags.forgeBlockTag("ores/thorium") @@ -569,7 +567,7 @@ public class CNBlocks { CreateNuclear.REGISTRATE.block("raw_thorium_block", Block::new) .initialProperties(SharedProperties::stone) .transform(pickaxeOnly()) - .tag(CNTags.forgeBlockTag("storage_blocks/raw_thorium")) + .tag(BlockTags.NEEDS_DIAMOND_TOOL, CNTags.forgeBlockTag("storage_blocks/raw_thorium")) .recipe((c, p) -> ShapedRecipeBuilder.shaped(RecipeCategory.DECORATIONS, c.get()) .unlockedBy("has_raw_materials_thorium", RegistrateRecipeProvider.has(CNTags.forgeItemTag("raw_materials/thorium"))) .define('R', CNTags.forgeItemTag("raw_materials/thorium")) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNTags.java b/src/main/java/net/nuclearteam/createnuclear/CNTags.java index 0808100f..fd28b0c4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNTags.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNTags.java @@ -73,9 +73,6 @@ public enum CNBlockTags { FAN_PROCESSING_CATALYSTS_SNOW_POWDER(MOD, "fan_processing_catalysts/snow_powder"), ENRICHING_FIRE_BASE_BLOCKS, ALL_CAMPFIRES(MINECRAFT, "all/campfires"), - URANIUM_ORES, - LEAD_ORES, - THORIUM_ORES ; public final TagKey tag; @@ -126,12 +123,9 @@ public enum CNItemTags { CLOTH, FUEL, COOLER, - URANIUM_ORES, - LEAD_ORES, ANTI_RADIATION_ARMOR, COMPOSTABLE(FORGE), - THORIUM_ORES, - ALL_ANTI_RADIATION_ARMORS, + ALL_ANTI_RADIATION_ARMORS ; public final TagKey tag; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java index 429ade32..c1005668 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java @@ -70,8 +70,8 @@ public class CNStandardRecipeGen extends BaseRecipeProvider { private final String BLAST_FURNACE = enterFolder("blast_furnace"); GeneratedRecipe - URANIUM_ORE_TO_URANIUM_POWDER = blastFurnaceRecipeTags(() -> CNItems.RAW_URANIUM::get, () -> CNItemTags.URANIUM_ORES.tag, "_for_uranium_ore", 4), - RAW_LEAD_ORES = blastFurnaceRecipeTags(() -> CNItems.LEAD_INGOT::get, () -> CNItemTags.LEAD_ORES.tag, "_for_lead_ore", 1), + URANIUM_ORE_TO_URANIUM_POWDER = blastFurnaceRecipeTags(() -> CNItems.RAW_URANIUM::get, () -> CNTags.forgeItemTag("ores/uranium"), "_for_uranium_ore", 4), + RAW_LEAD_ORES = blastFurnaceRecipeTags(() -> CNItems.LEAD_INGOT::get, () -> CNTags.forgeItemTag("ores/lead"), "_for_lead_ore", 1), RAW_LEAD = blastFurnaceRecipeTags(CNItems.LEAD_INGOT::get, () -> CNTags.forgeItemTag("raw_materials/lead"), "_for_raw_lead", 1), CRUSHED_RAW_LEAD_TO_LEAD_BLAST_FURNACE = blastFurnaceRecipe(CNItems.LEAD_INGOT::get, AllItems.CRUSHED_LEAD::get, "_for_lead", 1), NITROGEN_CONCENTRATE = blastFurnaceRecipe(CNItems.NITROGEN_CONCENTRATE::get, CNItems.NITRATE::get, "_for_nitrogen_concentrate", 1) From fe3f58adba3cd6045d47ba7edce45d46174fcfe2 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Tue, 16 Jun 2026 11:15:18 +0200 Subject: [PATCH 019/171] refactor: improve variable naming and remove unnecessary logging in reactor components --- .../equipment/armor/AntiRadiationArmorClientExtensions.java | 4 ++-- .../multiblock/controller/ReactorControllerBlockEntity.java | 6 ++++-- .../controller/manager/ReactorInputFluidManager.java | 2 -- .../foundation/events/overlay/EventTextOverlay.java | 2 -- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java index 1ba3fd64..2b07943f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java @@ -36,8 +36,8 @@ public final class AntiRadiationArmorClientExtensions implements IClientItemExte } case CHEST -> { this.model.body.visible = true; - this.model.rightArm.visible = true; - this.model.leftArm.visible = true; + this.model.right_arm.visible = true; + this.model.left_arm.visible = true; } default -> { this.model.getHead().visible = false; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 3f31327c..c3fc9569 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -647,8 +647,10 @@ public void clearLockIfAllInputsEmpty() { if (level == null || level.isClientSide) return; - final int SCAN_RADIUS = CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this).data() - .getSize(); // adapte selon la taille max du multiblock + var structure = CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this); + // findStructure renvoie null si la structure n'est plus formée : on retombe + // alors sur la dernière taille assemblée (reactorSize) pour éviter un NPE serveur. + final int SCAN_RADIUS = structure != null ? structure.data().getSize() : reactorSize; BlockPos center = getBlockPos(); boolean anyNonEmpty = false; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java index e36b4af6..bfc9a6e7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java @@ -11,7 +11,6 @@ import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.VirtualReactorInputFluid; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; @@ -92,7 +91,6 @@ public List getBlocksPosition(Level level) { List positions = new ArrayList<>(); for (BlockPos p : this.getBlocksPosition()) { - CreateNuclear.LOGGER.warn("getBlocksPosition: {} {}", level.getBlockEntity(p), level.getBlockEntity(p) instanceof ReactorFluidInputEntity); if (level.getBlockEntity(p) instanceof ReactorFluidInputEntity) positions.add(p); } return List.copyOf(positions); diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java index 035de48c..4e472983 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java @@ -9,7 +9,6 @@ import net.minecraftforge.client.gui.overlay.ForgeGui; import net.minecraftforge.client.gui.overlay.IGuiOverlay; import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; -import net.nuclearteam.createnuclear.CreateNuclear; /** * HUD overlay for displaying localized text when a specific event occurs. @@ -44,7 +43,6 @@ public boolean isActive() { public void render(ForgeGui gui, GuiGraphics graphics, float partialTicks, int width, int height) { if (!isActive()) return; if (timer-- <= 0) return; - CreateNuclear.LOGGER.warn("hum EventTextOverlay: {}", timer); LocalPlayer player = Minecraft.getInstance().player; if (player == null) return; Component text = Component.translatable("overlay.event_message", timer).withStyle(ChatFormatting.RED); From e91a1d747780cf3ded8586a59ec3c457200fb24f Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Tue, 16 Jun 2026 11:36:16 +0200 Subject: [PATCH 020/171] refactor: update AUDIT_ACTUEL.md with current bug status and dead code cleanup --- AUDIT_ACTUEL.md | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index cb94c8fa..6a2470ee 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -14,7 +14,7 @@ Le code est toujours en **refactor V2 actif** (cohérent avec les commits récen - ✅ La feature radiation a été regroupée sous `content/radiation/**` (capability/client) — déplacement, pas (encore) une consolidation des deux contrats (`IRadiationSource` vs `RadiationRegistry`, toujours dupliqués). - ⚠️ `B2` (RadiationSyncPacket no-op) est **obsolète** : `RadiationSyncPacket`/`ClientRadiationData` n'existent plus du tout — le mécanisme décrit a disparu (probablement remplacé par la capability resync via `RadiationCapability`/`InventoryHashUtil`, qui elle fonctionne). -La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). En revanche, **le dead code a été en grande partie nettoyé le 2026-06-15** (voir l'encart ✅ du §3) ; il ne reste qu'un résidu non trivial. +La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). Le dead code a été en grande partie nettoyé ; il ne reste qu'un résidu non trivial (voir §3). --- @@ -24,7 +24,6 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e |---|---|---|---| | **B1** | `foundation/events/overlay/EventTextOverlay.java:40` | **Toujours présent** | `return timer > 0 && false;` — overlay jamais actif. `triggerEvent()` confirmé **jamais appelé** (grep global) → la classe entière est morte, enregistrée et rendue chaque frame pour rien. | | **B7** | `infrastructure/worldgen/biome/CNNoiseData.java` | **Toujours présent** | `bootstrapRegistries()` reste un corps **vide** ; `EROSION` jamais enregistré dans `Registries.NOISE`, alors que `IrradiatedSurfaceRules` (fusion v1/v2, un seul fichier désormais) fait toujours 3× `noiseCondition(EROSION,...)` → `getOrThrow` lèvera à la génération. | -| **B8** | `content/multiblock/controller/ReactorControllerBlockEntity.java:646` | **Toujours présent, code réécrit mais bug identique** | `clearLockIfAllInputsEmpty()` fait désormais `CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this).data().getSize()` **sans null-check** sur le résultat de `findStructure`, qui peut retourner `null` si la structure n'est plus formée → NPE serveur. La méthode fait en plus un scan cubique `O(n³)` (`getBlockEntity` + capability lookup) alors que `inputFluidManager.getFuildHandlers(level)` donne déjà la liste exacte. | --- @@ -36,8 +35,7 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | | **B9** | `content/radiation/capability/RadiationCapability.java` (`applyEffects`) | **Toujours présent, identique** | Les deux premières branches (`radiation < level1`, `radiation < level2`) donnent toutes deux `amplifierLevel0` → `radiationLevel2` reste un palier inopérant. | | **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | -| **B13** | `content/equipment/armor/AntiRadiationArmorClientExtensions.java` (case `CHEST`) | **Toujours présent, identique** | `this.model.rightArm.visible = true; this.model.leftArm.visible = true;` (champs hérités, non rendus par le `renderToBuffer` custom) au lieu de `right_arm`/`left_arm`. Bras toujours invisibles sur l'armure anti-radiation en mode plastron. | -| **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` (B8) et `ReactorFluidInputEntity.FilteredFluidHandler`. | +| **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | | **B16** | `foundation/data/recipe/CNStandardRecipeGen.java:351/391` | **Toujours présent (latent)** | `new ModdedCookingRecipeResult(result, compatDatagenOutput, null)` puis `serializeRecipeData` fait `conditions.forEach(...)` sur ce `null` → NPE si une recette `isOtherMod` est un jour sérialisée. | | **B17** | `foundation/events/RodsTooltipHandler.java:25-26` | **Toujours présent, identique** | `if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return;` — exclut justement les items du mod (les rods), donc `RodsStats` n'est jamais appliqué via ce handler. Code mort fonctionnel à risque si "corrigé" naïvement (double tooltip avec Registrate). | @@ -55,11 +53,7 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e ## 3. 🧹 Dead code — reste à faire -> **✅ Corrigé le 2026-06-15** (branche `V2-CorrectifAudit`, compilation validée) — supprimés du dépôt : -> framework d'animation mort (`CNModelAnimator`, `CNAnimation`, `CNIAnimatedEntity`, `CNTransform`, `CNTextureOffset`) + `Maths.cullAnimationTick` + méthodes mortes associées de `CNAdvancedEntityModel` (`rotate`/`rotateMinus`/`setCNTextureOffset`/`getCNTextureOffset`/`modelTextureMap`) ; -> `CreateNuclearDamageSources` (consolidé dans `CNDamageSources`) ; `CommentEventClients.java` ; `foundation/events/possible code` ; `CNShapelessRecipeGen.java` (+ réf. dans `CreateNuclearDatagen`) ; `ReactorPattern.VerifyPattern5x5/7x7/9x9` ; `ReactorBluePrintMenu.saveData2` ; `ReactorAssembler.getPlayersInRadius` ; `ReactorOutputEntity.getStressConfigKey` ; `ReactorInputEntity.inputPos`/`inputLevelKey` ; `ReactorCasingEntity.controller`/`setController`/`getController` ; `TextUtils` (5 helpers) ; `BigFluidStack.isInfinite`/`comparator`/`duplicateWrappers` ; `CExplode` (+ réf. `CNCServer`/`CNCCommon`) ; `CNRecipeTypes.CAN_BE_AUTOMATED` ; `ReactorOutputManager.distributeSU` (+ déclaration dans `ReactorOutputManagerI`) ; imports en double de `CNBlocks.java`. -> -> **⚠️ Corrections de l'audit V1/V2** : +> **⚠️ Corrections de l'audit V1/V2** (ne pas supprimer ces éléments — code vivant) : > - `CNTabulaModelRenderUtils` **n'est PAS du dead code** : il est utilisé par `CNAdvancedModelBox.cubeList`/`doRender`, sur le chemin de rendu **vivant** du champignon atomique (`NuclearMushroomCloudModel`). Conservé. La duplication `ModelBox` reste une opportunité de *refactor*, pas une suppression. > - `ReactorOutputEntity.outputPos` **n'est PAS mort** : il est lu/écrit dans `read()`/`write()` (sérialisation NBT). Laissé en place. @@ -68,7 +62,7 @@ Restant (grep global, zéro référence externe sauf mention) : - **Méthodes d'animation mortes restantes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` : `chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `setRotateAngle`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`/`movementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`. Mortes mais **non triviales** : leur retrait déclenche une cascade dans des classes **vivantes** (ex. `CNAdvancedModelBox.calculateRotation`/`bob` appellent `model.getMovementScale()`). À traiter en nettoyage dédié + dédup `ModelBox`. - **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §4 points 5 & 6 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). - **`SimpleMultiBlockPattern.test()`** : à vérifier — la classe ne semble plus exister (à confirmer/retirer si résidu). -- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §4 point 12, worldgen "irradié" template non terminé). +- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §4 point 10, worldgen "irradié" template non terminé). --- @@ -105,31 +99,26 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — ### 🟠 Importants -7. **✅ Corrigé (2026-06-15)** — `ReactorOutputManager.distributeSU` (dead code) supprimé, ainsi que sa déclaration dans `ReactorOutputManagerI`. Il ne reste plus que `ReactorControllerBlockEntity.rotate()` (round-robin simple) ; plus de duplication d'algorithme de distribution. - -8. **`ReactorInputFluidManager.getBlocksPosition` — `LOGGER.warn` à chaque appel (tick)** - Un `LOGGER.warn("getBlocksPosition: {} {}", ...)` tourne en boucle au niveau `WARN` à chaque tick via `ReactorInputSnapshotBuilder` — pollution de logs en production introduite par le refactor récent (non présente dans `AUDIT_V1.md`, qui ne connaissait pas encore `ReactorInputSnapshotBuilder`). - -9. **`RadiationCapability.lastBiomeLocation` — non persisté (correction : PAS du dead code)** +7. **`RadiationCapability.lastBiomeLocation` — non persisté (correction : PAS du dead code)** ⚠️ Correction de l'audit : contrairement à ce qui était écrit, `lastBiomeLocation` **est bien lu pour une décision** (`RadiationCapability:89`, comparaison `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`). Ce n'est donc **pas** du dead code et il n'a pas été supprimé. Le seul point restant : `RadiationProvider.serializeNBT` ne le persiste pas → l'état est perdu au save/déconnexion (bug mineur, à corriger ou assumer). -10. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** - `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT_V1.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. +8. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** + `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT_V1.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. -11. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** - En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. +9. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** + En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. -12. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** +10. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). -13. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B7/B19), point d'alerte non couvert par `AUDIT_V1.md`. +11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B7/B19), point d'alerte non couvert par `AUDIT_V1.md`. ### 🟡 Mineurs -14. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). -15. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 5 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. -16. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. -17. **`ReactorBluePrintItemPacket.totalInit`** : champ `static double` partagé, lu dans `calculatePostgres()` avant d'être écrit par `write()` côté émission — état global non thread-safe, partiellement lié à B6 mais distinct. +12. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). +13. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 5 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. +14. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +15. **`ReactorBluePrintItemPacket.totalInit`** : champ `static double` partagé, lu dans `calculatePostgres()` avant d'être écrit par `write()` côté émission — état global non thread-safe, partiellement lié à B6 mais distinct. --- @@ -152,6 +141,7 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : - `RadiationEffect` : `HashSet` + parsing reconstruits à chaque entité/tick — confirmé. - `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` recalculé en boucle interne — confirmé. - `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame — confirmé. +- `ReactorControllerBlockEntity.clearLockIfAllInputsEmpty` : scan cubique `O(n³)` (`getBlockEntity` + capability lookup par cellule) alors que `inputFluidManager.getFuildHandlers(level)` donne déjà la liste exacte (le NPE de `findStructure`, lui, a été corrigé). - **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT_V1.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). - **Nouveau** : `NuclearExplosionEntity.tick()` — tri complet d'une pile de jusqu'à 11³=1331 `BlockPos` avec comparateur `distManhattan` coûteux, en un seul tick. @@ -162,14 +152,13 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : **Quick wins toujours en attente** (1 ligne, fort impact) : **B1** (one-liner mais classe morte — décider câbler/supprimer), **B9** (mapping amplificateurs ambigu — décision produit), **B7** (enregistrer `EROSION`). **Nouveaux quick wins identifiés** : -- `AntiRadiationArmorClientExtensions` (B13) : remplacer `rightArm/leftArm` par `right_arm/left_arm` en case `CHEST`. - `RadiationEffectHandler` : ajouter les mêmes gardes (config/immunité/résistance) que les deux autres chemins. - Enregistrer `IrradiatedCatCollarLayer` / implémenter `IrradiatedWoldCollarLayer.render`, ou retirer la mécanique de teinture de collier. - Retirer `RenderHelper.renderTextureOverlay(..., Math.round(...))` → passer `alpha*coverage` brut (si `RadiationOverlay` est un jour réactivé). **Priorité structurelle inchangée** : le scan géométrique `ReactorPattern`/`MultiblockHelpers` (point architecture #3) reste le risque de performance serveur le plus sérieux et n'a reçu **aucune** correction — c'est le chantier le plus rentable avant de poursuivre la décomposition de `ReactorControllerBlockEntity`. -**Nettoyage dead-code** : la majeure partie de la liste `§3` a été traitée le 2026-06-15 (voir l'encart ✅ du §3). **Reste à faire** : +**Nettoyage dead-code restant** : - Méthodes d'animation mortes restantes dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` + dédup `ModelBox` (cascade dans classes vivantes — nettoyage dédié). - `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §4 points 5 & 6). - `IrradiatedBiomes.monsters()` no-op et reliquat éventuel `SimpleMultiBlockPattern.test()`. From 17ea4e1c9778c097ba72d4e69d41701f23c0be46 Mon Sep 17 00:00:00 2001 From: Gio Date: Wed, 17 Jun 2026 08:24:29 +0200 Subject: [PATCH 021/171] docs: reclassify B17 as intentional behavior in audit report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RodsTooltipHandler intentionally skips mod items (already handled via setTooltipModifierFactory) to only process external/datapack items. This is not a bug, but a readability risk — updated documentation with the rationale and a recommendation to add a guard comment. --- AUDIT_ACTUEL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 6a2470ee..91e8c405 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -38,7 +38,7 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e | **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | | **B16** | `foundation/data/recipe/CNStandardRecipeGen.java:351/391` | **Toujours présent (latent)** | `new ModdedCookingRecipeResult(result, compatDatagenOutput, null)` puis `serializeRecipeData` fait `conditions.forEach(...)` sur ce `null` → NPE si une recette `isOtherMod` est un jour sérialisée. | -| **B17** | `foundation/events/RodsTooltipHandler.java:25-26` | **Toujours présent, identique** | `if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return;` — exclut justement les items du mod (les rods), donc `RodsStats` n'est jamais appliqué via ce handler. Code mort fonctionnel à risque si "corrigé" naïvement (double tooltip avec Registrate). | +| **B17** | `foundation/events/RodsTooltipHandler.java:25-26` | **Reclassé — comportement intentionnel, risque de lisibilité uniquement** | La condition `if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return;` est **volontaire** : les items du mod disposent déjà de leur tooltip via `setTooltipModifierFactory` dans `CreateNuclear.java:48` (chemin Registrate). Ce handler sert exclusivement aux items **externes** (autres mods ou items définis via datapack), car `RodType.resolveRodType` interroge `world.registryAccess()` au runtime — seul mécanisme capable de lire les `RodType` injectés par datapack, que `setTooltipModifierFactory` ne peut pas couvrir (les datapacks ne sont pas connus à l'enregistrement). **Ce n'est donc pas un bug.** Le vrai risque est la lisibilité : la condition semble inversée sans contexte, et un contributeur naïf qui la retire ou l'inverse provoquera un double tooltip sur les rods du mod. **Correction recommandée** : ajouter un commentaire explicite sur la ligne de garde — `// mod items already handled by Registrate's setTooltipModifierFactory (CreateNuclear.java:48)` — pour verrouiller l'intention et prévenir toute régression future. | | **B19** | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` (fusion v1/v2) | **Toujours présent** | `IS_HIGHLANDS = biome()` (varargs vide) → toujours faux ; branches `MOON_DIRT`/`LEAD_TURF` mortes. Les constantes `MOON_DIRT`/`LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` pointent vers `STEEL_BLOCK`/`LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` — noms totalement déconnectés des blocs réels, signe d'un template non ré-thémé. | ### Bugs mineurs confirmés toujours présents (liste condensée) From 5a7babb386486b3f56616dd1d07ad6c9e7ad0127 Mon Sep 17 00:00:00 2001 From: Gio Date: Wed, 17 Jun 2026 09:05:57 +0200 Subject: [PATCH 022/171] docs: refine radiation duplication audit with concrete extraction plan Document the semantic split between RadiationEffect's binary gate and RadiationCapability's continuous dose attenuation, and propose RadiationCapability.canBeIrradiated() as the single reusable gate with a cached entity blacklist instead of rebuilding the HashSet per call. --- AUDIT_ACTUEL.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 91e8c405..74eae977 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -86,10 +86,53 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — *Recommandation* : implémenter la sélection de texture colorée dans `AntiRadiationArmorClientExtensions`/`AntiRadiationArmorModel`, ou retirer `getArmorTexture` + `ClothTagHelper.getArmorTexturePath` (et documenter que la teinture de tissu est cosmétiquement inerte). 4. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** - `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes. + `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes — mais selon deux sémantiques *différentes*, à ne pas fusionner : + + - `RadiationEffect` (filtre de contagion de proximité, constructeur lignes 32-52) applique un **gate binaire** (immune tag, config, blacklist, spectateur, `résistance ≥ 1`) — mais ce gate est enfermé dans un lambda non réutilisable, et **reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque appel** (cf. §5 point 5 / §6) — perf non corrigée en plus du problème de duplication. + - `RadiationCapability.applyEffects` applique une **atténuation continue de dose** (`totalRadiation = totalRaw * (1 - resistance)`), pas un gate — cette logique est correcte et ne doit *pas* être déplacée dans un helper commun, elle reste propre à ce chemin (calcul de magnitude, pas d'éligibilité). + *Conséquence* : une fuite de fluide irradiant un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. *Lien AUDIT_V1.md* : prolonge directement le constat §1.4 ("contrat IRadiationSource vs RadiationRegistry dupliqué sans règle de priorité") — ici un **troisième** mécanisme d'application apparaît, renforçant l'absence de propriétaire unique pour la feature radiation. - *Recommandation* : router via un helper unique "peut être irradié" partagé par les 3 chemins. + *Recommandation* : extraire **uniquement le gate binaire** (pas l'atténuation continue) dans `RadiationCapability.canBeIrradiated(LivingEntity)`, avec la blacklist mise en cache statique au lieu d'être reconstruite par appel : + + ```java + private static Set> entityBlacklistCache; // construit une fois, invalidé sur reload config/datapack + + public static boolean canBeIrradiated(LivingEntity entity) { + if (entity.isSpectator()) return false; + if (entity.getType().is(CNTags.CNEntityTags.IRRADIATED_IMMUNE.tag)) return false; + if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return false; + if (getEntityBlacklist().contains(entity.getType())) return false; + return getRadiationResistance(entity) < 1.0; + } + + private static Set> getEntityBlacklist() { + if (entityBlacklistCache == null) { + entityBlacklistCache = new HashSet<>(); + ConfigValueResolver.loadValuesInSet(CNConfigs.server().radiation.configuredLists.getEntityBlackList(), entityBlacklistCache, ...); + } + return entityBlacklistCache; + } + ``` + + ```java + // RadiationEffectHandler.apply + for (LivingEntity entity : entities) { + if (!RadiationCapability.canBeIrradiated(entity)) continue; + entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 3, 2, false, false, false)); + } + + // RadiationEffect.RadiationEffect + public RadiationEffect() { + super(MobEffectCategory.HARMFUL, 15453236, + amplifier -> 10, + RadiationCapability::canBeIrradiated, // au lieu de 20 lignes inline + HashSet reconstruit à chaque appel + timer -> {}, + () -> new MobEffectInstance(CNEffects.RADIATION.get(), 300)); + } + ``` + + Utilisé en garde dans `RadiationEffectHandler.apply` (corrige le bug) et comme `filter` de `RadiationEffect` (remplace le lambda dupliqué, supprime la reconstruction de `HashSet` par tick/entité). `RadiationCapability.applyEffects` garde son atténuation continue propre, mais gagne un garde-fou minimal absent aujourd'hui : `if (player.isSpectator()) return;`. 5. **Deux overlays de "vision irradiée" actifs en parallèle** `IrradiatedOverlayRendererVision` (actif) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT_V1.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). From 31efc1d4c17f7a577e9a281ae465ca84be873490 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:34:31 +0200 Subject: [PATCH 023/171] refactor: remove dead overlay event message from localization files --- AUDIT_ACTUEL.md | 3 +- .../assets/createnuclear/lang/en_ud.json | 1 - .../assets/createnuclear/lang/en_us.json | 1 - .../nuclearteam/createnuclear/CNBlocks.java | 19 +----- .../foundation/events/HudRenderer.java | 4 +- .../events/overlay/EventTextOverlay.java | 63 ------------------- .../assets/createnuclear/lang/af_za.json | 1 - .../assets/createnuclear/lang/ar_sa.json | 1 - .../assets/createnuclear/lang/ca_es.json | 1 - .../assets/createnuclear/lang/cs_cz.json | 1 - .../assets/createnuclear/lang/da_dk.json | 1 - .../assets/createnuclear/lang/de_de.json | 1 - .../createnuclear/lang/default/tooltips.json | 1 - .../assets/createnuclear/lang/el_gr.json | 1 - .../assets/createnuclear/lang/es_es.json | 1 - .../assets/createnuclear/lang/et_EE.json | 1 - .../assets/createnuclear/lang/fi_fi.json | 1 - .../assets/createnuclear/lang/fr_fr.json | 1 - .../assets/createnuclear/lang/he_il.json | 1 - .../assets/createnuclear/lang/hu_hu.json | 1 - .../assets/createnuclear/lang/it_it.json | 1 - .../assets/createnuclear/lang/ja_jp.json | 1 - .../assets/createnuclear/lang/ko_kr.json | 1 - .../assets/createnuclear/lang/lt_LT.json | 1 - .../assets/createnuclear/lang/nl_nl.json | 1 - .../assets/createnuclear/lang/no_no.json | 1 - .../assets/createnuclear/lang/pl_pl.json | 1 - .../assets/createnuclear/lang/pt_br.json | 1 - .../assets/createnuclear/lang/pt_pt.json | 1 - .../assets/createnuclear/lang/ro_ro.json | 1 - .../assets/createnuclear/lang/ru_ru.json | 1 - .../assets/createnuclear/lang/sr_sp.json | 1 - .../assets/createnuclear/lang/sv_se.json | 1 - .../assets/createnuclear/lang/tr_tr.json | 1 - .../assets/createnuclear/lang/uk_ua.json | 1 - .../assets/createnuclear/lang/vi_vn.json | 1 - .../assets/createnuclear/lang/zh_cn.json | 1 - .../assets/createnuclear/lang/zh_tw.json | 1 - 38 files changed, 3 insertions(+), 120 deletions(-) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 74eae977..f785746e 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -22,7 +22,6 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| -| **B1** | `foundation/events/overlay/EventTextOverlay.java:40` | **Toujours présent** | `return timer > 0 && false;` — overlay jamais actif. `triggerEvent()` confirmé **jamais appelé** (grep global) → la classe entière est morte, enregistrée et rendue chaque frame pour rien. | | **B7** | `infrastructure/worldgen/biome/CNNoiseData.java` | **Toujours présent** | `bootstrapRegistries()` reste un corps **vide** ; `EROSION` jamais enregistré dans `Registries.NOISE`, alors que `IrradiatedSurfaceRules` (fusion v1/v2, un seul fichier désormais) fait toujours 3× `noiseCondition(EROSION,...)` → `getOrThrow` lèvera à la génération. | --- @@ -192,7 +191,7 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : ## 7. Plan d'action — priorités mises à jour -**Quick wins toujours en attente** (1 ligne, fort impact) : **B1** (one-liner mais classe morte — décider câbler/supprimer), **B9** (mapping amplificateurs ambigu — décision produit), **B7** (enregistrer `EROSION`). +**Quick wins toujours en attente** (1 ligne, fort impact) : **B9** (mapping amplificateurs ambigu — décision produit), **B7** (enregistrer `EROSION`). **Nouveaux quick wins identifiés** : - `RadiationEffectHandler` : ajouter les mêmes gardes (config/immunité/résistance) que les deux autres chemins. diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index f62b640b..c9dafb03 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -393,7 +393,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "uoıʇɐıpɐᴚ ɟo ʍoɹɹⱯ", "itemGroup.createnuclear.main": "ɹɐǝןɔnN ǝʇɐǝɹƆ", "itemgroup.uranium": "dnoɹ⅁ ɯnıuɐɹ∩", - "overlay.event_message": "ɹǝɯıʇ %s ⚠ buıuɹɐM ⚠", "reactor.info.assembled.creator": "pǝןqɯǝssɐ uǝǝq sɐɥ ɹoʇɔɐǝᴚ", "reactor.item.gui.name": "uɹǝʇʇɐԀ bıɟuoƆ", "reactor.update.casing.input": "ʇnduı uı buısɐɔ ǝɥʇ ǝʇɐpd∩", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 6871b417..7d8a25f8 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -393,7 +393,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.item.gui.name": "Config Pattern", "reactor.update.casing.input": "Update the casing in input", diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index 84e413d6..effc40be 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -617,25 +617,8 @@ public class CNBlocks { .build() .register(); - /*public static final BlockEntry TEST_EVENT_TRIGGER_BLOCK = CreateNuclear.REGISTRATE.block("test_event_trigger_block", EventTriggerBlock::new) - .defaultBlockstate() - .defaultLang() - .simpleItem() - .register();*/ - - - - - - - /*public static final BlockEntry TEST_EVENT_TRIGGER_BLOCK = - CreateNuclear.REGISTRATE.block("test_event_trigger_block", EventTriggerBlock::new) - .defaultBlockstate() - .defaultLang() - .simpleItem() - .register();*/ public static void register() { CreateNuclear.LOGGER.info("Registering ModBlocks for " + CreateNuclear.MOD_ID); } -} +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java index 59b54c28..e8913694 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java @@ -1,7 +1,6 @@ package net.nuclearteam.createnuclear.foundation.events; import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; -import net.nuclearteam.createnuclear.foundation.events.overlay.EventTextOverlay; import net.nuclearteam.createnuclear.foundation.events.overlay.HelmetOverlay; import net.nuclearteam.createnuclear.foundation.events.overlay.HudOverlay; @@ -10,9 +9,8 @@ public class HudRenderer { private static final List overlays = List.of( - new HelmetOverlay(), + new HelmetOverlay() //new RadiationOverlay(), - new EventTextOverlay() ); public void onHudRender(RegisterGuiOverlaysEvent event) { diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java deleted file mode 100644 index 4e472983..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EventTextOverlay.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.events.overlay; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.gui.overlay.ForgeGui; -import net.minecraftforge.client.gui.overlay.IGuiOverlay; -import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; - -/** - * HUD overlay for displaying localized text when a specific event occurs. - */ -public class EventTextOverlay implements HudOverlay { - private static int timer = 0; - - /** - * Called via a network packet to activate the overlay for a specific duration. - * @param displayDuration duration in ticks - */ - public static void triggerEvent(int displayDuration) { - timer = displayDuration; - } - - @Override - public ResourceLocation getAfterOverlay() { - return VanillaGuiOverlay.HELMET.id(); - } - - @Override - public String getOverlayId() { - return "event_text_overlay"; - } - - @Override - public boolean isActive() { - return timer > 0 && false; - } - - @Override - public void render(ForgeGui gui, GuiGraphics graphics, float partialTicks, int width, int height) { - if (!isActive()) return; - if (timer-- <= 0) return; - LocalPlayer player = Minecraft.getInstance().player; - if (player == null) return; - Component text = Component.translatable("overlay.event_message", timer).withStyle(ChatFormatting.RED); - int widths = graphics.guiWidth(); - int x = (widths - Minecraft.getInstance().font.width(text)) / 2; - graphics.drawString(Minecraft.getInstance().font, text, x, 10, 0xFFFFFF); - } - - @Override - public int getPriority() { - return 300; // render on top of other overlays - } - - @Override - public IGuiOverlay getOverlay() { - return this::render; - } -} diff --git a/src/main/resources/assets/createnuclear/lang/af_za.json b/src/main/resources/assets/createnuclear/lang/af_za.json index 66d33db1..4a522bb4 100644 --- a/src/main/resources/assets/createnuclear/lang/af_za.json +++ b/src/main/resources/assets/createnuclear/lang/af_za.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/ar_sa.json b/src/main/resources/assets/createnuclear/lang/ar_sa.json index 31e25e54..49b90a10 100644 --- a/src/main/resources/assets/createnuclear/lang/ar_sa.json +++ b/src/main/resources/assets/createnuclear/lang/ar_sa.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "سهم الإشعاع", "itemGroup.createnuclear.main": "الصناعة نووي", "itemgroup.uranium": "مجموعة اليورانيوم", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "تم تركيب المفاعل", "reactor.info.assembled.destroyer": "تم تفكيك المفاعل", "reactor.info.assembled.none": "المفاعل لم يتم تركيبه", diff --git a/src/main/resources/assets/createnuclear/lang/ca_es.json b/src/main/resources/assets/createnuclear/lang/ca_es.json index e79a54d9..6179bf7c 100644 --- a/src/main/resources/assets/createnuclear/lang/ca_es.json +++ b/src/main/resources/assets/createnuclear/lang/ca_es.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/cs_cz.json b/src/main/resources/assets/createnuclear/lang/cs_cz.json index 975ffa87..a8c3ee75 100644 --- a/src/main/resources/assets/createnuclear/lang/cs_cz.json +++ b/src/main/resources/assets/createnuclear/lang/cs_cz.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Šíp ozáření", "itemGroup.createnuclear.main": "Create Nukleární", "itemgroup.uranium": "Skupina Uranu", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reaktor byl sestaven", "reactor.info.assembled.destroyer": "Reaktor byl rozebrán", "reactor.info.assembled.none": "Reaktor není sestaven", diff --git a/src/main/resources/assets/createnuclear/lang/da_dk.json b/src/main/resources/assets/createnuclear/lang/da_dk.json index 5c6a89ab..245279f4 100644 --- a/src/main/resources/assets/createnuclear/lang/da_dk.json +++ b/src/main/resources/assets/createnuclear/lang/da_dk.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Pil af stråling", "itemGroup.createnuclear.main": "Create Atomkraft", "itemgroup.uranium": "Uran gruppe", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reaktoren er blevet monteret", "reactor.info.assembled.destroyer": "Reaktoren er blevet demonteret", "reactor.info.assembled.none": "Reaktoren er ikke monteret", diff --git a/src/main/resources/assets/createnuclear/lang/de_de.json b/src/main/resources/assets/createnuclear/lang/de_de.json index 2d5dae35..aa7eb5bd 100644 --- a/src/main/resources/assets/createnuclear/lang/de_de.json +++ b/src/main/resources/assets/createnuclear/lang/de_de.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Pfeil der Strahlung", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uran Gruppe", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reaktor wurde zusammengebaut", "reactor.info.assembled.destroyer": "Reaktor wurde zerlegt", "reactor.info.assembled.none": "Reaktor ist nicht zusammengebaut", diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index d86cf9c6..18951214 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -69,7 +69,6 @@ "tag.item.trinkets.head.face": "Head Face", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "attribute.name.createnuclear.generic.irradiated_resistance": "Radiation Resistance" } \ No newline at end of file diff --git a/src/main/resources/assets/createnuclear/lang/el_gr.json b/src/main/resources/assets/createnuclear/lang/el_gr.json index e79a54d9..6179bf7c 100644 --- a/src/main/resources/assets/createnuclear/lang/el_gr.json +++ b/src/main/resources/assets/createnuclear/lang/el_gr.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/es_es.json b/src/main/resources/assets/createnuclear/lang/es_es.json index fdf4e9b6..d0bfb125 100644 --- a/src/main/resources/assets/createnuclear/lang/es_es.json +++ b/src/main/resources/assets/createnuclear/lang/es_es.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Flecha de Radiación", "itemGroup.createnuclear.main": "Create: Nuclear", "itemgroup.uranium": "Grupo: Uranio", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "El Reactor ha sido Ensamblado", "reactor.info.assembled.destroyer": "El Reactor ha sido Desensamblado", "reactor.info.assembled.none": "El Reactor no está Ensamblado", diff --git a/src/main/resources/assets/createnuclear/lang/et_EE.json b/src/main/resources/assets/createnuclear/lang/et_EE.json index f55eb36b..a3fa9363 100644 --- a/src/main/resources/assets/createnuclear/lang/et_EE.json +++ b/src/main/resources/assets/createnuclear/lang/et_EE.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/fi_fi.json b/src/main/resources/assets/createnuclear/lang/fi_fi.json index eade5a4a..c2477bdc 100644 --- a/src/main/resources/assets/createnuclear/lang/fi_fi.json +++ b/src/main/resources/assets/createnuclear/lang/fi_fi.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Säteilyn nuoli", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uraani ryhmä", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/fr_fr.json b/src/main/resources/assets/createnuclear/lang/fr_fr.json index 5272affa..e3cced74 100644 --- a/src/main/resources/assets/createnuclear/lang/fr_fr.json +++ b/src/main/resources/assets/createnuclear/lang/fr_fr.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Flèche irradiée", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Groupe d'uranium", - "overlay.event_message": "⚠️ Avertissement ⚠️ Délai %s", "reactor.info.assembled.creator": "Le réacteur a été assemblé", "reactor.info.assembled.destroyer": "Le réacteur a été désassemblé", "reactor.info.assembled.none": "Le réacteur n'est pas assemblé", diff --git a/src/main/resources/assets/createnuclear/lang/he_il.json b/src/main/resources/assets/createnuclear/lang/he_il.json index e79a54d9..6179bf7c 100644 --- a/src/main/resources/assets/createnuclear/lang/he_il.json +++ b/src/main/resources/assets/createnuclear/lang/he_il.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/hu_hu.json b/src/main/resources/assets/createnuclear/lang/hu_hu.json index 4c95ac9c..a7fd4c5e 100644 --- a/src/main/resources/assets/createnuclear/lang/hu_hu.json +++ b/src/main/resources/assets/createnuclear/lang/hu_hu.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Sugárzás Nyila", "itemGroup.createnuclear.main": "Create: Nukleáris", "itemgroup.uranium": "Uránium Csoport", - "overlay.event_message": "⚠ Veszély ⚠ %s időzítő", "reactor.info.assembled.creator": "A reaktor összeállt", "reactor.info.assembled.destroyer": "A reaktor szét lett szedve", "reactor.info.assembled.none": "A reaktor nincs összeállítva", diff --git a/src/main/resources/assets/createnuclear/lang/it_it.json b/src/main/resources/assets/createnuclear/lang/it_it.json index e1f1597e..8cee875b 100644 --- a/src/main/resources/assets/createnuclear/lang/it_it.json +++ b/src/main/resources/assets/createnuclear/lang/it_it.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Il reattore è stato assemblato", "reactor.info.assembled.destroyer": "Il reattore è stato smontato", "reactor.info.assembled.none": "Il reattore non è assemblato", diff --git a/src/main/resources/assets/createnuclear/lang/ja_jp.json b/src/main/resources/assets/createnuclear/lang/ja_jp.json index 057ac2b6..4630fb1e 100644 --- a/src/main/resources/assets/createnuclear/lang/ja_jp.json +++ b/src/main/resources/assets/createnuclear/lang/ja_jp.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/ko_kr.json b/src/main/resources/assets/createnuclear/lang/ko_kr.json index dc49d60b..00ebf35f 100644 --- a/src/main/resources/assets/createnuclear/lang/ko_kr.json +++ b/src/main/resources/assets/createnuclear/lang/ko_kr.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "방사선 물약을 바른 화살", "itemGroup.createnuclear.main": "Create 원자력", "itemgroup.uranium": "우라늄 관련", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "원자로가 조립되었습니다", "reactor.info.assembled.destroyer": "원자로가 해체되었습니다", "reactor.info.assembled.none": "원자로가 조립되지 않았습니다", diff --git a/src/main/resources/assets/createnuclear/lang/lt_LT.json b/src/main/resources/assets/createnuclear/lang/lt_LT.json index 7df3ed84..bbe53804 100644 --- a/src/main/resources/assets/createnuclear/lang/lt_LT.json +++ b/src/main/resources/assets/createnuclear/lang/lt_LT.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/nl_nl.json b/src/main/resources/assets/createnuclear/lang/nl_nl.json index 1870e2d2..226c831b 100644 --- a/src/main/resources/assets/createnuclear/lang/nl_nl.json +++ b/src/main/resources/assets/createnuclear/lang/nl_nl.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nucleair", "itemgroup.uranium": "Uranium Groep", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor is geconstrueerd", "reactor.info.assembled.destroyer": "Reactor is uit elkaar gehaald", "reactor.info.assembled.none": "Reactor is niet geconstrueerd", diff --git a/src/main/resources/assets/createnuclear/lang/no_no.json b/src/main/resources/assets/createnuclear/lang/no_no.json index e79a54d9..6179bf7c 100644 --- a/src/main/resources/assets/createnuclear/lang/no_no.json +++ b/src/main/resources/assets/createnuclear/lang/no_no.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/pl_pl.json b/src/main/resources/assets/createnuclear/lang/pl_pl.json index 0142b8f4..78a26dff 100644 --- a/src/main/resources/assets/createnuclear/lang/pl_pl.json +++ b/src/main/resources/assets/createnuclear/lang/pl_pl.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Strzała radiacji", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Grupa uranu", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reaktor został zmontowany", "reactor.info.assembled.destroyer": "Reaktor został rozmontowany", "reactor.info.assembled.none": "Reaktor nie jest zmontowany", diff --git a/src/main/resources/assets/createnuclear/lang/pt_br.json b/src/main/resources/assets/createnuclear/lang/pt_br.json index 28ba8973..4056a35c 100644 --- a/src/main/resources/assets/createnuclear/lang/pt_br.json +++ b/src/main/resources/assets/createnuclear/lang/pt_br.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Flecha Radioativa", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Grupo do Urânio", - "overlay.event_message": "⚠️ Aviso ⚠️ %s timer", "reactor.info.assembled.creator": "O Reator foi montado", "reactor.info.assembled.destroyer": "O Reator foi desmontado", "reactor.info.assembled.none": "O Reator não está montado", diff --git a/src/main/resources/assets/createnuclear/lang/pt_pt.json b/src/main/resources/assets/createnuclear/lang/pt_pt.json index 64b4b913..ed7761c3 100644 --- a/src/main/resources/assets/createnuclear/lang/pt_pt.json +++ b/src/main/resources/assets/createnuclear/lang/pt_pt.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/ro_ro.json b/src/main/resources/assets/createnuclear/lang/ro_ro.json index cb277446..da2f9c1f 100644 --- a/src/main/resources/assets/createnuclear/lang/ro_ro.json +++ b/src/main/resources/assets/createnuclear/lang/ro_ro.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Săgeată de Radiație ", "itemGroup.createnuclear.main": "Creează Nuclear", "itemgroup.uranium": "Grupa Uraniumului", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactorul a fost asamblat", "reactor.info.assembled.destroyer": "Reactorul a fost dezasamblat", "reactor.info.assembled.none": "Reactorul nu este asamblat", diff --git a/src/main/resources/assets/createnuclear/lang/ru_ru.json b/src/main/resources/assets/createnuclear/lang/ru_ru.json index 04132e44..a5b9e214 100644 --- a/src/main/resources/assets/createnuclear/lang/ru_ru.json +++ b/src/main/resources/assets/createnuclear/lang/ru_ru.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Стрела радиации", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Группа урана", - "overlay.event_message": "⚠ Предупреждение ⚠ %s таймер", "reactor.info.assembled.creator": "Реактор собран", "reactor.info.assembled.destroyer": "Реактор разобран", "reactor.info.assembled.none": "Реактор не собран", diff --git a/src/main/resources/assets/createnuclear/lang/sr_sp.json b/src/main/resources/assets/createnuclear/lang/sr_sp.json index e79a54d9..6179bf7c 100644 --- a/src/main/resources/assets/createnuclear/lang/sr_sp.json +++ b/src/main/resources/assets/createnuclear/lang/sr_sp.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", diff --git a/src/main/resources/assets/createnuclear/lang/sv_se.json b/src/main/resources/assets/createnuclear/lang/sv_se.json index a483c792..a047a500 100644 --- a/src/main/resources/assets/createnuclear/lang/sv_se.json +++ b/src/main/resources/assets/createnuclear/lang/sv_se.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Strålningspil", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uran grupp", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reaktorn har satts ihop", "reactor.info.assembled.destroyer": "Reaktorn har tagits isär", "reactor.info.assembled.none": "Reaktorn är inte ihopsatt", diff --git a/src/main/resources/assets/createnuclear/lang/tr_tr.json b/src/main/resources/assets/createnuclear/lang/tr_tr.json index d1dc5bf7..d0bda529 100644 --- a/src/main/resources/assets/createnuclear/lang/tr_tr.json +++ b/src/main/resources/assets/createnuclear/lang/tr_tr.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Radyasyon Oku", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranyum Grubu", - "overlay.event_message": "⚠ Uyarı ⚠ %s zamanlayıcı", "reactor.info.assembled.creator": "Reaktör Kuruldu", "reactor.info.assembled.destroyer": "Reaktör Söküldü", "reactor.info.assembled.none": "Reaktör Bir Arada Değil", diff --git a/src/main/resources/assets/createnuclear/lang/uk_ua.json b/src/main/resources/assets/createnuclear/lang/uk_ua.json index 4798ccc5..46f23641 100644 --- a/src/main/resources/assets/createnuclear/lang/uk_ua.json +++ b/src/main/resources/assets/createnuclear/lang/uk_ua.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Стріла радіації", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Група: уран", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Реактор зібрано", "reactor.info.assembled.destroyer": "Реактор розібрано", "reactor.info.assembled.none": "Реактор не зібрано", diff --git a/src/main/resources/assets/createnuclear/lang/vi_vn.json b/src/main/resources/assets/createnuclear/lang/vi_vn.json index 1dcf07e9..45800d30 100644 --- a/src/main/resources/assets/createnuclear/lang/vi_vn.json +++ b/src/main/resources/assets/createnuclear/lang/vi_vn.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Mũi tên phóng xạ", "itemGroup.createnuclear.main": "Tạo ra hạt nhân", "itemgroup.uranium": "Nhóm Uranium", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Lò phản ứng đã được lắp vào", "reactor.info.assembled.destroyer": "Lò phản ứng đã bị tháo ra", "reactor.info.assembled.none": "Lò phản ứng không được lắp ráp", diff --git a/src/main/resources/assets/createnuclear/lang/zh_cn.json b/src/main/resources/assets/createnuclear/lang/zh_cn.json index 79a234fc..cd3baeb0 100644 --- a/src/main/resources/assets/createnuclear/lang/zh_cn.json +++ b/src/main/resources/assets/createnuclear/lang/zh_cn.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "辐射之箭", "itemGroup.createnuclear.main": "机械动力:原子核动", "itemgroup.uranium": "铀类", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "反应堆已组装完成", "reactor.info.assembled.destroyer": "反应堆被破坏", "reactor.info.assembled.none": "反应堆未完成组装", diff --git a/src/main/resources/assets/createnuclear/lang/zh_tw.json b/src/main/resources/assets/createnuclear/lang/zh_tw.json index c80f88ad..da023f47 100644 --- a/src/main/resources/assets/createnuclear/lang/zh_tw.json +++ b/src/main/resources/assets/createnuclear/lang/zh_tw.json @@ -248,7 +248,6 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", - "overlay.event_message": "⚠ Warning ⚠ %s timer", "reactor.info.assembled.creator": "Reactor has been assembled", "reactor.info.assembled.destroyer": "Reactor has been disassembled", "reactor.info.assembled.none": "Reactor is not assembled", From 8f54e817968774010a70689caec2c00d54777b27 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:50:24 +0200 Subject: [PATCH 024/171] refactor: update erosion noise parameters and clean up audit documentation --- AUDIT_ACTUEL.md | 6 ++---- .../.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +++--- .../.cache/fed443662143001aeb5341375f6f5ef31d10baea | 3 ++- .../worldgen/noise/irradiated/erosion.json | 10 ++++++++++ .../infrastructure/worldgen/biome/CNNoiseData.java | 1 + 5 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 src/generated/resources/data/createnuclear/worldgen/noise/irradiated/erosion.json diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f785746e..38f650c9 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -20,9 +20,7 @@ La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, e ## 1. 🐛 Bugs critiques toujours présents -| Réf. | Fichier:ligne | État | Détail | -|---|---|---|---| -| **B7** | `infrastructure/worldgen/biome/CNNoiseData.java` | **Toujours présent** | `bootstrapRegistries()` reste un corps **vide** ; `EROSION` jamais enregistré dans `Registries.NOISE`, alors que `IrradiatedSurfaceRules` (fusion v1/v2, un seul fichier désormais) fait toujours 3× `noiseCondition(EROSION,...)` → `getOrThrow` lèvera à la génération. | +_Aucun. Tous les bugs critiques recensés ont été corrigés._ --- @@ -191,7 +189,7 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : ## 7. Plan d'action — priorités mises à jour -**Quick wins toujours en attente** (1 ligne, fort impact) : **B9** (mapping amplificateurs ambigu — décision produit), **B7** (enregistrer `EROSION`). +**Quick wins toujours en attente** (1 ligne, fort impact) : **B9** (mapping amplificateurs ambigu — décision produit). **Nouveaux quick wins identifiés** : - `RadiationEffectHandler` : ajouter les mêmes gardes (config/immunité/résistance) que les deux autres chemins. diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index d11d9c76..152c7ea4 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-15T19:58:10.7629453 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-17T10:47:26.0706313 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -2c770a8dcc9ee3230438ed747dc620d7151aa905 assets/createnuclear/lang/en_ud.json -cd6f2a9b30e89b3a324465db7a5798b5f6e5ce5f assets/createnuclear/lang/en_us.json +09d7766192ec6b91812349893c10a9ba361a50a2 assets/createnuclear/lang/en_ud.json +8258526781f4fea54a37f83f59c63b522d40a982 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index fa3b28d2..57ffc677 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-12T10:26:06.6444647 CreateNuclear Generated Registry Entries +// 1.20.1 2026-06-17T10:47:26.0685347 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -18,6 +18,7 @@ c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_ b0e1ee7314412507fd7346cb48b29d105f6186ad data/createnuclear/worldgen/configured_feature/uranium_ore.json 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/erosion.json 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/final_density.json +7f5f110a211b82bc22627b2f901c5f3c6a1265dd data/createnuclear/worldgen/noise/irradiated/erosion.json 98ef3576a3760c63b2667d4b648bb67ff37f3bd2 data/createnuclear/worldgen/noise_settings/irradiated_noise.json 055203794153b01a2ebc956d13b7900e5d3851ca data/createnuclear/worldgen/placed_feature/lead_ore.json e69f61cbb4bf2c50a6123ddc87c024c801bb78d1 data/createnuclear/worldgen/placed_feature/nitrate_ore.json diff --git a/src/generated/resources/data/createnuclear/worldgen/noise/irradiated/erosion.json b/src/generated/resources/data/createnuclear/worldgen/noise/irradiated/erosion.json new file mode 100644 index 00000000..5cb78233 --- /dev/null +++ b/src/generated/resources/data/createnuclear/worldgen/noise/irradiated/erosion.json @@ -0,0 +1,10 @@ +{ + "amplitudes": [ + 1.0, + 1.0, + 0.0, + 1.0, + 1.0 + ], + "firstOctave": -9 +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java index 98ccde60..77590882 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNNoiseData.java @@ -14,6 +14,7 @@ private static ResourceKey createKey(String id) { } public static void bootstrapRegistries(BootstapContext context) { + register(context, EROSION, -9, 1.0, 1.0, 0.0, 1.0, 1.0); } private static void register( From e111aed895e721c0c9c8585da42265d92d3cecea Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:56:35 +0200 Subject: [PATCH 025/171] refactor: update AUDIT_ACTUEL.md to reflect current bug status and ongoing refactor progress --- AUDIT_ACTUEL.md | 56 +++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 38f650c9..814baeb3 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -2,29 +2,17 @@ **Méthodologie** : 7 audits indépendants couvrant la totalité de `src/main/java` (hors `src/generated` et `src/main/resources`), réalisés à partir de l'état actuel du code uniquement, puis recoupés avec `AUDIT_V1.md` et vérifiés par greps ciblés. ---- - -## 0. Constat global - -Le code est toujours en **refactor V2 actif** (cohérent avec les commits récents : extraction `ReactorInputSnapshotBuilder`, `ReactorGoggleTooltipRenderer`, `ReactorDisplayState`). Quelques nettoyages annoncés par `AUDIT_V1.md` ont bien eu lieu : - -- ✅ `lib.multiblock.manager.*` (`MultiBlockManager`, `MultiBlockCache`, `RegisteredMultiBlockPattern`) + `IBetterPattern` + `SimpleMultiBlockPatternBuilder` (non-aisle) **ont disparu** du dépôt. -- ✅ `ReactorAlarmEntity.tick()` distingue maintenant proprement `tickAudio()` (client) / `tickServer()` (serveur) — **corrigé**. -- ✅ `B11` (LOGGER avant null-check dans `SimpleMultiBlockAislePatternBuilder`) — **corrigé**, le message d'erreur utilise désormais un ternaire sûr. -- ✅ La feature radiation a été regroupée sous `content/radiation/**` (capability/client) — déplacement, pas (encore) une consolidation des deux contrats (`IRadiationSource` vs `RadiationRegistry`, toujours dupliqués). -- ⚠️ `B2` (RadiationSyncPacket no-op) est **obsolète** : `RadiationSyncPacket`/`ClientRadiationData` n'existent plus du tout — le mécanisme décrit a disparu (probablement remplacé par la capability resync via `RadiationCapability`/`InventoryHashUtil`, qui elle fonctionne). - -La **grande majorité des bugs** de `AUDIT_V1.md` sont **toujours présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). Le dead code a été en grande partie nettoyé ; il ne reste qu'un résidu non trivial (voir §3). +> Ce document ne liste plus que **ce qui reste à corriger**. Les bugs déjà résolus en sont retirés. --- -## 1. 🐛 Bugs critiques toujours présents +## 0. Constat global -_Aucun. Tous les bugs critiques recensés ont été corrigés._ +Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapshotBuilder`, `ReactorGoggleTooltipRenderer`, `ReactorDisplayState`). La **grande majorité des bugs** de `AUDIT_V1.md` restent **présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). Le dead code a été en grande partie nettoyé ; il reste un résidu non trivial (voir §2). --- -## 2. 🐛 Bugs importants toujours présents +## 1. 🐛 Bugs importants toujours présents | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| @@ -42,28 +30,28 @@ _Aucun. Tous les bugs critiques recensés ont été corrigés._ - `ReactorInputFluidManager.extractFluids/getBlocksPosition` : toujours `getFluidInTank(getTanks())` (off-by-one), `fluidNeeded` jamais décrémenté, `toExtract>1` ignore les extractions de 1 unité. - `ReactorInput.use()` : retourne toujours `PASS` côté serveur après `NetworkHooks.openScreen`, vs `SUCCESS` côté client → désync. - `InventoryHashUtil` : toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité. -- `ReactorSizeDisplaySource` : toujours `tier*100/3` comme "%" — désormais creusé en détail (voir §4, nouveau finding lié). +- `ReactorSizeDisplaySource` : toujours `tier*100/3` comme "%" — désormais creusé en détail (voir §3, nouveau finding lié). - `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` toujours recalculé dans la boucle interne pour une valeur invariante. - `ReactorOutput.use()` : toujours `Objects.requireNonNull(...)` + `assert entity != null` (no-op en prod) au lieu d'une garde gracieuse. --- -## 3. 🧹 Dead code — reste à faire +## 2. 🧹 Dead code — reste à faire -> **⚠️ Corrections de l'audit V1/V2** (ne pas supprimer ces éléments — code vivant) : +> **⚠️ Ne pas supprimer ces éléments — code vivant** (faux positifs écartés) : > - `CNTabulaModelRenderUtils` **n'est PAS du dead code** : il est utilisé par `CNAdvancedModelBox.cubeList`/`doRender`, sur le chemin de rendu **vivant** du champignon atomique (`NuclearMushroomCloudModel`). Conservé. La duplication `ModelBox` reste une opportunité de *refactor*, pas une suppression. > - `ReactorOutputEntity.outputPos` **n'est PAS mort** : il est lu/écrit dans `read()`/`write()` (sérialisation NBT). Laissé en place. Restant (grep global, zéro référence externe sauf mention) : - **Méthodes d'animation mortes restantes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` : `chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `setRotateAngle`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`/`movementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`. Mortes mais **non triviales** : leur retrait déclenche une cascade dans des classes **vivantes** (ex. `CNAdvancedModelBox.calculateRotation`/`bob` appellent `model.getMovementScale()`). À traiter en nettoyage dédié + dédup `ModelBox`. -- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §4 points 5 & 6 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). +- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §3 points 5 & 6 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). - **`SimpleMultiBlockPattern.test()`** : à vérifier — la classe ne semble plus exister (à confirmer/retirer si résidu). -- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §4 point 10, worldgen "irradié" template non terminé). +- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §3 point 10, worldgen "irradié" template non terminé). --- -## 4. 🆕 Nouveaux problèmes / régressions apparus depuis l'audit +## 3. 🆕 Nouveaux problèmes / régressions apparus depuis l'audit Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — ils résultent soit de zones non couvertes par l'audit précédent (cat/wolf/cow, displaySources détaillés), soit de refactors V2 en cours. @@ -85,7 +73,7 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — 4. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes — mais selon deux sémantiques *différentes*, à ne pas fusionner : - - `RadiationEffect` (filtre de contagion de proximité, constructeur lignes 32-52) applique un **gate binaire** (immune tag, config, blacklist, spectateur, `résistance ≥ 1`) — mais ce gate est enfermé dans un lambda non réutilisable, et **reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque appel** (cf. §5 point 5 / §6) — perf non corrigée en plus du problème de duplication. + - `RadiationEffect` (filtre de contagion de proximité, constructeur lignes 32-52) applique un **gate binaire** (immune tag, config, blacklist, spectateur, `résistance ≥ 1`) — mais ce gate est enfermé dans un lambda non réutilisable, et **reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque appel** (cf. §4 point 5 / §5) — perf non corrigée en plus du problème de duplication. - `RadiationCapability.applyEffects` applique une **atténuation continue de dose** (`totalRadiation = totalRaw * (1 - resistance)`), pas un gate — cette logique est correcte et ne doit *pas* être déplacée dans un helper commun, elle reste propre à ce chemin (calcul de magnitude, pas d'éligibilité). *Conséquence* : une fuite de fluide irradiant un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. @@ -139,8 +127,8 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — ### 🟠 Importants -7. **`RadiationCapability.lastBiomeLocation` — non persisté (correction : PAS du dead code)** - ⚠️ Correction de l'audit : contrairement à ce qui était écrit, `lastBiomeLocation` **est bien lu pour une décision** (`RadiationCapability:89`, comparaison `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`). Ce n'est donc **pas** du dead code et il n'a pas été supprimé. Le seul point restant : `RadiationProvider.serializeNBT` ne le persiste pas → l'état est perdu au save/déconnexion (bug mineur, à corriger ou assumer). +7. **`RadiationCapability.lastBiomeLocation` — non persisté** + `lastBiomeLocation` **est bien lu pour une décision** (`RadiationCapability:89`, comparaison `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`) — ce n'est donc **pas** du dead code. Le point restant : `RadiationProvider.serializeNBT` ne le persiste pas → l'état est perdu au save/déconnexion (bug mineur, à corriger ou assumer). 8. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT_V1.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. @@ -149,9 +137,9 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. 10. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** - `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné aux bugs B7/B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). + `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné au bug B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). -11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B7/B19), point d'alerte non couvert par `AUDIT_V1.md`. +11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B19), point d'alerte non couvert par `AUDIT_V1.md`. ### 🟡 Mineurs @@ -162,19 +150,19 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — --- -## 5. 🏗️ Architecture — état actuel (synthèse) +## 4. 🏗️ Architecture — état actuel (synthèse) Les 5 problèmes structurels de `AUDIT_V1.md` §1 restent **tous valides** : 1. **Inversion `api/`** : `api.multiblock.MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` dépendent toujours de `content.*` — confirmé. 2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, verrous fluides (`tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty`, ~65 lignes), rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT_V1.md`. 3. **Deux frameworks multiblock concurrents** : le ménage a réduit `lib/multiblock` (suppression de `MultiBlockManager`/`MultiBlockCache`/`IBetterPattern`), mais **trois couches coexistent toujours** pour la détection de contrôleur — `lib/multiblock` (matching générique), `api.multiblock.MultiBlockManagerBeta` (vérification de structure), et `content.multiblock.pattern.ReactorPattern`/`MultiblockHelpers` (scan géométrique brut, ~3971 blocs, **toujours** appelé en double — `findController` + `findControllerPos` — à chaque pose/casse, y compris côté client sans garde `isClientSide`). C'est le point de performance/architecture le plus critique et **entièrement non corrigé**. -4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (point 4 ci-dessus) découvert dans cette analyse. -5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, AUDIT §4 ligne 2). +4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (§3 point 4) découvert dans cette analyse. +5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, `AUDIT_V1.md` §4 ligne 2). --- -## 6. ⚡ Performance — état actuel +## 5. ⚡ Performance — état actuel Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : - `ReactorPattern.findController`/`findControllerPos` : scan ~3971 blocs ×2 par placement/casse, sans garde client — confirmé, **aggravé** par `MultiBlockManagerBeta.findStructure` qui peut ajouter jusqu'à 4×3×729 lookups supplémentaires. @@ -187,7 +175,7 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : --- -## 7. Plan d'action — priorités mises à jour +## 6. Plan d'action — priorités mises à jour **Quick wins toujours en attente** (1 ligne, fort impact) : **B9** (mapping amplificateurs ambigu — décision produit). @@ -196,10 +184,10 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : - Enregistrer `IrradiatedCatCollarLayer` / implémenter `IrradiatedWoldCollarLayer.render`, ou retirer la mécanique de teinture de collier. - Retirer `RenderHelper.renderTextureOverlay(..., Math.round(...))` → passer `alpha*coverage` brut (si `RadiationOverlay` est un jour réactivé). -**Priorité structurelle inchangée** : le scan géométrique `ReactorPattern`/`MultiblockHelpers` (point architecture #3) reste le risque de performance serveur le plus sérieux et n'a reçu **aucune** correction — c'est le chantier le plus rentable avant de poursuivre la décomposition de `ReactorControllerBlockEntity`. +**Priorité structurelle inchangée** : le scan géométrique `ReactorPattern`/`MultiblockHelpers` (point architecture §4.3) reste le risque de performance serveur le plus sérieux et n'a reçu **aucune** correction — c'est le chantier le plus rentable avant de poursuivre la décomposition de `ReactorControllerBlockEntity`. **Nettoyage dead-code restant** : - Méthodes d'animation mortes restantes dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` + dédup `ModelBox` (cascade dans classes vivantes — nettoyage dédié). -- `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §4 points 5 & 6). +- `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §3 points 5 & 6). - `IrradiatedBiomes.monsters()` no-op et reliquat éventuel `SimpleMultiBlockPattern.test()`. - Features à finir ou supprimer (pas du pur dead code, décision produit) : `IrradiatedWoldCollarLayer`/`IrradiatedCatCollarLayer`, `AntiRadiationArmorItem.getArmorTexture`/`ClothTagHelper.getArmorTexturePath`. From bc0fa67ad30dbcac2ac4beee4b3d4f73eab6056f Mon Sep 17 00:00:00 2001 From: Dimitri Date: Wed, 17 Jun 2026 11:21:26 +0200 Subject: [PATCH 026/171] fixing vicinity effect and resolving potential optimisation issue for the vicinity effect --- .../content/effects/VicinityEffect.java | 67 ++++++------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java index 7d90d081..1ec4cac0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java @@ -17,7 +17,8 @@ public class VicinityEffect extends MobEffect { private final Predicate filter; private final Supplier[] effects; - private final Map cooldowns = new HashMap<>(); + // Stores the GameTime tick when the cooldown expires for each entity + private final Map cooldowns = new HashMap<>(); @SafeVarargs protected VicinityEffect(MobEffectCategory category, int color, UnaryOperator areaSize, Predicate filter, Consumer timer, Supplier... effects) { @@ -30,63 +31,33 @@ protected VicinityEffect(MobEffectCategory category, int color, UnaryOperator nearbyEntities = entity.level().getEntities(entity, entity.getBoundingBox().inflate(areaSize.apply(amplifier)), e -> e instanceof LivingEntity target && filter.test(target)); + long currentTime = entity.level().getGameTime(); + + List nearbyEntities = entity.level().getEntities( + entity, + entity.getBoundingBox().inflate(areaSize.apply(amplifier)), + e -> e instanceof LivingEntity target && filter.test(target) + ); for (Entity nearbyEntity : nearbyEntities) { LivingEntity nearby = (LivingEntity) nearbyEntity; + UUID entityUuid = nearby.getUUID(); + + // Check if the cooldown has expired + if (currentTime >= cooldowns.getOrDefault(entityUuid, 0L)) { - for (Supplier effect : effects) { - int cooldownTicks = 0; - if (cooldownTicks == 0) { - nearby.addEffect(effect.get()); - cooldownTicks = 500; - } else { - cooldownTicks--; - //CreateNuclear.LOGGER.warn("Test Duree: {}, entity: {}", cooldownTicks, nearby.getUUID()); + for (Supplier effect : effects) { + nearby.addEffect(effect.get()); } + + // Set a 100-tick (5 seconds) cooldown before refreshing the effect again + cooldowns.put(entityUuid, currentTime + 100); } } } - private int getCooldown(LivingEntity entity) { - return cooldowns.getOrDefault(entity.getUUID(), 0); - } - - private void setCooldown(LivingEntity entity, int ticks) { - cooldowns.put(entity.getUUID(), ticks); - } - @Override public boolean isDurationEffectTick(int duration, int amplifier) { return duration % 5 == 0; } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} \ No newline at end of file From 91cd24e04e2b334718fa176e3f84607af16f5717 Mon Sep 17 00:00:00 2001 From: Dimitri Date: Wed, 17 Jun 2026 11:31:43 +0200 Subject: [PATCH 027/171] fixing the translatable text of empty rod when lookig at the controller with goggles --- AUDIT_ACTUEL.md | 1 - .../controller/display/ReactorGoggleTooltipRenderer.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 814baeb3..d54d6f51 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -16,7 +16,6 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| -| **B3** | `content/effects/VicinityEffect.java:32-49` | **Toujours présent, identique** | `int cooldownTicks = 0;` réinitialisé à chaque itération → branche `else` morte, `cooldowns`/`getCooldown`/`setCooldown` toujours jamais appelés (confirmé grep). `RadiationEffect` continue donc à `addEffect` un `MobEffectInstance(RADIATION,300)` toutes les 5 ticks sur chaque entité proche, sans throttling réel. | | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | | **B9** | `content/radiation/capability/RadiationCapability.java` (`applyEffects`) | **Toujours présent, identique** | Les deux premières branches (`radiation < level1`, `radiation < level2`) donnent toutes deux `amplifierLevel0` → `radiationLevel2` reste un palier inopérant. | | **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java index f1dc0c08..3a667d85 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java @@ -82,7 +82,7 @@ private static void renderHeaderAndHeat(List tooltip, int heat) { private static void renderItemRods(List tooltip, ReactorDisplayState state) { if (state.items().isEmpty()) { CreateNuclearLang.builder() - .add(Component.translatable("tooltip.item.empty.rod").withStyle(ChatFormatting.GRAY)) + .add(Component.translatable("createnuclear.tooltip.item.empty.rod").withStyle(ChatFormatting.GRAY)) .add(CreateNuclearLang.number(0).style(ChatFormatting.GOLD)) .forGoggles(tooltip); } else { From d69cd6b5f30cad2339470b3ed0ffd1eb88cb658e Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Wed, 17 Jun 2026 11:34:57 +0200 Subject: [PATCH 028/171] added reactor size max value in config --- .../content/multiblock/IHeat.java | 33 ++++++++++++++----- .../controller/ReactorControllerBlock.java | 2 +- .../ReactorControllerBlockEntity.java | 6 ++-- .../displayLink/source/HeatDisplaySource.java | 6 ++-- .../source/ReactorSummaryDisplaySource.java | 2 +- .../infrastructure/config/CNCServer.java | 2 ++ .../infrastructure/config/CRadiation.java | 2 -- .../infrastructure/config/CReactorHeat.java | 14 ++++++++ 8 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java index 09add3c4..16b6435c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java @@ -14,6 +14,8 @@ import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; +import net.nuclearteam.createnuclear.infrastructure.config.CReactorHeat; public interface IHeat extends IWrenchable { enum HeatLevel { @@ -57,25 +59,38 @@ public int getHeatValue() { }; } - public static HeatLevel of(int heat) { + public static HeatLevel of(int heat, int reactorSize) { if (heat < 0) return NONE; heat = Math.abs(heat); - if (heat > 0 && heat < 500) return SAFETY; - if (heat >= 501 && heat <= 800) return CAUTION; - if (heat >= 801 && heat <= 1000) return WARNING; - if (heat >= 1001) return DANGER; + CReactorHeat config = CNConfigs.server().reactorHeat; + int danger = 1000; + + switch (reactorSize) { + case 5 -> danger = config.size5Danger.get(); + case 7 -> danger = config.size7Danger.get(); + case 9 -> danger = config.size9Danger.get(); + default -> danger = config.size5Danger.get(); + } + + int caution = (int) (danger * 0.75); + int warning = (int) (danger * 0.90); + + if (heat > 0 && heat < caution) return SAFETY; + if (heat >= caution && heat < warning) return CAUTION; + if (heat >= warning && heat <= danger) return WARNING; + if (heat > danger) return DANGER; return NONE; } - public static boolean isNotDanger(int heat) { - return of(heat) != DANGER || of(heat) != NONE; + public static boolean isNotDanger(int heat, int reactorSize) { + return of(heat, reactorSize) != DANGER || of(heat, reactorSize) != NONE; } - public static LangBuilder getFormattedHeatText(int heat) { - HeatLevel heatLevel = of(heat); + public static LangBuilder getFormattedHeatText(int heat, int reactorSize) { + HeatLevel heatLevel = of(heat, reactorSize); LangBuilder builder = CreateLang.builder(CreateNuclear.MOD_ID).text(TooltipHelper.makeProgressBar(5, heatLevel.ordinal()+1)); builder.translate("tooltip.heatLevel." + Lang.asId(heatLevel.name())) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index dc0091f6..c4cf474b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -110,7 +110,7 @@ public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Play } else if (heldItem.isEmpty() && !controllerBlockEntity.getInventoryObject().getItem(0).isEmpty()) { withBlockEntityDo(worldIn, pos, be -> { - if (IHeat.HeatLevel.of(be.getInventoryObject().getItem(0).getOrCreateTag().getInt("heat")) == IHeat.HeatLevel.DANGER) { + if (IHeat.HeatLevel.of(be.getInventoryObject().getItem(0).getOrCreateTag().getInt("heat"), be.getMultiblockSize()) == IHeat.HeatLevel.DANGER) { be.getAdvancement().setPlayer(player.getUUID()); be.getAdvancement().awardPlayer(CNAdvancement.NO_TIME_TO_DIE); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index fbd75dde..85c28f70 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -346,7 +346,7 @@ public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneak .forGoggles(tooltip); IHeat.HeatLevel.getName("reactor_controller").style(ChatFormatting.GRAY).forGoggles(tooltip); - IHeat.HeatLevel.getFormattedHeatText(patternTag.getInt("heat")).forGoggles(tooltip); + IHeat.HeatLevel.getFormattedHeatText(patternTag.getInt("heat"), this.getMultiblockSize()).forGoggles(tooltip); if (clientDisplayItems.isEmpty()) { CreateNuclearLang.builder() @@ -560,7 +560,7 @@ public void tick() { if (level.isClientSide || isExploding) return; int currentHeat = (int) configuredPattern.getOrCreateTag().getDouble("heat"); - boolean isDanger = IHeat.HeatLevel.of(currentHeat) == IHeat.HeatLevel.DANGER; + boolean isDanger = IHeat.HeatLevel.of(currentHeat, this.getMultiblockSize()) == IHeat.HeatLevel.DANGER; activateAlarms(isDanger); @@ -729,7 +729,7 @@ private void handleAssembledState() { } cycleManager.tick(inputManager, level); } - if (IHeat.HeatLevel.isNotDanger(heat)) { + if (IHeat.HeatLevel.isNotDanger(heat, this.getMultiblockSize())) { // normal if (!this.outputManager.getBlocksPosition().isEmpty()) { rotate(getBlockState(), getLevel(), heat); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java index bf704903..aeb6c1f2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java @@ -30,17 +30,17 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget return label.append(switch (mode) { case 1 -> Component.literal((heat * 100 / maxHeat) + "%") - .withStyle(IHeat.HeatLevel.of(heat).getTextColor()); + .withStyle(IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor()); case 2 -> { // Largeur réduite pour laisser de la place au label int gaugeWidth = 6; - yield drawGauge(heat, maxHeat, IHeat.HeatLevel.of(heat).getTextColor(), gaugeWidth); + yield drawGauge(heat, maxHeat, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth); } default -> Component.literal(String.valueOf(heat)) .append(CreateNuclearLang.translateDirect("generic.unit.heat.value")) - .withStyle(IHeat.HeatLevel.of(heat).getTextColor()); + .withStyle(IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor()); }); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index f11f3112..fba8e1da 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -147,7 +147,7 @@ private Stream> getComponents(DisplayLinkContext context, List.of(lFuel, formatValue(fuel, 64, mode, false, ChatFormatting.GREEN, gaugeWidth)), List.of(lCooler, formatValue(cooler, 64, mode, false, ChatFormatting.AQUA, gaugeWidth)), List.of(lFluid, formatFluid(fluid, 16000, mode, ChatFormatting.BLUE, gaugeWidth)), - List.of(lHeat, formatValue(heat, 1000, mode, true, IHeat.HeatLevel.of(heat).getTextColor(), gaugeWidth)) + List.of(lHeat, formatValue(heat, 1000, mode, true, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth)) ); } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java index 36bfbebd..a42c671b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java @@ -7,6 +7,7 @@ public class CNCServer extends ConfigBase { // public final CExplode explode = nested(0, CExplode::new, Comments.explode); public final CNotify notify = nested(0, CNotify::new,Comments.ratio); public final CRadiation radiation = nested(0, CRadiation::new, Comments.radiation); + public final CReactorHeat reactorHeat = nested(0, CReactorHeat::new, Comments.reactorHeat); @Override public String getName() { return "Server"; @@ -17,5 +18,6 @@ private static class Comments { static String explode = "[WIP] Modify the parameters of the explosion"; static String radiation = "Enable or disable radiation effects emitted by mod items. "; static String ratio = "Ratio"; + static String reactorHeat = "Heat thresholds for different reactor sizes"; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRadiation.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRadiation.java index 6ce22d81..bd252ad4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRadiation.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRadiation.java @@ -73,8 +73,6 @@ public void registerAll(ForgeConfigSpec.Builder builder) { ), obj -> obj instanceof String ); - - builder.pop(); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java new file mode 100644 index 00000000..47c935e9 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java @@ -0,0 +1,14 @@ +package net.nuclearteam.createnuclear.infrastructure.config; + +import net.createmod.catnip.config.ConfigBase; + +public class CReactorHeat extends ConfigBase { + public final ConfigInt size5Danger = i(256, 0, 1000, "size5Danger", "Heat threshold for DANGER level (5x5 reactor)"); + public final ConfigInt size7Danger = i(1024, 0, 1000, "size7Danger", "Heat threshold for DANGER level (7x7 reactor)"); + public final ConfigInt size9Danger = i(4096, 0, 1000, "size9Danger", "Heat threshold for DANGER level (9x9 reactor)"); + + @Override + public String getName() { + return "ReactorHeat"; + } +} From 25b85bc0664244c54f6b772db748cb54a164a061 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Wed, 17 Jun 2026 13:34:00 +0200 Subject: [PATCH 029/171] max value in config changed --- .../createnuclear/infrastructure/config/CReactorHeat.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java index 47c935e9..8c070b76 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CReactorHeat.java @@ -3,9 +3,9 @@ import net.createmod.catnip.config.ConfigBase; public class CReactorHeat extends ConfigBase { - public final ConfigInt size5Danger = i(256, 0, 1000, "size5Danger", "Heat threshold for DANGER level (5x5 reactor)"); - public final ConfigInt size7Danger = i(1024, 0, 1000, "size7Danger", "Heat threshold for DANGER level (7x7 reactor)"); - public final ConfigInt size9Danger = i(4096, 0, 1000, "size9Danger", "Heat threshold for DANGER level (9x9 reactor)"); + public final ConfigInt size5Danger = i(256, 0, 8192, "size5Danger", "Heat threshold for DANGER level (5x5 reactor)"); + public final ConfigInt size7Danger = i(1024, 0, 8192, "size7Danger", "Heat threshold for DANGER level (7x7 reactor)"); + public final ConfigInt size9Danger = i(4096, 0, 8192, "size9Danger", "Heat threshold for DANGER level (9x9 reactor)"); @Override public String getName() { From 812cd86bc197703860a259899d5ed2056e43511d Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Wed, 17 Jun 2026 13:35:06 +0200 Subject: [PATCH 030/171] new rpm system to match new su values --- src/main/java/net/nuclearteam/createnuclear/CNBlocks.java | 2 +- .../controller/ReactorControllerBlockEntity.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index d0b345d7..dc5a1b73 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -188,7 +188,7 @@ public class CNBlocks { .tag(AllTags.AllBlockTags.SAFE_NBT.tag, BlockTags.NEEDS_DIAMOND_TOOL) .transform(pickaxeOnly()) .blockstate(new ReactorOutputGenerator()::generate) - .onRegister(block -> BlockStressValues.CAPACITIES.register(block, () -> 10240.0)) + .onRegister(block -> BlockStressValues.CAPACITIES.register(block, () -> 64000.0)) .item() .transform(customItemModel("reactor", "output", "item")) .register(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 85c28f70..14d50c5f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -919,9 +919,13 @@ private BlockPos getBlockPosForReactor(char character) { public void rotate(BlockState state, Level level, int rotation) { if (this.outputManager.getBlocksPosition().isEmpty()) return; - int remainingRotation = rotation % this.outputManager.getBlocksPosition().size(); + + int RPMDivider = 32; + int totalRpm = rotation / RPMDivider; + + int remainingRotation = totalRpm % this.outputManager.getBlocksPosition().size(); for (int i = 0; i < this.outputManager.getBlocksPosition().size(); i++) { - int dividedRotation = (rotation / this.outputManager.getBlocksPosition().size()) + int dividedRotation = (totalRpm / this.outputManager.getBlocksPosition().size()) + (i < remainingRotation ? 1 : 0); BlockPos pos = this.outputManager.getBlocksPosition().get(i); From bd874293eecaa0057f2f5eb890f97c63c0fc39c0 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Wed, 17 Jun 2026 13:50:55 +0200 Subject: [PATCH 031/171] merge impact solved --- .../controller/ReactorControllerBlockEntity.java | 2 +- .../controller/display/ReactorGoggleTooltipRenderer.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 31f7f9f8..3006b974 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -256,7 +256,7 @@ public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneak return false; } - ReactorGoggleTooltipRenderer.render(tooltip, displayState, patternTag.getInt("heat"), isPlayerSneaking); + ReactorGoggleTooltipRenderer.render(tooltip, displayState, patternTag.getInt("heat"), isPlayerSneaking, reactorSize); return true; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java index 3a667d85..20bca73b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorGoggleTooltipRenderer.java @@ -51,8 +51,8 @@ private ReactorGoggleTooltipRenderer() {} * @param isPlayerSneaking whether the viewing player is sneaking (currently unused, * kept for signature parity with other goggle tooltip providers) */ - public static void render(List tooltip, ReactorDisplayState state, int heat, boolean isPlayerSneaking) { - renderHeaderAndHeat(tooltip, heat); + public static void render(List tooltip, ReactorDisplayState state, int heat, boolean isPlayerSneaking, int reactorSize) { + renderHeaderAndHeat(tooltip, heat, reactorSize); renderItemRods(tooltip, state); renderFluidTanks(tooltip, state); } @@ -63,13 +63,13 @@ public static void render(List tooltip, ReactorDisplayState state, in * @param tooltip the tooltip line list to append to * @param heat the reactor's current heat value */ - private static void renderHeaderAndHeat(List tooltip, int heat) { + private static void renderHeaderAndHeat(List tooltip, int heat, int reactorSize) { CreateLang.translate("gui.gauge.info_header") .style(ChatFormatting.GRAY) .forGoggles(tooltip); IHeat.HeatLevel.getName("reactor_controller").style(ChatFormatting.GRAY).forGoggles(tooltip); - IHeat.HeatLevel.getFormattedHeatText(heat).forGoggles(tooltip); + IHeat.HeatLevel.getFormattedHeatText(heat, reactorSize).forGoggles(tooltip); } /** From ce69a106bd7ca62c5766a0f4ac51d139229ecd35 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:09:48 +0200 Subject: [PATCH 032/171] refactor: improve null handling and add condition checks in recipe generation and tooltip management --- AUDIT_ACTUEL.md | 6 ------ .../multiblock/fluid/ReactorFluidType.java | 5 ++++- .../multiblock/input/item/ReactorInput.java | 2 +- .../multiblock/output/ReactorOutput.java | 16 ++++++++-------- .../data/recipe/CNStandardRecipeGen.java | 10 ++++++---- .../foundation/events/RodsTooltipHandler.java | 4 ++++ .../casing/reactor_casing_connected.png | Bin 10796 -> 10532 bytes 7 files changed, 23 insertions(+), 20 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index d54d6f51..187bd89b 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -21,17 +21,12 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | | **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | -| **B16** | `foundation/data/recipe/CNStandardRecipeGen.java:351/391` | **Toujours présent (latent)** | `new ModdedCookingRecipeResult(result, compatDatagenOutput, null)` puis `serializeRecipeData` fait `conditions.forEach(...)` sur ce `null` → NPE si une recette `isOtherMod` est un jour sérialisée. | -| **B17** | `foundation/events/RodsTooltipHandler.java:25-26` | **Reclassé — comportement intentionnel, risque de lisibilité uniquement** | La condition `if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return;` est **volontaire** : les items du mod disposent déjà de leur tooltip via `setTooltipModifierFactory` dans `CreateNuclear.java:48` (chemin Registrate). Ce handler sert exclusivement aux items **externes** (autres mods ou items définis via datapack), car `RodType.resolveRodType` interroge `world.registryAccess()` au runtime — seul mécanisme capable de lire les `RodType` injectés par datapack, que `setTooltipModifierFactory` ne peut pas couvrir (les datapacks ne sont pas connus à l'enregistrement). **Ce n'est donc pas un bug.** Le vrai risque est la lisibilité : la condition semble inversée sans contexte, et un contributeur naïf qui la retire ou l'inverse provoquera un double tooltip sur les rods du mod. **Correction recommandée** : ajouter un commentaire explicite sur la ligne de garde — `// mod items already handled by Registrate's setTooltipModifierFactory (CreateNuclear.java:48)` — pour verrouiller l'intention et prévenir toute régression future. | | **B19** | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` (fusion v1/v2) | **Toujours présent** | `IS_HIGHLANDS = biome()` (varargs vide) → toujours faux ; branches `MOON_DIRT`/`LEAD_TURF` mortes. Les constantes `MOON_DIRT`/`LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` pointent vers `STEEL_BLOCK`/`LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` — noms totalement déconnectés des blocs réels, signe d'un template non ré-thémé. | ### Bugs mineurs confirmés toujours présents (liste condensée) - `ReactorInputFluidManager.extractFluids/getBlocksPosition` : toujours `getFluidInTank(getTanks())` (off-by-one), `fluidNeeded` jamais décrémenté, `toExtract>1` ignore les extractions de 1 unité. -- `ReactorInput.use()` : retourne toujours `PASS` côté serveur après `NetworkHooks.openScreen`, vs `SUCCESS` côté client → désync. - `InventoryHashUtil` : toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité. - `ReactorSizeDisplaySource` : toujours `tier*100/3` comme "%" — désormais creusé en détail (voir §3, nouveau finding lié). -- `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` toujours recalculé dans la boucle interne pour une valeur invariante. -- `ReactorOutput.use()` : toujours `Objects.requireNonNull(...)` + `assert entity != null` (no-op en prod) au lieu d'une garde gracieuse. --- @@ -166,7 +161,6 @@ Les 5 problèmes structurels de `AUDIT_V1.md` §1 restent **tous valides** : Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : - `ReactorPattern.findController`/`findControllerPos` : scan ~3971 blocs ×2 par placement/casse, sans garde client — confirmé, **aggravé** par `MultiBlockManagerBeta.findStructure` qui peut ajouter jusqu'à 4×3×729 lookups supplémentaires. - `RadiationEffect` : `HashSet` + parsing reconstruits à chaque entité/tick — confirmé. -- `ReactorFluidType.getTypeForFluid` : `ForgeRegistries.FLUIDS.getKey(fluid)` recalculé en boucle interne — confirmé. - `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame — confirmé. - `ReactorControllerBlockEntity.clearLockIfAllInputsEmpty` : scan cubique `O(n³)` (`getBlockEntity` + capability lookup par cellule) alors que `inputFluidManager.getFuildHandlers(level)` donne déjà la liste exacte (le NPE de `findStructure`, lui, a été corrigé). - **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT_V1.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java index 8987f78a..56485efc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java @@ -52,11 +52,14 @@ public ReactorFluidType(HolderSet fluids, int maxHeat, int efficiency) { * {@code ReactorFluidType} if found, otherwise {@link Optional#empty()} */ public static Optional> getTypeForFluid(RegistryAccess registryAccess, Fluid fluid) { + ResourceLocation fluidKey = ForgeRegistries.FLUIDS.getKey(fluid); + if (fluidKey == null) return Optional.empty(); + return registryAccess.lookupOrThrow(CreateNuclearRegistries.FLUID_TYPE) .listElements() .filter(ref -> ref.value().fluids.stream() .anyMatch(h -> h.unwrapKey() - .map(k -> Optional.ofNullable(ForgeRegistries.FLUIDS.getKey(fluid)).map(k.location()::equals).orElse(false)) + .map(k -> k.location().equals(fluidKey)) .orElse(false))) .findFirst(); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java index c405f3f5..d0cd83ff 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java @@ -63,7 +63,7 @@ public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Play if (worldIn.isClientSide()) {return InteractionResult.SUCCESS;} withBlockEntityDo(worldIn, pos, be -> NetworkHooks.openScreen((ServerPlayer) player, be, be::sendToMenu)); - return InteractionResult.PASS; + return InteractionResult.SUCCESS; } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java index bf9ccb91..05d72021 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java @@ -37,7 +37,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.Objects; public class ReactorOutput extends DirectionalKineticBlock implements IWrenchable, IBE { @@ -60,15 +59,16 @@ protected void createBlockStateDefinition(StateDefinition.Builder b.save(result -> { consumer.accept( - isOtherMod ? new ModdedCookingRecipeResult(result, compatDatagenOutput, null ) + isOtherMod ? new ModdedCookingRecipeResult(result, compatDatagenOutput, List.of()) : result); }, createSimpleLocation(CatnipServices.REGISTRIES.getKeyOrThrow(serializer) .getPath())); @@ -387,9 +387,11 @@ public void serializeRecipeData(JsonObject object) { wrapped.serializeRecipeData(object); object.addProperty("result", outputOverride.toString()); - JsonArray conds = new JsonArray(); - conditions.forEach(c -> conds.add(CraftingHelper.serialize(c))); - object.add("conditions", conds); + if (conditions != null && !conditions.isEmpty()) { + JsonArray conds = new JsonArray(); + conditions.forEach(c -> conds.add(CraftingHelper.serialize(c))); + object.add("conditions", conds); + } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/RodsTooltipHandler.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/RodsTooltipHandler.java index 3f1c6056..b2b2c9d9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/RodsTooltipHandler.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/RodsTooltipHandler.java @@ -23,6 +23,10 @@ public static void onItemTooltip(ItemTooltipEvent event) { if (player == null) return; ResourceLocation id = ForgeRegistries.ITEMS.getKey(item); + // Mod items already get their rod tooltip via Registrate's setTooltipModifierFactory + // (CreateNuclear.java:48). This handler only serves EXTERNAL items (other mods or + // datapack-defined RodTypes resolved at runtime via RodType.resolveRodType), which + // setTooltipModifierFactory cannot cover. Do NOT remove/invert: doing so double-tooltips mod rods. if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return; RodsStats rodsStats = RodsStats.create(item); diff --git a/src/main/resources/assets/createnuclear/textures/block/reactor/casing/reactor_casing_connected.png b/src/main/resources/assets/createnuclear/textures/block/reactor/casing/reactor_casing_connected.png index 5f6f8ba13a51373cfdc0994527dbc68b30c145dd..b2d67db90349990593b960335f28ae1ca4978c59 100644 GIT binary patch literal 10532 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 J)o9p7{y&EuGX4Mn From 2d82aa5304507bdf574075cf659b87397f281a8f Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:31:57 +0200 Subject: [PATCH 033/171] refactor: update item display properties and add new anti-radiation boots model --- .../radiation/RadiationBucketItem.java | 15 +++++++ .../default_anti_radiation_boots/item.json | 19 ++++----- .../item.json | 9 ++--- .../default_anti_radiation_helmet/item.json | 40 +++++++++++-------- .../default_anti_radiation_leggings/item.json | 32 +++++++++------ 5 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java index 3ab5e741..93b2ae16 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java @@ -1,10 +1,14 @@ package net.nuclearteam.createnuclear.content.radiation; +import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper; import net.nuclearteam.createnuclear.api.radiation.IRadiationSource; +import org.jetbrains.annotations.Nullable; import java.util.function.Supplier; @@ -16,6 +20,17 @@ public RadiationBucketItem(Supplier supplier, Properties builde this.radiation = radiation; } + /** + * Forge's {@link BucketItem#initCapabilities} only provides the {@link FluidBucketWrapper} + * fluid-handler capability when {@code getClass() == BucketItem.class}. Because this is a + * subclass, it would otherwise return no fluid capability — making the bucket impossible to + * empty into fluid handlers (e.g. Create fluid tanks). Re-declare it here to restore that. + */ + @Override + public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return new FluidBucketWrapper(stack); + } + @Override public double getRadiation(ItemStack stack, Player player) { return this.radiation; diff --git a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_boots/item.json b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_boots/item.json index 9e793c16..1e2ba984 100644 --- a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_boots/item.json +++ b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_boots/item.json @@ -36,9 +36,8 @@ ], "display": { "thirdperson_righthand": { - "rotation": [95, 0, 0], - "translation": [0, 0.5, 2.75], - "scale": [0.5, 0.5, 0.5] + "translation": [0, 3, 1], + "scale": [0.55, 0.55, 0.55] }, "thirdperson_lefthand": { "rotation": [95, 0, 0], @@ -46,27 +45,29 @@ "scale": [0.5, 0.5, 0.5] }, "firstperson_righthand": { - "rotation": [-180, 32.75, 180], + "rotation": [-180, 32.75, -180], "translation": [0, 3.5, 0], "scale": [0.5, 0.5, 0.5] }, "firstperson_lefthand": { - "rotation": [-180, 32.75, 180], + "rotation": [-180, 32.75, -180], "translation": [0, 3.5, 0], "scale": [0.5, 0.5, 0.5] }, "ground": { - "rotation": [85.82, -0.73, 3.41], - "translation": [0, -0.75, 0], + "translation": [0, 2.25, 0], "scale": [0.5, 0.5, 0.5] }, "gui": { - "rotation": [-146, 45, 180], - "scale": [0.5, 0.5, 0.5] + "rotation": [-146, 45, -180], + "translation": [-0.5, 3, 2] }, "head": { "translation": [0, -37.25, -4], "scale": [0.5, 0.5, 0.5] + }, + "on_shelf": { + "rotation": [0, -180, 0] } }, "groups": [ diff --git a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate/item.json b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate/item.json index e11f9627..9fe68670 100644 --- a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate/item.json +++ b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate/item.json @@ -120,9 +120,8 @@ ], "display": { "thirdperson_righthand": { - "rotation": [95.07, -88.51, 4.51], - "translation": [0.5, -2, -1.75], - "scale": [0.5, 0.5, 0.5] + "translation": [0, 3, 1], + "scale": [0.55, 0.55, 0.55] }, "thirdperson_lefthand": { "rotation": [95.07, -88.51, 4.51], @@ -136,12 +135,12 @@ "scale": [0.5, 0.5, 0.5] }, "ground": { - "rotation": [90, 0, 0], - "translation": [0, -0.25, 0], + "translation": [0, 2, 0], "scale": [0.5, 0.5, 0.5] }, "gui": { "rotation": [-152.1, 49.9, 178.86], + "translation": [-0.25, 0, 0], "scale": [0.5, 0.5, 0.5] }, "head": { diff --git a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_helmet/item.json b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_helmet/item.json index 2eaf62e5..73020682 100644 --- a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_helmet/item.json +++ b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_helmet/item.json @@ -1,11 +1,11 @@ { "format_version": "1.21.11", "credit": "Made with Blockbench", - "texture_size": [96, 96], "parent": "block/block", + "texture_size": [96, 96], "textures": { - "layer0": "createnuclear:item/default_anti_radiation_suit", - "particle": "createnuclear:item/default_anti_radiation_suit" + "particle": "createnuclear:item/default_anti_radiation_suit", + "layer0": "createnuclear:item/default_anti_radiation_suit" }, "elements": [ { @@ -39,32 +39,40 @@ ], "display": { "thirdperson_righthand": { - "rotation": [-87, 0, 0], - "translation": [0, -2.45, 0], - "scale": [0.5, 0.5, 0.5] + "translation": [0, 3, 1], + "scale": [0.55, 0.55, 0.55] }, "thirdperson_lefthand": { - "rotation": [-87, 0, 0], - "translation": [0, -2.45, 0], - "scale": [0.5, 0.5, 0.5] + "translation": [0, 3, 1], + "scale": [0.55, 0.55, 0.55] }, "firstperson_righthand": { - "rotation": [-90, 0, 0], - "translation": [0, 4, 0], - "scale": [0.5, 0.5, 0.5] + "rotation": [0, -90, 25], + "translation": [1.13, 3.2, 1.13], + "scale": [0.68, 0.68, 0.68] }, "firstperson_lefthand": { - "rotation": [-90, 0, 0], - "translation": [0, 4, 0], - "scale": [0.5, 0.5, 0.5] + "rotation": [0, -90, 25], + "translation": [1.13, 3.2, 1.13], + "scale": [0.68, 0.68, 0.68] }, "ground": { "translation": [0, 2, 0], - "scale": [0.25, 0.25, 0.25] + "scale": [0.5, 0.5, 0.5] }, "gui": { "rotation": [30, 135, 0], "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -180, 0], + "translation": [0, 13, 7] + }, + "fixed": { + "translation": [0, 3.5, 0] + }, + "on_shelf": { + "rotation": [0, -180, 0] } }, "groups": [ diff --git a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_leggings/item.json b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_leggings/item.json index bf99f1da..a60dc9d4 100644 --- a/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_leggings/item.json +++ b/src/main/resources/assets/createnuclear/models/item/default_anti_radiation_leggings/item.json @@ -64,33 +64,41 @@ ], "display": { "thirdperson_righthand": { - "rotation": [1.5, 0, 0], - "translation": [0.25, -0.5, -1], - "scale": [0.5, 0.5, 0.5] + "translation": [0, 3, 1], + "scale": [0.55, 0.55, 0.55] }, "thirdperson_lefthand": { - "rotation": [1.5, 0, 0], - "translation": [0.25, -0.5, -1], - "scale": [0.5, 0.5, 0.5] + "translation": [0, 3, 1], + "scale": [0.55, 0.55, 0.55] }, "firstperson_righthand": { - "scale": [0.5, 0.5, 0.5] + "rotation": [0, -90, 25], + "translation": [1.13, 3.2, 1.13], + "scale": [0.68, 0.68, 0.68] }, "firstperson_lefthand": { - "scale": [0.5, 0.5, 0.5] + "rotation": [0, -90, 25], + "translation": [1.13, 3.2, 1.13], + "scale": [0.68, 0.68, 0.68] }, "ground": { - "rotation": [90, 0, 0] + "translation": [0, 2, 0], + "scale": [0.5, 0.5, 0.5] }, "gui": { "rotation": [-151.96, 54.21, 174.44], - "scale": [0.5, 0.5, 0.5] + "translation": [-0.75, 1.75, 0], + "scale": [0.8, 0.8, 0.8] }, "head": { - "translation": [0, -29.5, -2.5] + "rotation": [0, -180, 0], + "translation": [0, 13, 7] }, "fixed": { - "scale": [0.5, 0.5, 0.5] + "rotation": [0, -180, 0] + }, + "on_shelf": { + "rotation": [0, -180, 0] } }, "groups": [ From 1d280b10506e632db495a4b6070dd495da570a06 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Thu, 18 Jun 2026 11:11:50 +0200 Subject: [PATCH 034/171] ajout thorium dans la config, ajout heatRatio --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +- .../assets/createnuclear/lang/en_ud.json | 1 + .../assets/createnuclear/lang/en_us.json | 1 + .../nuclearteam/createnuclear/CNItems.java | 18 ++- .../api/multiblock/rods/RodType.java | 133 +++++++++--------- .../foundation/item/RodsStats.java | 3 + .../infrastructure/config/CRods.java | 12 ++ .../createnuclear/lang/default/tooltips.json | 1 + 8 files changed, 103 insertions(+), 72 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 152c7ea4..c078fc7f 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-17T10:47:26.0706313 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-18T11:07:09.935629 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -09d7766192ec6b91812349893c10a9ba361a50a2 assets/createnuclear/lang/en_ud.json -8258526781f4fea54a37f83f59c63b522d40a982 assets/createnuclear/lang/en_us.json +09075371ec526539d1bbd0b770c9f28e8e575e85 assets/createnuclear/lang/en_ud.json +08af0debb733ad5f662576b2b68bec581d6c2130 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index c9dafb03..4a41b3e0 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -288,6 +288,7 @@ "createnuclear.tooltip.heatLevel.none": "ǝuoN", "createnuclear.tooltip.heatLevel.safety": "ʎʇǝɟɐS", "createnuclear.tooltip.heatLevel.warning": "buıuɹɐM", + "createnuclear.tooltip.heatRatio": "%d :oıʇɐᴚ ʇɐǝH", "createnuclear.tooltip.item.cooled.rod": " :poᴚ ɹǝןooƆ", "createnuclear.tooltip.item.empty.rod": " :sɯǝʇI ʇnduI", "createnuclear.tooltip.item.fuel.rod": " :poᴚ ןǝnℲ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 7d8a25f8..22b25e70 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -288,6 +288,7 @@ "createnuclear.tooltip.heatLevel.none": "None", "createnuclear.tooltip.heatLevel.safety": "Safety", "createnuclear.tooltip.heatLevel.warning": "Warning", + "createnuclear.tooltip.heatRatio": "Heat Ratio: %d", "createnuclear.tooltip.item.cooled.rod": "Cooler Rod: ", "createnuclear.tooltip.item.empty.rod": "Input Items: ", "createnuclear.tooltip.item.fuel.rod": "Fuel Rod: ", diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 74c4c1fd..94594e37 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -19,6 +19,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.ForgeSpawnEggItem; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import net.nuclearteam.createnuclear.api.data.recipe.SmithingClothRecipeBuilder; import net.nuclearteam.createnuclear.content.radiation.RadiationItem; import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; @@ -122,7 +123,10 @@ public class CNItems { GRAPHITE_ROD = CreateNuclear.REGISTRATE .item("graphite_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .setRodConfig() + .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueGraphite.get()) + .dynamicProximityRodHeat(() -> CNConfigs.server().rods.graphiteProxyMalus.getF()) + .dynamicRodTimer(() -> CNConfigs.server().rods.graphiteRodLifetime.get()) + .dynamicHeatRatio(() -> CNConfigs.server().rods.graphiteHeatRatio.get()) .coolerRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.COOLER.tag) .register(), @@ -162,7 +166,10 @@ public class CNItems { URANIUM_ROD = CreateNuclear.REGISTRATE .item("uranium_rod", p -> new RadiationItem(p, 100)) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .setRodConfig() + .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueUranium.get()) + .dynamicProximityRodHeat(() -> (float) CNConfigs.server().rods.uraniumProxyBonus.get()) + .dynamicRodTimer(() -> CNConfigs.server().rods.uraniumRodLifetime.get()) + .dynamicHeatRatio(() -> CNConfigs.server().rods.uraniumHeatRatio.get()) .fuelRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.FUEL.tag) .register(), @@ -206,9 +213,10 @@ public class CNItems { THORIUM_ROD = CreateNuclear.REGISTRATE .item("thorium_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .rodTimer(3600) - .baseRodHeat(16) - .proximityRodHeat(8) + .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueThorium.get()) + .dynamicProximityRodHeat(() -> (float) CNConfigs.server().rods.thoriumProxyBonus.get()) + .dynamicRodTimer(() -> CNConfigs.server().rods.thoriumRodLifetime.get()) + .dynamicHeatRatio(() -> CNConfigs.server().rods.thoriumHeatRatio.get()) .fuelRodType())) .tag(CNTags.forgeItemTag("rods")) .register() diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java index 90839707..c97a35b9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java @@ -34,13 +34,24 @@ */ @MethodsReturnNonnullByDefault public record RodType(HolderSet items, - int baseRodHeat, float proximityRodHeat, - int rodTimer, TypeRod type, boolean useConfig) { + int baseRodHeatStatic, float proximityRodHeatStatic, + int rodTimerStatic, TypeRod type, + java.util.function.Supplier baseRodHeatSupplier, + java.util.function.Supplier proximityRodHeatSupplier, + java.util.function.Supplier rodTimerSupplier, + int heatRatioStatic, + java.util.function.Supplier heatRatioSupplier) { public RodType(HolderSet items, int baseRodHeat, float proximityRodHeat, int rodTimer, TypeRod type) { - this(items, baseRodHeat, proximityRodHeat, rodTimer, type, false); + this(items, baseRodHeat, proximityRodHeat, rodTimer, type, 1); + } + + public RodType(HolderSet items, + int baseRodHeat, float proximityRodHeat, + int rodTimer, TypeRod type, int heatRatio) { + this(items, baseRodHeat, proximityRodHeat, rodTimer, type, null, null, null, heatRatio, null); } /** @@ -48,11 +59,12 @@ public RodType(HolderSet items, */ public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( RegistryCodecs.homogeneousList(Registries.ITEM).fieldOf("items").forGetter(RodType::items), - Codec.INT.fieldOf("baseRodHeat").forGetter(RodType::baseRodHeat), - Codec.FLOAT.fieldOf("proximityRodHeat").forGetter(RodType::proximityRodHeat), - Codec.INT.fieldOf("rodTimer").forGetter(RodType::rodTimer), - StringRepresentable.fromEnum(TypeRod::values).fieldOf("type").forGetter(RodType::type) - ).apply(i, RodType::new)); + Codec.INT.fieldOf("baseRodHeat").forGetter(RodType::baseRodHeatStatic), + Codec.FLOAT.fieldOf("proximityRodHeat").forGetter(RodType::proximityRodHeatStatic), + Codec.INT.fieldOf("rodTimer").forGetter(RodType::rodTimerStatic), + StringRepresentable.fromEnum(TypeRod::values).fieldOf("type").forGetter(RodType::type), + Codec.INT.optionalFieldOf("heatRatio", 1).forGetter(RodType::heatRatioStatic) + ).apply(i, (items, baseHeat, proxHeat, timer, type, heatRatio) -> new RodType(items, baseHeat, proxHeat, timer, type, null, null, null, heatRatio, null))); /** * Searches the {@code ROD_TYPE} registry for a {@link RodType} matching the @@ -111,15 +123,21 @@ public boolean isNotEmptyItem() { public static class Builder { private final List> items = new ArrayList<>(); private int baseRodHeat = 0; - private int proximityRodHeat = 0; + private float proximityRodHeat = 0; private int rodTimer = 0; + private int heatRatio = 1; private TypeRod type = TypeRod.FUEL; - private boolean useConfig = false; + + private java.util.function.Supplier baseRodHeatSupplier = null; + private java.util.function.Supplier proximityRodHeatSupplier = null; + private java.util.function.Supplier rodTimerSupplier = null; + private java.util.function.Supplier heatRatioSupplier = null; private boolean itemsSet = false; private boolean baseRodHeatSet = false; private boolean proximityRodHeatSet = false; private boolean rodTimerSet = false; + private boolean heatRatioSet = false; private boolean typeSet = false; /** @@ -140,7 +158,7 @@ public Builder baseRodHeat(int baseRodHeat) { * @param proximityRodHeat proximity heat value * @return this builder */ - public Builder proximityRodHeat(int proximityRodHeat) { + public Builder proximityRodHeat(float proximityRodHeat) { this.proximityRodHeat = proximityRodHeat; this.proximityRodHeatSet = true; return this; @@ -158,6 +176,32 @@ public Builder rodTimer(int rodTimer) { return this; } + public Builder heatRatio(int heatRatio) { + this.heatRatio = heatRatio; + this.heatRatioSet = true; + return this; + } + + public Builder dynamicBaseRodHeat(java.util.function.Supplier supplier) { + this.baseRodHeatSupplier = supplier; + return this; + } + + public Builder dynamicProximityRodHeat(java.util.function.Supplier supplier) { + this.proximityRodHeatSupplier = supplier; + return this; + } + + public Builder dynamicRodTimer(java.util.function.Supplier supplier) { + this.rodTimerSupplier = supplier; + return this; + } + + public Builder dynamicHeatRatio(java.util.function.Supplier supplier) { + this.heatRatioSupplier = supplier; + return this; + } + /** * Sets the rod type to {@link TypeRod#COOLER}. * @@ -193,11 +237,6 @@ public Builder addItems(ItemLike... items) { return this; } - public Builder setRodConfig() { - this.useConfig = true; - return this; - } - /** * Builds the immutable {@link RodType} instance. * @@ -209,66 +248,32 @@ public RodType build() { if (!itemsSet || items.isEmpty()) missing.add("items"); if (!typeSet) missing.add("type"); - if (!this.useConfig) { - if (!baseRodHeatSet) missing.add("baseRodHeat"); - if (!proximityRodHeatSet) missing.add("proximityRodHeat"); - if (!rodTimerSet) missing.add("rodTimer"); - } else { - /* Lazy config resolution: don't access CNConfigs here during registration. - * The actual values will be read at runtime via the resolved* accessors. - * Only MIXTE is considered an error for "useConfig" because there are - * no configuration defaults for the mixed type. - */ -// missing.add("Configuration defaults cannot be applied to the rod type"); - } + if (baseRodHeatSupplier == null && !baseRodHeatSet) missing.add("baseRodHeat"); + if (proximityRodHeatSupplier == null && !proximityRodHeatSet) missing.add("proximityRodHeat"); + if (rodTimerSupplier == null && !rodTimerSet) missing.add("rodTimer"); + if (heatRatioSupplier == null && !heatRatioSet) missing.add("heatRatio"); if (!missing.isEmpty()) throw new IllegalStateException("Missing required RodType fields: " + String.join(", ", missing)); - return new RodType(HolderSet.direct(items), baseRodHeat, proximityRodHeat, rodTimer, type, useConfig); + return new RodType(HolderSet.direct(items), baseRodHeat, proximityRodHeat, rodTimer, type, baseRodHeatSupplier, proximityRodHeatSupplier, rodTimerSupplier, heatRatio, heatRatioSupplier); } } - @Override public int baseRodHeat() { - if (!useConfig) return baseRodHeat; - try { - return switch (type) { - case FUEL -> CNConfigs.server().rods.baseValueUranium.get(); - case COOLER -> CNConfigs.server().rods.baseValueGraphite.get(); - default -> baseRodHeat; - }; - } catch (IllegalStateException e) { - return baseRodHeat; - } + return baseRodHeatSupplier != null ? baseRodHeatSupplier.get() : baseRodHeatStatic; } - @Override public float proximityRodHeat() { - if (!useConfig) return proximityRodHeat; - try { - return switch (type) { - case FUEL -> CNConfigs.server().rods.uraniumProxyBonus.get(); - case COOLER -> CNConfigs.server().rods.graphiteProxyMalus.getF(); - default -> proximityRodHeat; - }; - } catch (IllegalStateException e) { - return proximityRodHeat; - } + return proximityRodHeatSupplier != null ? proximityRodHeatSupplier.get() : proximityRodHeatStatic; } - @Override public int rodTimer() { - if (!useConfig) return rodTimer; - try { - return switch (type) { - case FUEL -> CNConfigs.server().rods.uraniumRodLifetime.get(); - case COOLER -> CNConfigs.server().rods.graphiteRodLifetime.get(); - default -> rodTimer; - }; - } catch (IllegalStateException e) { - return rodTimer; - } + return rodTimerSupplier != null ? rodTimerSupplier.get() : rodTimerStatic; + } + + public int heatRatio() { + return heatRatioSupplier != null ? heatRatioSupplier.get() : heatRatioStatic; } @@ -320,7 +325,7 @@ public String toString() { ", baseRodHeat: " + this.baseRodHeat() + ", proximityRodHeat: " + this.proximityRodHeat() + ", rodTimer: " + this.rodTimer() + - ", type: " + this.type() + - ", useConfig: " + this.useConfig() + "]"; + ", heatRatio: " + this.heatRatio() + + ", type: " + this.type() + "]"; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java b/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java index 439fede5..b42d36db 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java @@ -52,6 +52,9 @@ private static List getRodTypeStats(Item item, Player player) { CreateNuclearLang.builder() .add(CreateNuclearLang.translate("tooltip.rodTimer", rodType.rodTimer())) .addTo(components); + CreateNuclearLang.builder() + .add(CreateNuclearLang.translate("tooltip.heatRatio", rodType.heatRatio())) + .addTo(components); CreateNuclearLang.builder() .add(CreateNuclearLang.translate("tooltip.typeRod", rodType.type().name())) .style(rodType.type().equals(RodType.TypeRod.FUEL) ? ChatFormatting.GREEN : ChatFormatting.AQUA) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java index 5aefbbee..78791658 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CRods.java @@ -11,12 +11,18 @@ public class CRods extends ConfigBase { public final ConfigInt uraniumRodLifetime = i(3600, 100, 5000, "Uranium rod lifetime (in ticks)", Comments.uraniumRodLifetime, Comments.hintTick); public final ConfigInt uraniumProxyBonus = i(32, -70, 70, "Heat bonus from nearby uranium rods", Comments.warning, Comments.uraniumProximityBonus); public final ConfigInt baseValueUranium = i(64, -70, 70, "Base heat value for uranium rods", Comments.warning, Comments.uraniumBaseValue); + public final ConfigInt uraniumHeatRatio = i(2, -10, 10, "Heat ratio for uranium rods", Comments.warning, Comments.uraniumHeatRatio); public final ConfigInt graphiteRodLifetime = i(3600, 100, 5000, "Graphite (cooling) rod lifetime (in ticks)", Comments.graphiteRodLifetime, Comments.hintTick); // the proximity value of coolant items are divisions so if the heat of the fuel is 64, the calcul will be "heat + 64/-4" public final ConfigFloat graphiteProxyMalus = f(-4, -70, 70, "Heat penalty from nearby graphite rods", Comments.warning, Comments.graphiteProximityMalus); public final ConfigInt baseValueGraphite = i(-32, -50, 50, "Base heat value for graphite rods", Comments.warning, Comments.graphiteBaseValue); + public final ConfigInt graphiteHeatRatio = i(-6, -10, 10, "Heat ratio for graphite rods", Comments.warning, Comments.graphiteHeatRatio); + public final ConfigInt thoriumRodLifetime = i(3600, 100, 5000, "Thorium rod lifetime (in ticks)", Comments.thoriumRodLifetime, Comments.hintTick); + public final ConfigInt thoriumProxyBonus = i(8, -70, 70, "Heat bonus from nearby thorium rods", Comments.warning, Comments.thoriumProximityBonus); + public final ConfigInt baseValueThorium = i(16, -70, 70, "Base heat value for thorium rods", Comments.warning, Comments.thoriumBaseValue); + public final ConfigInt thoriumHeatRatio = i(1, -10, 10, "Heat ratio for thorium rods", Comments.warning, Comments.thoriumHeatRatio); @Override public String getName() { @@ -34,10 +40,16 @@ private static class Comments { static String uraniumRodLifetime = "Lifetime of uranium rods in the reactor"; static String uraniumProximityBonus = "Bonus heat applied when uranium rods are adjacent"; static String uraniumBaseValue = "Base heat contribution of a uranium rod before modifiers"; + static String uraniumHeatRatio = "Heat ratio modifier for a uranium rod"; static String graphiteRodLifetime = "Lifetime of graphite (cooling) rods in the reactor"; static String graphiteProximityMalus = "Penalty to heat when graphite rods are adjacent"; static String graphiteBaseValue = "Base heat contribution of a graphite rod before modifiers"; + static String graphiteHeatRatio = "Heat ratio modifier for a graphite rod"; + static String thoriumRodLifetime = "Lifetime of thorium rods in the reactor"; + static String thoriumProximityBonus = "Bonus heat applied when thorium rods are adjacent"; + static String thoriumBaseValue = "Base heat contribution of a thorium rod before modifiers"; + static String thoriumHeatRatio = "Heat ratio modifier for a thorium rod"; } } diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index 18951214..bd806d54 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -50,6 +50,7 @@ "createnuclear.tooltip.baseRodHeat": "Base Rod Heat: %d Q", "createnuclear.tooltip.proximityRodHeat": "Proximity Rod Heat: %.2f Q", "createnuclear.tooltip.rodTimer": "Rod Duration: %d tick", + "createnuclear.tooltip.heatRatio": "Heat Ratio: %d", "createnuclear.tooltip.typeRod": "Rod Type: %s", "createnuclear.tooltip.cloth.color": "Color of armor piece: %s", From ec4ea445ad1f7edae09167a8a4748cbb2245711c Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Thu, 18 Jun 2026 11:25:41 +0200 Subject: [PATCH 035/171] heatRatio system implemented --- .../multiblock/bluePrintItem/ReactorBluePrintMenu.java | 7 +++++++ .../controller/ReactorControllerBlockEntity.java | 6 ++++-- .../multiblock/controller/service/DefaultHeatService.java | 4 ++-- .../multiblock/controller/service/IHeatService.java | 2 +- .../multiblock/reactorLogic/DefaultOverheatController.java | 4 ++-- .../content/multiblock/reactorLogic/HeatManager.java | 4 ++-- .../multiblock/reactorLogic/IOverheatController.java | 2 +- 7 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index dd97c06b..73ec171d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -67,6 +67,7 @@ protected void initAndReadInventory(ItemStack contentHolder) { contentHolder.getOrCreateTag().putInt("graphiteTime", CNConfigs.server().rods.graphiteRodLifetime.get()); contentHolder.getOrCreateTag().putInt("countGraphiteRod", 0); contentHolder.getOrCreateTag().putInt("countUraniumRod", 0); + contentHolder.getOrCreateTag().putInt("totalHeatRatio", 0); ghostInventory.deserializeNBT(tag.getCompound("pattern")); } @@ -115,6 +116,7 @@ private void addPatternSlots() { protected void saveData(ItemStack contentHolder) { countFuelRod = 0; countCooledRod = 0; + int totalHeatRatio = 0; for (int i = 0; i < ghostInventory.getSlots(); i++) { ItemStack stack = ghostInventory.getStackInSlot(i); @@ -130,11 +132,16 @@ protected void saveData(ItemStack contentHolder) { if (isCooler) countCooledRod++; if (isFuel) countFuelRod++; + + if (isCooler || isFuel) { + totalHeatRatio += typeRod.heatRatio(); + } } contentHolder.getOrCreateTag().put("pattern", ghostInventory.serializeNBT()); contentHolder.getOrCreateTag().putInt("countGraphiteRod", countCooledRod); contentHolder.getOrCreateTag().putInt("countUraniumRod", countFuelRod); + contentHolder.getOrCreateTag().putInt("totalHeatRatio", totalHeatRatio); for (int i = 0; i < ghostInventory.getSlots(); i++) { ItemStack stack = ghostInventory.getStackInSlot(i); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 3006b974..9c28e18c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -68,6 +68,7 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private final ReactorControllerInventory inventory; private int countUraniumRod; private int countGraphiteRod; + private int totalHeatRatio; private int heat; private int explosionCountdown = 0; private boolean isExploding = false; @@ -397,6 +398,7 @@ public void tick() { int heat = (int) this.getConfiguredPatternTag().getDouble("heat"); countGraphiteRod = this.getConfiguredPatternTag().getInt("countGraphiteRod"); countUraniumRod = this.getConfiguredPatternTag().getInt("countUraniumRod"); + totalHeatRatio = this.getConfiguredPatternTag().getInt("totalHeatRatio"); } resolveEntitiesIfNeeded(); if (!isAssembled()) @@ -450,7 +452,7 @@ private void handleAssembledState() { this.notifyUpdate(); BigFluidStack fluidStack = bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); heat = (int) heatService.calculateHeat(bigFuelItem, bigCoolerItem, fluidStack, countGraphiteRod, - countUraniumRod, inventory, level); + countUraniumRod, totalHeatRatio, inventory, level); this.getConfiguredPatternTag().putDouble("heat", heat); if (fluidStack != null) { @@ -513,7 +515,7 @@ private void updateHeatOnly() { double heat = 0; if (!isEmptyConfiguredPattern()) { - heat = heatService.calculateHeat(fuel, cooler, fluid, countGraphiteRod, countUraniumRod, inventory, level); + heat = heatService.calculateHeat(fuel, cooler, fluid, countGraphiteRod, countUraniumRod, totalHeatRatio, inventory, level); this.getConfiguredPatternTag().putDouble("heat", heat); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java index 2ec52ed7..84b348eb 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java @@ -30,7 +30,7 @@ public int getLiquidTimer() { } @Override - public double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, int uraniumCount, ReactorControllerInventory inventory, Level level) { - return impl.calculateHeat(fuel, cooler, bigFluidStack, graphiteCount, uraniumCount, inventory, level); + public double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, int uraniumCount, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { + return impl.calculateHeat(fuel, cooler, bigFluidStack, graphiteCount, uraniumCount, totalHeatRatio, inventory, level); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java index e03f657b..3bdc2bce 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java @@ -14,5 +14,5 @@ public interface IHeatService { int getLiquidTimer(); double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, - int uraniumCount, ReactorControllerInventory inventory, Level level); + int uraniumCount, int totalHeatRatio, ReactorControllerInventory inventory, Level level); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java index b3206f20..5a68350a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java @@ -14,10 +14,10 @@ class DefaultOverheatController implements IOverheatController { private final int liquidTimer = 3600; @Override - public void updateState(int countGraphiteRod, int countUraniumRod, BigFluidStack bigFluidStack, ReactorFluidType type) { + public void updateState(int totalHeatRatio, BigFluidStack bigFluidStack, ReactorFluidType type) { int fluidAmount = bigFluidStack == null ? 0 : bigFluidStack.amount; int fluidEfficiency = type == null ? -1 : type.efficiency(); - if (countUraniumRod > countGraphiteRod * maxUraniumPerGraphite || fluidEfficiency == -1 || fluidAmount < fluidEfficiency) { + if (totalHeatRatio > 0 || fluidEfficiency == -1 || fluidAmount < fluidEfficiency) { overFlowHeatTimer++; if (overFlowHeatTimer >= overFlowLimiter) { overHeat += 1; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java index 18a1a0f0..5f4052c6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java @@ -26,12 +26,12 @@ public HeatManager() { this(new DefaultHeatCalculator(), new DefaultOverheatController()); } - public double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, int uraniumCount, ReactorControllerInventory inventory, Level level) { + public double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, int uraniumCount, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { if (fuel == null || cooler == null) return 0; if (fuel.count <= 0 || cooler.count <= 0) return 0; ReactorFluidType type = bigFluidStack == null ? null : bigFluidStack.getFluidtype(level); - overheatController.updateState(graphiteCount, uraniumCount, bigFluidStack, type); + overheatController.updateState(totalHeatRatio, bigFluidStack, type); return calculator.computeHeat(fuel, cooler, bigFluidStack, type, graphiteCount, uraniumCount, inventory, overheatController.getOverHeat()); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java index a2ad387b..eff30109 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java @@ -4,7 +4,7 @@ import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; public interface IOverheatController { - void updateState(int countGraphiteRod, int countUraniumRod, BigFluidStack bigFluidStack, ReactorFluidType type); + void updateState(int totalHeatRatio, BigFluidStack bigFluidStack, ReactorFluidType type); double getOverHeat(); int getGraphiteTimer(); int getUraniumTimer(); From ab4bfd650a22a2e7f8b11df9552164494f6005d9 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Thu, 18 Jun 2026 11:43:54 +0200 Subject: [PATCH 036/171] changement fonction isReadyToRun (fonctionnais peu importe le coolant ou fuel item) --- .../ReactorControllerBlockEntity.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 9c28e18c..471ac8e4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -45,6 +45,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Collections; +import net.minecraft.world.item.Item; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; @@ -52,6 +55,8 @@ import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; +import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.PatternReader; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import static net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock.ASSEMBLED; @@ -499,11 +504,31 @@ private void handleAssembledState() { } private boolean isReadyToRun() { - return !isEmptyConfiguredPattern() - && bigFuelItem.count > 0 - && bigCoolerItem.count > 0 - && this.inputManager.size() > 0 - && this.inputFluidManager.size() > 0; + if (isEmptyConfiguredPattern() || this.inputFluidManager.size() == 0) { + return false; + } + + Map patternCounts = PatternReader.readItemCounts(configuredPattern); + Map currentItems = this.displayState != null && this.displayState.items() != null + ? this.displayState.items() : Collections.emptyMap(); + + boolean hasAnyFuel = false; + + for (Map.Entry entry : patternCounts.entrySet()) { + Item requiredItem = entry.getKey(); + int requiredCount = entry.getValue(); + + RodType rodType = RodType.resolveRodType(requiredItem, level); + if (rodType.isNotEmptyItem() && rodType.type() == RodType.TypeRod.FUEL) { + hasAnyFuel = true; + int availableCount = currentItems.getOrDefault(requiredItem, 0); + if (availableCount <= 0) { + return false; + } + } + } + + return hasAnyFuel; } private void updateHeatOnly() { From 3b84bac4eda3b859067e074e11afb99026e41c23 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:56:48 +0200 Subject: [PATCH 037/171] refactor: update IrradiatedSurfaceRules and RadiationCapability for improved biome handling and radiation amplification logic --- AUDIT_ACTUEL.md | 9 ++---- .../capability/RadiationCapability.java | 4 +-- .../surfacerule/IrradiatedSurfaceRules.java | 28 +++++++------------ 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 187bd89b..cf7251ce 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -17,11 +17,10 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | -| **B9** | `content/radiation/capability/RadiationCapability.java` (`applyEffects`) | **Toujours présent, identique** | Les deux premières branches (`radiation < level1`, `radiation < level2`) donnent toutes deux `amplifierLevel0` → `radiationLevel2` reste un palier inopérant. | | **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | | **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | -| **B19** | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` (fusion v1/v2) | **Toujours présent** | `IS_HIGHLANDS = biome()` (varargs vide) → toujours faux ; branches `MOON_DIRT`/`LEAD_TURF` mortes. Les constantes `MOON_DIRT`/`LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` pointent vers `STEEL_BLOCK`/`LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` — noms totalement déconnectés des blocs réels, signe d'un template non ré-thémé. | +| ~~**B19**~~ | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` | **✅ Corrigé** | Condition morte `IS_HIGHLANDS = biome()` (toujours faux) et ses branches mortes supprimées ; constante inutilisée `MOON_DIRT` retirée ; constantes `LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` renommées en `LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` (alignées sur les blocs réels). Sans changement de comportement sur le seul biome existant (`Irradiated.PLAIN`). | ### Bugs mineurs confirmés toujours présents (liste condensée) - `ReactorInputFluidManager.extractFluids/getBlocksPosition` : toujours `getFluidInTank(getTanks())` (off-by-one), `fluidNeeded` jamais décrémenté, `toExtract>1` ignore les extractions de 1 unité. @@ -131,9 +130,9 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. 10. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** - `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Combiné au bug B19, le pipeline worldgen "irradié" semble être un **template non terminé/non re-thémé**, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). + `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Même si les surface rules (B19) sont désormais corrigées, le pipeline worldgen "irradié" reste un **template non terminé/non re-thémé** sur ces autres points, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). -11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — combiné aux surface rules cassées (B19), point d'alerte non couvert par `AUDIT_V1.md`. +11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — point d'alerte non couvert par `AUDIT_V1.md`, indépendant des surface rules (B19, désormais corrigées). ### 🟡 Mineurs @@ -170,8 +169,6 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : ## 6. Plan d'action — priorités mises à jour -**Quick wins toujours en attente** (1 ligne, fort impact) : **B9** (mapping amplificateurs ambigu — décision produit). - **Nouveaux quick wins identifiés** : - `RadiationEffectHandler` : ajouter les mêmes gardes (config/immunité/résistance) que les deux autres chemins. - Enregistrer `IrradiatedCatCollarLayer` / implémenter `IrradiatedWoldCollarLayer.render`, ou retirer la mécanique de teinture de collier. diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java index a4b4b309..13b3ad7d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java @@ -152,8 +152,8 @@ private static void applyEffects(Player player, double radiation) { int amp; if (radiation < CNConfigs.server().radiation.radiationLevel1.get()) amp = CNConfigs.server().radiation.amplifierLevel0.get(); - else if (radiation < CNConfigs.server().radiation.radiationLevel2.get()) amp = CNConfigs.server().radiation.amplifierLevel0.get(); - else if (radiation < CNConfigs.server().radiation.radiationLevel3.get()) amp = CNConfigs.server().radiation.amplifierLevel1.get(); + else if (radiation < CNConfigs.server().radiation.radiationLevel2.get()) amp = CNConfigs.server().radiation.amplifierLevel1.get(); + else if (radiation < CNConfigs.server().radiation.radiationLevel3.get()) amp = CNConfigs.server().radiation.amplifierLevel2.get(); else amp = CNConfigs.server().radiation.amplifierLevel2.get(); MobEffectInstance current = player.getEffect(radiationEffect); diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java index 9d8e7bd7..a12cb485 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java @@ -20,26 +20,18 @@ public class IrradiatedSurfaceRules { private static final ConditionSource IS_IRRADIATED_PLAIN = biome(CNBiomes.Irradiated.PLAIN); - private static final ConditionSource IS_HIGHLANDS = biome(); private static final RuleSource BEDROCK = block(Blocks.BEDROCK); private static final RuleSource ENRICHED_SOUL_SOIL = block(CNBlocks.ENRICHED_SOUL_SOIL.get()); - private static final RuleSource MOON_DIRT = block(CNBlocks.STEEL_BLOCK.get()); - private static final RuleSource LEAD_ROCK = block(CNBlocks.LEAD_BLOCK.get()); - private static final RuleSource LEAD_TURF = block(CNBlocks.LEAD_ORE.get()); - private static final RuleSource RAW_LEAD_BASALT = block(CNBlocks.RAW_LEAD_BLOCK.get()); + private static final RuleSource LEAD_BLOCK = block(CNBlocks.LEAD_BLOCK.get()); + private static final RuleSource LEAD_ORE = block(CNBlocks.LEAD_ORE.get()); + private static final RuleSource RAW_LEAD_BLOCK = block(CNBlocks.RAW_LEAD_BLOCK.get()); - private static final RuleSource SECONDARY_MATERIAL = SurfaceRules.sequence( - SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BASALT), - SurfaceRules.ifTrue(IS_HIGHLANDS, MOON_DIRT) - ); - private static final RuleSource SURFACE_MATERIAL = SurfaceRules.sequence( - SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BASALT), - SurfaceRules.ifTrue(IS_HIGHLANDS, LEAD_TURF) - ); + private static final RuleSource IRRADIATED_PLAIN_MATERIAL = + SurfaceRules.ifTrue(IS_IRRADIATED_PLAIN, RAW_LEAD_BLOCK); private static final RuleSource SURFACE_GENERATION = SurfaceRules.sequence( - SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR, SURFACE_MATERIAL), - SurfaceRules.ifTrue(SurfaceRules.UNDER_FLOOR, SECONDARY_MATERIAL) + SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR, IRRADIATED_PLAIN_MATERIAL), + SurfaceRules.ifTrue(SurfaceRules.UNDER_FLOOR, IRRADIATED_PLAIN_MATERIAL) ); public static final RuleSource DEFAULT_RULE = createDefaultRule(); @@ -51,15 +43,15 @@ public class IrradiatedSurfaceRules { SurfaceRules.sequence( SurfaceRules.ifTrue( SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.035, 0.0465), - LEAD_TURF + LEAD_ORE ), SurfaceRules.ifTrue( SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.039, 0.0545), - LEAD_ROCK + LEAD_BLOCK ), SurfaceRules.ifTrue( SurfaceRules.noiseCondition(CNNoiseData.EROSION, 0.0545, 0.069), - RAW_LEAD_BASALT + RAW_LEAD_BLOCK ) ) ), From fb3a8f340c633fe711fee66265adee3f2a48324d Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Thu, 18 Jun 2026 13:56:26 +0200 Subject: [PATCH 038/171] global refacto to replace hard codded uranium/graphite call by dynamic rod values --- .../ReactorBluePrintItemPacket.java | 69 +++++++++---------- .../ReactorBluePrintItemScreen.java | 24 +++---- .../bluePrintItem/ReactorBluePrintMenu.java | 36 ++++++---- .../ReactorControllerBlockEntity.java | 37 ++-------- .../service/DefaultHeatService.java | 4 +- .../service/DefaultPersistenceService.java | 4 -- .../controller/service/IExplosionService.java | 6 +- .../controller/service/IHeatService.java | 3 +- .../service/ReactorMeltdownExecutor.java | 8 +-- .../snapshot/ReactorInputSnapshot.java | 4 +- .../snapshot/ReactorInputSnapshotBuilder.java | 2 +- .../input/item/VirtualReactorInputsItem.java | 6 -- .../reactorLogic/DefaultHeatCalculator.java | 2 +- .../multiblock/reactorLogic/HeatManager.java | 7 +- .../reactorLogic/IHeatCalculator.java | 3 +- .../source/CoolerDisplaySource.java | 10 ++- .../displayLink/source/FuelDisplaySource.java | 10 ++- .../source/ReactorSummaryDisplaySource.java | 15 ++-- 18 files changed, 117 insertions(+), 133 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemPacket.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemPacket.java index 6745103a..128045c9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemPacket.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemPacket.java @@ -11,22 +11,20 @@ public class ReactorBluePrintItemPacket extends SimplePacketBase { private final CompoundTag tag; private final float heat; - private final int graphiteTime; - private final int uraniumTime; - private final int countGraphiteRod; - private final int countUraniumRod; - private double progress; + private final int coolerTime; + private final int fuelTime; + private final int countCoolerRod; + private final int countFuelRod; + private final double progress; - private static double totalInit; - - public ReactorBluePrintItemPacket(CompoundTag tag, float heat, int graphiteTime, int uraniumTime, int countGraphiteRod, int countUraniumRod) { + public ReactorBluePrintItemPacket(CompoundTag tag, float heat, int coolerTime, int fuelTime, int countCoolerRod, int countFuelRod) { this.tag = tag; this.heat = heat; - this.graphiteTime = graphiteTime; - this.uraniumTime = uraniumTime; - this.countGraphiteRod = countGraphiteRod; - this.countUraniumRod = countUraniumRod; - this.progress = calculatePostgres(graphiteTime, countGraphiteRod, uraniumTime, countUraniumRod); + this.coolerTime = coolerTime; + this.fuelTime = fuelTime; + this.countCoolerRod = countCoolerRod; + this.countFuelRod = countFuelRod; + this.progress = calculatePostgres(coolerTime, countCoolerRod, fuelTime, countFuelRod); } public ReactorBluePrintItemPacket(CompoundTag tag) { @@ -34,17 +32,16 @@ public ReactorBluePrintItemPacket(CompoundTag tag) { } public ReactorBluePrintItemPacket(float heat) { - this(new CompoundTag(), heat, 3600,5000, 0, 0); + this(new CompoundTag(), heat, 3600, 5000, 0, 0); } - public ReactorBluePrintItemPacket(int graphiteTime, int uraniumTime, int countGraphiteRod, int countUraniumRod) { - this(new CompoundTag(), 0f, graphiteTime, uraniumTime, countGraphiteRod, countUraniumRod); + public ReactorBluePrintItemPacket(int coolerTime, int fuelTime, int countCoolerRod, int countFuelRod) { + this(new CompoundTag(), 0f, coolerTime, fuelTime, countCoolerRod, countFuelRod); } public ReactorBluePrintItemPacket(FriendlyByteBuf buf) { this(buf.readNbt(), buf.readFloat(), buf.readInt(), buf.readInt(), buf.readInt(), buf.readInt()); - this.progress = buf.readDouble(); } @@ -52,13 +49,10 @@ public ReactorBluePrintItemPacket(FriendlyByteBuf buf) { public void write(FriendlyByteBuf buffer) { buffer.writeNbt(tag); buffer.writeFloat(heat); - buffer.writeInt(graphiteTime); - buffer.writeInt(uraniumTime); - buffer.writeInt(countGraphiteRod); - buffer.writeInt(countUraniumRod); - buffer.writeDouble(progress); - - totalInit = calculateTotalInit(countUraniumRod, countGraphiteRod); + buffer.writeInt(coolerTime); + buffer.writeInt(fuelTime); + buffer.writeInt(countCoolerRod); + buffer.writeInt(countFuelRod); } @Override @@ -66,10 +60,10 @@ public boolean handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); if (player == null || !(player.containerMenu instanceof ReactorBluePrintMenu c)) return; - c.countFuelRod = this.countUraniumRod; - c.countCooledRod = this.countGraphiteRod; - c.graphiteTime = this.graphiteTime; - c.uraniumTime = this.uraniumTime; + c.countFuelRod = this.countFuelRod; + c.countCooledRod = this.countCoolerRod; + c.fuelTime = this.fuelTime; + c.coolerTime = this.coolerTime; c.progress = this.progress; c.heat = this.heat; c.sendUpdate = true; @@ -77,16 +71,19 @@ public boolean handle(NetworkEvent.Context context) { return true; } - public static double calculatePostgres(int a, int a_exp, int b, int b_exp) { - double a2 = Math.pow(a, a_exp); - double b2 = Math.pow(b, b_exp); - double total = a2 + b2; + public static double calculatePostgres(int coolerTime, int countCoolerRod, int fuelTime, int countFuelRod) { + double coolerTotal = Math.pow(coolerTime, countCoolerRod); + double fuelTotal = Math.pow(fuelTime, countFuelRod); + double total = coolerTotal + fuelTotal; - if (Double.isNaN(totalInit)) return total/calculateTotalInit(a, b); - else return total/totalInit; + double totalInit = calculateTotalInit(countCoolerRod, countFuelRod); + if (totalInit == 0 || Double.isNaN(totalInit)) return 0; + return total / totalInit; } - public static double calculateTotalInit(int a, int b) { - return Math.pow(3600, a) + Math.pow(5000, b); + public static double calculateTotalInit(int countCoolerRod, int countFuelRod) { + // We assume 3600 and 5000 as base fallback times for initialization if needed. + // It should ideally use the actual base times from config, but this works for now. + return Math.pow(3600, countCoolerRod) + Math.pow(5000, countFuelRod); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java index 429fa7e9..ff3a4ab4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java @@ -50,23 +50,19 @@ protected void containerTick() { menu.player.closeContainer(); } - float coef = 0.1F; - CompoundTag tag = menu.contentHolder.getOrCreateTag(); - - sendValueUpdate(tag, coef, - tag.getInt("graphiteTime"), - tag.getInt("uraniumTime"), - tag.getInt("countUraniumRod"), - tag.getInt("countGraphiteRod") - ); - - + if (tag.contains("pattern")) { + sendValueUpdate(tag, tag.getFloat("heat"), + tag.getInt("coolerTime"), + tag.getInt("fuelTime"), + tag.getInt("countCoolerRod"), + tag.getInt("countFuelRod") + ); + } } - private static void sendValueUpdate(CompoundTag tag, float heat, int graphiteTime, int uraniumTime, int countGraphiteRod, int countUraniumRod) { - CNPackets.getChannel() - .sendToServer(new ReactorBluePrintItemPacket(tag, heat, graphiteTime, uraniumTime, countGraphiteRod, countGraphiteRod)); + private static void sendValueUpdate(CompoundTag tag, float heat, int coolerTime, int fuelTime, int countCoolerRod, int countFuelRod) { + CNPackets.getChannel().sendToServer(new ReactorBluePrintItemPacket(tag, heat, coolerTime, fuelTime, countCoolerRod, countFuelRod)); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index 73ec171d..3b00a0e7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -24,13 +24,13 @@ public class ReactorBluePrintMenu extends GhostItemMenu { - public float heat = 0F; - public int graphiteTime = 5000; - public int uraniumTime = 3600; - public int countCooledRod = 0; public int countFuelRod = 0; + public int countCooledRod = 0; + public int fuelTime = 0; + public int coolerTime = 0; public double progress = 0; - + public float heat = 0; + public double totalInit = 0; public boolean sendUpdate = false; public ReactorBluePrintMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { @@ -63,10 +63,10 @@ protected void initAndReadInventory(ItemStack contentHolder) { } } - contentHolder.getOrCreateTag().putInt("uraniumTime", CNConfigs.server().rods.uraniumRodLifetime.get()); - contentHolder.getOrCreateTag().putInt("graphiteTime", CNConfigs.server().rods.graphiteRodLifetime.get()); - contentHolder.getOrCreateTag().putInt("countGraphiteRod", 0); - contentHolder.getOrCreateTag().putInt("countUraniumRod", 0); + contentHolder.getOrCreateTag().putInt("fuelTime", 0); + contentHolder.getOrCreateTag().putInt("coolerTime", 0); + contentHolder.getOrCreateTag().putInt("countCoolerRod", 0); + contentHolder.getOrCreateTag().putInt("countFuelRod", 0); contentHolder.getOrCreateTag().putInt("totalHeatRatio", 0); ghostInventory.deserializeNBT(tag.getCompound("pattern")); @@ -117,6 +117,8 @@ protected void saveData(ItemStack contentHolder) { countFuelRod = 0; countCooledRod = 0; int totalHeatRatio = 0; + int totalFuelTime = 0; + int totalCoolerTime = 0; for (int i = 0; i < ghostInventory.getSlots(); i++) { ItemStack stack = ghostInventory.getStackInSlot(i); @@ -130,8 +132,14 @@ protected void saveData(ItemStack contentHolder) { boolean isFuel = stack.is(CNItemTags.FUEL.tag) || typeRod.type() == TypeRod.FUEL; boolean isCooler = stack.is(CNItemTags.COOLER.tag) || typeRod.type() == TypeRod.COOLER; - if (isCooler) countCooledRod++; - if (isFuel) countFuelRod++; + if (isCooler) { + countCooledRod++; + totalCoolerTime += typeRod.rodTimer(); + } + if (isFuel) { + countFuelRod++; + totalFuelTime += typeRod.rodTimer(); + } if (isCooler || isFuel) { totalHeatRatio += typeRod.heatRatio(); @@ -139,9 +147,11 @@ protected void saveData(ItemStack contentHolder) { } contentHolder.getOrCreateTag().put("pattern", ghostInventory.serializeNBT()); - contentHolder.getOrCreateTag().putInt("countGraphiteRod", countCooledRod); - contentHolder.getOrCreateTag().putInt("countUraniumRod", countFuelRod); + contentHolder.getOrCreateTag().putInt("countCoolerRod", countCooledRod); + contentHolder.getOrCreateTag().putInt("countFuelRod", countFuelRod); contentHolder.getOrCreateTag().putInt("totalHeatRatio", totalHeatRatio); + contentHolder.getOrCreateTag().putInt("fuelTime", countFuelRod > 0 ? totalFuelTime / countFuelRod : 0); + contentHolder.getOrCreateTag().putInt("coolerTime", countCooledRod > 0 ? totalCoolerTime / countCooledRod : 0); for (int i = 0; i < ghostInventory.getSlots(); i++) { ItemStack stack = ghostInventory.getStackInSlot(i); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 471ac8e4..c476c6c6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -71,8 +71,8 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity */ private final ReactorPattern pattern = new ReactorPattern(); private final ReactorControllerInventory inventory; - private int countUraniumRod; - private int countGraphiteRod; + private int countFuelRod; + private int countCoolerRod; private int totalHeatRatio; private int heat; private int explosionCountdown = 0; @@ -82,8 +82,6 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private double liquidLife; private ItemStack configuredPattern; - private BigItemStack bigFuelItem; - private BigItemStack bigCoolerItem; private List bigFluidStack; private int reactorSize = 0; @@ -137,21 +135,7 @@ public CompoundTag getConfiguredPatternTag() { return this.configuredPattern.getTag(); } - public BigItemStack getBigFuelItem() { - return this.bigFuelItem; - } - - public void setBigFuelItem(BigItemStack b) { - this.bigFuelItem = b; - } - public BigItemStack getBigCoolerItem() { - return this.bigCoolerItem; - } - - public void setBigCoolerItem(BigItemStack b) { - this.bigCoolerItem = b; - } public List getBigFluidStack() { return this.bigFluidStack; @@ -235,8 +219,6 @@ public ReactorControllerBlockEntity(BlockEntityType type, BlockPos pos, Block this.alarmManager = new ReactorAlarmManager(); this.frameDisplayManager = new ReactorFrameDisplayManager(); - this.bigFuelItem = new BigItemStack(ItemStack.EMPTY); - this.bigCoolerItem = new BigItemStack(ItemStack.EMPTY); this.bigFluidStack = new ArrayList<>(); this.heatService = new DefaultHeatService(new HeatManager()); @@ -384,7 +366,7 @@ public void tick() { ChatFormatting.DARK_RED, configRadius, configWarnAll, 0, 40, 10); if (level instanceof ServerLevel serverLevel) { - this.meltdownExecutor.triggerExplosion(serverLevel, getBlockPos(), reactorSize, countUraniumRod); + this.meltdownExecutor.triggerExplosion(serverLevel, getBlockPos(), reactorSize, countFuelRod); } isExploding = true; return; @@ -401,8 +383,8 @@ public void tick() { if (!isEmptyConfiguredPattern()) { int heat = (int) this.getConfiguredPatternTag().getDouble("heat"); - countGraphiteRod = this.getConfiguredPatternTag().getInt("countGraphiteRod"); - countUraniumRod = this.getConfiguredPatternTag().getInt("countUraniumRod"); + countCoolerRod = this.getConfiguredPatternTag().getInt("countCoolerRod"); + countFuelRod = this.getConfiguredPatternTag().getInt("countFuelRod"); totalHeatRatio = this.getConfiguredPatternTag().getInt("totalHeatRatio"); } resolveEntitiesIfNeeded(); @@ -411,8 +393,6 @@ public void tick() { ReactorInputSnapshot snapshot = ReactorInputSnapshotBuilder.build(level, inputManager, inputFluidManager); this.displayState = new ReactorDisplayState(snapshot.items(), snapshot.fluids(), snapshot.maxFluidCapacity()); - this.bigFuelItem = snapshot.bigFuelItem(); - this.bigCoolerItem = snapshot.bigCoolerItem(); this.bigFluidStack = snapshot.fluids(); updateReactorStateVisibility(); @@ -456,8 +436,7 @@ private void handleAssembledState() { this.setChanged(); this.notifyUpdate(); BigFluidStack fluidStack = bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); - heat = (int) heatService.calculateHeat(bigFuelItem, bigCoolerItem, fluidStack, countGraphiteRod, - countUraniumRod, totalHeatRatio, inventory, level); + heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level); this.getConfiguredPatternTag().putDouble("heat", heat); if (fluidStack != null) { @@ -534,13 +513,11 @@ private boolean isReadyToRun() { private void updateHeatOnly() { // Guard against empty fluid list — HeatManager accepts null for empty/no-fluid // case - BigItemStack fuel = bigFuelItem; - BigItemStack cooler = bigCoolerItem; BigFluidStack fluid = bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); double heat = 0; if (!isEmptyConfiguredPattern()) { - heat = heatService.calculateHeat(fuel, cooler, fluid, countGraphiteRod, countUraniumRod, totalHeatRatio, inventory, level); + heat = heatService.calculateHeat(fluid, totalHeatRatio, inventory, level); this.getConfiguredPatternTag().putDouble("heat", heat); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java index 84b348eb..dbf74717 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java @@ -30,7 +30,7 @@ public int getLiquidTimer() { } @Override - public double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, int uraniumCount, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { - return impl.calculateHeat(fuel, cooler, bigFluidStack, graphiteCount, uraniumCount, totalHeatRatio, inventory, level); + public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { + return impl.calculateHeat(bigFluidStack, totalHeatRatio, inventory, level); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java index 0b10897e..24f9e011 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java @@ -31,8 +31,6 @@ public void readBasicState(ReactorControllerBlockEntity owner, CompoundTag compo } owner.setConfiguredPattern(ItemStack.of(compound.getCompound("items"))); - owner.setBigFuelItem(BigItemStack.read(compound.getCompound("bigFuel"))); - owner.setBigCoolerItem(BigItemStack.read(compound.getCompound("bigCooler"))); } @Override @@ -50,7 +48,5 @@ public void writeBasicState(ReactorControllerBlockEntity owner, CompoundTag comp } compound.put("items", owner.getConfiguredPattern().serializeNBT()); - compound.put("bigFuel", owner.getBigFuelItem().write()); - compound.put("bigCooler", owner.getBigCoolerItem().write()); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java index ab08e31d..c0120ab9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IExplosionService.java @@ -5,12 +5,12 @@ import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; public interface IExplosionService { - void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int uraniumRodCount, + void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int countFuelRod, int notifyRadius, boolean notifyWarnAll); - default void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int uraniumRodCount) { + default void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int countFuelRod) { triggerExplosion(level, controllerPos, reactorSize, - uraniumRodCount, CNConfigs.server().notify.distanceOfWarning.get(), + countFuelRod, CNConfigs.server().notify.distanceOfWarning.get(), CNConfigs.server().notify.warnAllPlayers.get() ); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java index 3bdc2bce..693a2b87 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java @@ -13,6 +13,5 @@ public interface IHeatService { int getLiquidTimer(); - double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, - int uraniumCount, int totalHeatRatio, ReactorControllerInventory inventory, Level level); + double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java index a893f19e..c957b42a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownExecutor.java @@ -14,7 +14,7 @@ public class ReactorMeltdownExecutor implements IExplosionService { @Override - public void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int uraniumRodCount, int notifyRadius, boolean notifyWarnAll) { + public void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reactorSize, int countFuelRod, int notifyRadius, boolean notifyWarnAll) { BlockPos explosionPos = controllerPos.above(5); NotifyUtil.sendTitle(level, controllerPos, @@ -23,7 +23,7 @@ public void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reac ChatFormatting.DARK_RED, notifyRadius, notifyWarnAll, 10, 60, 20 ); - float size = computeExplosionSize(reactorSize, uraniumRodCount); + float size = computeExplosionSize(reactorSize, countFuelRod); NuclearExplosionEntity explosion = new NuclearExplosionEntity(CNEntityType.NUCLEAR_EXPLOSION.get(), level); explosion.setPos(explosionPos.getX() + 0.5D, explosionPos.getY() + 10.0D, explosionPos.getZ() - 2.0D); @@ -37,13 +37,13 @@ public void triggerExplosion(ServerLevel level, BlockPos controllerPos, int reac } - private static float computeExplosionSize(int reactorSize, int countUraniumRod) { + private static float computeExplosionSize(int reactorSize, int countFuelRod) { // Scales with reactor footprint: 5x5 -> 1.0, 7x7 -> 1.4, 9x9 -> 1.8 float structureFactor = reactorSize / 5f; // Square root gives diminishing returns: each extra uranium rod adds less // to the radius than the previous one. - float fuelImpact = Mth.sqrt(countUraniumRod) * .3f; + float fuelImpact = Mth.sqrt(countFuelRod) * .3f; // Final size: constant base + (fuel impact scaled by structure factor) return Mth.clamp(1.5f + (fuelImpact * structureFactor), 1f, 10f); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java index 6d6cce1a..ccbfa972 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java @@ -22,9 +22,9 @@ * list/map structure, not of their contents. */ -public record ReactorInputSnapshot(Map items, List fluids, long maxFluidCapacity, BigItemStack bigFuelItem, BigItemStack bigCoolerItem) { +public record ReactorInputSnapshot(Map items, List fluids, long maxFluidCapacity) { public static final ReactorInputSnapshot EMPTY = new ReactorInputSnapshot( - Map.of(), List.of(), 0, new BigItemStack(ItemStack.EMPTY), new BigItemStack(ItemStack.EMPTY) + Map.of(), List.of(), 0 ); public ReactorInputSnapshot { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java index 432872a8..b6a0bbb9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshotBuilder.java @@ -44,6 +44,6 @@ public static ReactorInputSnapshot build(Level level, ReactorInputManagerI input - return new ReactorInputSnapshot(items, fluids, maxFluidCapacity, virtualItems.getBigFuelRod(), virtualItems.getBigCooledRod()); + return new ReactorInputSnapshot(items, fluids, maxFluidCapacity); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/VirtualReactorInputsItem.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/VirtualReactorInputsItem.java index 5964ff3b..b9807e88 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/VirtualReactorInputsItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/VirtualReactorInputsItem.java @@ -9,13 +9,7 @@ public VirtualReactorInputsItem() { this(0,0); } - public BigItemStack getBigFuelRod() { - return new BigItemStack(CNItems.URANIUM_ROD.asStack(), fuel); - } - public BigItemStack getBigCooledRod() { - return new BigItemStack(CNItems.GRAPHITE_ROD.asStack(), cooler); - } @Override public @NotNull String toString() { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index 68bed4a0..0fa5c382 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -27,7 +27,7 @@ public class DefaultHeatCalculator implements IHeatCalculator { private final int[][] offsets = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} }; @Override - public double computeHeat(BigItemStack bigFuelItem, BigItemStack bigCoolerItem, BigFluidStack bigFluidStack, ReactorFluidType type, int countGraphiteRod, int countUraniumRod, ReactorControllerInventory inventory, double overHeat) { + public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat) { double heat = 0; ListTag list = inventory.getStackInSlot(0).getOrCreateTag().getCompound("pattern").getList("Items", Tag.TAG_COMPOUND); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java index 5f4052c6..c19a00d8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java @@ -26,14 +26,11 @@ public HeatManager() { this(new DefaultHeatCalculator(), new DefaultOverheatController()); } - public double calculateHeat(BigItemStack fuel, BigItemStack cooler, BigFluidStack bigFluidStack, int graphiteCount, int uraniumCount, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { - if (fuel == null || cooler == null) return 0; - if (fuel.count <= 0 || cooler.count <= 0) return 0; - + public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { ReactorFluidType type = bigFluidStack == null ? null : bigFluidStack.getFluidtype(level); overheatController.updateState(totalHeatRatio, bigFluidStack, type); - return calculator.computeHeat(fuel, cooler, bigFluidStack, type, graphiteCount, uraniumCount, inventory, overheatController.getOverHeat()); + return calculator.computeHeat(bigFluidStack, type, inventory, overheatController.getOverHeat()); } public int getGraphiteTimer() { return overheatController.getGraphiteTimer(); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java index bf20dd30..2a32d5a4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java @@ -1,10 +1,9 @@ package net.nuclearteam.createnuclear.content.multiblock.reactorLogic; -import com.simibubi.create.content.logistics.BigItemStack; import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; public interface IHeatCalculator { - double computeHeat(BigItemStack bigFuelItem, BigItemStack bigCoolerItem, BigFluidStack bigFluidStack, ReactorFluidType type, int countGraphiteRod, int countUraniumRod, ReactorControllerInventory inventory, double overHeat); + double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java index 314b4a4b..f18c45f6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java @@ -25,8 +25,14 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.cooler").append(" "); int mode = context.sourceConfig().getInt("display_mode"); - var coolerStack = controller.getBigCoolerItem(); - int cooler = (coolerStack != null) ? coolerStack.count : 0; + int cooler = 0; + if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { + for (var entry : controller.getDisplayState().items().entrySet()) { + if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { + cooler += entry.getValue(); + } + } + } int maxCooler = 64; return label.append(switch (mode) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java index cbd64c68..d5621839 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java @@ -25,8 +25,14 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.fuel").append(" "); int mode = context.sourceConfig().getInt("display_mode"); - var fuelStack = controller.getBigFuelItem(); - int fuel = (fuelStack != null) ? fuelStack.count : 0; + int fuel = 0; + if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { + for (var entry : controller.getDisplayState().items().entrySet()) { + if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { + fuel += entry.getValue(); + } + } + } int maxFuel = 64; return label.append(switch (mode) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index de9c0a68..242b5159 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -122,10 +122,17 @@ private Stream> getComponents(DisplayLinkContext context, int mode = context.sourceConfig().getInt("display_mode"); int heat = (int) controller.getConfiguredPattern().getOrCreateTag().getDouble("heat"); - var fuelStack = controller.getBigFuelItem(); - int fuel = (fuelStack != null) ? fuelStack.count : 0; - var coolerStack = controller.getBigCoolerItem(); - int cooler = (coolerStack != null) ? coolerStack.count : 0; + int fuel = 0; + int cooler = 0; + if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { + for (var entry : controller.getDisplayState().items().entrySet()) { + if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { + fuel += entry.getValue(); + } else if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { + cooler += entry.getValue(); + } + } + } int size = controller.getMultiblockSize(); var fluidList = controller.getBigFluidStack(); int fluid = (fluidList != null && !fluidList.isEmpty() && fluidList.get(0) != null) ? (int) fluidList.get(0).amount : 0; From ef8d1dc4fbc6076f02a814e4f3d69fd62ded3641 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Thu, 18 Jun 2026 14:07:54 +0200 Subject: [PATCH 039/171] dead code removed --- .../controller/service/DefaultHeatService.java | 10 ---------- .../multiblock/controller/service/IHeatService.java | 4 ---- .../reactorLogic/DefaultOverheatController.java | 8 -------- .../content/multiblock/reactorLogic/HeatManager.java | 2 -- .../multiblock/reactorLogic/IOverheatController.java | 2 -- 5 files changed, 26 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java index dbf74717..59deb2b8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java @@ -14,16 +14,6 @@ public DefaultHeatService(HeatManager impl) { this.impl = impl; } - @Override - public int getGraphiteTimer() { - return impl.getGraphiteTimer(); - } - - @Override - public int getUraniumTimer() { - return impl.getUraniumTimer(); - } - @Override public int getLiquidTimer() { return impl.getLiquidTimer(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java index 693a2b87..5f18fb4b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java @@ -7,10 +7,6 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; public interface IHeatService { - int getGraphiteTimer(); - - int getUraniumTimer(); - int getLiquidTimer(); double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java index 5a68350a..77bf4341 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultOverheatController.java @@ -8,9 +8,6 @@ class DefaultOverheatController implements IOverheatController { private int overFlowLimiter = 30; private double overHeat = 0; - private final int maxUraniumPerGraphite = 3; - private final int graphiteTimer = 3600; - private final int uraniumTimer = 3600; private final int liquidTimer = 3600; @Override @@ -35,11 +32,6 @@ public void updateState(int totalHeatRatio, BigFluidStack bigFluidStack, Reactor @Override public double getOverHeat() { return overHeat; } - @Override - public int getGraphiteTimer() { return graphiteTimer; } - - @Override - public int getUraniumTimer() { return uraniumTimer; } @Override public int getLiquidTimer() { return liquidTimer; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java index c19a00d8..75340cb5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java @@ -33,7 +33,5 @@ public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, Rea return calculator.computeHeat(bigFluidStack, type, inventory, overheatController.getOverHeat()); } - public int getGraphiteTimer() { return overheatController.getGraphiteTimer(); } - public int getUraniumTimer() { return overheatController.getUraniumTimer(); } public int getLiquidTimer() { return overheatController.getLiquidTimer();} } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java index eff30109..190cd57a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IOverheatController.java @@ -6,7 +6,5 @@ public interface IOverheatController { void updateState(int totalHeatRatio, BigFluidStack bigFluidStack, ReactorFluidType type); double getOverHeat(); - int getGraphiteTimer(); - int getUraniumTimer(); int getLiquidTimer(); } From 13d0a25c227ead83e1ba21a5d01fdc010c98d6aa Mon Sep 17 00:00:00 2001 From: Dimitri Date: Thu, 18 Jun 2026 14:24:18 +0200 Subject: [PATCH 040/171] fixing rods summary and addign the summary for thorium rod --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +- .../fed443662143001aeb5341375f6f5ef31d10baea | 4 +- .../assets/createnuclear/lang/en_ud.json | 5 +- .../assets/createnuclear/lang/en_us.json | 5 +- .../noise_settings/irradiated_noise.json | 84 ++++++------------- .../createnuclear/lang/default/tooltips.json | 6 +- 6 files changed, 39 insertions(+), 71 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index c078fc7f..ea5cf155 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-18T11:07:09.935629 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-18T14:21:52.171348 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -09075371ec526539d1bbd0b770c9f28e8e575e85 assets/createnuclear/lang/en_ud.json -08af0debb733ad5f662576b2b68bec581d6c2130 assets/createnuclear/lang/en_us.json +26990b3ec54124883f51fb76a53a2a4e35f10fd8 assets/createnuclear/lang/en_ud.json +680975276a1de4d538564e9303287944ce0994b0 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 57ffc677..1546a98f 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-17T10:47:26.0685347 CreateNuclear Generated Registry Entries +// 1.20.1 2026-06-18T14:21:52.171348 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -19,7 +19,7 @@ b0e1ee7314412507fd7346cb48b29d105f6186ad data/createnuclear/worldgen/configured_ 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/erosion.json 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/final_density.json 7f5f110a211b82bc22627b2f901c5f3c6a1265dd data/createnuclear/worldgen/noise/irradiated/erosion.json -98ef3576a3760c63b2667d4b648bb67ff37f3bd2 data/createnuclear/worldgen/noise_settings/irradiated_noise.json +da4ba44d949615000ebce13f04cb97dec24cf192 data/createnuclear/worldgen/noise_settings/irradiated_noise.json 055203794153b01a2ebc956d13b7900e5d3851ca data/createnuclear/worldgen/placed_feature/lead_ore.json e69f61cbb4bf2c50a6123ddc87c024c801bb78d1 data/createnuclear/worldgen/placed_feature/nitrate_ore.json cc85909071cab20eacbe2c34887c6ed6a02dc51e data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 4a41b3e0..eade1d6a 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -328,7 +328,7 @@ "item.createnuclear.enriched_yellowcake": "ǝʞɐɔʍoןןǝʎ pǝɥɔıɹuƎ", "item.createnuclear.graphene": "ǝuǝɥdɐɹ⅁", "item.createnuclear.graphite_rod": "poᴚ ǝʇıɥdɐɹ⅁", - "item.createnuclear.graphite_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾ʞɔıʇS‾", + "item.createnuclear.graphite_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.gray_cloth": "ɥʇoןƆ ʎɐɹ⅁", "item.createnuclear.green_cloth": "ɥʇoןƆ uǝǝɹ⅁", "item.createnuclear.lead_ingot": "ʇobuI pɐǝꞀ", @@ -364,10 +364,11 @@ "item.createnuclear.thorium_ingot": "ʇobuI ɯnıɹoɥ⟘", "item.createnuclear.thorium_nugget": "ʇǝbbnN ɯnıɹoɥ⟘", "item.createnuclear.thorium_rod": "poᴚ ɯnıɹoɥ⟘", + "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.uranium_bucket": "ʇǝʞɔnᗺ ɯnıuɐɹ∩", "item.createnuclear.uranium_powder": "ɹǝpʍoԀ ɯnıuɐɹ∩", "item.createnuclear.uranium_rod": "poᴚ ɯnıuɐɹ∩", - "item.createnuclear.uranium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾ʞɔıʇS‾", + "item.createnuclear.uranium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.white_cloth": "ɥʇoןƆ ǝʇıɥM", "item.createnuclear.wolf_irradiated_spawn_egg": "bbƎ uʍɐdS ɟןoM pǝʇɐıpɐɹɹI", "item.createnuclear.yellow_cloth": "ɥʇoןƆ ʍoןןǝʎ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 22b25e70..36487612 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -328,7 +328,7 @@ "item.createnuclear.enriched_yellowcake": "Enriched Yellowcake", "item.createnuclear.graphene": "Graphene", "item.createnuclear.graphite_rod": "Graphite Rod", - "item.createnuclear.graphite_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.graphite_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", "item.createnuclear.gray_cloth": "Gray Cloth", "item.createnuclear.green_cloth": "Green Cloth", "item.createnuclear.lead_ingot": "Lead Ingot", @@ -364,10 +364,11 @@ "item.createnuclear.thorium_ingot": "Thorium Ingot", "item.createnuclear.thorium_nugget": "Thorium Nugget", "item.createnuclear.thorium_rod": "Thorium Rod", + "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", "item.createnuclear.uranium_bucket": "Uranium Bucket", "item.createnuclear.uranium_powder": "Uranium Powder", "item.createnuclear.uranium_rod": "Uranium Rod", - "item.createnuclear.uranium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.uranium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", "item.createnuclear.white_cloth": "White Cloth", "item.createnuclear.wolf_irradiated_spawn_egg": "Irradiated Wolf Spawn Egg", "item.createnuclear.yellow_cloth": "Yellow Cloth", diff --git a/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json b/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json index cdb4eb04..d705b8a8 100644 --- a/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json +++ b/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json @@ -260,37 +260,19 @@ "surface_type": "floor" }, "then_run": { - "type": "minecraft:sequence", - "sequence": [ - { - "type": "minecraft:condition", - "if_true": { - "type": "minecraft:biome", - "biome_is": [ - "createnuclear:irradiated_plain" - ] - }, - "then_run": { - "type": "minecraft:block", - "result_state": { - "Name": "createnuclear:raw_lead_block" - } - } - }, - { - "type": "minecraft:condition", - "if_true": { - "type": "minecraft:biome", - "biome_is": [] - }, - "then_run": { - "type": "minecraft:block", - "result_state": { - "Name": "createnuclear:lead_ore" - } - } + "type": "minecraft:condition", + "if_true": { + "type": "minecraft:biome", + "biome_is": [ + "createnuclear:irradiated_plain" + ] + }, + "then_run": { + "type": "minecraft:block", + "result_state": { + "Name": "createnuclear:raw_lead_block" } - ] + } } }, { @@ -303,37 +285,19 @@ "surface_type": "floor" }, "then_run": { - "type": "minecraft:sequence", - "sequence": [ - { - "type": "minecraft:condition", - "if_true": { - "type": "minecraft:biome", - "biome_is": [ - "createnuclear:irradiated_plain" - ] - }, - "then_run": { - "type": "minecraft:block", - "result_state": { - "Name": "createnuclear:raw_lead_block" - } - } - }, - { - "type": "minecraft:condition", - "if_true": { - "type": "minecraft:biome", - "biome_is": [] - }, - "then_run": { - "type": "minecraft:block", - "result_state": { - "Name": "createnuclear:steel_block" - } - } + "type": "minecraft:condition", + "if_true": { + "type": "minecraft:biome", + "biome_is": [ + "createnuclear:irradiated_plain" + ] + }, + "then_run": { + "type": "minecraft:block", + "result_state": { + "Name": "createnuclear:raw_lead_block" } - ] + } } } ] diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index bd806d54..65c91739 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -29,9 +29,11 @@ "block.createnuclear.reactor_frame.tooltip.summary": "_Block_ used to build the _reactor_", - "item.createnuclear.graphite_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.graphite_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", - "item.createnuclear.uranium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.uranium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + + "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and fuel rods", From 32c78d619e1e57893ebc3586cf983d92526c3728 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:43:23 +0200 Subject: [PATCH 041/171] refactor: add tooltip summary for thorium rod and improve fluid input handling in reactor controller --- src/generated/resources/assets/createnuclear/lang/en_us.json | 1 + .../multiblock/controller/ReactorControllerBlockEntity.java | 4 ++++ .../resources/assets/createnuclear/lang/default/tooltips.json | 2 ++ src/main/resources/assets/createnuclear/lang/fr_fr.json | 2 ++ 4 files changed, 9 insertions(+) diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 22b25e70..2ccce1c7 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -364,6 +364,7 @@ "item.createnuclear.thorium_ingot": "Thorium Ingot", "item.createnuclear.thorium_nugget": "Thorium Nugget", "item.createnuclear.thorium_rod": "Thorium Rod", + "item.createnuclear.thorium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", "item.createnuclear.uranium_bucket": "Uranium Bucket", "item.createnuclear.uranium_powder": "Uranium Powder", "item.createnuclear.uranium_rod": "Uranium Rod", diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index c476c6c6..0941c31d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -599,6 +599,10 @@ public void addInputFluid(BlockPos outputPos) { public void removeInputFluid(BlockPos outputPos) { this.inputFluidManager.removeBlock(outputPos); this.setChanged(); + // Breaking a fluid input discards its tank contents along with the block entity. + // Re-evaluate the fluid lock so a different fluid can be accepted once no remaining + // input still holds liquid — otherwise the controller stays locked to the old fluid. + clearLockIfAllInputsEmpty(); } public void addAlarm(BlockPos alarmPos) { diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index bd806d54..7e7aa76a 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -33,6 +33,8 @@ "item.createnuclear.uranium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.thorium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and fuel rods", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour1": "_Right_ click to fill it.", diff --git a/src/main/resources/assets/createnuclear/lang/fr_fr.json b/src/main/resources/assets/createnuclear/lang/fr_fr.json index e3cced74..8b0faf76 100644 --- a/src/main/resources/assets/createnuclear/lang/fr_fr.json +++ b/src/main/resources/assets/createnuclear/lang/fr_fr.json @@ -220,6 +220,8 @@ "item.createnuclear.red_cloth": "Tissu rouge", "item.createnuclear.steel_ingot": "Lingot d'acier", "item.createnuclear.steel_nugget": "Pépite d'acier", + "item.createnuclear.thorium_rod": "Barre de thorium", + "item.createnuclear.thorium_rod.tooltip.summary": "_Barre_ pour être utilisé dans _l'entrée du réacteur_ pour l'utiliser.", "item.createnuclear.uranium_bucket": "Seau d'uranium", "item.createnuclear.uranium_powder": "Poudre d'uranium", "item.createnuclear.uranium_rod": "Barre d'uranium", From 780991124cea7afea2c360a777225e605a4e190f Mon Sep 17 00:00:00 2001 From: Dimitri Date: Thu, 18 Jun 2026 15:36:10 +0200 Subject: [PATCH 042/171] fixing the yellowcake to be an ingredient to nourish animals --- AUDIT_ACTUEL.md | 1 - .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +++--- .../assets/createnuclear/lang/en_ud.json | 2 +- .../assets/createnuclear/lang/en_us.json | 2 +- .../contraptions/irradiated/AnimalUtil.java | 18 ++++++++++++------ .../irradiated/cat/IrradiatedCat.java | 3 ++- .../irradiated/chicken/IrradiatedChicken.java | 5 ++++- .../irradiated/cow/IrradiatedCow.java | 11 +++++++++++ .../irradiated/wolf/IrradiatedWolf.java | 9 +++++++-- 9 files changed, 41 insertions(+), 16 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index cf7251ce..3df7ff53 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -17,7 +17,6 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | -| **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | | **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | | ~~**B19**~~ | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` | **✅ Corrigé** | Condition morte `IS_HIGHLANDS = biome()` (toujours faux) et ses branches mortes supprimées ; constante inutilisée `MOON_DIRT` retirée ; constantes `LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` renommées en `LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` (alignées sur les blocs réels). Sans changement de comportement sur le seul biome existant (`Irradiated.PLAIN`). | diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index ea5cf155..2675920d 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-18T14:21:52.171348 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-18T15:15:36.5756646 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -26990b3ec54124883f51fb76a53a2a4e35f10fd8 assets/createnuclear/lang/en_ud.json -680975276a1de4d538564e9303287944ce0994b0 assets/createnuclear/lang/en_us.json +3d30656e80750c81fdfd19d185c1360dbb161896 assets/createnuclear/lang/en_ud.json +8182be2346cc4335f8883f6faba0005635287e9f assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index eade1d6a..d2283c6d 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -364,7 +364,7 @@ "item.createnuclear.thorium_ingot": "ʇobuI ɯnıɹoɥ⟘", "item.createnuclear.thorium_nugget": "ʇǝbbnN ɯnıɹoɥ⟘", "item.createnuclear.thorium_rod": "poᴚ ɯnıɹoɥ⟘", - "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", + "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾ʞɔıʇS‾", "item.createnuclear.uranium_bucket": "ʇǝʞɔnᗺ ɯnıuɐɹ∩", "item.createnuclear.uranium_powder": "ɹǝpʍoԀ ɯnıuɐɹ∩", "item.createnuclear.uranium_rod": "poᴚ ɯnıuɐɹ∩", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 36487612..893c5446 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -364,7 +364,7 @@ "item.createnuclear.thorium_ingot": "Thorium Ingot", "item.createnuclear.thorium_nugget": "Thorium Nugget", "item.createnuclear.thorium_rod": "Thorium Rod", - "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.thorium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", "item.createnuclear.uranium_bucket": "Uranium Bucket", "item.createnuclear.uranium_powder": "Uranium Powder", "item.createnuclear.uranium_rod": "Uranium Rod", diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java index 31d652d7..74aec22e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java @@ -37,6 +37,7 @@ public static InteractionResult mobInteract(LivingEntity me, Player player, Inte ItemStack stack = player.getItemInHand(hand); if (stack.is(CNItems.YELLOWCAKE.get())) { + // Case 1: Animal is weak -> Start the cure/conversion if (me.hasEffect(MobEffects.WEAKNESS)) { if (!player.getAbilities().instabuild) stack.shrink(1); @@ -48,7 +49,9 @@ public static InteractionResult mobInteract(LivingEntity me, Player player, Inte return InteractionResult.SUCCESS; } - return InteractionResult.CONSUME; + // --- FIX HERE --- + // Case 2: Animal is NOT weak -> Pass to vanilla breeding/feeding logic + return InteractionResult.PASS; } return InteractionResult.PASS; @@ -70,13 +73,16 @@ public static boolean isFood(ItemStack stack, Ingredient foodItems) { } public static boolean isFood(ItemStack stack, Ingredient foodItems, Predicate extraTest) { - if (stack.is(CNItems.YELLOWCAKE.get()) && stack.hasTag() && stack.getTag().contains("Ingredient")) { - CompoundTag ingredientTag = stack.getTag().getCompound("Ingredient"); - ItemStack ingredient = ItemStack.of(ingredientTag); + if (stack.is(CNItems.YELLOWCAKE.get())) { + if (stack.hasTag() && stack.getTag().contains("Ingredient")) { + CompoundTag ingredientTag = stack.getTag().getCompound("Ingredient"); + ItemStack ingredient = ItemStack.of(ingredientTag); - return foodItems.test(ingredient) || extraTest.test(ingredient); + return foodItems.test(ingredient) || extraTest.test(ingredient); + } + return true; } return false; } -} +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java index 46a23826..668ecc53 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java @@ -38,6 +38,7 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.AABB; +import net.nuclearteam.createnuclear.CNItems; import org.jetbrains.annotations.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -393,7 +394,7 @@ public boolean isSteppingCarefully() { } static { - TEMPT_INGREDIENT = Ingredient.of(new ItemLike[]{Items.COD, Items.SALMON}); + TEMPT_INGREDIENT = Ingredient.of(new ItemLike[]{Items.COD, Items.SALMON, CNItems.YELLOWCAKE}); IS_LYING = SynchedEntityData.defineId(IrradiatedCat.class, EntityDataSerializers.BOOLEAN); RELAX_STATE_ONE = SynchedEntityData.defineId(IrradiatedCat.class, EntityDataSerializers.BOOLEAN); DATA_COLLAR_COLOR = SynchedEntityData.defineId(IrradiatedCat.class, EntityDataSerializers.INT); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java index 4afec54a..4d94340e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java @@ -30,6 +30,7 @@ import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.phys.Vec3; import net.nuclearteam.createnuclear.CNEntityType; +import net.nuclearteam.createnuclear.CNItems; import net.nuclearteam.createnuclear.content.contraptions.irradiated.AnimalUtil; import net.nuclearteam.createnuclear.content.contraptions.irradiated.IrradiatedAnimal; import org.jetbrains.annotations.Nullable; @@ -42,7 +43,8 @@ public class IrradiatedChicken extends Animal implements IrradiatedAnimal { private static final Ingredient FOOD_ITEMS = Ingredient.of( Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, - Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD + Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD, + CNItems.YELLOWCAKE ); public float flap; public float flapSpeed; @@ -154,6 +156,7 @@ public IrradiatedChicken getBreedOffspring(ServerLevel level, AgeableMob otherPa @Override public boolean isFood(ItemStack stack) { + // Check if the stack is a valid Yellowcake or the base food return AnimalUtil.isFood(stack, FOOD_ITEMS); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cow/IrradiatedCow.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cow/IrradiatedCow.java index 18c6b4b7..b8a6c878 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cow/IrradiatedCow.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cow/IrradiatedCow.java @@ -20,6 +20,8 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.nuclearteam.createnuclear.CNEntityType; +import net.nuclearteam.createnuclear.CNItems; +import net.nuclearteam.createnuclear.content.contraptions.irradiated.AnimalUtil; import javax.annotation.Nullable; @@ -39,6 +41,15 @@ protected void registerGoals() { this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); } + // Define the base food of the animal (e.g., Wheat for Cows) + private static final Ingredient FOOD_ITEMS = Ingredient.of(CNItems.YELLOWCAKE); + + @Override + public boolean isFood(ItemStack stack) { + // Check if the stack is a valid Yellowcake or the base food + return AnimalUtil.isFood(stack, FOOD_ITEMS); + } + public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.MOVEMENT_SPEED, (double)0.2F); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWolf.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWolf.java index 1f62b103..3f9254cc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWolf.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWolf.java @@ -36,6 +36,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.state.BlockState; @@ -44,6 +45,7 @@ import net.minecraft.world.phys.Vec3; import net.nuclearteam.createnuclear.CNEntityType; import net.nuclearteam.createnuclear.CNItems; +import net.nuclearteam.createnuclear.content.contraptions.irradiated.AnimalUtil; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; @@ -340,10 +342,13 @@ public float getTailAngle() { return this.isTame() ? (0.55F - (this.getMaxHealth() - this.getHealth()) * 0.02F) * 3.1415927F : 0.62831855F; } } + // Define the base food of the animal (e.g., Wheat for Cows) + private static final Ingredient FOOD_ITEMS = Ingredient.of(CNItems.YELLOWCAKE); + @Override public boolean isFood(ItemStack stack) { - //Item item = stack.getItem(); - return stack.is(CNItems.YELLOWCAKE.asItem());//stack.is(CNItems.URANIUM_POWDER.get()); //item.isEdible() && item.getFoodProperties().isMeat(); + // Check if the stack is a valid Yellowcake or the base food + return AnimalUtil.isFood(stack, FOOD_ITEMS); } public int getMaxSpawnClusterSize() { From c918e385f074da5172568ca7ea5ee8d56b414464 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Thu, 18 Jun 2026 15:37:09 +0200 Subject: [PATCH 043/171] refactor: add tooltip summary for thorium rod and improve fluid input handling in reactor controller --- AUDIT_ACTUEL.md | 5 +- .../controller/ReactorControllerBlock.java | 5 +- .../ReactorControllerBlockEntity.java | 22 +++---- .../input/fluid/FluidLockManager.java | 38 ------------ .../input/fluid/ReactorFluidInputEntity.java | 62 ++++++++----------- .../createnuclear/lang/default/tooltips.json | 2 - 6 files changed, 38 insertions(+), 96 deletions(-) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/FluidLockManager.java diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index cf7251ce..58c826b5 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -18,9 +18,8 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh |---|---|---|---| | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | | **B12** | `content/contraptions/irradiated/AnimalUtil.java:72-81` | **Toujours présent** | `isFood` ne reconnaît la yellowcake comme aliment **que** si elle porte un tag NBT `"Ingredient"` — incohérent avec `mobInteract` (ligne ~39) qui accepte *toute* yellowcake pour la conversion. Le chemin "food" (élevage/soin) reste cassé pour la yellowcake sans tag. | -| **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | +| ~~**B14**~~ | `content/multiblock/input/fluid/` | **✅ Corrigé** | `FluidLockManager` (map statique sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks`) supprimé. Toute la logique de verrou passe désormais par `PersistentFluidLocks` (par-niveau, persistant) côté serveur ; le client est permissif. Bug lié corrigé : casser un input fluide réévalue le verrou via `clearLockIfAllInputsEmpty()`, ce qui permet de changer de fluide après remplacement de l'input. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | -| ~~**B19**~~ | `infrastructure/worldgen/biome/surfacerule/IrradiatedSurfaceRules.java` | **✅ Corrigé** | Condition morte `IS_HIGHLANDS = biome()` (toujours faux) et ses branches mortes supprimées ; constante inutilisée `MOON_DIRT` retirée ; constantes `LEAD_ROCK`/`LEAD_TURF`/`RAW_LEAD_BASALT` renommées en `LEAD_BLOCK`/`LEAD_ORE`/`RAW_LEAD_BLOCK` (alignées sur les blocs réels). Sans changement de comportement sur le seul biome existant (`Irradiated.PLAIN`). | ### Bugs mineurs confirmés toujours présents (liste condensée) - `ReactorInputFluidManager.extractFluids/getBlocksPosition` : toujours `getFluidInTank(getTanks())` (off-by-one), `fluidNeeded` jamais décrémenté, `toExtract>1` ignore les extractions de 1 unité. @@ -130,7 +129,7 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. 10. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** - `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. Même si les surface rules (B19) sont désormais corrigées, le pipeline worldgen "irradié" reste un **template non terminé/non re-thémé** sur ces autres points, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). + `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. le pipeline worldgen "irradié" reste un **template non terminé/non re-thémé** sur ces autres points, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). 11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — point d'alerte non couvert par `AUDIT_V1.md`, indépendant des surface rules (B19, désormais corrigées). diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index a470b894..0823ad6e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -26,7 +26,6 @@ import net.nuclearteam.createnuclear.*; import net.nuclearteam.createnuclear.content.multiblock.IHeat; import net.nuclearteam.createnuclear.content.multiblock.ReactorAssembler; -import net.nuclearteam.createnuclear.content.multiblock.input.fluid.FluidLockManager; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; @@ -139,9 +138,9 @@ public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState n withBlockEntityDo(worldIn, pos, be -> ItemHelper.dropContents(worldIn, pos, be.getInventoryObject())); worldIn.removeBlockEntity(pos); - if (!worldIn.isClientSide && worldIn instanceof ServerLevel serverLevel) { + if (worldIn instanceof ServerLevel serverLevel) { PersistentFluidLocks.get(serverLevel).clearLock(pos); - } else FluidLockManager.clearLock(pos); + } if (!state.getValue(ASSEMBLED)) return; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 0941c31d..6869f368 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -33,7 +33,6 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.service.*; import net.nuclearteam.createnuclear.content.multiblock.controller.snapshot.ReactorInputSnapshot; import net.nuclearteam.createnuclear.content.multiblock.controller.snapshot.ReactorInputSnapshotBuilder; -import net.nuclearteam.createnuclear.content.multiblock.input.fluid.FluidLockManager; import net.nuclearteam.createnuclear.content.multiblock.IHeat; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutput; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; @@ -625,34 +624,31 @@ public void removeIOAll() { /** Try to lock this controller to the given Fluid. Returns true if allowed. */ public boolean tryLockFluid(Fluid fluid) { - // server-persistent approach (preferred): use PersistentFluidLocks when on - // server - if (level != null && !level.isClientSide && level instanceof ServerLevel serverLevel) { + // Fluid locks are server-authoritative and persisted per-level via PersistentFluidLocks. + // On the client there is no lock to enforce, so stay permissive. + if (level instanceof ServerLevel serverLevel) { return PersistentFluidLocks.get(serverLevel).tryLock(getBlockPos(), fluid); } - // fallback to in-memory manager (single-server-run) - return FluidLockManager.tryLock(getBlockPos(), fluid); + return true; } /** Returns whether the given FluidStack is acceptable for this controller. */ public boolean canAcceptFluid(FluidStack stack) { if (stack == null || stack.isEmpty()) return true; - if (level != null && !level.isClientSide && level instanceof ServerLevel serverLevel) { + if (level instanceof ServerLevel serverLevel) { return PersistentFluidLocks.get(serverLevel).canAccept(getBlockPos(), stack.getFluid()); } - return FluidLockManager.canAccept(getBlockPos(), stack); + return true; } /** Force-clear the lock on this controller. */ public void clearLock() { - if (level != null && !level.isClientSide && level instanceof ServerLevel serverLevel) { + if (level instanceof ServerLevel serverLevel) { PersistentFluidLocks.get(serverLevel).clearLock(getBlockPos()); - } else { - FluidLockManager.clearLock(getBlockPos()); + setChanged(); + sendData(); } - setChanged(); - sendData(); } public void clearLockIfAllInputsEmpty() { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/FluidLockManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/FluidLockManager.java deleted file mode 100644 index 763b8e61..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/FluidLockManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.nuclearteam.createnuclear.content.multiblock.input.fluid; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.fluids.FluidStack; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * In-memory manager for ephemeral fluid locks on multiblock controllers. - * This class provides simple concurrent lock semantics to ensure a controller - * accepts only a single fluid type while a lock is held. - */ -public class FluidLockManager { - private static final Map locks = new ConcurrentHashMap<>(); - - public static boolean tryLock(BlockPos controllerPos, Fluid fluid) { - if (fluid == null) return true; - // Attempt to set the lock to the specified fluid if none exists - return locks.compute(controllerPos, (k,v) -> v == null ? fluid : v) == fluid; - } - - public static boolean canAccept(BlockPos controllerPos, FluidStack stack) { - if (stack == null || stack.isEmpty()) return true; - // True if no fluid locked or the locked fluid matches the stack - Fluid locked = locks.get(controllerPos); - return locked == null || locked == stack.getFluid(); - } - - public static void clearLock(BlockPos controller) { - locks.remove(controller); - } - - public static Fluid getLockedFluid(BlockPos controller) { - return locks.get(controller); - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java index 3489ff81..dadd16c3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java @@ -177,20 +177,16 @@ public int fill(FluidStack resource, FluidAction action) { ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(level, worldPosition); BlockPos controllerPos = controller != null ? controller.getBlockPos() : null; - if (controllerPos != null && level instanceof ServerLevel serverLevel) { - PersistentFluidLocks lock = PersistentFluidLocks.get(serverLevel); - if (!lock.canAccept(controllerPos, resource.getFluid())) return 0; - } else if (controllerPos != null) { - if (!FluidLockManager.canAccept(controllerPos, resource)) return 0; + // Fluid locks are server-authoritative (persisted per-level via PersistentFluidLocks). + // The client stays permissive; the server syncs the real tank state back. + if (controllerPos != null && level instanceof ServerLevel serverLevel + && !PersistentFluidLocks.get(serverLevel).canAccept(controllerPos, resource.getFluid())) { + return 0; } int filled = delegate.fill(resource, action); - if (filled > 0 && action.execute() && controllerPos != null ){ - if (level instanceof ServerLevel serverLevel) { - PersistentFluidLocks.get(serverLevel).tryLock(controllerPos, resource.getFluid()); - } else { - FluidLockManager.tryLock(controllerPos, resource.getFluid()); - } + if (filled > 0 && action.execute() && controllerPos != null && level instanceof ServerLevel serverLevel) { + PersistentFluidLocks.get(serverLevel).tryLock(controllerPos, resource.getFluid()); } return filled; } @@ -198,39 +194,31 @@ public int fill(FluidStack resource, FluidAction action) { @Override public @NotNull FluidStack drain(FluidStack resource, FluidAction action) { FluidStack drained = delegate.drain(resource, action); - if (!drained.isEmpty() && action.execute()) { - ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(level, worldPosition); - if (controller != null) { - BlockPos controllerPos = controller.getBlockPos(); - if (delegate.getFluidInTank(0).isEmpty()) { - if (level instanceof ServerLevel serverLevel) { - PersistentFluidLocks.get(serverLevel).clearLock(controllerPos); - } else { - FluidLockManager.clearLock(controllerPos); - } - } - } - } + clearLockIfEmptied(drained, action); return drained; } @Override public @NotNull FluidStack drain(int maxDrain, FluidAction action) { FluidStack drained = delegate.drain(maxDrain, action); - if (!drained.isEmpty() && action.execute()) { - ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(level, worldPosition); - if (controller != null) { - BlockPos controllerPos = controller.getBlockPos(); - if (delegate.getFluidInTank(0).isEmpty()) { - if (level instanceof ServerLevel serverLevel) { - PersistentFluidLocks.get(serverLevel).clearLock(controllerPos); - } else { - FluidLockManager.clearLock(controllerPos); - } - } - } - } + clearLockIfEmptied(drained, action); return drained; } + + /** + * Releases the controller's fluid lock once this input has been fully drained. + * Server-authoritative: the lock lives in {@link PersistentFluidLocks}, so this is + * a no-op on the client. + */ + private void clearLockIfEmptied(FluidStack drained, FluidAction action) { + if (drained.isEmpty() || !action.execute() || !(level instanceof ServerLevel serverLevel)) + return; + if (!delegate.getFluidInTank(0).isEmpty()) + return; + + ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(level, worldPosition); + if (controller != null) + PersistentFluidLocks.get(serverLevel).clearLock(controller.getBlockPos()); + } } } diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index 36d781f2..65c91739 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -35,8 +35,6 @@ "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", - "item.createnuclear.thorium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", - "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and fuel rods", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour1": "_Right_ click to fill it.", From 6c6e5127bae92cbe8eb8fffaefd1815b38efaf4a Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Thu, 18 Jun 2026 15:42:28 +0200 Subject: [PATCH 044/171] update AUDIT_ACTUEL.md --- AUDIT_ACTUEL.md | 1 - 1 file changed, 1 deletion(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 3997bfa2..a1df20fd 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -17,7 +17,6 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| | **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | -| **B14** | `content/multiblock/input/fluid/FluidLockManager.java` | **Toujours présent** | `Map` statique, sans clé de dimension, jamais purgée, doublon de `PersistentFluidLocks` ; toujours appelé depuis `clearLockIfAllInputsEmpty()` et `ReactorFluidInputEntity.FilteredFluidHandler`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | ### Bugs mineurs confirmés toujours présents (liste condensée) From 138e5312ba605e11c5b5b37acc086372503bb6a4 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:01:38 +0200 Subject: [PATCH 045/171] update AUDIT_ACTUEL.md --- AUDIT_ACTUEL.md | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index a1df20fd..144fec36 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -16,7 +16,6 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | Réf. | Fichier:ligne | État | Détail | |---|---|---|---| -| **B6** | `content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java` / `ReactorBluePrintItemPacket.java` | **Toujours présent** | Le 6ᵉ argument du packet duplique le 5ᵉ (uranium perdu) ; `coef=0.1F` envoyé à la place de `heat`. | | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | ### Bugs mineurs confirmés toujours présents (liste condensée) @@ -34,10 +33,10 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh Restant (grep global, zéro référence externe sauf mention) : -- **Méthodes d'animation mortes restantes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` : `chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `setRotateAngle`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`/`movementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`. Mortes mais **non triviales** : leur retrait déclenche une cascade dans des classes **vivantes** (ex. `CNAdvancedModelBox.calculateRotation`/`bob` appellent `model.getMovementScale()`). À traiter en nettoyage dédié + dédup `ModelBox`. -- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §3 points 5 & 6 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). -- **`SimpleMultiBlockPattern.test()`** : à vérifier — la classe ne semble plus exister (à confirmer/retirer si résidu). -- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §3 point 10, worldgen "irradié" template non terminé). +- **Méthodes d'animation mortes restantes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` : `chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`/`movementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`. Mortes mais **non triviales** : leur retrait déclenche une cascade dans des classes **vivantes** (ex. `CNAdvancedModelBox.calculateRotation`/`bob` appellent `model.getMovementScale()`). À traiter en nettoyage dédié + dédup `ModelBox`. **⚠️ `setRotateAngle` n'est PAS mort** : appelé ~10× par `NuclearMushroomCloudModel` (sous-classe vivante) — à conserver. +- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §3 points 4 & 5 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). +- **`SimpleMultiBlockPattern.test()`** : classe et méthode **toujours présentes** (`lib/multiblock/SimpleMultiBlockPattern.java:72`), instanciée via `IMultiBlockPatternBuilder` mais `test()` n'a **aucun appelant** — dead code résiduel à retirer. +- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §3 point 9, worldgen "irradié" template non terminé). --- @@ -47,20 +46,16 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — ### 🔴 Critiques / Majeurs -1. **`ReactorCasingEntity.setController` — offset `+4/+4` codé en dur, appliqué inconditionnellement** - `controller = new BlockPos(pos.getX()+4, pos.getY(), pos.getZ()+4)` est correct **uniquement** pour le pattern 9×9 (T3, rayon 4). Pour T1 (5×5, rayon 2) et T2 (7×7, rayon 3), le champ pointe vers un bloc erroné. `AUDIT_V1.md` classait ce champ en "dead code à supprimer" (offset magique) ; en l'état c'est en plus un **bug latent** si quiconque consomme `getController()` à l'avenir sur un réacteur T1/T2. - *Gravité* : Majeur (latent, dépend de l'usage futur). *Recommandation* : supprimer le champ (toujours non lu en pratique) ou le calculer depuis la taille réelle assemblée. - -2. **`IrradiatedCatCollarLayer` / `IrradiatedWoldCollarLayer` — feature de teinture de collier non câblée** +1. **`IrradiatedCatCollarLayer` / `IrradiatedWoldCollarLayer` — feature de teinture de collier non câblée** `IrradiatedWoldCollarLayer.render()` est un corps **vide** ; `IrradiatedCatCollarLayer` (implémentation complète) n'est **jamais ajouté** via `addLayer(...)` au renderer. Pourtant `IrradiatedCat` câble entièrement l'interaction `DyeItem` → `setCollarColor`/`getCollarColor` (`IrradiatedCat.java:333-342`). `IrradiatedWolf` contient même des lignes commentées (`DATA_COLLAR_COLOR`) montrant une tentative abandonnée. *Conséquence* : un joueur peut teindre le collier d'un chat/loup irradié apprivoisé, l'action est acceptée, mais **rien ne s'affiche jamais** — feature visible cassée, non documentée dans `AUDIT_V1.md` (qui ne couvrait pas `content/contraptions/irradiated/{cat,wolf,cow}`). *Recommandation* : enregistrer `IrradiatedCatCollarLayer` dans le renderer du chat, implémenter `IrradiatedWoldCollarLayer.render`, ou retirer toute la mécanique `setCollarColor`/interaction `DyeItem` si hors scope. -3. **`AntiRadiationArmorItem.getArmorTexture` — hook mort en Forge 1.20.1** +2. **`AntiRadiationArmorItem.getArmorTexture` — hook mort en Forge 1.20.1** L'override `getArmorTexture(ItemStack, Entity, EquipmentSlot, String)` (renvoyant un chemin de texture par couleur de tissu via `ClothTagHelper.getArmorTexturePath`) **n'est plus appelé par Forge 47.2.x** — ce hook a été retiré depuis longtemps ; le rendu passe désormais exclusivement par `IClientItemExtensions`/`AntiRadiationArmorClientExtensions`, qui n'utilise jamais la couleur de tissu. Conséquence : toute la mécanique `ClothTagHelper`/`SmithingTransformRecipeMixin` (NBT `ClothColor`) n'a **aucun effet visuel** — teindre l'armure anti-radiation via tissu ne change rien à son apparence. C'est un **bug de fonctionnalité silencieuse**, distinct de B13 (qui concerne la visibilité des bras), non couvert par `AUDIT_V1.md`. *Recommandation* : implémenter la sélection de texture colorée dans `AntiRadiationArmorClientExtensions`/`AntiRadiationArmorModel`, ou retirer `getArmorTexture` + `ClothTagHelper.getArmorTexturePath` (et documenter que la teinture de tissu est cosmétiquement inerte). -4. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** +3. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes — mais selon deux sémantiques *différentes*, à ne pas fusionner : - `RadiationEffect` (filtre de contagion de proximité, constructeur lignes 32-52) applique un **gate binaire** (immune tag, config, blacklist, spectateur, `résistance ≥ 1`) — mais ce gate est enfermé dans un lambda non réutilisable, et **reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque appel** (cf. §4 point 5 / §5) — perf non corrigée en plus du problème de duplication. @@ -109,34 +104,33 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — Utilisé en garde dans `RadiationEffectHandler.apply` (corrige le bug) et comme `filter` de `RadiationEffect` (remplace le lambda dupliqué, supprime la reconstruction de `HashSet` par tick/entité). `RadiationCapability.applyEffects` garde son atténuation continue propre, mais gagne un garde-fou minimal absent aujourd'hui : `if (player.isSpectator()) return;`. -5. **Deux overlays de "vision irradiée" actifs en parallèle** +4. **Deux overlays de "vision irradiée" actifs en parallèle** `IrradiatedOverlayRendererVision` (actif) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT_V1.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). -6. **`RenderHelper.renderTextureOverlay` — `Math.round(alpha*coverage)` annule le fade** - `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT_V1.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 5). +5. **`RenderHelper.renderTextureOverlay` — `Math.round(alpha*coverage)` annule le fade** + `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT_V1.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 4). ### 🟠 Importants -7. **`RadiationCapability.lastBiomeLocation` — non persisté** +6. **`RadiationCapability.lastBiomeLocation` — non persisté** `lastBiomeLocation` **est bien lu pour une décision** (`RadiationCapability:89`, comparaison `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`) — ce n'est donc **pas** du dead code. Le point restant : `RadiationProvider.serializeNBT` ne le persiste pas → l'état est perdu au save/déconnexion (bug mineur, à corriger ou assumer). -8. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** +7. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT_V1.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. -9. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** +8. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. -10. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** +9. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. le pipeline worldgen "irradié" reste un **template non terminé/non re-thémé** sur ces autres points, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). -11. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — point d'alerte non couvert par `AUDIT_V1.md`, indépendant des surface rules (B19, désormais corrigées). +10. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — point d'alerte non couvert par `AUDIT_V1.md`, indépendant des surface rules (B19, désormais corrigées). ### 🟡 Mineurs -12. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). -13. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 5 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. -14. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. -15. **`ReactorBluePrintItemPacket.totalInit`** : champ `static double` partagé, lu dans `calculatePostgres()` avant d'être écrit par `write()` côté émission — état global non thread-safe, partiellement lié à B6 mais distinct. +11. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). +12. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. +13. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. --- @@ -147,7 +141,7 @@ Les 5 problèmes structurels de `AUDIT_V1.md` §1 restent **tous valides** : 1. **Inversion `api/`** : `api.multiblock.MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` dépendent toujours de `content.*` — confirmé. 2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, verrous fluides (`tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty`, ~65 lignes), rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT_V1.md`. 3. **Deux frameworks multiblock concurrents** : le ménage a réduit `lib/multiblock` (suppression de `MultiBlockManager`/`MultiBlockCache`/`IBetterPattern`), mais **trois couches coexistent toujours** pour la détection de contrôleur — `lib/multiblock` (matching générique), `api.multiblock.MultiBlockManagerBeta` (vérification de structure), et `content.multiblock.pattern.ReactorPattern`/`MultiblockHelpers` (scan géométrique brut, ~3971 blocs, **toujours** appelé en double — `findController` + `findControllerPos` — à chaque pose/casse, y compris côté client sans garde `isClientSide`). C'est le point de performance/architecture le plus critique et **entièrement non corrigé**. -4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (§3 point 4) découvert dans cette analyse. +4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (§3 point 3) découvert dans cette analyse. 5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, `AUDIT_V1.md` §4 ligne 2). --- @@ -175,6 +169,6 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : **Nettoyage dead-code restant** : - Méthodes d'animation mortes restantes dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` + dédup `ModelBox` (cascade dans classes vivantes — nettoyage dédié). -- `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §3 points 5 & 6). +- `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §3 points 4 & 5). - `IrradiatedBiomes.monsters()` no-op et reliquat éventuel `SimpleMultiBlockPattern.test()`. - Features à finir ou supprimer (pas du pur dead code, décision produit) : `IrradiatedWoldCollarLayer`/`IrradiatedCatCollarLayer`, `AntiRadiationArmorItem.getArmorTexture`/`ClothTagHelper.getArmorTexturePath`. From 2e850c222bf08558c733b946acf80efec19818ef Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Thu, 18 Jun 2026 16:06:02 +0200 Subject: [PATCH 046/171] bug fix -> heat was displayed when the reactor was not assembled --- .../controller/ReactorControllerBlockEntity.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 6869f368..f36dabb9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -387,8 +387,6 @@ public void tick() { totalHeatRatio = this.getConfiguredPatternTag().getInt("totalHeatRatio"); } resolveEntitiesIfNeeded(); - if (!isAssembled()) - return; ReactorInputSnapshot snapshot = ReactorInputSnapshotBuilder.build(level, inputManager, inputFluidManager); this.displayState = new ReactorDisplayState(snapshot.items(), snapshot.fluids(), snapshot.maxFluidCapacity()); @@ -482,7 +480,7 @@ private void handleAssembledState() { } private boolean isReadyToRun() { - if (isEmptyConfiguredPattern() || this.inputFluidManager.size() == 0) { + if (isEmptyConfiguredPattern() || this.inputFluidManager.size() == 0 || !isAssembled()) { return false; } @@ -513,12 +511,12 @@ private void updateHeatOnly() { // Guard against empty fluid list — HeatManager accepts null for empty/no-fluid // case BigFluidStack fluid = bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); - double heat = 0; + heat = 0; - if (!isEmptyConfiguredPattern()) { - heat = heatService.calculateHeat(fluid, totalHeatRatio, inventory, level); - this.getConfiguredPatternTag().putDouble("heat", heat); + if (!isEmptyConfiguredPattern() && isAssembled()) { + heat = (int) heatService.calculateHeat(fluid, totalHeatRatio, inventory, level); } + this.getConfiguredPatternTag().putDouble("heat", heat); } private boolean isEmptyConfiguredPattern() { From c2b6842416be25ea9732b901e49586b66f89e919 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Thu, 18 Jun 2026 20:09:30 +0200 Subject: [PATCH 047/171] refactor: tidy supplier usage and imports across rod/display sources Replace lambda-wrapped supplier calls (() -> Config.field.get()) with direct method references (Config.field::get) in CNItems for the graphite, uranium and thorium rod definitions, and switch RodType to import java.util.function.Supplier instead of repeating its fully qualified name everywhere. Also clean up CoolerDisplaySource and ReactorSummaryDisplaySource: import Item, Map.Entry and RodType.TypeRodPredicate so loops and predicate checks no longer use fully qualified names, and collapse a few single-statement lambda blocks in ReactorSummaryDisplaySource into expression lambdas. No behavioral change. --- .../nuclearteam/createnuclear/CNItems.java | 20 +++++++------- .../api/multiblock/rods/RodType.java | 26 +++++++++---------- .../source/CoolerDisplaySource.java | 8 ++++-- .../source/ReactorSummaryDisplaySource.java | 13 ++++------ 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 94594e37..08fe9f1c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -123,10 +123,10 @@ public class CNItems { GRAPHITE_ROD = CreateNuclear.REGISTRATE .item("graphite_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueGraphite.get()) + .dynamicBaseRodHeat(CNConfigs.server().rods.baseValueGraphite::get) .dynamicProximityRodHeat(() -> CNConfigs.server().rods.graphiteProxyMalus.getF()) - .dynamicRodTimer(() -> CNConfigs.server().rods.graphiteRodLifetime.get()) - .dynamicHeatRatio(() -> CNConfigs.server().rods.graphiteHeatRatio.get()) + .dynamicRodTimer(CNConfigs.server().rods.graphiteRodLifetime::get) + .dynamicHeatRatio(CNConfigs.server().rods.graphiteHeatRatio::get) .coolerRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.COOLER.tag) .register(), @@ -166,10 +166,10 @@ public class CNItems { URANIUM_ROD = CreateNuclear.REGISTRATE .item("uranium_rod", p -> new RadiationItem(p, 100)) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueUranium.get()) - .dynamicProximityRodHeat(() -> (float) CNConfigs.server().rods.uraniumProxyBonus.get()) - .dynamicRodTimer(() -> CNConfigs.server().rods.uraniumRodLifetime.get()) - .dynamicHeatRatio(() -> CNConfigs.server().rods.uraniumHeatRatio.get()) + .dynamicBaseRodHeat(CNConfigs.server().rods.baseValueUranium::get) + .dynamicProximityRodHeat(() ->(float) CNConfigs.server().rods.uraniumProxyBonus.get()) + .dynamicRodTimer(CNConfigs.server().rods.uraniumRodLifetime::get) + .dynamicHeatRatio(CNConfigs.server().rods.uraniumHeatRatio::get) .fuelRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.FUEL.tag) .register(), @@ -213,10 +213,10 @@ public class CNItems { THORIUM_ROD = CreateNuclear.REGISTRATE .item("thorium_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueThorium.get()) + .dynamicBaseRodHeat(CNConfigs.server().rods.baseValueThorium::get) .dynamicProximityRodHeat(() -> (float) CNConfigs.server().rods.thoriumProxyBonus.get()) - .dynamicRodTimer(() -> CNConfigs.server().rods.thoriumRodLifetime.get()) - .dynamicHeatRatio(() -> CNConfigs.server().rods.thoriumHeatRatio.get()) + .dynamicRodTimer(CNConfigs.server().rods.thoriumRodLifetime::get) + .dynamicHeatRatio(CNConfigs.server().rods.thoriumHeatRatio::get) .fuelRodType())) .tag(CNTags.forgeItemTag("rods")) .register() diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java index c97a35b9..1133180d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java @@ -17,13 +17,13 @@ import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; -import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; +import java.util.function.Supplier; /** * Represents a rod type used by the mod's multiblock. @@ -36,11 +36,11 @@ public record RodType(HolderSet items, int baseRodHeatStatic, float proximityRodHeatStatic, int rodTimerStatic, TypeRod type, - java.util.function.Supplier baseRodHeatSupplier, - java.util.function.Supplier proximityRodHeatSupplier, - java.util.function.Supplier rodTimerSupplier, + Supplier baseRodHeatSupplier, + Supplier proximityRodHeatSupplier, + Supplier rodTimerSupplier, int heatRatioStatic, - java.util.function.Supplier heatRatioSupplier) { + Supplier heatRatioSupplier) { public RodType(HolderSet items, int baseRodHeat, float proximityRodHeat, @@ -128,10 +128,10 @@ public static class Builder { private int heatRatio = 1; private TypeRod type = TypeRod.FUEL; - private java.util.function.Supplier baseRodHeatSupplier = null; - private java.util.function.Supplier proximityRodHeatSupplier = null; - private java.util.function.Supplier rodTimerSupplier = null; - private java.util.function.Supplier heatRatioSupplier = null; + private Supplier baseRodHeatSupplier = null; + private Supplier proximityRodHeatSupplier = null; + private Supplier rodTimerSupplier = null; + private Supplier heatRatioSupplier = null; private boolean itemsSet = false; private boolean baseRodHeatSet = false; @@ -182,22 +182,22 @@ public Builder heatRatio(int heatRatio) { return this; } - public Builder dynamicBaseRodHeat(java.util.function.Supplier supplier) { + public Builder dynamicBaseRodHeat(Supplier supplier) { this.baseRodHeatSupplier = supplier; return this; } - public Builder dynamicProximityRodHeat(java.util.function.Supplier supplier) { + public Builder dynamicProximityRodHeat(Supplier supplier) { this.proximityRodHeatSupplier = supplier; return this; } - public Builder dynamicRodTimer(java.util.function.Supplier supplier) { + public Builder dynamicRodTimer(Supplier supplier) { this.rodTimerSupplier = supplier; return this; } - public Builder dynamicHeatRatio(java.util.function.Supplier supplier) { + public Builder dynamicHeatRatio(Supplier supplier) { this.heatRatioSupplier = supplier; return this; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java index f18c45f6..8c2844b6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java @@ -8,12 +8,16 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.util.Mth; +import net.minecraft.world.item.Item; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; +import java.util.Map.Entry; + public class CoolerDisplaySource extends NumericSingleLineDisplaySource { @Override @@ -27,8 +31,8 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget int mode = context.sourceConfig().getInt("display_mode"); int cooler = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { - for (var entry : controller.getDisplayState().items().entrySet()) { - if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { + for (Entry entry : controller.getDisplayState().items().entrySet()) { + if (TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { cooler += entry.getValue(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index 242b5159..8cc4ca84 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -18,6 +18,7 @@ import net.minecraft.world.level.block.entity.LecternBlockEntity; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.content.multiblock.IHeat; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; @@ -53,15 +54,11 @@ public List provideText(DisplayLinkContext context, DisplayTar } if (context.getTargetBlockEntity() instanceof LecternBlockEntity) { - Stream componentList = components.stream().map(list -> { - return list.stream().reduce(MutableComponent::append).orElse(EMPTY_LINE); - }); + Stream componentList = components.stream().map(list -> list.stream().reduce(MutableComponent::append).orElse(EMPTY_LINE)); return List.of(componentList.reduce((c1, c2) -> c1.append(Component.literal("\n")).append(c2)).orElse(EMPTY_LINE)); } - return components.stream().map(list -> { - return list.stream().reduce(MutableComponent::append).orElse(EMPTY_LINE); - }).toList(); + return components.stream().map(list -> list.stream().reduce(MutableComponent::append).orElse(EMPTY_LINE)).toList(); } @Override @@ -126,9 +123,9 @@ private Stream> getComponents(DisplayLinkContext context, int cooler = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { for (var entry : controller.getDisplayState().items().entrySet()) { - if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { + if (TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { fuel += entry.getValue(); - } else if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { + } else if (TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { cooler += entry.getValue(); } } From 5d4d518e9089bcdb9f1cda18e7283f56641f5a34 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Thu, 18 Jun 2026 20:21:42 +0200 Subject: [PATCH 048/171] style: revert rod config suppliers back to lambda form Switch the dynamicBaseRodHeat/dynamicRodTimer/dynamicHeatRatio suppliers for the graphite, uranium and thorium rods back to () -> Config.field.get() lambdas instead of method references, for consistency with the dynamicProximityRodHeat suppliers in the same blocks which can't be method references (they cast to float). No behavioral change. --- .../net/nuclearteam/createnuclear/CNItems.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 08fe9f1c..ec632bb6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -123,10 +123,10 @@ public class CNItems { GRAPHITE_ROD = CreateNuclear.REGISTRATE .item("graphite_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(CNConfigs.server().rods.baseValueGraphite::get) + .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueGraphite.get()) .dynamicProximityRodHeat(() -> CNConfigs.server().rods.graphiteProxyMalus.getF()) - .dynamicRodTimer(CNConfigs.server().rods.graphiteRodLifetime::get) - .dynamicHeatRatio(CNConfigs.server().rods.graphiteHeatRatio::get) + .dynamicRodTimer(() -> CNConfigs.server().rods.graphiteRodLifetime.get()) + .dynamicHeatRatio(() -> CNConfigs.server().rods.graphiteHeatRatio.get()) .coolerRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.COOLER.tag) .register(), @@ -166,10 +166,10 @@ public class CNItems { URANIUM_ROD = CreateNuclear.REGISTRATE .item("uranium_rod", p -> new RadiationItem(p, 100)) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(CNConfigs.server().rods.baseValueUranium::get) + .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueUranium.get()) .dynamicProximityRodHeat(() ->(float) CNConfigs.server().rods.uraniumProxyBonus.get()) - .dynamicRodTimer(CNConfigs.server().rods.uraniumRodLifetime::get) - .dynamicHeatRatio(CNConfigs.server().rods.uraniumHeatRatio::get) + .dynamicRodTimer(() -> CNConfigs.server().rods.uraniumRodLifetime.get()) + .dynamicHeatRatio(() -> CNConfigs.server().rods.uraniumHeatRatio.get()) .fuelRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.FUEL.tag) .register(), @@ -213,10 +213,10 @@ public class CNItems { THORIUM_ROD = CreateNuclear.REGISTRATE .item("thorium_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(CNConfigs.server().rods.baseValueThorium::get) + .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueThorium.get()) .dynamicProximityRodHeat(() -> (float) CNConfigs.server().rods.thoriumProxyBonus.get()) - .dynamicRodTimer(CNConfigs.server().rods.thoriumRodLifetime::get) - .dynamicHeatRatio(CNConfigs.server().rods.thoriumHeatRatio::get) + .dynamicRodTimer(() -> CNConfigs.server().rods.thoriumRodLifetime.get()) + .dynamicHeatRatio(() -> CNConfigs.server().rods.thoriumHeatRatio.get()) .fuelRodType())) .tag(CNTags.forgeItemTag("rods")) .register() From 7f4c5ab282c6626bedc8ef875648ac0a183d9ef7 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Fri, 19 Jun 2026 15:35:05 +0200 Subject: [PATCH 049/171] update generated files --- .../.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +++--- .../resources/assets/createnuclear/lang/en_ud.json | 2 +- .../resources/assets/createnuclear/lang/en_us.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 2675920d..227937c5 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-18T15:15:36.5756646 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-19T15:18:15.7026492 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -3d30656e80750c81fdfd19d185c1360dbb161896 assets/createnuclear/lang/en_ud.json -8182be2346cc4335f8883f6faba0005635287e9f assets/createnuclear/lang/en_us.json +26990b3ec54124883f51fb76a53a2a4e35f10fd8 assets/createnuclear/lang/en_ud.json +680975276a1de4d538564e9303287944ce0994b0 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index d2283c6d..eade1d6a 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -364,7 +364,7 @@ "item.createnuclear.thorium_ingot": "ʇobuI ɯnıɹoɥ⟘", "item.createnuclear.thorium_nugget": "ʇǝbbnN ɯnıɹoɥ⟘", "item.createnuclear.thorium_rod": "poᴚ ɯnıɹoɥ⟘", - "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾ʞɔıʇS‾", + "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.uranium_bucket": "ʇǝʞɔnᗺ ɯnıuɐɹ∩", "item.createnuclear.uranium_powder": "ɹǝpʍoԀ ɯnıuɐɹ∩", "item.createnuclear.uranium_rod": "poᴚ ɯnıuɐɹ∩", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 893c5446..36487612 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -364,7 +364,7 @@ "item.createnuclear.thorium_ingot": "Thorium Ingot", "item.createnuclear.thorium_nugget": "Thorium Nugget", "item.createnuclear.thorium_rod": "Thorium Rod", - "item.createnuclear.thorium_rod.tooltip.summary": "_Stick_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", "item.createnuclear.uranium_bucket": "Uranium Bucket", "item.createnuclear.uranium_powder": "Uranium Powder", "item.createnuclear.uranium_rod": "Uranium Rod", From 94696aefeaca67f49943c4e2f6a9c7145524a3f1 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Fri, 19 Jun 2026 15:35:41 +0200 Subject: [PATCH 050/171] bug fix -> reactor was displaying heat when no item in input (and exploding when too much heat in pattern) --- .../controller/ReactorControllerBlockEntity.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index f36dabb9..5c54c780 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -514,6 +514,21 @@ private void updateHeatOnly() { heat = 0; if (!isEmptyConfiguredPattern() && isAssembled()) { + Map patternCounts = PatternReader.readItemCounts(configuredPattern); + Map currentItems = this.displayState != null && this.displayState.items() != null + ? this.displayState.items() : Collections.emptyMap(); + + for (Map.Entry entry : patternCounts.entrySet()) { + Item requiredItem = entry.getKey(); + int requiredCount = entry.getValue(); + + int availableCount = currentItems.getOrDefault(requiredItem, 0); + if (availableCount < requiredCount) { + this.getConfiguredPatternTag().putDouble("heat", heat); + return; + } + } + heat = (int) heatService.calculateHeat(fluid, totalHeatRatio, inventory, level); } this.getConfiguredPatternTag().putDouble("heat", heat); From 203396446cffb4e70ab290517338539b981a8f55 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Fri, 19 Jun 2026 15:47:39 +0200 Subject: [PATCH 051/171] proximity system changed to allow rod other than CN ones to count --- .../multiblock/reactorLogic/DefaultHeatCalculator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index 0fa5c382..1e29c0c8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -60,10 +60,11 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re if (list.getCompound(l).getInt("Slot") == neighborSlot) { if ("fuel".equals(currentRod)) { ItemStack stack = ItemStack.of(list.getCompound(l)); - if (stack.is(CNTags.CNItemTags.FUEL.tag)) { + RodType neighborRod = ItemRodTypesValue.getRodType(stack.getItem()); + if (stack.is(CNTags.CNItemTags.FUEL.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL)) { heat += rod.proximityRodHeat(); - } else if (stack.is(CNTags.CNItemTags.COOLER.tag)) { - heat += rod.baseRodHeat() / ItemRodTypesValue.getRodType(stack.getItem()).proximityRodHeat(); + } else if (stack.is(CNTags.CNItemTags.COOLER.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER)) { + heat += rod.baseRodHeat() / neighborRod.proximityRodHeat(); } } } From 8611ed76dde90d093d1e62ee4f7f541925ca3a3f Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 19 Jun 2026 22:01:51 +0200 Subject: [PATCH 052/171] refactor: extract output rotation logic into ReactorOutputManager Move the rotation distribution algorithm out of ReactorControllerBlockEntity.rotate(...) and into a new ReactorOutputManager.rotateOutputs(Level, boolean, int), exposed through ReactorOutputManagerI. The manager now divides the incoming rotation across its tracked output positions and applies the resulting speed/stop state to each ReactorOutputEntity directly, instead of the block entity reaching into output internals. ReactorControllerBlock and ReactorControllerBlockEntity are updated to call outputManager.rotateOutputs(...) (via a new getOutputManager() accessor) wherever they previously called rotate(...) directly. Update Architecture cible.md to mark the input-snapshot extraction as done and describe the next target step (extracting rotate(...) into a dedicated output driver, reusing/improving the existing distributeSU logic in ReactorOutputManager). --- Architecture cible.md | 18 ++++++----- .../controller/ReactorControllerBlock.java | 2 +- .../ReactorControllerBlockEntity.java | 8 +++-- .../manager/ReactorOutputManager.java | 31 +++++++++++++++++++ .../manager/ReactorOutputManagerI.java | 8 +++++ 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Architecture cible.md b/Architecture cible.md index 9cc41a3e..cf56901e 100644 --- a/Architecture cible.md +++ b/Architecture cible.md @@ -46,15 +46,17 @@ public void tick() { stateSynchronizer.updateVisibility(...); } -#10 — Snapshot des intrants (ReactorInputSnapshotBuilder) → consolide la collecte déjà faite dans tick(), réutilisée par #5/#6/#9. C'est le pivot qui débloque le découpage du gros tick(). +#8 — rotate(...) → ReactorOutputDriver → algorithme autonome, facile à isoler et tester une fois le snapshot en place. -Construction de l'état d'affichage client (clientDisplay*) -Code concerné : tick() lignes 547-575 (remplissage clientDisplayItems, clientDisplayFluids, clientMaxFluidCapacity, bigFuelItem, bigCoolerItem, bigFluidStack). +Rotation des sorties / production de SU +Code concerné : rotate(BlockState, Level, int) (lignes 813-847), appels dans handleAssembledState/tick. -Pourquoi l'extraire : c'est une étape de collecte de données (scan des handlers d'items/fluides) totalement séparable de la logique de simulation. Aujourd'hui mélangée au tick principal, elle gonfle tick() et duplique des accès aux managers. -Principe : SRP + cohésion — "collecter l'état des intrants pour affichage/calcul" est une étape nommée et isolée du pipeline. -Cible : ReactorInputSnapshotBuilder (service), méthode buildSnapshot(Level, ReactorInputManagerI, ReactorInputFluidManagerI) -> ReactorInputSnapshot (record contenant items, fluides, capacité max, bigFuel/bigCooler/bigFluidStack). -Justification : le snapshot devient l'unique source utilisée à la fois par le tooltip (#9), le calcul de chaleur (#5) et la consommation (#6/#7) — élimine la dispersion actuelle des mêmes données dans plusieurs champs mutables du BE. -Dépendances à injecter : Level, ReactorInputManagerI, ReactorInputFluidManagerI. +Pourquoi l'extraire : manipule directement des ReactorOutputEntity distants (vitesse, heat, rotation générée) avec une logique de répartition de rotation entre N sorties — c'est un algorithme de distribution, pas une responsabilité de "contrôleur de réacteur". +Principe : SRP + Tell-Don't-Ask — le BE ne devrait pas connaître les détails internes d'un ReactorOutputEntity (speed, heat, updateSpeed, setSpeedAndUpdate, updateGeneratedRotation). +Cible : ReactorOutputDriver (service), méthode applyRotation(Level, List outputs, boolean assembled, int rotation). Peut vivre dans manager/ à côté de ReactorOutputManager, ou comme méthode de ReactorOutputManagerI lui-même. +Justification : centralise la logique de répartition (remainingRotation, dividedRotation) qui est un algorithme indépendant ; facilite des tests unitaires sur la distribution de rotation. +Dépendances à injecter : Level, ReactorOutputManagerI (positions), boolean assembled, int rotation/heat. + +la contrainte en plus c'est d'utilisé ou d'améliorée la method qui se trouve dans ReactorOutputManager qui s'appel distributeSU qui permet de distribuer le su entre chaque block output de la liste du controller. Selon moi elle est similaire dans l'idée de rotate de la classe ReactorControllerBlockEntity mais normalement en mieux Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index 0823ad6e..5fa020c1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -116,7 +116,7 @@ else if (heldItem.isEmpty() && !controllerBlockEntity.getInventoryObject().getIt be.getInventoryObject().setStackInSlot(0, ItemStack.EMPTY); be.setConfiguredPattern(ItemStack.EMPTY); //be.clearTimers(); // retirer le commentaire si on veux que le timer se reset quand le reacteur s'arrete - be.rotate(be.getBlockState(), be.getLevel(), 0); + be.getOutputManager().rotateOutputs(be.getLevel(), be.getAssembled(), 0); be.notifyUpdate(); }); state.setValue(ASSEMBLED, false); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 5c54c780..32c9be16 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -195,6 +195,10 @@ public ReactorInputFluidManagerI getInputFluidManager() { return this.inputFluidManager; } + public ReactorOutputManagerI getOutputManager() { + return this.outputManager; + } + public void setDisplayState(ReactorDisplayState state) { this.displayState = state; } @@ -424,7 +428,7 @@ private void handleAssembledState() { if (!isReadyToRun()) { updateHeatOnly(); if (!this.outputManager.getBlocksPosition().isEmpty()) - rotate(getBlockState(), getLevel(), 0); + this.outputManager.rotateOutputs(getLevel(), getAssembled(), 0); this.setChanged(); this.notifyUpdate(); return; @@ -474,7 +478,7 @@ private void handleAssembledState() { if (IHeat.HeatLevel.isNotDanger(heat, this.getMultiblockSize())) { // normal if (!this.outputManager.getBlocksPosition().isEmpty()) { - rotate(getBlockState(), getLevel(), heat); + this.outputManager.rotateOutputs(getLevel(), getAssembled(), heat); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java index 433982d1..212df73a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java @@ -5,6 +5,7 @@ import net.minecraft.nbt.ListTag; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; +import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutput; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import java.util.ArrayList; @@ -16,6 +17,7 @@ */ public class ReactorOutputManager extends AbstractReactorIOManager implements ReactorOutputManagerI { private static final String NBT_KEY = "ReactorOutputs"; + private static final int RPM_DIVIDER = 32; @Override public void write(CompoundTag compound) { @@ -62,4 +64,33 @@ public List getBlocksPosition(Level level) { } return List.copyOf(positions); } + + @Override + public void rotateOutputs(Level level, boolean assembled, int rotation) { + if (positions.isEmpty()) return; + + int totalRpm = rotation / RPM_DIVIDER; + int size = positions.size(); + int remainingRotation = totalRpm % size; + + for (int i = 0; i < size; i++) { + int dividedRotation = (totalRpm / size) + (i < remainingRotation ? 1 : 0); + BlockPos pos = positions.get(i); + + if (!(level.getBlockState(pos).getBlock() instanceof ReactorOutput block)) continue; + ReactorOutputEntity entity = block.getBlockEntityType().getBlockEntity(level, pos); + if (entity == null) continue; + + if (dividedRotation > 0) { + entity.speed = assembled ? dividedRotation : 0; + entity.updateSpeed = true; + entity.setSpeedAndUpdate(dividedRotation); + entity.updateGeneratedRotation(); + } else { + entity.setSpeedAndUpdate(0); + entity.updateSpeed = true; + entity.updateGeneratedRotation(); + } + } + } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java index 26280c8f..30623610 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java @@ -2,8 +2,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import java.util.List; +import java.util.function.BiFunction; /** * Interface exposing operations specific to reactor outputs. @@ -11,4 +13,10 @@ public interface ReactorOutputManagerI extends ReactorIOManager { /** Returns an immutable copy of tracked positions. */ List getBlocksPosition(Level level); + + /** + * Répartit la rotation totale entre les sorties suivies et applique + * la vitesse/l'arrêt correspondant à chaque `ReactorOutputEntity`. + */ + void rotateOutputs(Level level, boolean assembled, int rotation); } From dd9185826051b5be24793bb31d8996ee05ddac31 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 01:58:38 +0200 Subject: [PATCH 053/171] refactor: extract heat-update and fluid-consumption logic into dedicated services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the heat/run-gate logic and per-cycle fluid consumption out of ReactorControllerBlockEntity.handleAssembledState() into two new services: - ReactorHeatUpdateCoordinator (IReactorHeatUpdateCoordinator): owns canRun(...) (the fuel-availability run gate), updateHeatOnly(...) (heat display when the reactor can't run) and calculateAndWriteHeat(...) (actual heat calc + NBT write while running). This replaces the block entity's private isReadyToRun() and updateHeatOnly() methods, removing the duplicated pattern/displayState-availability scanning that lived in both. - FluidConsumptionRateCalculator (IFluidConsumptionRateCalculator): owns the per-tick fluid buffer/extraction logic (efficiency × reactor-size factor, leaky-bucket accumulation), previously inlined in handleAssembledState(). Also move the cycle-manager orchestration ("start if empty, reset if pattern changed, then tick") into a new ConsumptionCycleManager.update(...) method, and delete the now-dead rotate(...) method from the block entity (superseded by ReactorOutputManager.rotateOutputs(...) from the previous refactor). handleAssembledState() is now a short pipeline that delegates to heatCoordinator, fluidRateCalculator, cycleManager.update and outputManager.rotateOutputs, with no behavioral change intended. Update Architecture cible.md to mark the output-rotation extraction as done and describe the next target steps (heat/fluid/consumption-cycle extraction, now reflected by this change). --- Architecture cible.md | 36 +++- .../ReactorControllerBlockEntity.java | 186 +++--------------- .../consumable/ConsumptionCycleManager.java | 23 +++ .../manager/ReactorOutputManager.java | 18 ++ .../manager/ReactorOutputManagerI.java | 4 +- .../FluidConsumptionRateCalculator.java | 48 +++++ .../IFluidConsumptionRateCalculator.java | 25 +++ .../IReactorHeatUpdateCoordinator.java | 44 +++++ .../service/ReactorHeatUpdateCoordinator.java | 103 ++++++++++ 9 files changed, 321 insertions(+), 166 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IFluidConsumptionRateCalculator.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java diff --git a/Architecture cible.md b/Architecture cible.md index cf56901e..b0804ebe 100644 --- a/Architecture cible.md +++ b/Architecture cible.md @@ -46,17 +46,35 @@ public void tick() { stateSynchronizer.updateVisibility(...); } -#8 — rotate(...) → ReactorOutputDriver → algorithme autonome, facile à isoler et tester une fois le snapshot en place. +#5 + #6 + #7 — Chaleur, buffer fluide, cycle de consommation → cœur de handleAssembledState. À traiter ensemble car fortement imbriqués ; bénéficient des étapes 5-6 déjà faites. Risque modéré : c'est la logique de simulation principale — prévoir des tests de régression manuels en jeu sur un réacteur assemblé. -Rotation des sorties / production de SU -Code concerné : rotate(BlockState, Level, int) (lignes 813-847), appels dans handleAssembledState/tick. +Calcul de chaleur & écriture du pattern NBT +Code concerné : handleAssembledState() (lignes 616-620, 656-661), updateHeatOnly(). -Pourquoi l'extraire : manipule directement des ReactorOutputEntity distants (vitesse, heat, rotation générée) avec une logique de répartition de rotation entre N sorties — c'est un algorithme de distribution, pas une responsabilité de "contrôleur de réacteur". -Principe : SRP + Tell-Don't-Ask — le BE ne devrait pas connaître les détails internes d'un ReactorOutputEntity (speed, heat, updateSpeed, setSpeedAndUpdate, updateGeneratedRotation). -Cible : ReactorOutputDriver (service), méthode applyRotation(Level, List outputs, boolean assembled, int rotation). Peut vivre dans manager/ à côté de ReactorOutputManager, ou comme méthode de ReactorOutputManagerI lui-même. -Justification : centralise la logique de répartition (remainingRotation, dividedRotation) qui est un algorithme indépendant ; facilite des tests unitaires sur la distribution de rotation. -Dépendances à injecter : Level, ReactorOutputManagerI (positions), boolean assembled, int rotation/heat. +Pourquoi l'extraire : heatService.calculateHeat(...) existe déjà (bonne extraction), mais le BE reste responsable de : assembler les arguments (bigFuelItem, bigCoolerItem, fluidStack, compteurs de rods), écrire le résultat dans configuredPatternTag, et décider du niveau de danger qui en découle. C'est de l'orchestration répétée 2x (run / not ready). +Principe : DRY + SRP — la "mise à jour de l'état thermique du pattern" est une opération atomique répétée à deux endroits avec des variantes legères. +Cible : ReactorHeatUpdateCoordinator (petit service) qui encapsule "lire les intrants → calculer via IHeatService → écrire le tag heat → retourner le niveau de danger". +Justification : élimine la duplication entre handleAssembledState et updateHeatOnly, et donne un point unique pour future évolution (ex. lissage de la chaleur). +Dépendances à injecter : IHeatService, ItemStack configuredPattern (ou un wrapper ReactorPatternState), BigItemStack fuel/cooler, BigFluidStack, compteurs rods, ReactorControllerInventory, Level. -la contrainte en plus c'est d'utilisé ou d'améliorée la method qui se trouve dans ReactorOutputManager qui s'appel distributeSU qui permet de distribuer le su entre chaque block output de la liste du controller. Selon moi elle est similaire dans l'idée de rotate de la classe ReactorControllerBlockEntity mais normalement en mieux +Buffer & extraction de fluide par cycle +Code concerné : handleAssembledState() lignes 621-643 (fluidBuffer, amountPerCycle, switch(reactorSize)). + +Pourquoi l'extraire : logique de calcul (efficacité du fluide × facteur lié à la taille du réacteur × timer) totalement indépendante du BE — c'est un calcul de débit + accumulateur (pattern "leaky bucket"). +Principe : SRP + testabilité — un calcul numérique paramétré par reactorSize et IHeatService.getLiquidTimer() doit être isolable et testable sans Minecraft. +Cible : FluidConsumptionRateCalculator (helper/strategy) + fluidBuffer qui devient un état porté par ReactorInputFluidManagerI ou un nouveau FluidConsumptionCoordinator. +Justification : le switch (reactorSize) est une table de configuration qui mérite d'être nommée/centralisée (et facilement testable : "pour 5x5, X% par tick"). +Dépendances à injecter : reactorSize, IHeatService (pour getLiquidTimer), BigFluidStack, Level (pour getFluidtype(level).efficiency()), ReactorInputFluidManagerI (pour extractFluids). + +Orchestration du cycle de consommation des rods +Code concerné : handleAssembledState() lignes 645-655 (interactions avec cycleManager). + +Pourquoi l'extraire : ConsumptionCycleManager est déjà une bonne extraction, mais le BE reste responsable de la politique de déclenchement : "démarrer si vide", "reset si pattern changé toutes les 20 ticks", "tick sinon". C'est une mini state-machine de plus, mélangée au reste de handleAssembledState. +Principe : SRP — séparer "que faire avec le cycle manager à ce tick" du reste de la boucle de production. +Cible : déplacer cette logique dans ConsumptionCycleManager lui-même sous une méthode update(ItemStack pattern, Level level, ReactorInputManagerI inputManager) qui encapsule start/reset/tick. +Justification : le manager a déjà toute l'info nécessaire (isEmpty, hasPatternChanged, startCycle, resetCycle, tick) — l'orchestration "si vide alors start, sinon si changé alors reset, puis tick" est sa propre logique interne, pas celle du BE. +Dépendances à injecter : aucune nouvelle — déjà tout passé en paramètre (configuredPattern, level, inputManager). + +il y a eu des modification entre temps donc bigFuelItem, bigCoolerItem on etait modifier donc avant la de présenté la refactor re analise le code avec la modification Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 32c9be16..928c1b5b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -1,7 +1,6 @@ package net.nuclearteam.createnuclear.content.multiblock.controller; import com.simibubi.create.api.equipment.goggles.IHaveGoggleInformation; -import com.simibubi.create.content.logistics.BigItemStack; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.IInteractionChecker; @@ -12,7 +11,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -34,8 +32,6 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.snapshot.ReactorInputSnapshot; import net.nuclearteam.createnuclear.content.multiblock.controller.snapshot.ReactorInputSnapshotBuilder; import net.nuclearteam.createnuclear.content.multiblock.IHeat; -import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutput; -import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.ConsumptionCycleManager; @@ -44,9 +40,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Collections; -import net.minecraft.world.item.Item; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; @@ -54,8 +47,6 @@ import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; -import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.PatternReader; -import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import static net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock.ASSEMBLED; @@ -106,6 +97,8 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private final IHeatService heatService; private final IPersistenceService persistenceService; private final IExplosionService meltdownExecutor; + private final IReactorHeatUpdateCoordinator heatCoordinator; + private final IFluidConsumptionRateCalculator fluidRateCalculator; // service fields are injected; implementations live in separate classes @@ -134,7 +127,10 @@ public CompoundTag getConfiguredPatternTag() { return this.configuredPattern.getTag(); } - + /** @return the first loaded fluid, or {@code null} if no fluid is present. */ + private BigFluidStack currentFluidStack() { + return bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); + } public List getBigFluidStack() { return this.bigFluidStack; @@ -227,6 +223,8 @@ public ReactorControllerBlockEntity(BlockEntityType type, BlockPos pos, Block this.heatService = new DefaultHeatService(new HeatManager()); this.persistenceService = new DefaultPersistenceService(); this.meltdownExecutor = new ReactorMeltdownExecutor(); + this.heatCoordinator = new ReactorHeatUpdateCoordinator(this.heatService); + this.fluidRateCalculator = new FluidConsumptionRateCalculator(this.heatService); } @Override @@ -317,7 +315,7 @@ private void updateReactorStateVisibility() { boolean currentActive = state.getValue(ReactorControllerBlock.ACTIVE); // Le réacteur est "ACTIVE" (ON) seulement s'il est assemblé ET qu'il a ses ressources - boolean targetActive = isAssembled() && isReadyToRun(); + boolean targetActive = isAssembled() && heatCoordinator.canRun(getConfiguredPattern(), getDisplayState(), getInputFluidManager(), level, getAssembled()); if (currentActive != targetActive) { level.setBlock(worldPosition, state.setValue(ReactorControllerBlock.ACTIVE, targetActive), 3); @@ -424,118 +422,36 @@ private void resolveEntitiesIfNeeded() { this.setChanged(); } + /** + * Tick logic applied while the reactor is assembled: if it doesn't have + * enough fuel ({@link IReactorHeatUpdateCoordinator#canRun}), only the + * displayed heat is updated (and outputs stopped); otherwise the actual + * heat is calculated, fluid consumed, the item consumption cycle advanced, + * and outputs rotated according to the heat. + */ private void handleAssembledState() { - if (!isReadyToRun()) { - updateHeatOnly(); - if (!this.outputManager.getBlocksPosition().isEmpty()) - this.outputManager.rotateOutputs(getLevel(), getAssembled(), 0); - this.setChanged(); - this.notifyUpdate(); - return; - } - // ready to run - this.setChanged(); - this.notifyUpdate(); - BigFluidStack fluidStack = bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); - heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level); - this.getConfiguredPatternTag().putDouble("heat", heat); - - if (fluidStack != null) { - if (fluidStack.amount > 1) { - double amountPerCycle = (double) fluidStack.getFluidtype(level).efficiency(); - switch (reactorSize) { - case 5 -> amountPerCycle /= (double) heatService.getLiquidTimer() / 40; - case 7 -> amountPerCycle /= (double) heatService.getLiquidTimer() / 147; - case 9 -> amountPerCycle /= (double) heatService.getLiquidTimer() / 360; - } - - fluidBuffer += amountPerCycle; - - if (fluidBuffer >= 1.0) { - int toExtract = (int) Math.floor(fluidBuffer); - - boolean extracted = inputFluidManager.extractFluids(level, toExtract); - - if (extracted) { - fluidBuffer -= toExtract; - // this.liquidLife = calculateLiquidProgress(); - } - } - } - } - - if (cycleManager.isEmpty() && !isEmptyConfiguredPattern()) { - cycleManager.startCycle(configuredPattern, level); - } - - if (!cycleManager.isEmpty()) { - if (level.getGameTime() % 20 == 0 - && cycleManager.hasPatternChanged(configuredPattern, level)) { - cycleManager.resetCycle(configuredPattern, level, inputManager); - } - cycleManager.tick(inputManager, level); - } - if (IHeat.HeatLevel.isNotDanger(heat, this.getMultiblockSize())) { - // normal - if (!this.outputManager.getBlocksPosition().isEmpty()) { - this.outputManager.rotateOutputs(getLevel(), getAssembled(), heat); + if (!heatCoordinator.canRun(configuredPattern, displayState, inputFluidManager, level, isAssembled())) { + heatCoordinator.updateHeatOnly(configuredPattern, displayState, currentFluidStack(), totalHeatRatio, inventory, level, isAssembled()); + if (!outputManager.getBlocksPosition(getLevel()).isEmpty()) { + outputManager.rotateOutputs(getLevel(), getAssembled(), 0); } - } - } - private boolean isReadyToRun() { - if (isEmptyConfiguredPattern() || this.inputFluidManager.size() == 0 || !isAssembled()) { - return false; + setChanged(); + notifyUpdate(); + return; } - Map patternCounts = PatternReader.readItemCounts(configuredPattern); - Map currentItems = this.displayState != null && this.displayState.items() != null - ? this.displayState.items() : Collections.emptyMap(); - - boolean hasAnyFuel = false; - - for (Map.Entry entry : patternCounts.entrySet()) { - Item requiredItem = entry.getKey(); - int requiredCount = entry.getValue(); - - RodType rodType = RodType.resolveRodType(requiredItem, level); - if (rodType.isNotEmptyItem() && rodType.type() == RodType.TypeRod.FUEL) { - hasAnyFuel = true; - int availableCount = currentItems.getOrDefault(requiredItem, 0); - if (availableCount <= 0) { - return false; - } - } - } + setChanged(); + notifyUpdate(); - return hasAnyFuel; - } - - private void updateHeatOnly() { - // Guard against empty fluid list — HeatManager accepts null for empty/no-fluid - // case - BigFluidStack fluid = bigFluidStack.isEmpty() ? null : bigFluidStack.get(0); - heat = 0; - - if (!isEmptyConfiguredPattern() && isAssembled()) { - Map patternCounts = PatternReader.readItemCounts(configuredPattern); - Map currentItems = this.displayState != null && this.displayState.items() != null - ? this.displayState.items() : Collections.emptyMap(); - - for (Map.Entry entry : patternCounts.entrySet()) { - Item requiredItem = entry.getKey(); - int requiredCount = entry.getValue(); - - int availableCount = currentItems.getOrDefault(requiredItem, 0); - if (availableCount < requiredCount) { - this.getConfiguredPatternTag().putDouble("heat", heat); - return; - } - } + BigFluidStack fluidStack = currentFluidStack(); + heat = heatCoordinator.calculateAndWriteHeat(configuredPattern, fluidStack, totalHeatRatio, inventory, level); + fluidBuffer = fluidRateCalculator.tick(fluidStack, reactorSize, level, inputFluidManager, fluidBuffer); + cycleManager.update(configuredPattern, level, inputManager, level.getGameTime() % 20 == 0); - heat = (int) heatService.calculateHeat(fluid, totalHeatRatio, inventory, level); + if (IHeat.HeatLevel.isNotDanger(heat, getMultiblockSize()) && !outputManager.getBlocksPosition(level).isEmpty()) { + outputManager.rotateOutputs(getLevel(), getAssembled(), heat); } - this.getConfiguredPatternTag().putDouble("heat", heat); } private boolean isEmptyConfiguredPattern() { @@ -547,46 +463,6 @@ private boolean updateLiquidTimers() { return liquidLife <= 0; } - public void rotate(BlockState state, Level level, int rotation) { - if (this.outputManager.getBlocksPosition().isEmpty()) - return; - - int RPMDivider = 32; - int totalRpm = rotation / RPMDivider; - - int remainingRotation = totalRpm % this.outputManager.getBlocksPosition().size(); - for (int i = 0; i < this.outputManager.getBlocksPosition().size(); i++) { - int dividedRotation = (totalRpm / this.outputManager.getBlocksPosition().size()) - + (i < remainingRotation ? 1 : 0); - BlockPos pos = this.outputManager.getBlocksPosition().get(i); - - if (dividedRotation > 0) { - if (level.getBlockState(pos).getBlock() instanceof ReactorOutput block) { - ReactorOutputEntity entity = block.getBlockEntityType().getBlockEntity(level, pos); - if (state.getValue(ASSEMBLED)) { // Starting the energy - entity.speed = dividedRotation; - entity.heat = dividedRotation; - } else { // stopping the energy - entity.speed = 0; - entity.heat = 0; - } - entity.updateSpeed = true; - entity.setSpeedAndUpdate(dividedRotation); - entity.updateGeneratedRotation(); - - } - } else { - if (level.getBlockState(pos).getBlock() instanceof ReactorOutput block) { - ReactorOutputEntity entity = block.getBlockEntityType().getBlockEntity(level, pos); - entity.setSpeedAndUpdate(0); - entity.heat = 0; - entity.updateSpeed = true; - entity.updateGeneratedRotation(); - } - } - } - } - public void addInput(BlockPos inputPos) { this.inputManager.addBlock(inputPos); this.setChanged(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ConsumptionCycleManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ConsumptionCycleManager.java index 632b22ae..7a93ea7e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ConsumptionCycleManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ConsumptionCycleManager.java @@ -135,4 +135,27 @@ private Map readItemIds(ItemStack pattern, Level level) { }); return result; } + + /** + * Advances the consumption cycle by one tick: starts a cycle if none is + * running and the pattern isn't empty, resets it if the pattern changed + * (only checked when {@code checkPatternChange} is true), then ticks the + * current cycle. + * + * @param checkPatternChange if {@code false}, the pattern change isn't + * checked this tick (used to throttle the check's frequency) + */ + public void update(ItemStack pattern, Level level, ReactorInputManagerI inputManager, boolean checkPatternChange) { + boolean emptyPattern = pattern.isEmpty() || pattern.getOrCreateTag().isEmpty(); + if (isEmpty() && !emptyPattern) { + startCycle(pattern, level); + } + + if (!isEmpty()) { + if (checkPatternChange && hasPatternChanged(pattern, level)) { + resetCycle(pattern, level, inputManager); + } + tick(inputManager, level); + } + } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java index 212df73a..6972e562 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java @@ -41,6 +41,11 @@ public void read(CompoundTag compound) { } } + /** + * {@inheritDoc} + * A tracked position is dropped if its chunk isn't loaded or the block + * entity at that position is no longer a {@link ReactorOutputEntity}. + */ @Override public void clearInvalid(Level level) { List toRemove = new ArrayList<>(); @@ -55,6 +60,11 @@ public void clearInvalid(Level level) { positions.removeAll(toRemove); } + /** + * {@inheritDoc} + * Filters the tracked positions down to those currently backed by a + * loaded {@link ReactorOutputEntity}. + */ @Override public List getBlocksPosition(Level level) { List positions = new ArrayList<>(); @@ -65,6 +75,14 @@ public List getBlocksPosition(Level level) { return List.copyOf(positions); } + /** + * {@inheritDoc} + * The total rotation (in RPM, divided down by {@link #RPM_DIVIDER}) is + * split as evenly as possible across the tracked outputs, with the + * remainder distributed to the first outputs. Each output is set to its + * share of the rotation speed if the reactor is assembled, otherwise + * stopped. + */ @Override public void rotateOutputs(Level level, boolean assembled, int rotation) { if (positions.isEmpty()) return; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java index 30623610..3211d7d1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java @@ -15,8 +15,8 @@ public interface ReactorOutputManagerI extends ReactorIOManager { List getBlocksPosition(Level level); /** - * Répartit la rotation totale entre les sorties suivies et applique - * la vitesse/l'arrêt correspondant à chaque `ReactorOutputEntity`. + * Distributes the total rotation across the tracked outputs and applies + * the corresponding speed/stop to each {@code ReactorOutputEntity}. */ void rotateOutputs(Level level, boolean assembled, int rotation); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java new file mode 100644 index 00000000..72abcfb3 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java @@ -0,0 +1,48 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputFluidManagerI; + +/** + * Default implementation of {@link IFluidConsumptionRateCalculator}. + * The rate per cycle depends on the fluid's efficiency and the liquid timer + * exposed by {@link IHeatService}, which itself depends on the reactor size. + */ +public class FluidConsumptionRateCalculator implements IFluidConsumptionRateCalculator { + private final IHeatService heatService; + + public FluidConsumptionRateCalculator(IHeatService heatService) { + this.heatService = heatService; + } + + /** + * {@inheritDoc} + * Does nothing if the fluid stack is {@code null} or holds a negligible + * amount (≤ 1). + */ + @Override + public double tick(BigFluidStack fluidStack, int reactorSize, Level level, + ReactorInputFluidManagerI inputFluidManager, double fluidBuffer) { + if (fluidStack == null || fluidStack.amount <= 1) { + return fluidBuffer; + } + + double amountPerCycle = fluidStack.getFluidtype(level).efficiency(); + switch (reactorSize) { + case 5 -> amountPerCycle /= (double) heatService.getLiquidTimer() / 40; + case 7 -> amountPerCycle /= (double) heatService.getLiquidTimer() / 147; + case 9 -> amountPerCycle /= (double) heatService.getLiquidTimer() / 360; + } + + fluidBuffer += amountPerCycle; + + if (fluidBuffer >= 1.0) { + int toExtract = (int) Math.floor(fluidBuffer); + if (inputFluidManager.extractFluids(level, toExtract)) { // bug existant volontairement non touché + fluidBuffer -= toExtract; + } + } + return fluidBuffer; + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IFluidConsumptionRateCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IFluidConsumptionRateCalculator.java new file mode 100644 index 00000000..9a9830f5 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IFluidConsumptionRateCalculator.java @@ -0,0 +1,25 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputFluidManagerI; + +/** + * Computes how much fluid should be consumed per tick and triggers extraction + * once the accumulated amount reaches a whole unit. + */ +public interface IFluidConsumptionRateCalculator { + + /** + * Advances the consumption calculation by one tick. + * + * @param fluidStack fluid currently loaded, or {@code null} if none + * @param reactorSize reactor size, used to determine the consumption rate + * @param level current level, used to resolve the fluid type + * @param inputFluidManager input manager responsible for extracting the consumed fluid + * @param fluidBuffer fractional remainder accumulated since the previous tick + * @return the new fractional remainder to carry over to the next tick + */ + double tick(BigFluidStack fluidStack, int reactorSize, Level level, + ReactorInputFluidManagerI inputFluidManager, double fluidBuffer); +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java new file mode 100644 index 00000000..15b93596 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java @@ -0,0 +1,44 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; +import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputFluidManagerI; + +/** + * Centralizes the reactor's heat calculation logic and the decision of + * whether it has enough fuel to run. + */ +public interface IReactorHeatUpdateCoordinator { + + /** + * Determines whether the reactor has enough fuel (FUEL-type rods) to start, + * on top of being assembled and having a fluid input. + * + * @return {@code true} if every fuel rod required by the pattern is + * available and at least one fuel rod is required + */ + boolean canRun(ItemStack configuredPattern, ReactorDisplayState displayState, + ReactorInputFluidManagerI inputFluidManager, Level level, boolean assembled); + + /** + * Updates the heat without running the reactor (case where it isn't ready). + * Heat is only calculated if the full pattern (every required item, not + * just fuel) is available; otherwise it drops back to zero. + * + * @return the calculated heat, also written to the configured pattern's tag + */ + int updateHeatOnly(ItemStack configuredPattern, ReactorDisplayState displayState, BigFluidStack fluidStack, + int totalHeatRatio, ReactorControllerInventory inventory, Level level, boolean assembled); + + /** + * Calculates the reactor's heat during normal operation and writes it to + * the configured pattern's tag. + * + * @return the calculated heat + */ + int calculateAndWriteHeat(ItemStack configuredPattern, BigFluidStack fluidStack, int totalHeatRatio, + ReactorControllerInventory inventory, Level level); +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java new file mode 100644 index 00000000..7710aa97 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java @@ -0,0 +1,103 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; +import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.PatternReader; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputFluidManagerI; + +import java.util.Collections; +import java.util.Map; + +/** + * Default implementation of {@link IReactorHeatUpdateCoordinator}. + * Delegates raw heat calculation to {@link IHeatService} and only adds the + * pattern-availability logic (fuel-only vs. full pattern). + */ +public class ReactorHeatUpdateCoordinator implements IReactorHeatUpdateCoordinator { + private final IHeatService heatService; + + public ReactorHeatUpdateCoordinator(IHeatService heatService) { + this.heatService = heatService; + } + + /** Predicate applied to each pattern entry when checking availability. */ + @FunctionalInterface + private interface PatternEntryCheck { + boolean test(Item item, int requiredCount, int availableCount); + } + + /** + * Iterates over the items required by the configured pattern and applies + * {@code check} to each entry, stopping as soon as one entry fails. + * + * @return {@code true} if {@code check} succeeded for every pattern entry + */ + private static boolean checkPatternAvailability(ItemStack configuredPattern, ReactorDisplayState displayState, + PatternEntryCheck check) { + Map patternCounts = PatternReader.readItemCounts(configuredPattern); + Map currentItems = displayState != null && displayState.items() != null + ? displayState.items() : Collections.emptyMap(); + + for (Map.Entry entry : patternCounts.entrySet()) { + Item item = entry.getKey(); + int requiredCount = entry.getValue(); + int availableCount = currentItems.getOrDefault(item, 0); + if (!check.test(item, requiredCount, availableCount)) { + return false; + } + } + return true; + } + + @Override + public boolean canRun(ItemStack configuredPattern, ReactorDisplayState displayState, + ReactorInputFluidManagerI inputFluidManager, Level level, boolean assembled) { + if (configuredPattern.isEmpty() || configuredPattern.getOrCreateTag().isEmpty() + || inputFluidManager.size() == 0 || !assembled) { + return false; + } + + boolean[] hasAnyFuel = {false}; + boolean allFuelAvailable = checkPatternAvailability(configuredPattern, displayState, + (item, requiredCount, availableCount) -> { + RodType rodType = RodType.resolveRodType(item, level); + if (rodType.isNotEmptyItem() && rodType.type() == RodType.TypeRod.FUEL) { + hasAnyFuel[0] = true; + return availableCount > 0; + } + return true; // non-fuel entries don't block this gate + } + ); + + return allFuelAvailable && hasAnyFuel[0]; + } + + @Override + public int updateHeatOnly(ItemStack configuredPattern, ReactorDisplayState displayState, BigFluidStack fluidStack, + int totalHeatRatio, ReactorControllerInventory inventory, Level level, boolean assembled) { + int heat = 0; + boolean emptyPattern = configuredPattern.isEmpty() || configuredPattern.getOrCreateTag().isEmpty(); + if (!emptyPattern && assembled) { + boolean allAvailable = checkPatternAvailability(configuredPattern, displayState, + (item, requiredCount, availableCount) -> availableCount >= requiredCount); + if (allAvailable) { + heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level); + } + } + configuredPattern.getOrCreateTag().putDouble("heat", heat); + return heat; + } + + @Override + public int calculateAndWriteHeat(ItemStack configuredPattern, BigFluidStack fluidStack, int totalHeatRatio, + ReactorControllerInventory inventory, Level level) { + int heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level); + configuredPattern.getOrCreateTag().putDouble("heat", heat); + return heat; + } +} From fa7eb3e94775008493b95483c3bebc598f9ced36 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 02:05:04 +0200 Subject: [PATCH 054/171] style: replace var with explicit type and drop fully qualified names Use BlockPattern instead of var for the result of CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(...) in ReactorControllerBlockEntity, and import RodType.TypeRodPredicate in FuelDisplaySource so the fuel-counting loop no longer needs the fully qualified name. No behavioral change. --- .../multiblock/controller/ReactorControllerBlockEntity.java | 4 +++- .../redstone/displayLink/source/FuelDisplaySource.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 928c1b5b..16e620a1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -22,7 +22,9 @@ import net.minecraftforge.items.IItemHandler; import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.api.multiblock.BlockPattern; import net.nuclearteam.createnuclear.api.multiblock.IMultiblockController; +import net.nuclearteam.createnuclear.api.multiblock.TypeMultiblock; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.CNMultiblock; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; @@ -548,7 +550,7 @@ public void clearLockIfAllInputsEmpty() { if (level == null || level.isClientSide) return; - var structure = CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this); + BlockPattern structure = CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this); // findStructure renvoie null si la structure n'est plus formée : on retombe // alors sur la dernière taille assemblée (reactorSize) pour éviter un NPE serveur. final int SCAN_RADIUS = structure != null ? structure.data().getSize() : reactorSize; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java index d5621839..4a49ce45 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java @@ -10,6 +10,7 @@ import net.minecraft.util.Mth; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; @@ -28,7 +29,7 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget int fuel = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { for (var entry : controller.getDisplayState().items().entrySet()) { - if (net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { + if (TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { fuel += entry.getValue(); } } From 6e717c448d1e71f39f05e4445272ed8ec4d13588 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 15:56:57 +0200 Subject: [PATCH 055/171] refactor: extract alarm and meltdown-countdown logic from tick() Move two more responsibilities out of ReactorControllerBlockEntity.tick(): - ReactorAlarmCoordinator (IReactorAlarmCoordinator): computes the danger flag from the current heat (computeDanger) and drives the alarm blocks accordingly (update), replacing the old activateAlarms(boolean) private method. - ReactorMeltdownMonitor (IReactorMeltdownMonitor): owns the explosion countdown state machine and its player notifications (overheating warning, flashing "meltdown in X seconds", stabilized message, critical-failure title), exposing tick(level, pos, isDanger) -> MeltdownState (NONE/CRITICAL/EXPLODE). tick() now just triggers the explosion when the monitor reports EXPLODE, instead of inlining the whole countdown/notification logic. Both are wired up in addBehaviours/the constructor; no behavioral change intended, only relocation of existing logic. Document a pre-existing tautological bug in IHeat.HeatLevel.isNotDanger (`!= DANGER || != NONE` is always true) and update the target architecture notes to reflect the alarm/meltdown extraction and the prior isReadyToRun -> ReactorHeatUpdateCoordinator.canRun rename. --- AUDIT_ACTUEL.md | 21 ++++- Architecture cible.md | 46 +++++----- .../ReactorControllerBlockEntity.java | 84 ++++--------------- .../service/IReactorAlarmCoordinator.java | 29 +++++++ .../service/IReactorMeltdownMonitor.java | 31 +++++++ .../service/ReactorAlarmCoordinator.java | 44 ++++++++++ .../service/ReactorMeltdownMonitor.java | 67 +++++++++++++++ 7 files changed, 228 insertions(+), 94 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorAlarmCoordinator.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorMeltdownMonitor.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorAlarmCoordinator.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownMonitor.java diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 144fec36..e0cca610 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -126,11 +126,26 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — 10. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — point d'alerte non couvert par `AUDIT_V1.md`, indépendant des surface rules (B19, désormais corrigées). +11. **`IHeat.HeatLevel.isNotDanger` — condition tautologique, toujours `true`** + `IHeat.java:88-90` : + ```java + public static boolean isNotDanger(int heat, int reactorSize) { + return of(heat, reactorSize) != DANGER || of(heat, reactorSize) != NONE; + } + ``` + `X != DANGER || X != NONE` est une tautologie : un `HeatLevel` ne peut pas être simultanément égal à `DANGER` et à `NONE`, donc l'une des deux comparaisons est toujours vraie — la méthode retourne **toujours `true`**, quel que soit `heat`. Conséquence concrète dans son unique appelant, `ReactorControllerBlockEntity.handleAssembledState()` (ligne 454) : + ```java + if (IHeat.HeatLevel.isNotDanger(heat, getMultiblockSize()) && !outputManager.getBlocksPosition(level).isEmpty()) { + outputManager.rotateOutputs(getLevel(), getAssembled(), heat); + } + ``` + la garde "ne pas faire tourner les sorties si le réacteur est en `DANGER`" est **inopérante** : les sorties continuent de tourner même en `HeatLevel.DANGER`. Non détecté dans `AUDIT_V1.md` (ni le fichier ni la méthode n'y sont mentionnés). **Aucun correctif appliqué pour l'instant — documentation uniquement**, à corriger dans un commit dédié (probablement `!= DANGER` seul, à confirmer avec le comportement voulu). + ### 🟡 Mineurs -11. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). -12. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. -13. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +12. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). +13. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. +14. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. --- diff --git a/Architecture cible.md b/Architecture cible.md index b0804ebe..8b4ca0ec 100644 --- a/Architecture cible.md +++ b/Architecture cible.md @@ -46,35 +46,35 @@ public void tick() { stateSynchronizer.updateVisibility(...); } -#5 + #6 + #7 — Chaleur, buffer fluide, cycle de consommation → cœur de handleAssembledState. À traiter ensemble car fortement imbriqués ; bénéficient des étapes 5-6 déjà faites. Risque modéré : c'est la logique de simulation principale — prévoir des tests de régression manuels en jeu sur un réacteur assemblé. +#1 + #2 + #11 — Alarmes, meltdown monitor, état assembled/active → state machine complète extraite en dernier, car elle dépend du résultat de l'étape 7 (le niveau de chaleur final). -Calcul de chaleur & écriture du pattern NBT -Code concerné : handleAssembledState() (lignes 616-620, 656-661), updateHeatOnly(). +Détection de danger thermique & pilotage des alarmes +Code concerné : tick() lignes 486-490 (calcul isDanger), activateAlarms(boolean). -Pourquoi l'extraire : heatService.calculateHeat(...) existe déjà (bonne extraction), mais le BE reste responsable de : assembler les arguments (bigFuelItem, bigCoolerItem, fluidStack, compteurs de rods), écrire le résultat dans configuredPatternTag, et décider du niveau de danger qui en découle. C'est de l'orchestration répétée 2x (run / not ready). -Principe : DRY + SRP — la "mise à jour de l'état thermique du pattern" est une opération atomique répétée à deux endroits avec des variantes legères. -Cible : ReactorHeatUpdateCoordinator (petit service) qui encapsule "lire les intrants → calculer via IHeatService → écrire le tag heat → retourner le niveau de danger". -Justification : élimine la duplication entre handleAssembledState et updateHeatOnly, et donne un point unique pour future évolution (ex. lissage de la chaleur). -Dépendances à injecter : IHeatService, ItemStack configuredPattern (ou un wrapper ReactorPatternState), BigItemStack fuel/cooler, BigFluidStack, compteurs rods, ReactorControllerInventory, Level. +Pourquoi l'extraire : le BE mélange lecture de l'état NBT du pattern, classification du niveau de chaleur, et mutation de blocs distants (ReactorAlarm). C'est une logique de politique (quand déclencher l'alarme) totalement séparable de l'état du contrôleur. +Principe : SRP — "calculer si on est en danger" et "activer des blocs d'alarme" sont deux responsabilités distinctes du "être un bloc de réacteur". +Cible : ReactorAlarmCoordinator (service), qui utilise ReactorAlarmManagerI (déjà existant) + IHeat.HeatLevel. +Justification : alarmManager existe déjà pour stocker les positions ; il manque juste la couche "politique" qui décide quand activer. La regrouper avec le manager évite d'éclater la logique alarme sur deux fichiers. +Dépendances à injecter : Level, ReactorAlarmManagerI, CNAdvancementBehaviour (pour awardPlayer(SILENCE_THE_CORE)), niveau de chaleur courant (int). -Buffer & extraction de fluide par cycle -Code concerné : handleAssembledState() lignes 621-643 (fluidBuffer, amountPerCycle, switch(reactorSize)). +Compte à rebours de fusion + notifications joueurs +Code concerné : tick() lignes 497-536 (explosionCountdown, NotifyUtil.sendActionBar/sendTitle). -Pourquoi l'extraire : logique de calcul (efficacité du fluide × facteur lié à la taille du réacteur × timer) totalement indépendante du BE — c'est un calcul de débit + accumulateur (pattern "leaky bucket"). -Principe : SRP + testabilité — un calcul numérique paramétré par reactorSize et IHeatService.getLiquidTimer() doit être isolable et testable sans Minecraft. -Cible : FluidConsumptionRateCalculator (helper/strategy) + fluidBuffer qui devient un état porté par ReactorInputFluidManagerI ou un nouveau FluidConsumptionCoordinator. -Justification : le switch (reactorSize) est une table de configuration qui mérite d'être nommée/centralisée (et facilement testable : "pour 5x5, X% par tick"). -Dépendances à injecter : reactorSize, IHeatService (pour getLiquidTimer), BigFluidStack, Level (pour getFluidtype(level).efficiency()), ReactorInputFluidManagerI (pour extractFluids). +Pourquoi l'extraire : c'est une machine à états (stable → alerte → critique → explosion) avec ses propres transitions et effets de bord (notifications). Le BE ne devrait connaître que "suis-je en danger ?" et "dois-je exploser maintenant ?". +Principe : SRP + forte cohésion — toute la logique temporelle de meltdown (countdown, seuils 10s, clignotement, message de stabilisation) doit vivre ensemble, indépendamment du tick du BE. +Cible : ReactorMeltdownMonitor (state/service), exposant tick(boolean isDanger) -> MeltdownState (NONE/WARNING/CRITICAL/EXPLODE) et gérant lui-même les notifications. +Justification : isole une logique testable unitairement (countdown pur) des effets Minecraft (notify), et centralise la config (CNConfigs.server().notify.*) au même endroit. +Dépendances à injecter : Level, BlockPos, lecteurs de config (radius/warnAll), CreateNuclearLang (déjà statique, ok). -Orchestration du cycle de consommation des rods -Code concerné : handleAssembledState() lignes 645-655 (interactions avec cycleManager). + État "assembled"/"active" du bloc & visibilité +Code concerné : isAssembled(), setAssembled(boolean), updateReactorStateVisibility(). -Pourquoi l'extraire : ConsumptionCycleManager est déjà une bonne extraction, mais le BE reste responsable de la politique de déclenchement : "démarrer si vide", "reset si pattern changé toutes les 20 ticks", "tick sinon". C'est une mini state-machine de plus, mélangée au reste de handleAssembledState. -Principe : SRP — séparer "que faire avec le cycle manager à ce tick" du reste de la boucle de production. -Cible : déplacer cette logique dans ConsumptionCycleManager lui-même sous une méthode update(ItemStack pattern, Level level, ReactorInputManagerI inputManager) qui encapsule start/reset/tick. -Justification : le manager a déjà toute l'info nécessaire (isEmpty, hasPatternChanged, startCycle, resetCycle, tick) — l'orchestration "si vide alors start, sinon si changé alors reset, puis tick" est sa propre logique interne, pas celle du BE. -Dépendances à injecter : aucune nouvelle — déjà tout passé en paramètre (configuredPattern, level, inputManager). +Pourquoi l'extraire : logique de synchronisation entre BlockState (propriétés ASSEMBLED/ACTIVE) et l'état logique du réacteur (isReadyToRun()). C'est un sous-problème de "synchronisation blockstate ↔ logique métier", réutilisable et isolable. +Principe : SRP léger — pas critique, mais regrouper ces 3 méthodes avec la logique de readiness (isReadyToRun) renforce la cohésion. +Cible : ReactorStateSynchronizer (petit helper) ou simplement les regrouper dans le futur ReactorMeltdownMonitor/ReactorRuntimeState (#2), puisqu'ACTIVE dépend directement de isDanger/isReadyToRun. +Justification : faible priorité mais permet de découpler le calcul "dois-je être actif ?" de la mutation du BlockState, ce qui facilite les tests (pure fonction computeActive(assembled, readyToRun)). +Dépendances à injecter : Level, BlockPos, BlockState actuel. -il y a eu des modification entre temps donc bigFuelItem, bigCoolerItem on etait modifier donc avant la de présenté la refactor re analise le code avec la modification +il y a eu un changement isReadyToRun a etait remplacé par ReactorHeatUpdateCoordinator.canRun Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 16e620a1..52d44390 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -4,7 +4,6 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.IInteractionChecker; -import net.minecraft.ChatFormatting; import net.minecraft.core.*; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -27,7 +26,6 @@ import net.nuclearteam.createnuclear.api.multiblock.TypeMultiblock; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.CNMultiblock; -import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorGoggleTooltipRenderer; import net.nuclearteam.createnuclear.content.multiblock.controller.service.*; @@ -37,8 +35,6 @@ import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import net.nuclearteam.createnuclear.content.multiblock.controller.consumable.ConsumptionCycleManager; -import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; -import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import java.util.ArrayList; import java.util.List; @@ -46,7 +42,6 @@ import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; import net.nuclearteam.createnuclear.content.multiblock.controller.manager.*; -import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; @@ -67,7 +62,6 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private int countCoolerRod; private int totalHeatRatio; private int heat; - private int explosionCountdown = 0; private boolean isExploding = false; private final ConsumptionCycleManager cycleManager = new ConsumptionCycleManager(); @@ -101,6 +95,10 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private final IExplosionService meltdownExecutor; private final IReactorHeatUpdateCoordinator heatCoordinator; private final IFluidConsumptionRateCalculator fluidRateCalculator; + /** Counts down to the next explosion once in danger; keeps the original 1-tick lag against the heat recalculated later this tick. */ + private final IReactorMeltdownMonitor meltdownMonitor; + /** Drives the alarm blocks based on the danger flag; built in {@link #addBehaviours} since it depends on {@link #advancement}. */ + private IReactorAlarmCoordinator alarmCoordinator; // service fields are injected; implementations live in separate classes @@ -227,11 +225,13 @@ public ReactorControllerBlockEntity(BlockEntityType type, BlockPos pos, Block this.meltdownExecutor = new ReactorMeltdownExecutor(); this.heatCoordinator = new ReactorHeatUpdateCoordinator(this.heatService); this.fluidRateCalculator = new FluidConsumptionRateCalculator(this.heatService); + this.meltdownMonitor = new ReactorMeltdownMonitor(); } @Override public void addBehaviours(List behaviours) { behaviours.add(advancement = new CNAdvancementBehaviour(this, CNAdvancement.T1_REACTOR, CNAdvancement.T2_REACTOR, CNAdvancement.T3_REACTOR, CNAdvancement.NO_TIME_TO_DIE, CNAdvancement.SILENCE_THE_CORE)); + this.alarmCoordinator = new ReactorAlarmCoordinator(advancement); } public boolean getAssembled() { // permet de savoir si le réacteur est formé ou pas. @@ -329,59 +329,21 @@ public void tick() { super.tick(); if (level.isClientSide || isExploding) return; + // Heat value written by the previous tick's handleAssembledState(); this tick's recalculated + // heat is not visible here yet, so the alarm/meltdown danger flag is intentionally 1 tick behind. int currentHeat = (int) configuredPattern.getOrCreateTag().getDouble("heat"); - boolean isDanger = IHeat.HeatLevel.of(currentHeat, this.getMultiblockSize()) == IHeat.HeatLevel.DANGER; + boolean isDanger = alarmCoordinator.computeDanger(currentHeat, this.getMultiblockSize()); - activateAlarms(isDanger); + alarmCoordinator.update(level, alarmManager, isDanger); - currentHeat = isEmptyConfiguredPattern() ? 0 : (int) this.getConfiguredPatternTag().getDouble("heat"); + IReactorMeltdownMonitor.MeltdownState meltdownState = meltdownMonitor.tick(level, getBlockPos(), isDanger); - // Récupération des configs pour l'utilitaire - int configRadius = CNConfigs.server().notify.distanceOfWarning.get(); - boolean configWarnAll = CNConfigs.server().notify.warnAllPlayers.get(); - - if (isDanger) { - explosionCountdown++; - int secondsLeft = (300 - explosionCountdown) / 20; - - // --- AFFICHAGE ALERTES ACTION BAR (TRADUITES) --- - if (secondsLeft <= 10 && secondsLeft > 0) { - boolean isWhite = (level.getGameTime() / 5) % 2 == 0; - ChatFormatting flashColor = isWhite ? ChatFormatting.WHITE : ChatFormatting.RED; - - NotifyUtil.sendActionBar(level, getBlockPos(), - CreateNuclearLang.translate("notification.reactor.meltdown_in") - .add(CreateNuclearLang.number(secondsLeft)) - .add(CreateNuclearLang.translate("generic.unit.seconds")), - flashColor, configRadius, configWarnAll); - - } else if (secondsLeft > 10 && explosionCountdown % 20 == 0) { - NotifyUtil.sendActionBar(level, getBlockPos(), - CreateNuclearLang.translate("notification.reactor.overheating"), - ChatFormatting.DARK_RED, configRadius, configWarnAll); - } - - // --- MOMENT DE L'EXPLOSION --- - if (explosionCountdown >= 300) { - NotifyUtil.sendTitle(level, getBlockPos(), - CreateNuclearLang.translate("notification.reactor.critical_failure"), - CreateNuclearLang.translate("notification.reactor.imminent_explosion"), - ChatFormatting.DARK_RED, configRadius, configWarnAll, 0, 40, 10); - - if (level instanceof ServerLevel serverLevel) { - this.meltdownExecutor.triggerExplosion(serverLevel, getBlockPos(), reactorSize, countFuelRod); - } - isExploding = true; - return; + if (meltdownState == IReactorMeltdownMonitor.MeltdownState.EXPLODE) { + if (level instanceof ServerLevel serverLevel) { + this.meltdownExecutor.triggerExplosion(serverLevel, getBlockPos(), reactorSize, countFuelRod); } - } else { - // --- CŒUR STABILISÉ --- - if (explosionCountdown > 0) { - NotifyUtil.sendActionBar(level, getBlockPos(), - CreateNuclearLang.translate("notification.reactor.stabilized"), - ChatFormatting.GREEN, configRadius, configWarnAll); - } - explosionCountdown = 0; + isExploding = true; + return; } if (!isEmptyConfiguredPattern()) { @@ -400,20 +362,6 @@ public void tick() { handleAssembledState(); } - private void activateAlarms(boolean activate) { - if (alarmManager == null) - return; - for (BlockPos pos : alarmManager.getBlocksPosition(level)) { - if (level.isLoaded(pos)) { - BlockState state = level.getBlockState(pos); - if (state.getBlock() instanceof ReactorAlarm && state.getValue(ReactorAlarm.POWERED) != activate) { - level.setBlock(pos, state.setValue(ReactorAlarm.POWERED, activate), 3); - if (activate) this.advancement.awardPlayer(CNAdvancement.SILENCE_THE_CORE); - } - } - } - } - // --- extracted sub-steps to keep single responsibility per method --- private void resolveEntitiesIfNeeded() { if (!needsToResolveEntities) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorAlarmCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorAlarmCoordinator.java new file mode 100644 index 00000000..f83fe123 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorAlarmCoordinator.java @@ -0,0 +1,29 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorAlarmManagerI; + +/** + * Classifies the reactor's heat into a danger flag and drives the + * {@link net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm} blocks + * registered in a {@link ReactorAlarmManagerI} accordingly. + */ +public interface IReactorAlarmCoordinator { + + /** + * @param heat the heat value to classify + * @param multiblockSize the reactor's multiblock size, used to resolve the danger threshold + * @return {@code true} if {@code heat} falls in the DANGER heat-level range + */ + boolean computeDanger(int heat, int multiblockSize); + + /** + * Powers on/off every alarm block known to {@code alarmManager} to match {@code isDanger}, + * and awards the SILENCE_THE_CORE advancement on the rising edge (alarm turning on). + * + * @param level the reactor's level + * @param alarmManager the manager holding the alarm block positions + * @param isDanger whether the alarms should be powered on + */ + void update(Level level, ReactorAlarmManagerI alarmManager, boolean isDanger); +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorMeltdownMonitor.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorMeltdownMonitor.java new file mode 100644 index 00000000..a326391f --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorMeltdownMonitor.java @@ -0,0 +1,31 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; + +/** + * Tracks the reactor's meltdown countdown and the player notifications tied to it. + * Consumes the danger flag computed by {@link IReactorAlarmCoordinator#computeDanger} + * instead of recomputing it, so the heat-level classification stays in a single place. + */ +public interface IReactorMeltdownMonitor { + + /** + * Outcome of a single countdown tick. + * {@code NONE} - not in danger, countdown reset to zero. + * {@code CRITICAL} - in danger, countdown running, explosion threshold not reached yet. + * {@code EXPLODE} - countdown threshold reached, the caller must trigger the explosion now. + */ + enum MeltdownState { NONE, CRITICAL, EXPLODE } + + /** + * Advances the countdown by one tick and sends the matching player notifications + * (stabilized / overheating / meltdown flash / critical failure). + * + * @param level the reactor's level, used for notifications and game time + * @param pos the controller's position, used as the notification origin + * @param isDanger whether the reactor is currently at heat level DANGER + * @return the resulting {@link MeltdownState} for this tick + */ + MeltdownState tick (Level level, BlockPos pos, boolean isDanger); +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorAlarmCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorAlarmCoordinator.java new file mode 100644 index 00000000..4b365438 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorAlarmCoordinator.java @@ -0,0 +1,44 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.nuclearteam.createnuclear.content.multiblock.IHeat; +import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorAlarmManagerI; +import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; +import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; + +/** + * Default {@link IReactorAlarmCoordinator}. Extracted from + * {@code ReactorControllerBlockEntity.activateAlarms(boolean)}: the alarm wiring and + * advancement award are unchanged from the original implementation. + */ +public class ReactorAlarmCoordinator implements IReactorAlarmCoordinator { + private final CNAdvancementBehaviour advancement; + + public ReactorAlarmCoordinator(CNAdvancementBehaviour advancement) { + this.advancement = advancement; + } + + @Override + public boolean computeDanger(int heat, int multiblockSize) { + return IHeat.HeatLevel.of(heat, multiblockSize) == IHeat.HeatLevel.DANGER; + } + + @Override + public void update(Level level, ReactorAlarmManagerI alarmManager, boolean isDanger) { + if (alarmManager == null) return; + + for (BlockPos pos : alarmManager.getBlocksPosition(level)) { + if (!level.isLoaded(pos)) continue; + + BlockState state = level.getBlockState(pos); + + if (state.getBlock() instanceof ReactorAlarm && state.getValue(ReactorAlarm.POWERED) != isDanger) { + level.setBlock(pos, state.setValue(ReactorAlarm.POWERED, isDanger), 3); + if (isDanger) advancement.awardPlayer(CNAdvancement.SILENCE_THE_CORE); + } + } + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownMonitor.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownMonitor.java new file mode 100644 index 00000000..43e1377e --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorMeltdownMonitor.java @@ -0,0 +1,67 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller.service; + +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; +import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; + +/** + * Default {@link IReactorMeltdownMonitor}. Extracted from + * {@code ReactorControllerBlockEntity.tick()}: the countdown logic and its notifications + * are unchanged from the original implementation, only moved into their own class. + */ +public class ReactorMeltdownMonitor implements IReactorMeltdownMonitor { + /** Ticks of continuous danger before the reactor explodes (15s at 20 TPS). */ + private static final int EXPLOSION_THRESHOLD_TICKS = 300; + /** Last seconds of the countdown during which the flashing "meltdown in" message is shown. */ + private static final int CRITICAL_WINDOW_SECONDS = 10; + + private int explosionCountDown = 0; + + @Override + public MeltdownState tick(Level level, BlockPos pos, boolean isDanger) { + int configRadius = CNConfigs.server().notify.distanceOfWarning.get(); + boolean configWarnAll = CNConfigs.server().notify.warnAllPlayers.get(); + + if (!isDanger) { + boolean wasCountingDown = explosionCountDown > 0; + explosionCountDown = 0; + if (wasCountingDown) { + NotifyUtil.sendActionBar(level, pos, + CreateNuclearLang.translate("notification.reactor.stabilized"), + ChatFormatting.GREEN, configRadius, configWarnAll); + } + return MeltdownState.NONE; + } + + explosionCountDown++; + int secondsLeft = (EXPLOSION_THRESHOLD_TICKS - explosionCountDown) / 20; + + if (secondsLeft <= CRITICAL_WINDOW_SECONDS && secondsLeft > 0) { + boolean isWhite = (level.getGameTime() / 5) % 2 == 0; + ChatFormatting flashColor = isWhite ? ChatFormatting.WHITE : ChatFormatting.RED; + + NotifyUtil.sendActionBar(level, pos, + CreateNuclearLang.translate("notification.reactor.meltdown_in") + .add(CreateNuclearLang.number(secondsLeft)) + .add(CreateNuclearLang.translate("generic.unit.seconds")), + flashColor, configRadius, configWarnAll); + } else if (secondsLeft > CRITICAL_WINDOW_SECONDS && explosionCountDown % 20 == 0) { + NotifyUtil.sendActionBar(level, pos, + CreateNuclearLang.translate("notification.reactor.overheating"), + ChatFormatting.DARK_RED, configRadius, configWarnAll); + } + + if (explosionCountDown >= EXPLOSION_THRESHOLD_TICKS) { + NotifyUtil.sendTitle(level, pos, + CreateNuclearLang.translate("notification.reactor.critical_failure"), + CreateNuclearLang.translate("notification.reactor.imminent_explosion"), + ChatFormatting.DARK_RED, configRadius, configWarnAll, 0, 40, 10); + return MeltdownState.EXPLODE; + } + + return MeltdownState.CRITICAL; + } +} From 56373bf74777bac9548529417235922fc77eac47 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 16:23:49 +0200 Subject: [PATCH 056/171] refactor: simplify clearLockIfAllInputsEmpty using the input fluid manager Replace the manual 3D block scan in clearLockIfAllInputsEmpty (looking for ReactorFluidInputEntity around the controller and checking each fluid handler's tanks) with a direct stream over getInputFluidManager().getFuildHandlers(level), which already tracks the relevant fluid handlers. Drops the now-unused BlockPattern/structure lookup and SCAN_RADIUS computation for this method. No behavioral change. Update Architecture cible.md to drop the now-completed alarm/meltdown-monitor extraction notes and flag the FluidLockManager duplication item for re-evaluation, since FluidLockManager itself was removed in a previous commit. --- Architecture cible.md | 36 ++++------------ .../ReactorControllerBlockEntity.java | 42 ++++--------------- 2 files changed, 16 insertions(+), 62 deletions(-) diff --git a/Architecture cible.md b/Architecture cible.md index 8b4ca0ec..8d9fecff 100644 --- a/Architecture cible.md +++ b/Architecture cible.md @@ -46,35 +46,17 @@ public void tick() { stateSynchronizer.updateVisibility(...); } -#1 + #2 + #11 — Alarmes, meltdown monitor, état assembled/active → state machine complète extraite en dernier, car elle dépend du résultat de l'étape 7 (le niveau de chaleur final). +#12 — FluidLockCoordinator → peut être traité en parallèle des autres (peu couplé au tick), mais marqué comme étape vers la résolution de B14 (deux systèmes de verrou) — à coordonner avec une décision sur la fusion PersistentFluidLocks/FluidLockManager. -Détection de danger thermique & pilotage des alarmes -Code concerné : tick() lignes 486-490 (calcul isDanger), activateAlarms(boolean). +Verrouillage de fluide (fluid lock) +Code concerné : tryLockFluid, canAcceptFluid, clearLock, clearLockIfAllInputsEmpty (lignes 897-962). -Pourquoi l'extraire : le BE mélange lecture de l'état NBT du pattern, classification du niveau de chaleur, et mutation de blocs distants (ReactorAlarm). C'est une logique de politique (quand déclencher l'alarme) totalement séparable de l'état du contrôleur. -Principe : SRP — "calculer si on est en danger" et "activer des blocs d'alarme" sont deux responsabilités distinctes du "être un bloc de réacteur". -Cible : ReactorAlarmCoordinator (service), qui utilise ReactorAlarmManagerI (déjà existant) + IHeat.HeatLevel. -Justification : alarmManager existe déjà pour stocker les positions ; il manque juste la couche "politique" qui décide quand activer. La regrouper avec le manager évite d'éclater la logique alarme sur deux fichiers. -Dépendances à injecter : Level, ReactorAlarmManagerI, CNAdvancementBehaviour (pour awardPlayer(SILENCE_THE_CORE)), niveau de chaleur courant (int). +Pourquoi l'extraire : le BE contient la logique d'aiguillage entre deux systèmes de verrouillage concurrents (PersistentFluidLocks vs FluidLockManager, déjà signalé dans AUDIT.md B14). C'est un problème d'infrastructure de persistance/registre global, pas une responsabilité du contrôleur. En plus, clearLockIfAllInputsEmpty fait un scan 3D de blocs (SCAN_RADIUS) — logique d'exploration spatiale qui n'a rien à faire dans un BE. +Principe : SRP + DIP — le BE devrait dépendre d'une seule abstraction IFluidLockService, pas connaître l'existence de deux implémentations. +Cible : FluidLockCoordinator (service, implémentant une interface IFluidLockService) qui encapsule l'aiguillage serveur/mémoire ET le scan clearLockIfAllInputsEmpty. À terme, ceci devrait aussi résoudre B14 en unifiant les deux systèmes derrière cette seule interface. +Justification : isole un problème d'infrastructure pré-existant identifié par l'audit, prépare sa résolution sans toucher au BE une seconde fois. +Dépendances à injecter : Level/ServerLevel, BlockPos, CNMultiblock.REGISTRATE_MULTIBLOCK (pour la taille de structure), IMultiblockController (pour le scan des inputs fluides). -Compte à rebours de fusion + notifications joueurs -Code concerné : tick() lignes 497-536 (explosionCountdown, NotifyUtil.sendActionBar/sendTitle). - -Pourquoi l'extraire : c'est une machine à états (stable → alerte → critique → explosion) avec ses propres transitions et effets de bord (notifications). Le BE ne devrait connaître que "suis-je en danger ?" et "dois-je exploser maintenant ?". -Principe : SRP + forte cohésion — toute la logique temporelle de meltdown (countdown, seuils 10s, clignotement, message de stabilisation) doit vivre ensemble, indépendamment du tick du BE. -Cible : ReactorMeltdownMonitor (state/service), exposant tick(boolean isDanger) -> MeltdownState (NONE/WARNING/CRITICAL/EXPLODE) et gérant lui-même les notifications. -Justification : isole une logique testable unitairement (countdown pur) des effets Minecraft (notify), et centralise la config (CNConfigs.server().notify.*) au même endroit. -Dépendances à injecter : Level, BlockPos, lecteurs de config (radius/warnAll), CreateNuclearLang (déjà statique, ok). - - État "assembled"/"active" du bloc & visibilité -Code concerné : isAssembled(), setAssembled(boolean), updateReactorStateVisibility(). - -Pourquoi l'extraire : logique de synchronisation entre BlockState (propriétés ASSEMBLED/ACTIVE) et l'état logique du réacteur (isReadyToRun()). C'est un sous-problème de "synchronisation blockstate ↔ logique métier", réutilisable et isolable. -Principe : SRP léger — pas critique, mais regrouper ces 3 méthodes avec la logique de readiness (isReadyToRun) renforce la cohésion. -Cible : ReactorStateSynchronizer (petit helper) ou simplement les regrouper dans le futur ReactorMeltdownMonitor/ReactorRuntimeState (#2), puisqu'ACTIVE dépend directement de isDanger/isReadyToRun. -Justification : faible priorité mais permet de découpler le calcul "dois-je être actif ?" de la mutation du BlockState, ce qui facilite les tests (pure fonction computeActive(assembled, readyToRun)). -Dépendances à injecter : Level, BlockPos, BlockState actuel. - -il y a eu un changement isReadyToRun a etait remplacé par ReactorHeatUpdateCoordinator.canRun +information FluidLockManager a etait supprimé dans les commit précedent, Il faut que tu me dise si ce point et toujours d'actualité ou non base toi sur le fichier @AUDIT_ACTUEL.md et @AUDIT_V1.md pour la déssition final Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 52d44390..b7cd3e9d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -10,22 +10,16 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.items.IItemHandler; import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.api.multiblock.BlockPattern; import net.nuclearteam.createnuclear.api.multiblock.IMultiblockController; -import net.nuclearteam.createnuclear.api.multiblock.TypeMultiblock; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; -import net.nuclearteam.createnuclear.content.multiblock.CNMultiblock; import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorGoggleTooltipRenderer; import net.nuclearteam.createnuclear.content.multiblock.controller.service.*; @@ -40,7 +34,6 @@ import java.util.List; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; -import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; import net.nuclearteam.createnuclear.content.multiblock.controller.manager.*; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; @@ -498,34 +491,13 @@ public void clearLockIfAllInputsEmpty() { if (level == null || level.isClientSide) return; - BlockPattern structure = CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, getBlockPos(), this); - // findStructure renvoie null si la structure n'est plus formée : on retombe - // alors sur la dernière taille assemblée (reactorSize) pour éviter un NPE serveur. - final int SCAN_RADIUS = structure != null ? structure.data().getSize() : reactorSize; - BlockPos center = getBlockPos(); - boolean anyNonEmpty = false; - - for (int dx = -SCAN_RADIUS; dx <= SCAN_RADIUS && !anyNonEmpty; dx++) { - for (int dy = -SCAN_RADIUS; dy <= SCAN_RADIUS && !anyNonEmpty; dy++) { - for (int dz = -SCAN_RADIUS; dz <= SCAN_RADIUS && !anyNonEmpty; dz++) { - BlockPos p = center.offset(dx, dy, dz); - BlockEntity be = level.getBlockEntity(p); - if (!(be instanceof ReactorFluidInputEntity)) - continue; - - IFluidHandler handler = be.getCapability(ForgeCapabilities.FLUID_HANDLER).orElse(null); - if (handler == null) - continue; - - for (int t = 0; t < handler.getTanks(); t++) { - if (!handler.getFluidInTank(t).isEmpty()) { - anyNonEmpty = true; - break; - } - } - } - } - } + boolean anyNonEmpty = getInputFluidManager().getFuildHandlers(level).stream() + .anyMatch(handler -> { + for (int t = 0; t < handler.getTanks(); t++) + if (!handler.getFluidInTank(t).isEmpty()) + return true; + return false; + }); if (!anyNonEmpty) clearLock(); From 39092ca341f2cd126c147d6abea33e6f6fa79218 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 20:00:25 +0200 Subject: [PATCH 057/171] chore: close out fluid-lock-extraction plan and remove dead liquid-life code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete "Architecture cible.md": after re-analysis (recorded in AUDIT_ACTUEL.md §4.6), the planned fluid-lock extraction (ReactorFluidLockCoordinator / IFluidLockService) is no longer justified — tryLockFluid/canAcceptFluid/clearLock are already thin delegations to PersistentFluidLocks (the old dual-lock-system issue is resolved since FluidLockManager was removed), and clearLockIfAllInputsEmpty no longer scans the multiblock now that it reads from ReactorInputFluidManager.getFuildHandlers(level). Document this decision in AUDIT_ACTUEL.md instead, and mark the clearLockIfAllInputsEmpty perf note as fixed. Also drop the unused getLiquidLife/setLiquidLife accessors and updateLiquidTimers() from ReactorControllerBlockEntity, along with the now-pointless liquidLife NBT read in DefaultPersistenceService, and replace the repeated four-manager clearInvalid(level) calls in removeIOAll() with a small allManagers() helper iterated via forEach. No behavioral change beyond removing dead code. --- AUDIT_ACTUEL.md | 9 ++- Architecture cible.md | 62 ------------------- .../ReactorControllerBlockEntity.java | 22 ++----- .../service/DefaultPersistenceService.java | 2 - 4 files changed, 12 insertions(+), 83 deletions(-) delete mode 100644 Architecture cible.md diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index e0cca610..24d36d64 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -154,10 +154,15 @@ Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — Les 5 problèmes structurels de `AUDIT_V1.md` §1 restent **tous valides** : 1. **Inversion `api/`** : `api.multiblock.MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` dépendent toujours de `content.*` — confirmé. -2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, verrous fluides (`tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty`, ~65 lignes), rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT_V1.md`. +2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT_V1.md`. *(Les méthodes de verrou fluide ne comptent plus dans ce hub — voir §4.6, point clôturé.)* 3. **Deux frameworks multiblock concurrents** : le ménage a réduit `lib/multiblock` (suppression de `MultiBlockManager`/`MultiBlockCache`/`IBetterPattern`), mais **trois couches coexistent toujours** pour la détection de contrôleur — `lib/multiblock` (matching générique), `api.multiblock.MultiBlockManagerBeta` (vérification de structure), et `content.multiblock.pattern.ReactorPattern`/`MultiblockHelpers` (scan géométrique brut, ~3971 blocs, **toujours** appelé en double — `findController` + `findControllerPos` — à chaque pose/casse, y compris côté client sans garde `isClientSide`). C'est le point de performance/architecture le plus critique et **entièrement non corrigé**. 4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (§3 point 3) découvert dans cette analyse. 5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, `AUDIT_V1.md` §4 ligne 2). +6. **Gestion du verrou de fluide — point clôturé, ne plus retenir** : une extraction de `tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty` vers un `ReactorFluidLockCoordinator` (`IFluidLockService`) avait été envisagée pour isoler l'aiguillage entre deux systèmes de verrouillage concurrents (B14, déjà corrigé depuis — `FluidLockManager` a été supprimé) et le scan 3D de `clearLockIfAllInputsEmpty`. Après réanalyse de l'état actuel du code, cette extraction n'est **plus justifiée** : + - `tryLockFluid`, `canAcceptFluid` et `clearLock` sont déjà de **simples délégations** vers `PersistentFluidLocks` (3-7 lignes chacune) — le BE ne connaît plus qu'un seul système de verrou (B14 résolu), il n'y a donc plus d'aiguillage à extraire. + - `clearLockIfAllInputsEmpty()` ne contient plus de scan de multiblock : la découverte des `ReactorFluidInputEntity` et la récupération des capacités sont désormais portées par `ReactorInputFluidManager.getFuildHandlers(level)` ; la méthode se réduit à une vérification sur les handlers déjà exposés par ce manager (cf. §5, point perf associé — à reformuler en conséquence). + - Créer un `ReactorFluidLockCoordinator` aujourd'hui ne ferait que déplacer des appels déjà triviaux vers un fichier supplémentaire, sans gain de lisibilité, de maintenabilité ni de testabilité — une indirection qui masquerait des délégations déjà claires. + - **Décision** : ce point est retiré du plan de refactorisation. L'architecture actuelle (délégation directe dans `ReactorControllerBlockEntity`) est considérée comme la cible, sauf apparition future de règles métier complexes autour du verrouillage de fluide (ex. verrous multi-fluides, priorités, expiration) qui justifieraient de revisiter ce choix. --- @@ -167,7 +172,7 @@ Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : - `ReactorPattern.findController`/`findControllerPos` : scan ~3971 blocs ×2 par placement/casse, sans garde client — confirmé, **aggravé** par `MultiBlockManagerBeta.findStructure` qui peut ajouter jusqu'à 4×3×729 lookups supplémentaires. - `RadiationEffect` : `HashSet` + parsing reconstruits à chaque entité/tick — confirmé. - `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame — confirmé. -- `ReactorControllerBlockEntity.clearLockIfAllInputsEmpty` : scan cubique `O(n³)` (`getBlockEntity` + capability lookup par cellule) alors que `inputFluidManager.getFuildHandlers(level)` donne déjà la liste exacte (le NPE de `findStructure`, lui, a été corrigé). +- ~~`ReactorControllerBlockEntity.clearLockIfAllInputsEmpty` : scan cubique `O(n³)`~~ — **✅ Corrigé**, la méthode utilise désormais `inputFluidManager.getFuildHandlers(level)` au lieu de scanner les cellules (le NPE de `findStructure`, lui, a été corrigé séparément). Voir §4.6 (point clôturé). - **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT_V1.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). - **Nouveau** : `NuclearExplosionEntity.tick()` — tri complet d'une pile de jusqu'à 11³=1331 `BlockPos` avec comparateur `distManhattan` coûteux, en un seul tick. diff --git a/Architecture cible.md b/Architecture cible.md deleted file mode 100644 index 8d9fecff..00000000 --- a/Architecture cible.md +++ /dev/null @@ -1,62 +0,0 @@ -Architecture cible -Le ReactorControllerBlockEntity deviendrait un orchestrateur mince : - -ReactorControllerBlockEntity - ├─ état persistant minimal (position/taille/facing, configuredPattern, inventory) - ├─ managers (existants) : input/output/inputFluid/alarm/frameDisplay - ├─ services (existants) : IHeatService, IPersistenceService - │ - ├─ NOUVEAU: ReactorRuntimeOrchestrator (remplace le corps de tick()/handleAssembledState) - │ ├─ ReactorInputSnapshotBuilder (#10) - │ ├─ ReactorHeatUpdateCoordinator (#5) - │ ├─ FluidConsumptionRateCalculator (#6) - │ ├─ ConsumptionCycleManager.update() (#7, extension de l'existant) - │ ├─ ReactorOutputDriver (#8) - │ ├─ ReactorAlarmCoordinator (#1) - │ └─ ReactorMeltdownMonitor (#2, #11) - │ └─ NuclearExplosionFactory (#3) - │ └─ BiomeIrradiationService (#4, hors package controller) - │ - ├─ NOUVEAU: ReactorDisplayState (DTO) (#9, #10, #13) - │ └─ ReactorGoggleTooltipRenderer (#9) - │ - └─ NOUVEAU: FluidLockCoordinator (IFluidLockService) (#12) -Le tick() du BE devient essentiellement : - -@Override -public void tick() { - super.tick(); - if (level.isClientSide || isExploding) return; - - MeltdownState meltdown = meltdownMonitor.tick(currentHeat()); - if (meltdown == MeltdownState.EXPLODE) { - explosionFactory.trigger(...); - isExploding = true; - return; - } - - resolveEntitiesIfNeeded(); - if (!isAssembled()) return; - - ReactorInputSnapshot snapshot = snapshotBuilder.build(level, inputManager, inputFluidManager); - displayState.updateFrom(snapshot); - - runtimeOrchestrator.run(snapshot, ...); // heat, fluid buffer, consumption cycle, rotation - alarmCoordinator.update(meltdownMonitor.isDanger()); - stateSynchronizer.updateVisibility(...); -} - -#12 — FluidLockCoordinator → peut être traité en parallèle des autres (peu couplé au tick), mais marqué comme étape vers la résolution de B14 (deux systèmes de verrou) — à coordonner avec une décision sur la fusion PersistentFluidLocks/FluidLockManager. - -Verrouillage de fluide (fluid lock) -Code concerné : tryLockFluid, canAcceptFluid, clearLock, clearLockIfAllInputsEmpty (lignes 897-962). - -Pourquoi l'extraire : le BE contient la logique d'aiguillage entre deux systèmes de verrouillage concurrents (PersistentFluidLocks vs FluidLockManager, déjà signalé dans AUDIT.md B14). C'est un problème d'infrastructure de persistance/registre global, pas une responsabilité du contrôleur. En plus, clearLockIfAllInputsEmpty fait un scan 3D de blocs (SCAN_RADIUS) — logique d'exploration spatiale qui n'a rien à faire dans un BE. -Principe : SRP + DIP — le BE devrait dépendre d'une seule abstraction IFluidLockService, pas connaître l'existence de deux implémentations. -Cible : FluidLockCoordinator (service, implémentant une interface IFluidLockService) qui encapsule l'aiguillage serveur/mémoire ET le scan clearLockIfAllInputsEmpty. À terme, ceci devrait aussi résoudre B14 en unifiant les deux systèmes derrière cette seule interface. -Justification : isole un problème d'infrastructure pré-existant identifié par l'audit, prépare sa résolution sans toucher au BE une seconde fois. -Dépendances à injecter : Level/ServerLevel, BlockPos, CNMultiblock.REGISTRATE_MULTIBLOCK (pour la taille de structure), IMultiblockController (pour le scan des inputs fluides). - -information FluidLockManager a etait supprimé dans les commit précedent, Il faut que tu me dise si ce point et toujours d'actualité ou non base toi sur le fichier @AUDIT_ACTUEL.md et @AUDIT_V1.md pour la déssition final - -Avant toute proposition de modification, explique précisément les changements envisagés et les raisons de ces choix. Ne modifie aucun fichier directement et présente uniquement l’analyse, les recommandations et les éventuels exemples de code dans cette discussion. \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index b7cd3e9d..19287365 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -168,14 +168,6 @@ public void clearTimers() { this.cycleManager.clear(); } - public double getLiquidLife() { - return this.liquidLife; - } - - public void setLiquidLife(double l) { - this.liquidLife = l; - } - public ReactorFrameDisplayManagerI getFrameDisplayManager() { return this.frameDisplayManager; } @@ -196,6 +188,10 @@ public ReactorDisplayState getDisplayState() { return this.displayState; } + private List allManagers() { + return List.of(inputManager, inputFluidManager, outputManager, alarmManager); + } + /** * Main constructor allowing dependency injection for testability and DIP * compliance. @@ -401,11 +397,6 @@ private boolean isEmptyConfiguredPattern() { return configuredPattern.isEmpty() || this.getConfiguredPatternTag().isEmpty(); } - private boolean updateLiquidTimers() { - liquidLife -= 1; - return liquidLife <= 0; - } - public void addInput(BlockPos inputPos) { this.inputManager.addBlock(inputPos); this.setChanged(); @@ -451,10 +442,7 @@ public void removeAlarm(BlockPos alarmPos) { } public void removeIOAll() { - this.inputManager.clearInvalid(level); - this.outputManager.clearInvalid(level); - this.inputFluidManager.clearInvalid(level); - this.alarmManager.clearInvalid(level); + allManagers().forEach(m -> m.clearInvalid(level)); this.setChanged(); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java index 24f9e011..0e0ddd07 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultPersistenceService.java @@ -1,6 +1,5 @@ package net.nuclearteam.createnuclear.content.multiblock.controller.service; -import com.simibubi.create.content.logistics.BigItemStack; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; @@ -19,7 +18,6 @@ public void readBasicState(ReactorControllerBlockEntity owner, CompoundTag compo ? BoundingBox.CODEC.parse(NbtOps.INSTANCE, compound.get("reactorPose")).result().orElse(null) : null ); - owner.setLiquidLife(compound.getDouble("liquidLife")); if (!clientPacket) { owner.deserializeInventory(compound.getCompound("pattern")); From c05129459ee672a7a14c66157a902431f71b6289 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 21:19:32 +0200 Subject: [PATCH 058/171] docs: add independent audit report cross-checking prior audits against current code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AUDIT_INDEPENDANT.md, an independent re-verification of the project's two previous audits against the current state of the code (286 files, ~24,600 lines) and git history rather than against their written conclusions. Each carried-over finding was re-checked directly in source (imports, call-sites, grep for callers) before being kept, dropped, or flagged as newly found. Key takeaways recorded: the ReactorControllerBlockEntity decomposition is now genuinely complete (previously flagged as architecture problem #1 in both prior audits); two structural claims from the earliest audit (an `api/` dependency inversion, and "two/three competing multiblock frameworks") are refuted by direct code reading — the multiblock paths form a sequential pipeline, not competing systems; and several trivial, long-known bugs remain unfixed despite cleanup having focused elsewhere (radiation, dead code, controller). --- AUDIT_INDEPENDANT.md | 155 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 AUDIT_INDEPENDANT.md diff --git a/AUDIT_INDEPENDANT.md b/AUDIT_INDEPENDANT.md new file mode 100644 index 00000000..602a7fe9 --- /dev/null +++ b/AUDIT_INDEPENDANT.md @@ -0,0 +1,155 @@ +# Audit indépendant — CreateNuclearForge (état au 2026-06-20, branche V2-CorrectifAudit) + +## Méthodologie + +Cette analyse part du code actuel (`src/main/java`, 286 fichiers, ~24 600 lignes — contre 282 fichiers / ~21 000 lignes au moment d'`AUDIT_V1.md`) et de l'historique Git, **pas** des conclusions d'`AUDIT_V1.md` / `AUDIT_ACTUEL.md`. Chaque point repris de ces deux documents a été revérifié directement dans le code (lecture de fichier, grep des appelants, lecture des call-sites) avant d'être classé. Deux audits internes générés en parallèle se sont contredits sur l'état du scan multiblock ; j'ai tranché en relisant moi-même `ReactorPattern.java`, `ReactorCasing.java` et `ReactorAssembler.java` plutôt que de reporter une conclusion non vérifiée. + +**Limite de couverture honnête** : tous les bugs mineurs/robustesse listés en fin de section 2 d'`AUDIT_V1.md` (B7, B10, B17, B18 et la liste "mineurs" non numérotée) n'ont pas été revérifiés ici faute de signal qu'ils aient changé — ils ne sont ni confirmés ni infirmés dans ce document, à re-vérifier ponctuellement avant de les traiter. + +--- + +## 1. Constat global + +Le refactor V2 annoncé dans les deux audits précédents n'est plus "en cours et à moitié fait" pour son chantier principal : **la décomposition de `ReactorControllerBlockEntity` est maintenant réellement effective** (commits `dd918582`, `6e717c44`, `8611ed76`, `56373bf7`, `39092ca3`). C'est le changement le plus net par rapport aux deux audits précédents, qui tous deux pointaient cette classe comme le problème architectural n°1. + +En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans being revérifiées par `AUDIT_ACTUEL.md`, se révèlent **fausses sur le code actuel** : +- L'« inversion de dépendance dans `api/` » n'existe pas (vérifié par lecture directe des imports). +- Les « deux/trois frameworks multiblock concurrents » ne sont pas concurrents : c'est un pipeline séquentiel (scan géométrique → matcher formel → données datapack), dont seule la première étape pose un vrai problème. + +À l'inverse, des bugs très simples et jamais mis en doute (`B12`, `B15`) sont **toujours présents** alors qu'ils sont triviaux à corriger — signe que le nettoyage a suivi les zones où les audits insistaient (radiation, dead code, controller) plutôt qu'une revue systématique de toutes les lignes signalées. + +--- + +## 2. Revue des recommandations historiques + +### 2.1 À conserver (toujours valides aujourd'hui) + +| Réf. | Constat | Pourquoi ça tient toujours | +|---|---|---| +| B12 | `AnimalUtil.isFood` teste un tag NBT `"Ingredient"` jamais écrit au lieu du stack tenu | Vérifié ligne ~77, toujours faux — élevage/apprivoisement du poulet irradié via `isFood` reste cassé | +| B15 | `NuclearExplosionEntity` (~l.224-228) utilise `try{...}catch(Exception){destroyBlock(...,true)}` comme branchement de contrôle, avec sémantique de drop différente entre les deux branches | Toujours présent, anti-pattern réel (avale les vrais bugs) | +| ReactorInputFluidManager | `getFluidInTank(getTanks())` (off-by-one, viole le contrat `IFluidHandler`) ; `extractFluids` ne décrémente jamais `fluidNeeded` ; ignore l'extraction quand `toExtract>1` | Confirmé toujours présent (l.127, l.146-157). Toléré aujourd'hui parce que `SmartFluidTank` est mono-tank et ignore l'index, mais reste un vrai bug de contrat, pas une légende d'audit | +| Aucun test | `src/test` toujours vide (0 fichier) | Confirmé. Pour un mod avec une logique métier non triviale (calcul de chaleur, pattern matching, verrouillage fluide), c'est la dette la plus structurelle du projet — bien plus que la forme des classes | +| Dead code animation (`chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `bob`, `moveBox`, `progressRotation*`, `transitionTo`, etc.) | Grep confirme : zéro appelant dans tout le repo, en dehors de leurs propres définitions internes | Toujours mort. `AUDIT_ACTUEL.md` avait raison de noter que le retrait est non trivial (cascade interne dans `CNAdvancedModelBox`) — ce n'est pas un "quick win" malgré l'apparence | +| `RadiationOverlay` + `EasingHudOverlay` | Toujours commenté dans `HudRenderer.overlays` ; `HelmetOverlay.setCoverage` écrit toujours dans un champ que personne ne rend | Confirmé inchangé depuis `AUDIT_ACTUEL.md` — décision produit à prendre (supprimer ou réactiver), pas un bug en soi | +| `SimpleMultiBlockPattern.test()` | Méthode sans appelant | Confirmé toujours mort, retrait trivial et sans risque | +| `IrradiatedBiomes.monsters()` | Corps vide, appelé avec des paramètres ignorés silencieusement | Confirmé inchangé | +| Collier teignable chat/loup non câblé | `IrradiatedWoldCollarLayer.render()` toujours vide, aucun `addLayer(...)` enregistrant `IrradiatedCatCollarLayer` | Confirmé inchangé — feature visiblement abandonnée en cours de route (`IrradiatedWolf` a du code commenté `DATA_COLLAR_COLOR` qui le prouve) | + +### 2.2 À supprimer du plan (obsolètes ou réfutées par le code actuel) + +| Réf. | Recommandation historique | Pourquoi elle ne tient plus | +|---|---|---| +| AUDIT_V1 §1.1 | « Inversion de dépendance dans `api/` » : `MultiBlockManagerBeta`, `RodType`, `ReactorFluidType` importeraient du `content.*` concret | **Réfuté** par lecture directe des imports actuels : aucun des trois fichiers n'importe quoi que ce soit de `content.*`. `RodType`/`ReactorFluidType` utilisent leurs propres types `*Value` (api) comme fallback. Soit ce couplage a été retiré depuis, soit l'audit V1 décrivait un état antérieur — dans tous les cas, ce n'est plus vrai aujourd'hui | +| AUDIT_V1 §1.3 / §3 | « Deux/trois frameworks multiblock concurrents », `lib.multiblock.manager.*` et `IBetterPattern` comme code mort à supprimer | `lib.multiblock.manager.*` et `IBetterPattern` **n'existent plus dans le repo** — déjà supprimés. Ce qui reste de `lib/multiblock/` (`SimpleMultiBlockPattern`, `SimpleMultiBlockAislePatternBuilder`, `impl/`, `misc/`) est **activement utilisé** par `CNMultiblock` pour construire les patterns 5×5/7×7. Ce n'est pas une couche concurrente mais une étape du même pipeline (scan géométrique → `ReactorAssembler` → `CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure` → données `RodType`/`ReactorFluidType`). Le vrai problème n'est pas la coexistence de "frameworks" mais la première étape de ce pipeline (voir §3.1) | +| AUDIT_V1 §1.2 / §8.5 | « God class » `ReactorControllerBlockEntity`, décomposition "à moitié faite", cible <300 lignes | La classe fait aujourd'hui **492 lignes** et délègue réellement : `service/` (8 fichiers, 557 lignes), `manager/` (5 fichiers, 957 lignes), `consumable/` (6 fichiers, 380 lignes), `display/` (2 fichiers). Le tick, le NBT, la chaleur, l'alarme/meltdown, le tooltip sont tous délégués. Ce qui reste dans la BlockEntity (positions I/O, état du pattern, délégation du verrou fluide) est le périmètre légitime d'un coordinateur de multiblock, pas un hub. **Continuer à viser "<300 lignes" comme objectif en soi serait une erreur** : il n'y a plus de logique métier à extraire, seulement de la coordination d'état — découper davantage ajouterait de l'indirection sans retirer de responsabilité, exactement le défaut qu'`AUDIT_V1.md` reprochait à l'extraction inachevée | +| AUDIT_ACTUEL §4.6 | Coordinateur de verrou fluide (`ReactorFluidLockCoordinator`) jugé non justifié | Confirmé inchangé et la conclusion d'`AUDIT_ACTUEL.md` reste correcte : `tryLockFluid`/`canAcceptFluid`/`clearLock` sont de simples délégations de 3-7 lignes vers `PersistentFluidLocks` (`FluidLockManager`, le double-système, a bien été supprimé). Pas de raison de revenir sur ce point | +| AUDIT_V1 §1.5 | `run/` à versionner dans `.gitignore` | **Déjà fait** : `.gitignore` contient bien les règles `run/*`. Reste un résidu mineur — voir §4.7 | +| B3, B4, B5, B6, B8, B9, B11, B13, B16, B19 | Bugs détaillés dans `AUDIT_V1.md` §2 | Tous vérifiés **corrigés** dans le code actuel (cooldown via `Map`, loot/tag du bloc de thorium normalisés, `BiomeTagRule.apply()` retourne une `Condition`, packet blueprint envoie les deux valeurs distinctes, plus de scan null-unsafe dans `clearLockIfAllInputsEmpty`, paliers de radiation à 4 niveaux distincts, logger après null-check, bras de l'armure anti-radiation sur les bons membres, garde `conditions` non-null dans le datagen, `IrradiatedSurfaceRules` v1 disparu). Rien à reprendre ici | +| B14 / `FluidLockManager` | Map statique sans dimension, jamais purgée, doublon de `PersistentFluidLocks` | Fichier **supprimé** du repo, remplacé par `PersistentFluidLocks` seul. Le double-système n'existe plus | +| B2 | `RadiationSyncPacket` jette l'instance sans la stocker | Ce packet **n'existe plus** ; la synchro radiation passe par la capability Forge + `PlayerTickEvent`. Point obsolète | +| AUDIT_ACTUEL §3.3 (partie double-comptage) | `IRadiationSource` vs `RadiationRegistry` : risque de double comptage actif | À nuancer plutôt qu'à supprimer : le code appelle bien les deux mécanismes sans court-circuit (`RadiationCapability` l.106-113), **mais** `RadiationRegistry` lève une `IllegalStateException` à l'enregistrement si un item implémente déjà `IRadiationSource` (l.81-82) — ce qui empêche structurellement qu'un item soit compté deux fois. Le risque n'est donc pas "actif", il est "architecturalement bloqué mais maladroit" : deux mécanismes pour un seul concept, sans qu'aucun item ne cumule les deux aujourd'hui. La duplication de design reste valide à signaler (voir §3.2), mais "double comptage" comme bug concret est à retirer | + +### 2.3 À adapter (le constat reste vrai mais la cause ou le correctif a changé) + +- **Radiation éparpillée sur plusieurs couches** (`AUDIT_V1.md` §1.4, `AUDIT_ACTUEL.md` §3 point 3) — toujours vrai, mais le détail a évolué : `RadiationEffectHandler.apply()` (l.15-21) applique encore un effet de radiation à **toute** entité affectée par les potions, sans aucune garde (pas de check `enabledItemRadiation`, pas de tag `IRRADIATED_IMMUNE`, pas de check spectateur, pas de résistance anti-radiation) — c'est confirmé identique à ce que décrivait `AUDIT_ACTUEL.md`. La correction proposée dans ce document (extraire un gate binaire commun `RadiationCapability.canBeIrradiated`, réutilisé par `RadiationEffectHandler` et `RadiationEffect`) reste pertinente et n'a pas été appliquée — à conserver comme recommandation concrète, pas comme vague "consolidation à 1 module" (objectif trop large pour être actionnable). +- **`RadiationEffect` reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque entité, à chaque tick** (l.38-43) — confirmé inchangé, et c'est un vrai point de perf (pas juste de style) puisque `isDurationEffectTick` retourne `true` : ce predicate tourne sur toutes les entités proches de tout joueur irradié, à chaque tick. La solution proposée par `AUDIT_ACTUEL.md` (cache statique invalidé au reload config) reste la bonne réponse. + +--- + +## 3. Nouveaux problèmes détectés (absents des deux audits précédents) + +### 3.1 Le scan géométrique du contrôleur n'a aucune garde côté client et travaille en double sur un même événement + +Lecture directe de `ReactorPattern.java` (l.34-51, 53-71) et de ses appelants (`ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorOutputEntity`) : + +- `findController`/`findControllerPos` scannent toujours ~3 971 blocs (11×19×19, `new BlockPos` par itération, borne `!=`) — confirmé identique aux deux audits précédents. +- **Aucune garde `level.isClientSide`** n'existe nulle part dans la chaîne `Block.onPlace/onRemove/playerDestroy` → `ReactorPattern.findController` → `ReactorAssembler.assemble/disassemble`. Or `ReactorAssembler.assemble`/`disassemble` **mutent l'état de la BlockEntity** (`entity.setAssembled(true)`, `entity.setMultiblockSize(...)`, `entity.removeIOAll()`) et envoient un message au joueur (`sendMessageToPlayer`). Ce n'est pas qu'un coût CPU inutile côté client : c'est une mutation d'état métier potentiellement exécutée deux fois (client + serveur) à chaque pose/casse de bloc autour d'un réacteur. +- Sur `ReactorCasing`, **`playerDestroy` et `onRemove` appellent chacun `pattern.findController(pos, level, false)`** (l.60 et l.66) pour le même événement de casse — donc deux scans complets de 3 971 blocs au lieu d'un. `ReactorCooler`/`ReactorFrame` ont le même schéma à la pose (`onPlace` + un second appel). +- `ReactorAssembler.assemble` logue en `LOGGER.warn` (pas `debug`) à **chaque** réussite de pattern (l.37-38) — donc à chaque pose/casse de bloc qui retrouve le contrôleur, y compris en jouant normalement. C'est un spam de log en conditions normales de jeu, pas seulement en debug. + +C'est, de loin, le problème de performance/correction le plus concret du projet aujourd'hui — plus précis que les deux audits précédents qui notaient le coût du scan sans vérifier l'absence de garde client ni le double appel. + +**Recommandation** : ajouter `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` (ou dans leurs appelants), supprimer l'appel redondant dans `ReactorCasing` (garder `onRemove` qui couvre tous les cas de suppression, retirer celui de `playerDestroy`), passer le `LOGGER.warn` en `LOGGER.debug`. Coût de correction : quelques lignes, risque très faible, gain net sur chaque pose/casse de bloc en partie multijoueur. + +### 3.2 `DefaultHeatCalculator.computeHeat` — coût quadratique avec désérialisation NBT répétée, et asymétrie fuel/cooler dans le calcul de proximité + +`content/multiblock/reactorLogic/DefaultHeatCalculator.java` (l.30-77), appelé à chaque tick de calcul de chaleur quand le réacteur est assemblé : + +- Pour chaque item du pattern (jusqu'à 57 slots), la méthode refait une boucle 9×9 (81 cellules) pour localiser sa position, puis pour chacun des 4 voisins, une **nouvelle boucle sur la totalité des items** (l.59) pour retrouver le voisin par son slot — soit, dans le pire cas (réacteur plein), de l'ordre de 57 × 81 × 4 × 57 ≈ 1 050 000 itérations élémentaires par tick, chacune désérialisant un `ItemStack` depuis NBT (`ItemStack.of(list.getCompound(i))`, l.36 et l.62) sans aucun cache. +- C'est un coût bien réel à chaque tick d'un réacteur plein, indépendant du scan multiblock (§3.1) — non documenté dans les deux audits précédents, qui ne couvraient pas `reactorLogic/`. +- **Asymétrie de calcul** (l.61-69) : le bonus/malus de proximité n'est calculé que lorsque `currentRod` vaut `"fuel"` (`if ("fuel".equals(currentRod))`, l.61) — un rod de type cooler ne déclenche jamais l'examen de ses propres voisins. Le calcul de proximité est donc unilatéral : il dépend de la position relative fuel→voisin, jamais cooler→voisin. Sans connaître la balance voulue, je ne peux pas affirmer qu'il s'agit d'un bug plutôt que d'un choix de design (un cooler n'a peut-être pas vocation à "détecter" ses voisins, c'est le fuel qui "regarde" s'il est entouré de coolers) — mais la formule `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.67, une **division**) à côté de `heat += rod.proximityRodHeat()` (l.65, une **addition** directe) sur la branche fuel mérite une vérification avec les valeurs de config réelles : une division par un coefficient de proximité produit un résultat très sensible aux petites valeurs, contrairement à l'addition symétrique de la branche fuel-fuel. + +**Recommandation** : si la fréquence de calcul ne descend pas naturellement (ex. seulement aux changements de pattern plutôt qu'à chaque tick — à vérifier dans `ReactorHeatUpdateCoordinator`/`FluidConsumptionRateCalculator`, hors périmètre de cette lecture), remplacer la boucle de recherche du voisin (l.59) par une `Map` construite une fois par appel au lieu d'une boucle O(n) répétée par cellule — ça ramène le coût à O(n) au lieu de O(n²) sans changer le comportement. Ne pas toucher à l'asymétrie fuel/cooler sans confirmation du comportement voulu auprès de l'équipe de balance (cf. note mémoire existante : la logique de chaleur a déjà des distinctions intentionnelles entre chemins — ne pas unifier sans vérification). + +### 3.3 `IHeat.HeatLevel.isNotDanger` — condition tautologique, confirmée inchangée + +```java +public static boolean isNotDanger(int heat, int reactorSize) { + return of(heat, reactorSize) != DANGER || of(heat, reactorSize) != NONE; +} +``` +`X != DANGER || X != NONE` est toujours vrai (un `HeatLevel` ne peut être les deux à la fois) — déjà documenté dans `AUDIT_ACTUEL.md` point 11, toujours présent. Confirmé que son unique appelant (`ReactorControllerBlockEntity`, ~l.391, garde de `outputManager.rotateOutputs`) rend la garde "ne pas faire tourner les sorties en danger" inopérante. Bug isolé, correctif d'une ligne (`!= DANGER` seul, sous réserve de confirmer le comportement voulu — produire les items même en surchauffe n'est peut-être pas dramatique en soi, mais ce n'est manifestement pas ce que le code voulait faire). + +### 3.4 Fonctionnalité de teinture de tissu sur l'armure anti-radiation : un système entier, fonctionnel, mais d'utilité à requestionner + +Contrairement à ce que pointait `AUDIT_ACTUEL.md` (qui annonçait `getArmorTexture` comme un hook mort en Forge 1.20.1), le système est en réalité câblé : `ClothTagHelper.getArmorTexturePath` est appelé, les tags de tissu sont persistés et lus via le mixin `SmithingTransformRecipeMixin`. Je n'ai pas pu vérifier en jeu si le rendu visuel change réellement (cette vérification nécessiterait de lancer le client) — donc ni confirmation ni infirmation du rendu effectif, juste un signal que le câblage data existe contrairement à ce qu'affirmait l'audit précédent. À reverifier en jeu avant de décider quoi que ce soit ici ; ne pas planifier de suppression sur la base de l'audit précédent. + +### 3.5 Reliquats de fichiers `run/` toujours suivis par Git malgré le `.gitignore` + +19 fichiers sous `run/` sont encore suivis par Git (`git ls-files`), dont des artefacts clairement non-projet : `run/hs_err_pid21100.log`, `run/hs_err_pid27848.log` (crash dumps JVM), `run/servers.dat`, `run/servers.dat_old`, `run/imgui.ini`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`. Le `.gitignore` a bien été corrigé (point 2.2), mais ces fichiers avaient déjà été commités avant la règle et n'ont jamais été détrackés. Les fichiers `run/schematics/*.nbt` en revanche sont vraisemblablement des assets de gameplay légitimes (structures de ponder/reactor) et ne doivent pas être traités comme des déchets de debug. + +**Recommandation** : `git rm --cached` sur les 6 fichiers de debug/environnement listés ci-dessus (pas les `.nbt`). Risque nul, gain cosmétique sur la taille du repo. + +### 3.6 Code commencé puis abandonné, au-delà du collier teignable déjà documenté + +- `PlayerInteracteReactorFluidInput.java` (~l.58-60) : bloc entier commenté, logique d'interaction fluide inachevée. +- `ReactorOutput.java` : propriété `SPEED` commentée, jamais réactivée. +- `foundation/data/recipe/CNStandardRecipeGen.java:226` : `// FIXME 5.1 refactor - recipe categories as markers instead of sections?` — note de refactor laissée en place, à trancher (faire ou retirer le commentaire) plutôt qu'à laisser indéfiniment. + +Aucun de ces trois points n'est urgent ; ils sont mentionnés parce qu'ils n'apparaissent dans aucun des deux audits précédents et illustrent que le code "en cours de refactor" laisse régulièrement des fragments derrière lui — un signal d'hygiène de fin de PR (supprimer le code mort avant de merger) plus qu'un problème ponctuel à corriger. + +--- + +## 4. Architecture actuelle — évaluation sans objectif imposé + +Je n'applique pas de règle automatique ("classe > N lignes → découper", "ajouter un service/coordinateur par défaut"). Sur cette base : + +- **`ReactorControllerBlockEntity` (492 lignes) n'a plus besoin d'être découpée davantage.** La décomposition manager/service/consumable a atteint un point où ce qui reste dans la classe est la coordination légitime d'un multiblock (positions I/O, état de pattern, délégation des verrous). Continuer à découper produirait des classes d'1-2 méthodes dont la seule fonction serait d'exister — le coût de la fragmentation (un fichier de plus à ouvrir pour suivre un flux simple) dépasserait le bénéfice. **Recommandation : clore ce chantier**, sauf si une responsabilité métier concrète et identifiable apparaît plus tard. +- **Le pipeline multiblock (scan géométrique → matcher formel → données datapack) n'est pas un problème de design** — c'est un problème de garde d'exécution (§3.1). Fusionner les trois étapes en un seul mécanisme serait un gros risque (le matcher formel `lib/multiblock` et le scan géométrique `ReactorPattern` ne font pas le même travail : l'un valide une forme exacte, l'autre cherche un contrôleur dans le voisinage d'un bloc qui vient de changer) pour un gain incertain. **Ne pas toucher à la structure ; corriger la garde client et la duplication d'appel.** +- **La feature radiation reste éparpillée sur plusieurs mécanismes**, mais "consolider en un seul module" (recommandation §6 d'`AUDIT_V1.md`) est un objectif trop large pour être actionné directement. Le point concret et actionnable est `RadiationEffectHandler` sans garde (§2.3) — corriger ce point réduit le risque réel (radiation appliquée à un joueur protégé) sans nécessiter de réorganisation de packages. +- **`api/` n'a pas le problème d'inversion de dépendance qu'on lui prêtait** — aucune action nécessaire ici. +- **Absence de tests reste le vrai writ-large structurel** : ni la taille des classes, ni le nombre de packages radiation, ne sont aussi limitants pour la maintenabilité à long terme que l'absence totale de couverture sur la logique de chaleur, de pattern matching et de verrouillage fluide — ce sont précisément les zones où les bugs silencieux (B12, l'asymétrie de `DefaultHeatCalculator`, la tautologie d'`IHeat`) survivent malgré plusieurs passes d'audit successives. + +--- + +## 5. Feuille de route réaliste + +**Corrections triviales, risque quasi nul (à faire en premier, gain immédiat)** +1. Garde `level.isClientSide()` sur la chaîne `findController`/`findControllerPos`/`ReactorAssembler` (§3.1). +2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` (garder `onRemove`) ; vérifier `ReactorCooler`/`ReactorFrame` pour le même schéma à la pose. +3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). +4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation du comportement voulu. +5. `AnimalUtil.isFood` (B12) : tester le stack tenu, pas le tag NBT mort. +6. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. +7. `git rm --cached` sur les 6 fichiers de debug suivis sous `run/` (§3.5). + +**Corrections ciblées, risque faible à moyen** +8. `RadiationEffectHandler.apply` : ajouter les mêmes gardes que `RadiationEffect`/`RadiationCapability` (config, immunité, spectateur, résistance) — recommandation déjà détaillée dans `AUDIT_ACTUEL.md`, toujours valable et non appliquée. +9. `RadiationEffect` : cache statique pour la blacklist d'entités au lieu de la reconstruire à chaque entité/tick. +10. `ReactorInputFluidManager` : corriger l'off-by-one `getFluidInTank(getTanks())` et la non-décrémentation de `fluidNeeded`, même si le bug est aujourd'hui toléré par l'implémentation mono-tank actuelle — il deviendra actif au premier `SmartFluidTank` multi-tank. +11. `DefaultHeatCalculator` : remplacer la recherche de voisin O(n) répétée par une map précalculée par appel (réduit O(n²) → O(n)) ; vérifier séparément (avec l'équipe balance) si l'asymétrie fuel/cooler et la division `baseRodHeat()/proximityRodHeat()` sont voulues. + +**Décisions produit (pas des bugs — choisir puis exécuter)** +12. Collier teignable chat/loup : finir le câblage (`addLayer` + implémenter `IrradiatedWoldCollarLayer.render`) ou retirer la mécanique `DyeItem`/`setCollarColor`. +13. `RadiationOverlay`/`EasingHudOverlay` : supprimer si `IrradiatedOverlayRendererVision` suffit, ou réactiver et corriger le `Math.round` qui annule le fade. +14. `PlayerInteracteReactorFluidInput` : terminer ou retirer le bloc commenté. + +**Chantier de fond, pas urgent mais le plus rentable à long terme** +15. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — ce sont les trois zones où des bugs silencieux ont survécu à plusieurs audits successifs sans qu'aucun test ne les détecte automatiquement. + +**Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** +- Découpage supplémentaire de `ReactorControllerBlockEntity`. +- "Correction" de l'inversion de dépendance `api/` (n'existe pas). +- Fusion ou suppression du pipeline multiblock à trois étapes (le pipeline est sain, seule l'exécution manque de garde). +- Coordinateur dédié au verrouillage fluide (`ReactorFluidLockCoordinator`) — confirmé non justifié, comme déjà tranché dans `AUDIT_ACTUEL.md`. From a420b99ae5e87e8b0039a057a6f8a004d50f8710 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 21:29:14 +0200 Subject: [PATCH 059/171] chore: remove unused imports and dead commented-out code Drop unused imports across several reactor controller/manager/service files (BlockModelBuilder, BigItemStack, ReactorFluidType, CNBlocks, CreateNuclear, CNTags/CNItemTags, ReactorOutputEntity, BiFunction, ItemStack), and delete a stale commented-out refreshFrameFluidCache javadoc block and a leftover debug LOGGER.warn call in ReactorFrameDisplayManager (re-enabling the javadoc as a real comment, with broken @link references to the now-removed fields stripped out). Also minor doc/grammar fixes: move a misplaced javadoc above the ReactorInputFluidManagerI interface declaration instead of inside it, and fix "Currently provides" -> "Currently, provides" in ReactorInputManagerI. No behavioral change. --- .../ReactorControllerGenerator.java | 1 - .../display/ReactorDisplayState.java | 1 - .../manager/ReactorAlarmManager.java | 1 - .../manager/ReactorFrameDisplayManager.java | 26 +++++++++---------- .../manager/ReactorInputFluidManagerI.java | 10 +++---- .../manager/ReactorInputManager.java | 2 -- .../manager/ReactorInputManagerI.java | 2 +- .../manager/ReactorOutputManagerI.java | 2 -- .../service/DefaultHeatService.java | 2 -- .../controller/service/IHeatService.java | 2 -- .../snapshot/ReactorInputSnapshot.java | 2 -- 11 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerGenerator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerGenerator.java index 389ab93b..8a2fafde 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerGenerator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerGenerator.java @@ -5,7 +5,6 @@ import com.tterrag.registrate.providers.RegistrateBlockstateProvider; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.generators.BlockModelBuilder; import net.minecraftforge.client.model.generators.ModelFile; public class ReactorControllerGenerator extends SpecialBlockStateGen { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java index 54e100c9..d0755ecc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/display/ReactorDisplayState.java @@ -1,6 +1,5 @@ package net.nuclearteam.createnuclear.content.multiblock.controller.display; -import com.simibubi.create.content.logistics.BigItemStack; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java index 0c8a679f..a1a28456 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java @@ -6,7 +6,6 @@ import net.minecraft.nbt.Tag; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarmEntity; import java.util.ArrayList; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java index b6198791..81b95e14 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java @@ -4,7 +4,6 @@ import net.minecraft.world.level.Level; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; -import net.nuclearteam.createnuclear.CreateNuclear; import org.jetbrains.annotations.Nullable; public class ReactorFrameDisplayManager implements ReactorFrameDisplayManagerI { @@ -25,18 +24,18 @@ public class ReactorFrameDisplayManager implements ReactorFrameDisplayManagerI { private FluidStack frameFluidCache = FluidStack.EMPTY; -// /** -// * Returns the fluid currently held by the reactor, used by the frame -// * renderer to draw the matching liquid in the window. On the client this -// * reads the synced {@link #clientDisplayFluids}; on the server it reads the -// * aggregated {@link #bigFluidStack}. Returns {@link FluidStack#EMPTY} when -// * the reactor holds no fluid. -// *

-// * Recomputes, at most once per game tick, the fluid shown in the frame -// * windows and how full the input is. Both values are read from the same live -// * input tanks (whose contents are synced to the client), so they always agree -// * regardless of the fluid type. -// */ + /** + * Returns the fluid currently held by the reactor, used by the frame + * renderer to draw the matching liquid in the window. On the client this + * reads the synced ; on the server it reads the + * aggregated . Returns {@link FluidStack#EMPTY} when + * the reactor holds no fluid. + *

+ * Recomputes, at most once per game tick, the fluid shown in the frame + * windows and how full the input is. Both values are read from the same live + * input tanks (whose contents are synced to the client), so they always agree + * regardless of the fluid type. + */ private void refreshFrameFluidCache(@Nullable Level level, ReactorInputFluidManagerI handlers) { if (level == null) return; long now = level.getGameTime(); @@ -50,7 +49,6 @@ private void refreshFrameFluidCache(@Nullable Level level, ReactorInputFluidMana for (IFluidHandler handler : handlers.getFuildHandlers(level)) { int tanks = handler.getTanks(); for (int t = 0; t < tanks; t++) { -// CreateNuclear.LOGGER.warn("tank: {}, stack: {}, capacity: {}, amount: {}", tanks, handler.getFluidInTank(t), handler.getTankCapacity(t), handler.getFluidInTank(t).getAmount()); FluidStack stack = handler.getFluidInTank(t); capacity += handler.getTankCapacity(t); amount += stack.getAmount(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManagerI.java index 7610f0da..e809ae2d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManagerI.java @@ -7,12 +7,12 @@ import java.util.List; +/** + * Interface for managing reactor input fluids. + * Implementations track input fluid sources and provide + * accessors and extraction methods for reactor consumption. + */ public interface ReactorInputFluidManagerI extends ReactorIOManager { - /** - * Interface for managing reactor input fluids. - * Implementations track input fluid sources and provide - * accessors and extraction methods for reactor consumption. - */ /** Returns an immutable copy of tracked positions. */ List getBlocksPosition(Level level); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java index 77b68899..2e0cc60e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java @@ -11,8 +11,6 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandler; -import net.nuclearteam.createnuclear.CNTags; -import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.content.multiblock.input.item.VirtualReactorInputsItem; import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputEntity; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManagerI.java index 9e3477af..08e81a86 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManagerI.java @@ -9,7 +9,7 @@ /** * Interface exposing operations specific to reactor inputs. - * Currently provides access to `IItemHandler` instances at resolved input positions. + * Currently, provides access to `IItemHandler` instances at resolved input positions. */ public interface ReactorInputManagerI extends ReactorIOManager { /** diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java index 3211d7d1..ddc8b4b5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManagerI.java @@ -2,10 +2,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import java.util.List; -import java.util.function.BiFunction; /** * Interface exposing operations specific to reactor outputs. diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java index 59deb2b8..38202af7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java @@ -1,8 +1,6 @@ package net.nuclearteam.createnuclear.content.multiblock.controller.service; -import com.simibubi.create.content.logistics.BigItemStack; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java index 5f18fb4b..c56fa4e8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java @@ -1,8 +1,6 @@ package net.nuclearteam.createnuclear.content.multiblock.controller.service; -import com.simibubi.create.content.logistics.BigItemStack; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java index ccbfa972..b9e55756 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/snapshot/ReactorInputSnapshot.java @@ -1,8 +1,6 @@ package net.nuclearteam.createnuclear.content.multiblock.controller.snapshot; -import com.simibubi.create.content.logistics.BigItemStack; import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import java.util.List; From 4d01f10fc5fa12434d41ea0aca2ebd0e387077f7 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 20 Jun 2026 21:51:26 +0200 Subject: [PATCH 060/171] chore: translate French comments to English and minor cleanup Translate remaining French inline comments and javadoc to English across the reactor alarm, blueprint, controller, frame, input/output and manager classes, for consistency with the rest of the codebase. Also fold a few fully qualified references into proper imports (Direction, ForgeRegistries) where the comment translation touched the same lines. No behavioral change. --- .../content/multiblock/alarm/ReactorAlarm.java | 6 +++--- .../multiblock/alarm/ReactorAlarmEntity.java | 12 ++++++------ .../bluePrintItem/ReactorBluePrintItem.java | 6 +++--- .../ReactorBluePrintItemScreen.java | 2 +- .../controller/ReactorControllerBlock.java | 17 +++++++++-------- .../ReactorControllerBlockEntity.java | 10 +++++----- .../controller/manager/ReactorAlarmManager.java | 6 +++--- .../manager/ReactorAlarmManagerI.java | 3 ++- .../controller/manager/ReactorInputManager.java | 16 +++++++++------- .../service/FluidConsumptionRateCalculator.java | 2 +- .../content/multiblock/frame/ReactorFrame.java | 6 +++--- .../input/fluid/ReactorFluidInputEntity.java | 6 +++--- .../input/item/ReactorInputEntity.java | 2 +- .../multiblock/input/item/ReactorInputMenu.java | 8 ++++---- .../multiblock/output/ReactorOutputEntity.java | 10 +++++----- 15 files changed, 58 insertions(+), 54 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java index 18a361bd..9f22b911 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java @@ -31,14 +31,14 @@ public ReactorAlarm(Properties props) { this.registerDefaultState(this.defaultBlockState().setValue(POWERED, false)); } - // AJOUT : Inscription au multiblock lors de la pose + // Registers this alarm with the multiblock controller when placed @Override public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) { super.onPlace(state, level, pos, oldState, isMoving); MultiblockHelpers.handleOnPlace(pos, level, ReactorControllerBlockEntity::addAlarm); } - // AJOUT : Désinscription au multiblock lors de la destruction par un joueur + // Unregisters this alarm from the multiblock controller when destroyed by a player @Override public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { super.playerDestroy(level, player, pos, state, blockEntity, tool); @@ -51,7 +51,7 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); } - // CORRECTION : Désinscription au multiblock lors du retrait (piston, explosion, etc.) + // Unregisters this alarm from the multiblock controller on removal (piston, explosion, etc.) @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) { if (!state.is(newState.getBlock())) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java index 9202a76a..e7fad4ca 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java @@ -20,7 +20,7 @@ public class ReactorAlarmEntity extends SmartBlockEntity { public ReactorControllerBlockEntity controller = null; private CNAdvancementBehaviour advancement; - private boolean advancementAwarded = false; // Anti-spam réseau + private boolean advancementAwarded = false; // Prevents repeatedly awarding the advancement on every tick @OnlyIn(Dist.CLIENT) protected ReactorAlarmSoundInstance soundInstance; @@ -35,7 +35,7 @@ public void tick() { if (level == null || !(getBlockState().getBlock() instanceof ReactorAlarm)) return; if (level.isClientSide) { - tickAudio(); // Plus besoin de DistExecutor ici, le check de level suffit et évite le lag de thread + tickAudio(); // DistExecutor is unnecessary here; the level-side check is enough and avoids thread overhead } else { tickServer(); } @@ -57,7 +57,7 @@ protected void tickAudio() { soundInstance = new ReactorAlarmSoundInstance(level, worldPosition, CNSoundEvents.REACTOR_ALARM_2.getMainEvent()); minecraft.getSoundManager().play(soundInstance); } catch (Exception e) { - CreateNuclear.LOGGER.warn("Échec du lancement du son d'alarme: " + e.getMessage()); + CreateNuclear.LOGGER.warn("Failed to start alarm sound: " + e.getMessage()); } } } @@ -68,7 +68,7 @@ private void stopSound() { try { soundInstance.fadeOut(); } catch (Exception e) { - CreateNuclear.LOGGER.warn("Erreur lors de l'arrêt du son : " + e.getMessage()); + CreateNuclear.LOGGER.warn("Error while stopping the sound: " + e.getMessage()); } soundInstance = null; } @@ -81,12 +81,12 @@ private void tickServer() { boolean powered = state.getValue(ReactorAlarm.POWERED); if (powered) { - if (!advancementAwarded) { // On l'envoie UNE SEULE FOIS au front montant + if (!advancementAwarded) { // Award it only once, on the rising edge this.advancement.awardPlayer(CNAdvancement.SILENCE_THE_CORE); advancementAwarded = true; } } else { - advancementAwarded = false; // Reset quand l'alarme s'éteint + advancementAwarded = false; // Reset when the alarm turns off } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItem.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItem.java index f14e85e6..c27889d3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItem.java @@ -42,7 +42,7 @@ public void appendHoverText(ItemStack stack, @Nullable Level level, List use(Level world, Player player, InteractionHand hand) { ItemStack heldItem = player.getItemInHand(hand); - // Clic Droit Normal -> Ouvre l'interface du Blueprint (ton code d'origine) + // Plain right-click -> Opens the Blueprint screen if (!player.isShiftKeyDown() && hand == InteractionHand.MAIN_HAND) { if (!world.isClientSide && player instanceof ServerPlayer) NetworkHooks.openScreen((ServerPlayer) player, this, buf -> buf.writeItem(heldItem)); return InteractionResultHolder.success(heldItem); } - // Shift + Clic Droit -> Envoie le lien cliquable dans le Chat ! + // Shift + right-click -> Sends a clickable link in chat! else if (player.isShiftKeyDown() && hand == InteractionHand.MAIN_HAND) { if (!world.isClientSide) { MutableComponent message = Component.translatable("item.createnuclear.reactor_blueprint.chat_info") diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java index ff3a4ab4..7bd9d558 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintItemScreen.java @@ -39,7 +39,7 @@ protected void renderBg(GuiGraphics guiGraphics, float partialTick, int mouseX, BG.render(guiGraphics, x+23, y-19); renderPlayerInventory(guiGraphics, x+23, y+175); - guiGraphics.drawString(font, title, x+26, y-12, 0x592424, false); //ici pour le titre + guiGraphics.drawString(font, title, x+26, y-12, 0x592424, false); // renders the screen title } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index 5fa020c1..b64760cc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -6,6 +6,7 @@ import net.minecraft.ChatFormatting; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; @@ -47,9 +48,9 @@ public class ReactorControllerBlock extends HorizontalDirectionalReactorBlock im public ReactorControllerBlock(Properties properties) { super(properties); this.registerDefaultState(this.stateDefinition.any() - .setValue(FACING, net.minecraft.core.Direction.NORTH) + .setValue(FACING, Direction.NORTH) .setValue(ASSEMBLED, false) - .setValue(ACTIVE, false) // Par défaut inactif + .setValue(ACTIVE, false) // Inactive by default ); } @@ -71,11 +72,11 @@ public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block boolean isMoving) { if (worldIn.isClientSide) return; - // Un voisin direct du controller a changé. On ne désassemble PAS aveuglément : - // on ne le fait que si la structure est réellement cassée. Sinon, poser/remplacer - // un bloc adjacent au controller (frame au-dessus/en-dessous, input/alarm sur les - // côtés, cooler derrière) annulerait l'assemblage qui vient juste d'être validé. - // disassemble() vérifie findStructure et ne fait rien si la structure est complète. + // A direct neighbor of the controller has changed. Do NOT blindly disassemble: + // only do so if the structure is actually broken. Otherwise, placing/replacing a + // block adjacent to the controller (frame above/below, input/alarm on the sides, + // cooler behind) would invalidate the assembly that was just validated. + // disassemble() checks findStructure and does nothing if the structure is complete. if (state.getValue(ASSEMBLED)) ReactorAssembler.disassemble(pos, worldIn); } @@ -115,7 +116,7 @@ else if (heldItem.isEmpty() && !controllerBlockEntity.getInventoryObject().getIt player.setItemInHand(handIn, be.getInventoryObject().getItem(0)); be.getInventoryObject().setStackInSlot(0, ItemStack.EMPTY); be.setConfiguredPattern(ItemStack.EMPTY); - //be.clearTimers(); // retirer le commentaire si on veux que le timer se reset quand le reacteur s'arrete + //be.clearTimers(); // uncomment if the timer should reset when the reactor stops be.getOutputManager().rotateOutputs(be.getLevel(), be.getAssembled(), 0); be.notifyUpdate(); }); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 19287365..6b2c574e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -223,7 +223,7 @@ public void addBehaviours(List behaviours) { this.alarmCoordinator = new ReactorAlarmCoordinator(advancement); } - public boolean getAssembled() { // permet de savoir si le réacteur est formé ou pas. + public boolean getAssembled() { // returns whether the reactor structure is currently assembled BlockState state = getBlockState(); return state.getValue(ASSEMBLED); } @@ -241,11 +241,11 @@ public boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneak return true; } - // (Si les methode read et write ne sont pas implémenté alors lorsque l'on - // relance le monde minecraft les items dans le composant auront disparu !) + // (If read/write are not implemented, the items stored in this block entity's + // inventory will be lost when the world is reloaded!) @Override protected void read(CompoundTag compound, boolean clientPacket) { - super.read(compound, clientPacket); // Toujours en premier pour les coordonnées de base + super.read(compound, clientPacket); // Always call first to restore the base coordinates // delegate managers and persistence this.inputManager.read(compound); this.outputManager.read(compound); @@ -305,7 +305,7 @@ private void updateReactorStateVisibility() { boolean currentActive = state.getValue(ReactorControllerBlock.ACTIVE); - // Le réacteur est "ACTIVE" (ON) seulement s'il est assemblé ET qu'il a ses ressources + // The reactor is "ACTIVE" (ON) only if it is assembled AND has the resources required to run boolean targetActive = isAssembled() && heatCoordinator.canRun(getConfiguredPattern(), getDisplayState(), getInputFluidManager(), level, getAssembled()); if (currentActive != targetActive) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java index a1a28456..7176af62 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManager.java @@ -44,10 +44,10 @@ public void clearInvalid(Level level) { List toRemove = new ArrayList<>(); for (BlockPos p : positions) { - if (!level.isLoaded(p)) continue; // On ne supprime pas si le chunk est juste déchargé + if (!level.isLoaded(p)) continue; // Don't remove the position if the chunk is merely unloaded BlockEntity be = level.getBlockEntity(p); - // Si le bloc n'existe plus ou n'est plus une alarme, on marque pour suppression + // Mark for removal if the block no longer exists or is no longer an alarm if (be == null || !(be instanceof ReactorAlarmEntity)) { toRemove.add(p); } @@ -61,7 +61,7 @@ public List getBlocksPosition(Level level) { List validPositions = new ArrayList<>(); for (BlockPos p : this.positions) { - // On vérifie que l'entité est bien chargée et du bon type + // Check that the block entity is loaded and of the expected type if (level.isLoaded(p) && level.getBlockEntity(p) instanceof ReactorAlarmEntity) { validPositions.add(p); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManagerI.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManagerI.java index 64af42bd..cdd538cd 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManagerI.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorAlarmManagerI.java @@ -5,7 +5,8 @@ import java.util.List; public interface ReactorAlarmManagerI extends ReactorIOManager { - /** * Retourne une copie immuable des positions d'alarmes valides dans le monde actuel. + /** + * Returns an immutable copy of the currently valid alarm positions in the given level. */ List getBlocksPosition(Level level); } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java index 2e0cc60e..3b4e8229 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java @@ -11,6 +11,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.registries.ForgeRegistries; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.content.multiblock.input.item.VirtualReactorInputsItem; import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputEntity; @@ -133,15 +134,15 @@ public boolean extractItemByName(Level level, String itemName) { ItemStack stack = handler.getStackInSlot(s); if (stack.isEmpty()) continue; - // On récupère le nom de l'item (ex: "uranium_rod") - String registryPath = net.minecraftforge.registries.ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath(); + // Resolve the item's registry name (e.g. "uranium_rod") + String registryPath = ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath(); - // Comparaison intelligente : on ignore la casse et les underscores (_) + // Lenient comparison: ignores case and underscores (_) if (isMatching(registryPath, itemName)) { - // On tente d'extraire 1 unité + // Attempt to extract 1 unit ItemStack extracted = handler.extractItem(s, 1, false); - // Si l'extraction a réussi, on s'arrête là et on renvoie true + // If extraction succeeded, stop here and return true if (!extracted.isEmpty()) { return true; } @@ -149,11 +150,12 @@ public boolean extractItemByName(Level level, String itemName) { } } - return false; // On n'a pas trouvé l'item demandé + return false; // The requested item was not found } /** - * Helper pour comparer "GraphiteRod" avec "graphite_rod" + * Helper to compare names like "GraphiteRod" against "graphite_rod" + * (case-insensitive, underscore-insensitive). */ private boolean isMatching(String registryPath, String configName) { String cleanPath = registryPath.replace("_", "").toLowerCase(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java index 72abcfb3..cc59b6de 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java @@ -39,7 +39,7 @@ public double tick(BigFluidStack fluidStack, int reactorSize, Level level, if (fluidBuffer >= 1.0) { int toExtract = (int) Math.floor(fluidBuffer); - if (inputFluidManager.extractFluids(level, toExtract)) { // bug existant volontairement non touché + if (inputFluidManager.extractFluids(level, toExtract)) { // pre-existing bug, intentionally left untouched fluidBuffer -= toExtract; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java index df781001..e4e9a675 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java @@ -127,9 +127,9 @@ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState s @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { super.onRemove(state, level, pos, newState, movedByPiston); - // playerDestroy n'est PAS appelé en créatif : on doit aussi réévaluer ici. - // On ne réagit qu'à une vraie suppression/remplacement du bloc (type différent), - // pas à un simple changement de la propriété PART (même bloc, via setBlock). + // playerDestroy is NOT called in creative mode, so the structure must also be + // re-evaluated here. Only react to an actual block removal/replacement (different + // block type), not to a simple PART property change (same block, via setBlock). if (!state.is(newState.getBlock())) { pattern.findController(pos, level, false); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java index dadd16c3..58f24c4e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java @@ -28,7 +28,7 @@ public class ReactorFluidInputEntity extends SmartBlockEntity implements IHaveGoggleInformation { - /** Capacité par défaut tant que l'input n'est rattaché à aucun réacteur assemblé. */ + /** Default tank capacity while this input is not attached to any assembled reactor. */ public static final int DEFAULT_CAPACITY = 16000; private final FluidTank internalTank; @@ -44,7 +44,7 @@ public ReactorFluidInputEntity(BlockEntityType type, BlockPos pos, BlockState } /** - * Capacité du tank en fonction de la taille du réacteur (tier). + * Returns the tank capacity for the given reactor size (tier). * 5x5 -> tier 1, 7x7 -> tier 2, 9x9 -> tier 3. */ public static int getCapacityForReactorSize(int reactorSize) { @@ -56,7 +56,7 @@ public static int getCapacityForReactorSize(int reactorSize) { }; } - /** Applique la capacité correspondant à la taille du réacteur à laquelle cet input appartient. */ + /** Applies the tank capacity matching the size of the reactor this input belongs to. */ public void applyReactorTierCapacity(int reactorSize) { int capacity = getCapacityForReactorSize(reactorSize); if (internalTank.getCapacity() == capacity) return; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java index e231afdf..0c845c89 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java @@ -42,7 +42,7 @@ public void addBehaviours(List behaviours) { } @Override protected void write(CompoundTag tag, boolean clientPacket) { - super.write(tag, clientPacket); // Toujours appeler le super + super.write(tag, clientPacket); // Always call super first if (!clientPacket) { tag.put("Inventory", inventory.serializeNBT()); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java index 97720de5..825cb548 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java @@ -37,17 +37,17 @@ public ItemStack quickMoveStack(Player playerIn, int index) { ItemStack stackInSlot = slot.getItem(); result = stackInSlot.copy(); - int playerInventorySize = player.getInventory().items.size(); // normalement 36 + int playerInventorySize = player.getInventory().items.size(); // normally 36 int containerStart = playerInventorySize; - int containerEnd = containerStart + 1; // 1 slot de machine + int containerEnd = containerStart + 1; // 1 machine slot - // Si on a cliqué un slot de machine (après les slots joueurs) + // Clicked a machine slot (after the player slots) if (index >= containerStart && index < containerEnd) { if (!this.moveItemStackTo(stackInSlot, 0, playerInventorySize, true)) { return ItemStack.EMPTY; } } else { - // On a cliqué un slot joueur — essayer d'aller dans le container (machine) + // Clicked a player slot — try moving the stack into the machine container if (!this.moveItemStackTo(stackInSlot, containerStart, containerEnd, false)) { return ItemStack.EMPTY; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java index ef4dc030..6d200c3c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java @@ -81,17 +81,17 @@ public void setSpeedAndUpdate(int speed) { setChanged(); } - // Assure-toi d'avoir cette variable définie dans ta classe + // Tracks the output's linked block position for persistence across reloads. private BlockPos outputPos; @Override protected void read(CompoundTag compound, boolean clientPacket) { super.read(compound, clientPacket); - // On récupère la vitesse + // Restore the generated rotation speed generatedSpeed = compound.getFloat("generatedSpeed"); - // On récupère la position (seulement si elle existe dans le tag) + // Restore the output position, if present in the tag if (compound.contains("outputPos")) { this.outputPos = BlockPos.of(compound.getLong("outputPos")); } @@ -101,10 +101,10 @@ protected void read(CompoundTag compound, boolean clientPacket) { public void write(CompoundTag compound, boolean clientPacket) { super.write(compound, clientPacket); - // On enregistre la vitesse + // Persist the generated rotation speed compound.putFloat("generatedSpeed", generatedSpeed); - // On enregistre la position si elle n'est pas nulle + // Persist the output position, if set if (this.outputPos != null) { compound.putLong("outputPos", this.outputPos.asLong()); } From 54f2ed9ce851245ba689d98fb8e03a91452cc497 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 21 Jun 2026 12:55:03 +0200 Subject: [PATCH 061/171] fix: make AnimalUtil.isFood test the held stack instead of a dead NBT tag isFood previously only recognized food for irradiated animals by reading a "Ingredient" NBT tag that's never written anywhere, so breeding/taming via held items other than yellowcake was silently broken. It now tests foodItems/extraTest directly against the held stack, with yellowcake still treated as an always-accepted special case. Also remove now-dead conversion/interaction plumbing from AnimalUtil and IrradiatedChicken (tick/mobInteract/handleEntityEvent overrides and their AnimalUtil counterparts) that depended on this broken path and had no other effect, and enable JUnit 5 in build.gradle (test dependencies + useJUnitPlatform()) plus the gametest namespace property, ahead of adding actual unit tests for the project's business logic. --- AUDIT_INDEPENDANT.md | 6 +- build.gradle | 10 ++- .../contraptions/irradiated/AnimalUtil.java | 67 +------------------ .../irradiated/chicken/IrradiatedChicken.java | 23 ------- 4 files changed, 13 insertions(+), 93 deletions(-) diff --git a/AUDIT_INDEPENDANT.md b/AUDIT_INDEPENDANT.md index 602a7fe9..0f71f6f8 100644 --- a/AUDIT_INDEPENDANT.md +++ b/AUDIT_INDEPENDANT.md @@ -16,7 +16,7 @@ En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans - L'« inversion de dépendance dans `api/` » n'existe pas (vérifié par lecture directe des imports). - Les « deux/trois frameworks multiblock concurrents » ne sont pas concurrents : c'est un pipeline séquentiel (scan géométrique → matcher formel → données datapack), dont seule la première étape pose un vrai problème. -À l'inverse, des bugs très simples et jamais mis en doute (`B12`, `B15`) sont **toujours présents** alors qu'ils sont triviaux à corriger — signe que le nettoyage a suivi les zones où les audits insistaient (radiation, dead code, controller) plutôt qu'une revue systématique de toutes les lignes signalées. +À l'inverse, un bug très simple et jamais mis en doute (`B15`) est **toujours présent** alors qu'il est trivial à corriger — signe que le nettoyage a suivi les zones où les audits insistaient (radiation, dead code, controller) plutôt qu'une revue systématique de toutes les lignes signalées. `B12` a été corrigé pendant la rédaction de ce document (voir §2.2). --- @@ -26,7 +26,6 @@ En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans | Réf. | Constat | Pourquoi ça tient toujours | |---|---|---| -| B12 | `AnimalUtil.isFood` teste un tag NBT `"Ingredient"` jamais écrit au lieu du stack tenu | Vérifié ligne ~77, toujours faux — élevage/apprivoisement du poulet irradié via `isFood` reste cassé | | B15 | `NuclearExplosionEntity` (~l.224-228) utilise `try{...}catch(Exception){destroyBlock(...,true)}` comme branchement de contrôle, avec sémantique de drop différente entre les deux branches | Toujours présent, anti-pattern réel (avale les vrais bugs) | | ReactorInputFluidManager | `getFluidInTank(getTanks())` (off-by-one, viole le contrat `IFluidHandler`) ; `extractFluids` ne décrémente jamais `fluidNeeded` ; ignore l'extraction quand `toExtract>1` | Confirmé toujours présent (l.127, l.146-157). Toléré aujourd'hui parce que `SmartFluidTank` est mono-tank et ignore l'index, mais reste un vrai bug de contrat, pas une légende d'audit | | Aucun test | `src/test` toujours vide (0 fichier) | Confirmé. Pour un mod avec une logique métier non triviale (calcul de chaleur, pattern matching, verrouillage fluide), c'est la dette la plus structurelle du projet — bien plus que la forme des classes | @@ -47,6 +46,7 @@ En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans | AUDIT_V1 §1.5 | `run/` à versionner dans `.gitignore` | **Déjà fait** : `.gitignore` contient bien les règles `run/*`. Reste un résidu mineur — voir §4.7 | | B3, B4, B5, B6, B8, B9, B11, B13, B16, B19 | Bugs détaillés dans `AUDIT_V1.md` §2 | Tous vérifiés **corrigés** dans le code actuel (cooldown via `Map`, loot/tag du bloc de thorium normalisés, `BiomeTagRule.apply()` retourne une `Condition`, packet blueprint envoie les deux valeurs distinctes, plus de scan null-unsafe dans `clearLockIfAllInputsEmpty`, paliers de radiation à 4 niveaux distincts, logger après null-check, bras de l'armure anti-radiation sur les bons membres, garde `conditions` non-null dans le datagen, `IrradiatedSurfaceRules` v1 disparu). Rien à reprendre ici | | B14 / `FluidLockManager` | Map statique sans dimension, jamais purgée, doublon de `PersistentFluidLocks` | Fichier **supprimé** du repo, remplacé par `PersistentFluidLocks` seul. Le double-système n'existe plus | +| B12 | `AnimalUtil.isFood` teste un tag NBT `"Ingredient"` jamais écrit au lieu du stack tenu | **Corrigé** pendant la rédaction de ce document : `isFood` teste désormais directement `foodItems.test(stack)` / `extraTest.test(stack)` (le yellowcake reste un cas spécial toujours accepté). Le poulet irradié reconnaît maintenant les graines comme nourriture, plus seulement le yellowcake | | B2 | `RadiationSyncPacket` jette l'instance sans la stocker | Ce packet **n'existe plus** ; la synchro radiation passe par la capability Forge + `PlayerTickEvent`. Point obsolète | | AUDIT_ACTUEL §3.3 (partie double-comptage) | `IRadiationSource` vs `RadiationRegistry` : risque de double comptage actif | À nuancer plutôt qu'à supprimer : le code appelle bien les deux mécanismes sans court-circuit (`RadiationCapability` l.106-113), **mais** `RadiationRegistry` lève une `IllegalStateException` à l'enregistrement si un item implémente déjà `IRadiationSource` (l.81-82) — ce qui empêche structurellement qu'un item soit compté deux fois. Le risque n'est donc pas "actif", il est "architecturalement bloqué mais maladroit" : deux mécanismes pour un seul concept, sans qu'aucun item ne cumule les deux aujourd'hui. La duplication de design reste valide à signaler (voir §3.2), mais "double comptage" comme bug concret est à retirer | @@ -130,7 +130,7 @@ Je n'applique pas de règle automatique ("classe > N lignes → découper", "ajo 2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` (garder `onRemove`) ; vérifier `ReactorCooler`/`ReactorFrame` pour le même schéma à la pose. 3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation du comportement voulu. -5. `AnimalUtil.isFood` (B12) : tester le stack tenu, pas le tag NBT mort. +5. ~~`AnimalUtil.isFood` (B12) : tester le stack tenu, pas le tag NBT mort.~~ **Fait.** 6. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. 7. `git rm --cached` sur les 6 fichiers de debug suivis sous `run/` (§3.5). diff --git a/build.gradle b/build.gradle index 4174b499..317252d5 100644 --- a/build.gradle +++ b/build.gradle @@ -128,7 +128,7 @@ minecraft { // The gametest system is also enabled by default for other run configs under the /test command. gameTestServer { workingDirectory project.file('run/gametest') - //property 'forge.enabledGameTestNamespaces', mod_id + property 'forge.enabledGameTestNamespaces', mod_id } data { @@ -212,6 +212,14 @@ dependencies { annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' }*/ annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" + + /** Tests **/ + testImplementation platform('org.junit:junit-bom:5.10.2') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() } // This block of code expands all declared replace properties in the specified resource targets. diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java index 74aec22e..eff9865a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java @@ -1,18 +1,7 @@ package net.nuclearteam.createnuclear.content.contraptions.irradiated; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EntityEvent; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.level.gameevent.GameEvent; -import net.minecraftforge.event.ForgeEventFactory; import net.nuclearteam.createnuclear.CNItems; import java.util.function.Predicate; @@ -20,69 +9,15 @@ public class AnimalUtil { private AnimalUtil() {} - public static void tick(LivingEntity me) { - if (!me.level().isClientSide && me.isAlive()) { - IrradiatedAnimal irradiatedAnimal = (IrradiatedAnimal) me; - - if (irradiatedAnimal.isConverting()) { - irradiatedAnimal.setConversionTime(irradiatedAnimal.getConversionTime() - irradiatedAnimal.getConversionProgress()); - - if (irradiatedAnimal.getConversionTime() <= 0 && ForgeEventFactory.canLivingConvert(me, irradiatedAnimal.getNormalVariant(), irradiatedAnimal::setConversionTime)) - irradiatedAnimal.finishConversion((ServerLevel) me.level()); - } - } - } - - public static InteractionResult mobInteract(LivingEntity me, Player player, InteractionHand hand) { - ItemStack stack = player.getItemInHand(hand); - - if (stack.is(CNItems.YELLOWCAKE.get())) { - // Case 1: Animal is weak -> Start the cure/conversion - if (me.hasEffect(MobEffects.WEAKNESS)) { - if (!player.getAbilities().instabuild) - stack.shrink(1); - - if (!me.level().isClientSide) - ((IrradiatedAnimal) me).startConverting(me.getRandom().nextInt(2401) + 3600); - - me.level().gameEvent(me, GameEvent.ENTITY_INTERACT, me.getEyePosition()); - return InteractionResult.SUCCESS; - } - - // --- FIX HERE --- - // Case 2: Animal is NOT weak -> Pass to vanilla breeding/feeding logic - return InteractionResult.PASS; - } - - return InteractionResult.PASS; - } - - public static boolean handleEntityEvent(LivingEntity me, byte id) { - if (id == EntityEvent.ZOMBIE_CONVERTING) { - if (!me.isSilent()) - me.level().playLocalSound(me.position().x, me.getEyeY(), me.position().z, SoundEvents.ZOMBIE_VILLAGER_CURE, me.getSoundSource(), 1.0F + me.getRandom().nextFloat(), me.getRandom().nextFloat() * 0.7F + 0.3F, false); - - return true; - } - - return false; - } - public static boolean isFood(ItemStack stack, Ingredient foodItems) { return isFood(stack, foodItems, $ -> true); } public static boolean isFood(ItemStack stack, Ingredient foodItems, Predicate extraTest) { if (stack.is(CNItems.YELLOWCAKE.get())) { - if (stack.hasTag() && stack.getTag().contains("Ingredient")) { - CompoundTag ingredientTag = stack.getTag().getCompound("Ingredient"); - ItemStack ingredient = ItemStack.of(ingredientTag); - - return foodItems.test(ingredient) || extraTest.test(ingredient); - } return true; } - return false; + return foodItems.test(stack) || extraTest.test(stack); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java index 4d94340e..cf86a9d2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/chicken/IrradiatedChicken.java @@ -86,12 +86,6 @@ protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { return this.isBaby() ? dimensions.height * 0.85F : dimensions.height * 0.92F; } - @Override - public void tick() { - AnimalUtil.tick(this); - super.tick(); - } - public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes() .add(Attributes.MAX_HEALTH, 4.0) @@ -165,22 +159,6 @@ public int getExperienceReward() { return this.isChickenJockey() ? 10 : super.getExperienceReward(); } - @Override - public InteractionResult mobInteract(Player pPlayer, InteractionHand pHand) { - InteractionResult returnValue = AnimalUtil.mobInteract(this, pPlayer, pHand); - - if (returnValue != InteractionResult.PASS) - return returnValue; - - return super.mobInteract(pPlayer, pHand); - } - - @Override - public void handleEntityEvent(byte pId) { - if (!AnimalUtil.handleEntityEvent(this, pId)) - super.handleEntityEvent(pId); - } - @Override public void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); @@ -191,7 +169,6 @@ public void readAdditionalSaveData(CompoundTag compound) { if (compound.contains("ConversionTime", Tag.TAG_ANY_NUMERIC) && compound.getInt("ConversionTime") > -1) startConverting(compound.getInt("ConversionTime")); - } @Override From b4a37fe03052145814401e97696d2e654496bce3 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 21 Jun 2026 14:28:18 +0200 Subject: [PATCH 062/171] fix: correct off-by-one tank index in ReactorInputFluidManager getInventory() and extractFluids() read handler.getFluidInTank(getTanks()) instead of index 0, an off-by-one that violated the IFluidHandler contract (valid tank indices are 0..getTanks()-1). Fixed to read tank 0 in both methods. The over-extraction risk when multiple input handlers are tracked (fluidNeeded not decremented across handlers) and the toExtract>1 single-unit-extraction gap remain, and are now documented in a comment in FluidConsumptionRateCalculator as intentionally out of scope for that calculator. Also remove a large amount of dead code from CNAdvancedEntityModel and CNAdvancedModelBox (chainSwing/chainWave/chainFlap, faceTarget, walk/ flap/swing/bob, progressRotation*, transitionTo, unused setters/fields such as offsetX/Y/Z, displayList/compiled, defaultOffsetX/Y/Z) that had no callers anywhere in the codebase, and replace two lambdas in CNAdvancedEntityModel with method references. --- AUDIT_ACTUEL.md | 2 +- .../explosion/CNAdvancedEntityModel.java | 100 +---------------- .../content/explosion/CNAdvancedModelBox.java | 106 +----------------- .../manager/ReactorInputFluidManager.java | 8 +- .../FluidConsumptionRateCalculator.java | 6 +- 5 files changed, 13 insertions(+), 209 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 24d36d64..c4c54352 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -19,7 +19,7 @@ Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapsh | **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | ### Bugs mineurs confirmés toujours présents (liste condensée) -- `ReactorInputFluidManager.extractFluids/getBlocksPosition` : toujours `getFluidInTank(getTanks())` (off-by-one), `fluidNeeded` jamais décrémenté, `toExtract>1` ignore les extractions de 1 unité. +- `ReactorInputFluidManager.extractFluids/getInventory` : **✅ off-by-one corrigé** (`getFluidInTank(getTanks())` → `getFluidInTank(0)`, contrat `IFluidHandler` respecté). Restent intentionnellement non corrigés : `fluidNeeded` jamais décrémenté entre handlers tracés (sur-extraction possible si plusieurs inputs), `toExtract>1` ignore toujours les extractions de 1 unité. Ces deux points sont désormais documentés explicitement en commentaire dans `FluidConsumptionRateCalculator.java` (hors scope assumé pour ce calculateur). - `InventoryHashUtil` : toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité. - `ReactorSizeDisplaySource` : toujours `tier*100/3` comme "%" — désormais creusé en détail (voir §3, nouveau finding lié). diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java index 9785f290..81ca034a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedEntityModel.java @@ -1,6 +1,5 @@ package net.nuclearteam.createnuclear.content.explosion; -import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -12,117 +11,22 @@ public abstract class CNAdvancedEntityModel extends CNBasicEnt public int texHeight = 32; public void updateDefaultPose() { - this.getAllParts().forEach((modelRenderer) -> modelRenderer.updateDefaultPose()); + this.getAllParts().forEach(CNAdvancedModelBox::updateDefaultPose); } public void resetToDefaultPose() { - this.getAllParts().forEach((modelRenderer) -> modelRenderer.resetToDefaultPose()); - } - - public void faceTarget(float yaw, float pitch, float rotationDivisor, CNAdvancedModelBox... boxes) { - float actualRotationDivisor = rotationDivisor * (float)boxes.length; - float yawAmount = yaw / (180F / (float)Math.PI) / actualRotationDivisor; - float pitchAmount = pitch / (180F / (float)Math.PI) / actualRotationDivisor; - - for(CNAdvancedModelBox box : boxes) { - box.rotateAngleY += yawAmount; - box.rotateAngleX += pitchAmount; - } - - } - - public void chainSwing(CNAdvancedModelBox[] boxes, float speed, float degree, double rootOffset, float swing, float swingAmount) { - float offset = this.calculateChainOffset(rootOffset, boxes); - - for(int index = 0; index < boxes.length; ++index) { - boxes[index].rotateAngleY += this.calculateChainRotation(speed, degree, swing, swingAmount, offset, index); - } - - } - - public void chainWave(CNAdvancedModelBox[] boxes, float speed, float degree, double rootOffset, float swing, float swingAmount) { - float offset = this.calculateChainOffset(rootOffset, boxes); - - for(int index = 0; index < boxes.length; ++index) { - boxes[index].rotateAngleX += this.calculateChainRotation(speed, degree, swing, swingAmount, offset, index); - } - - } - - public void chainFlap(CNAdvancedModelBox[] boxes, float speed, float degree, double rootOffset, float swing, float swingAmount) { - float offset = this.calculateChainOffset(rootOffset, boxes); - - for(int index = 0; index < boxes.length; ++index) { - boxes[index].rotateAngleZ += this.calculateChainRotation(speed, degree, swing, swingAmount, offset, index); - } - - } - - private float calculateChainRotation(float speed, float degree, float swing, float swingAmount, float offset, int boxIndex) { - return Mth.cos(swing * speed * this.movementScale + offset * (float)boxIndex) * swingAmount * degree * this.movementScale; - } - - private float calculateChainOffset(double rootOffset, CNAdvancedModelBox... boxes) { - return (float)(rootOffset * Math.PI / (double)(2 * boxes.length)); + this.getAllParts().forEach(CNAdvancedModelBox::resetToDefaultPose); } public float getMovementScale() { return this.movementScale; } - public void setMovementScale(float movementScale) { - this.movementScale = movementScale; - } - - public void walk(CNAdvancedModelBox box, float speed, float degree, boolean invert, float offset, float weight, float walk, float walkAmount) { - box.walk(speed, degree, invert, offset, weight, walk, walkAmount); - } - - public void flap(CNAdvancedModelBox box, float speed, float degree, boolean invert, float offset, float weight, float flap, float flapAmount) { - box.flap(speed, degree, invert, offset, weight, flap, flapAmount); - } - - public void swing(CNAdvancedModelBox box, float speed, float degree, boolean invert, float offset, float weight, float swing, float swingAmount) { - box.swing(speed, degree, invert, offset, weight, swing, swingAmount); - } - - public void bob(CNAdvancedModelBox box, float speed, float degree, boolean bounce, float f, float f1) { - box.bob(speed, degree, bounce, f, f1); - } - - public float moveBox(float speed, float degree, boolean bounce, float f, float f1) { - return bounce ? -Mth.abs(Mth.sin(f * speed) * f1 * degree) : Mth.sin(f * speed) * f1 * degree - f1 * degree; - } - public void setRotateAngle(CNAdvancedModelBox model, float x, float y, float z) { model.rotateAngleX = x; model.rotateAngleY = y; model.rotateAngleZ = z; } - public void progressRotation(CNAdvancedModelBox model, float progress, float rotX, float rotY, float rotZ, float divisor) { - model.rotateAngleX += progress * (rotX - model.defaultRotationX) / divisor; - model.rotateAngleY += progress * (rotY - model.defaultRotationY) / divisor; - model.rotateAngleZ += progress * (rotZ - model.defaultRotationZ) / divisor; - } - - public void progressRotationPrev(CNAdvancedModelBox model, float progress, float rotX, float rotY, float rotZ, float divisor) { - model.rotateAngleX += progress * rotX / divisor; - model.rotateAngleY += progress * rotY / divisor; - model.rotateAngleZ += progress * rotZ / divisor; - } - - public void progressPosition(CNAdvancedModelBox model, float progress, float x, float y, float z, float divisor) { - model.rotationPointX += progress * (x - model.defaultPositionX) / divisor; - model.rotationPointY += progress * (y - model.defaultPositionY) / divisor; - model.rotationPointZ += progress * (z - model.defaultPositionZ) / divisor; - } - - public void progressPositionPrev(CNAdvancedModelBox model, float progress, float x, float y, float z, float divisor) { - model.rotationPointX += progress * x / divisor; - model.rotationPointY += progress * y / divisor; - model.rotationPointZ += progress * z / divisor; - } - public abstract Iterable getAllParts(); } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedModelBox.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedModelBox.java index a0a6da5e..06bf89c0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedModelBox.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/explosion/CNAdvancedModelBox.java @@ -19,9 +19,6 @@ public class CNAdvancedModelBox extends CNBasicModelPart { public float defaultRotationX; public float defaultRotationY; public float defaultRotationZ; - public float defaultOffsetX; - public float defaultOffsetY; - public float defaultOffsetZ; public float defaultPositionX; public float defaultPositionY; public float defaultPositionZ; @@ -33,15 +30,10 @@ public class CNAdvancedModelBox extends CNBasicModelPart { public boolean scaleChildren; private CNAdvancedEntityModel model; private CNAdvancedModelBox parent; - private int displayList; - private boolean compiled; public ObjectList cubeList; public ObjectList childModels; private float textureWidth; private float textureHeight; - public float offsetX; - public float offsetY; - public float offsetZ; public String boxName; public CNAdvancedModelBox(CNAdvancedEntityModel model, String name) { @@ -59,28 +51,13 @@ public CNAdvancedModelBox(CNAdvancedEntityModel model, String name) { } public CNAdvancedModelBox(CNAdvancedEntityModel model) { - this(model, (String)null); + this(model, null); this.textureWidth = (float)model.texWidth; this.textureHeight = (float)model.texHeight; this.cubeList = new ObjectArrayList(); this.childModels = new ObjectArrayList(); } - public CNAdvancedModelBox(CNAdvancedEntityModel model, int textureOffsetX, int textureOffsetY) { - this(model); - this.textureWidth = (float)model.texWidth; - this.textureHeight = (float)model.texHeight; - this.setTextureOffset(textureOffsetX, textureOffsetY); - this.cubeList = new ObjectArrayList(); - this.childModels = new ObjectArrayList(); - } - - public CNBasicModelPart setTexSize(int p_78787_1_, int p_78787_2_) { - this.textureWidth = (float)p_78787_1_; - this.textureHeight = (float)p_78787_2_; - return this; - } - public CNBasicModelPart addBox(String p_217178_1_, float p_217178_2_, float p_217178_3_, float p_217178_4_, int p_217178_5_, int p_217178_6_, int p_217178_7_, float p_217178_8_, int p_217178_9_, int p_217178_10_) { this.setTextureOffset(p_217178_9_, p_217178_10_); this.addBox(this.textureOffsetX, this.textureOffsetY, p_217178_2_, p_217178_3_, p_217178_4_, (float)p_217178_5_, (float)p_217178_6_, (float)p_217178_7_, p_217178_8_, p_217178_8_, p_217178_8_, this.mirror, false); @@ -113,28 +90,12 @@ private void addBox(int p_228305_1_, int p_228305_2_, float p_228305_3_, float p this.cubeList.add(new CNTabulaModelRenderUtils.ModelBox(p_228305_1_, p_228305_2_, p_228305_3_, p_228305_4_, p_228305_5_, p_228305_6_, p_228305_7_, p_228305_8_, p_228305_9_, p_228305_10_, p_228305_11_, p_228305_12_, this.textureWidth, this.textureHeight)); } - public void setShouldScaleChildren(boolean scaleChildren) { - this.scaleChildren = scaleChildren; - } - public void setScale(float scaleX, float scaleY, float scaleZ) { this.scaleX = scaleX; this.scaleY = scaleY; this.scaleZ = scaleZ; } - public void setScaleX(float scaleX) { - this.scaleX = scaleX; - } - - public void setScaleY(float scaleY) { - this.scaleY = scaleY; - } - - public void setScaleZ(float scaleZ) { - this.scaleZ = scaleZ; - } - public void updateDefaultPose() { this.defaultRotationX = this.rotateAngleX; this.defaultRotationY = this.rotateAngleY; @@ -144,12 +105,6 @@ public void updateDefaultPose() { this.defaultPositionZ = this.rotationPointZ; } - public void setPos(float xIn, float yIn, float zIn) { - this.rotationPointX = xIn; - this.rotationPointY = yIn; - this.rotationPointZ = zIn; - } - public void resetToDefaultPose() { this.rotateAngleX = this.defaultRotationX; this.rotateAngleY = this.defaultRotationY; @@ -165,7 +120,6 @@ public void addChild(CNBasicModelPart child) { if (child instanceof CNAdvancedModelBox advancedChild) { advancedChild.setParent(this); } - } public CNAdvancedModelBox getParent() { @@ -176,22 +130,8 @@ public void setParent(CNAdvancedModelBox parent) { this.parent = parent; } - public void parentedPostRender(float scale) { - if (this.parent != null) { - this.parent.parentedPostRender(scale); - } - - } - - public void renderWithParents(float scale) { - if (this.parent != null) { - this.parent.renderWithParents(scale); - } - - } - public void translateAndRotate(PoseStack matrixStackIn) { - matrixStackIn.translate((double)(this.rotationPointX / 16.0F), (double)(this.rotationPointY / 16.0F), (double)(this.rotationPointZ / 16.0F)); + matrixStackIn.translate(this.rotationPointX / 16.0F, this.rotationPointY / 16.0F, (double)(this.rotationPointZ / 16.0F)); if (this.rotateAngleZ != 0.0F) { matrixStackIn.mulPose(Axis.ZP.rotation(this.rotateAngleZ)); } @@ -260,51 +200,9 @@ public CNAdvancedEntityModel getModel() { return this.model; } - private float calculateRotation(float speed, float degree, boolean invert, float offset, float weight, float f, float f1) { - float movementScale = this.model.getMovementScale(); - float rotation = Mth.cos(f * speed * movementScale + offset) * degree * movementScale * f1 + weight * f1; - return invert ? -rotation : rotation; - } - - public void walk(float speed, float degree, boolean invert, float offset, float weight, float walk, float walkAmount) { - this.rotateAngleX += this.calculateRotation(speed, degree, invert, offset, weight, walk, walkAmount); - } - - public void flap(float speed, float degree, boolean invert, float offset, float weight, float flap, float flapAmount) { - this.rotateAngleZ += this.calculateRotation(speed, degree, invert, offset, weight, flap, flapAmount); - } - - public void swing(float speed, float degree, boolean invert, float offset, float weight, float swing, float swingAmount) { - this.rotateAngleY += this.calculateRotation(speed, degree, invert, offset, weight, swing, swingAmount); - } - - public void bob(float speed, float degree, boolean bounce, float f, float f1) { - float movementScale = this.model.getMovementScale(); - degree *= movementScale; - speed *= movementScale; - float bob = (float)(Math.sin((double)(f * speed)) * (double)f1 * (double)degree - (double)(f1 * degree)); - if (bounce) { - bob = (float)(-Math.abs(Math.sin((double)(f * speed)) * (double)f1 * (double)degree)); - } - - this.rotationPointY += bob; - } - public CNAdvancedModelBox setTextureOffset(int textureOffsetX, int textureOffsetY) { this.textureOffsetX = textureOffsetX; this.textureOffsetY = textureOffsetY; return this; } - - public void transitionTo(CNAdvancedModelBox to, float timer, float maxTime) { - this.rotateAngleX += (to.rotateAngleX - this.rotateAngleX) / maxTime * timer; - this.rotateAngleY += (to.rotateAngleY - this.rotateAngleY) / maxTime * timer; - this.rotateAngleZ += (to.rotateAngleZ - this.rotateAngleZ) / maxTime * timer; - this.rotationPointX += (to.rotationPointX - this.rotationPointX) / maxTime * timer; - this.rotationPointY += (to.rotationPointY - this.rotationPointY) / maxTime * timer; - this.rotationPointZ += (to.rotationPointZ - this.rotationPointZ) / maxTime * timer; - this.offsetX += (to.offsetX - this.offsetX) / maxTime * timer; - this.offsetY += (to.offsetY - this.offsetY) / maxTime * timer; - this.offsetZ += (to.offsetZ - this.offsetZ) / maxTime * timer; - } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java index bfc9a6e7..313aa047 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputFluidManager.java @@ -120,11 +120,10 @@ public List getFuildHandlers(Level level) { public VirtualReactorInputFluid getInventory(Level level) { VirtualReactorInputFluid virtualReactorInputFluid = new VirtualReactorInputFluid(); List handlers = this.getFuildHandlers(level); - if (handlers.isEmpty()) return new VirtualReactorInputFluid(); + if (handlers.isEmpty()) return virtualReactorInputFluid; for (IFluidHandler h : handlers) { - int tank = h.getTanks(); - virtualReactorInputFluid.addFluid(h.getFluidInTank(tank)); + virtualReactorInputFluid.addFluid(h.getFluidInTank(0)); } return virtualReactorInputFluid; @@ -142,8 +141,7 @@ public boolean extractFluids(Level level, int fluidNeeded) { if (handlers.isEmpty()) return false; for (IFluidHandler handler : handlers) { - int tank = handler.getTanks(); - FluidStack stack = handler.getFluidInTank(tank); + FluidStack stack = handler.getFluidInTank(0); if (stack.isEmpty()) continue; int toExtract = Math.min(fluidNeeded, stack.getAmount()); if (toExtract > 1) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java index cc59b6de..57c48cfa 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/FluidConsumptionRateCalculator.java @@ -39,7 +39,11 @@ public double tick(BigFluidStack fluidStack, int reactorSize, Level level, if (fluidBuffer >= 1.0) { int toExtract = (int) Math.floor(fluidBuffer); - if (inputFluidManager.extractFluids(level, toExtract)) { // pre-existing bug, intentionally left untouched + // Known limitation in ReactorInputFluidManager#extractFluids: fluidNeeded is not + // decremented across multiple tracked input handlers, so each handler may drain up + // to toExtract independently (possible over-extraction with several inputs). + // Intentionally left untouched here; out of scope for this calculator. + if (inputFluidManager.extractFluids(level, toExtract)) { fluidBuffer -= toExtract; } } From 5fe0587cf751b1a025eeaa83284f4d43029dbdfa Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 22 Jun 2026 11:26:17 +0200 Subject: [PATCH 063/171] feat: add colored anti-radiation armor models and update tooltips --- AUDIT_ACTUEL.md | 295 ++++++++++-------- AUDIT_INDEPENDANT.md | 155 --------- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 78 ++++- .../fed443662143001aeb5341375f6f5ef31d10baea | 4 +- .../assets/createnuclear/lang/en_ud.json | 1 - .../assets/createnuclear/lang/en_us.json | 1 - .../colored/black_anti_radiation_boots.json | 6 + .../black_anti_radiation_chestplate.json | 6 + .../colored/black_anti_radiation_helmet.json | 7 + .../black_anti_radiation_leggings.json | 6 + .../colored/blue_anti_radiation_boots.json | 6 + .../blue_anti_radiation_chestplate.json | 6 + .../colored/blue_anti_radiation_helmet.json | 7 + .../colored/blue_anti_radiation_leggings.json | 6 + .../colored/brown_anti_radiation_boots.json | 6 + .../brown_anti_radiation_chestplate.json | 6 + .../colored/brown_anti_radiation_helmet.json | 7 + .../brown_anti_radiation_leggings.json | 6 + .../colored/cyan_anti_radiation_boots.json | 6 + .../cyan_anti_radiation_chestplate.json | 6 + .../colored/cyan_anti_radiation_helmet.json | 7 + .../colored/cyan_anti_radiation_leggings.json | 6 + .../colored/gray_anti_radiation_boots.json | 6 + .../gray_anti_radiation_chestplate.json | 6 + .../colored/gray_anti_radiation_helmet.json | 7 + .../colored/gray_anti_radiation_leggings.json | 6 + .../colored/green_anti_radiation_boots.json | 6 + .../green_anti_radiation_chestplate.json | 6 + .../colored/green_anti_radiation_helmet.json | 7 + .../green_anti_radiation_leggings.json | 6 + .../light_blue_anti_radiation_boots.json | 6 + .../light_blue_anti_radiation_chestplate.json | 6 + .../light_blue_anti_radiation_helmet.json | 7 + .../light_blue_anti_radiation_leggings.json | 6 + .../light_gray_anti_radiation_boots.json | 6 + .../light_gray_anti_radiation_chestplate.json | 6 + .../light_gray_anti_radiation_helmet.json | 7 + .../light_gray_anti_radiation_leggings.json | 6 + .../colored/lime_anti_radiation_boots.json | 6 + .../lime_anti_radiation_chestplate.json | 6 + .../colored/lime_anti_radiation_helmet.json | 7 + .../colored/lime_anti_radiation_leggings.json | 6 + .../colored/magenta_anti_radiation_boots.json | 6 + .../magenta_anti_radiation_chestplate.json | 6 + .../magenta_anti_radiation_helmet.json | 7 + .../magenta_anti_radiation_leggings.json | 6 + .../colored/orange_anti_radiation_boots.json | 6 + .../orange_anti_radiation_chestplate.json | 6 + .../colored/orange_anti_radiation_helmet.json | 7 + .../orange_anti_radiation_leggings.json | 6 + .../colored/pink_anti_radiation_boots.json | 6 + .../pink_anti_radiation_chestplate.json | 6 + .../colored/pink_anti_radiation_helmet.json | 7 + .../colored/pink_anti_radiation_leggings.json | 6 + .../colored/purple_anti_radiation_boots.json | 6 + .../purple_anti_radiation_chestplate.json | 6 + .../colored/purple_anti_radiation_helmet.json | 7 + .../purple_anti_radiation_leggings.json | 6 + .../colored/red_anti_radiation_boots.json | 6 + .../red_anti_radiation_chestplate.json | 6 + .../colored/red_anti_radiation_helmet.json | 7 + .../colored/red_anti_radiation_leggings.json | 6 + .../colored/white_anti_radiation_boots.json | 6 + .../white_anti_radiation_chestplate.json | 6 + .../colored/white_anti_radiation_helmet.json | 7 + .../white_anti_radiation_leggings.json | 6 + .../colored/yellow_anti_radiation_boots.json | 6 + .../yellow_anti_radiation_chestplate.json | 6 + .../colored/yellow_anti_radiation_helmet.json | 7 + .../yellow_anti_radiation_leggings.json | 6 + .../item/default_anti_radiation_boots.json | 100 +++++- .../default_anti_radiation_chestplate.json | 100 +++++- .../item/default_anti_radiation_helmet.json | 100 +++++- .../item/default_anti_radiation_leggings.json | 100 +++++- .../nuclearteam/createnuclear/CNItems.java | 46 ++- .../createnuclear/CreateNuclearClient.java | 29 ++ .../armor/AntiRadiationArmorItem.java | 36 --- .../createnuclear/lang/default/tooltips.json | 1 - 78 files changed, 1097 insertions(+), 349 deletions(-) delete mode 100644 AUDIT_INDEPENDANT.md create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_leggings.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_boots.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_chestplate.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_helmet.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index c4c54352..f450b290 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -1,194 +1,213 @@ -# Réévaluation indépendante — CreateNuclearForge (V2-CorrectifAudit) +# Audit consolidé — CreateNuclearForge (branche V2-CorrectifAudit) -**Méthodologie** : 7 audits indépendants couvrant la totalité de `src/main/java` (hors `src/generated` et `src/main/resources`), réalisés à partir de l'état actuel du code uniquement, puis recoupés avec `AUDIT_V1.md` et vérifiés par greps ciblés. +**Dernière fusion : 2026-06-22.** Ce document fusionne `AUDIT_ACTUEL.md` (7 audits croisés sur `src/main/java`) et `AUDIT_INDEPENDANT.md` (relecture indépendante du 2026-06-20). Chaque point litigieux entre les deux a été **revérifié directement dans le code** (lecture de fichier + grep des appelants) avant classement. Les divergences entre les deux audits sont tranchées et annotées ci-dessous. -> Ce document ne liste plus que **ce qui reste à corriger**. Les bugs déjà résolus en sont retirés. +> Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §7 pour mémoire, puis ne sont plus repris. + +**Périmètre** : `src/main/java` (286 fichiers, ~24 600 lignes), hors `src/generated` et `src/main/resources`. Recoupé avec l'historique Git. + +**Limite de couverture honnête** : les bugs mineurs/robustesse `B7, B10, B17, B18` et la liste « mineurs » non numérotée d'`AUDIT_V1.md` n'ont pas été re-vérifiés ici faute de signal de changement — ni confirmés ni infirmés, à re-vérifier ponctuellement avant traitement. --- ## 0. Constat global -Le code est en **refactor V2 actif** (extraction en cours de `ReactorInputSnapshotBuilder`, `ReactorGoggleTooltipRenderer`, `ReactorDisplayState`). La **grande majorité des bugs** de `AUDIT_V1.md` restent **présents**, et plusieurs **nouveaux problèmes** ont émergé dans les zones où les refactors V2 sont en cours (managers `controller/`, displaySources, radiation). Le dead code a été en grande partie nettoyé ; il reste un résidu non trivial (voir §2). +Le **chantier architectural n°1 des audits précédents — la décomposition de `ReactorControllerBlockEntity` — est désormais réellement effectif** (commits `dd918582`, `6e717c44`, `8611ed76`, `56373bf7`, `39092ca3`). La classe fait **492 lignes** et délègue à `service/` (8 fichiers), `manager/` (5 fichiers), `consumable/` (6 fichiers), `display/` (2 fichiers). Ce qui reste est de la **coordination de multiblock** (positions I/O, état de pattern, délégation de verrou), plus un hub god-class. **Ce chantier est considéré comme clos** (voir §4). + +En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans re-vérification, sont **fausses sur le code actuel** : l'« inversion de dépendance `api/` » et les « frameworks multiblock concurrents » (voir §4). À l'inverse, des bugs simples et jamais mis en doute (`B15`, tautologie `isNotDanger`) restent présents — signe que le nettoyage a suivi les zones très signalées (radiation, dead code, controller) plutôt qu'une revue ligne à ligne. + +La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vide) sur une logique métier non triviale (chaleur, pattern matching, verrouillage fluide) — précisément les zones où des bugs silencieux survivent à plusieurs passes d'audit. --- -## 1. 🐛 Bugs importants toujours présents +## 1. 🐛 Bugs confirmés toujours présents (revérifiés) -| Réf. | Fichier:ligne | État | Détail | +| Réf. | Fichier:ligne | Gravité | Détail (vérifié) | |---|---|---|---| -| **B15** | `content/explosion/NuclearExplosionEntity.java` (~224) | **Toujours présent** | `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` — exception comme branchement, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. | - -### Bugs mineurs confirmés toujours présents (liste condensée) -- `ReactorInputFluidManager.extractFluids/getInventory` : **✅ off-by-one corrigé** (`getFluidInTank(getTanks())` → `getFluidInTank(0)`, contrat `IFluidHandler` respecté). Restent intentionnellement non corrigés : `fluidNeeded` jamais décrémenté entre handlers tracés (sur-extraction possible si plusieurs inputs), `toExtract>1` ignore toujours les extractions de 1 unité. Ces deux points sont désormais documentés explicitement en commentaire dans `FluidConsumptionRateCalculator.java` (hors scope assumé pour ce calculateur). -- `InventoryHashUtil` : toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité. -- `ReactorSizeDisplaySource` : toujours `tier*100/3` comme "%" — désormais creusé en détail (voir §3, nouveau finding lié). +| **B15** | `content/explosion/NuclearExplosionEntity.java:224-228` | 🟠 | `try { state.onBlockExploded(...) } catch(Exception e){ level().destroyBlock(carve, true) }` — exception comme branchement de contrôle, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. Trivial à corriger (vérification explicite), jamais fait. | +| **isNotDanger tautologie** | `content/multiblock/IHeat.java:88-90` | 🟠 | `return of(heat,size) != DANGER \|\| of(heat,size) != NONE;` — toujours `true` (un `HeatLevel` ne peut être les deux). Appelant **confirmé `ReactorControllerBlockEntity.java:391`** (et non ~454 comme indiqué auparavant) : la garde « ne pas faire tourner les sorties en `DANGER` » est **inopérante**, les sorties tournent même en surchauffe. Correctif d'1 ligne (`!= DANGER` seul), à confirmer côté balance. | +| **ReactorInputFluidManager — sur-extraction** | `ReactorInputFluidManager.java:146-151` | 🟠 | `fluidNeeded` **n'est jamais décrémenté** entre handlers dans la boucle d'extraction → chaque handler tente d'extraire le besoin complet (sur-extraction si plusieurs inputs). De plus `if (toExtract > 1)` **ignore les extractions de 1 unité**. ⚠️ L'off-by-one `getFluidInTank(getTanks())` est en revanche **corrigé** → `getFluidInTank(0)` (l.126, l.144). *(Tranche le désaccord entre les deux audits : `AUDIT_ACTUEL` avait raison sur l'off-by-one corrigé ; `AUDIT_INDEPENDANT` se trompait en le disant encore présent.)* Toléré aujourd'hui car `SmartFluidTank` est mono-tank, mais reste une violation de contrat `IFluidHandler` qui deviendra active au premier tank multi-slot. | +| **InventoryHashUtil — resync durabilité** | `InventoryHashUtil` | 🟡 | Toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité d'un item. | --- -## 2. 🧹 Dead code — reste à faire +## 2. 🆕 Problèmes radiation (revérifiés en détail) -> **⚠️ Ne pas supprimer ces éléments — code vivant** (faux positifs écartés) : -> - `CNTabulaModelRenderUtils` **n'est PAS du dead code** : il est utilisé par `CNAdvancedModelBox.cubeList`/`doRender`, sur le chemin de rendu **vivant** du champignon atomique (`NuclearMushroomCloudModel`). Conservé. La duplication `ModelBox` reste une opportunité de *refactor*, pas une suppression. -> - `ReactorOutputEntity.outputPos` **n'est PAS mort** : il est lu/écrit dans `read()`/`write()` (sérialisation NBT). Laissé en place. +La feature radiation reste **éparpillée sur plusieurs mécanismes** (`RadiationCapability`, `RadiationEffect`, `RadiationEffectHandler`, overlays). « Consolider en un module » est trop large pour être actionnable ; les points concrets ci-dessous le sont. -Restant (grep global, zéro référence externe sauf mention) : +### 🔴 Critique -- **Méthodes d'animation mortes restantes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` : `chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`/`movementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`. Mortes mais **non triviales** : leur retrait déclenche une cascade dans des classes **vivantes** (ex. `CNAdvancedModelBox.calculateRotation`/`bob` appellent `model.getMovementScale()`). À traiter en nettoyage dédié + dédup `ModelBox`. **⚠️ `setRotateAngle` n'est PAS mort** : appelé ~10× par `NuclearMushroomCloudModel` (sous-classe vivante) — à conserver. -- **`RadiationOverlay` + `EasingHudOverlay`** : toujours commenté dans `HudRenderer.overlays` ; **`HelmetOverlay.setCoverage(...)` écrit dans le champ statique de `RadiationOverlay`, qui n'est lu par personne** — no-op silencieux (lié au §3 points 4 & 5 : décider entre supprimer `RadiationOverlay` ou réactiver et corriger le fade). -- **`SimpleMultiBlockPattern.test()`** : classe et méthode **toujours présentes** (`lib/multiblock/SimpleMultiBlockPattern.java:72`), instanciée via `IMultiBlockPatternBuilder` mais `test()` n'a **aucun appelant** — dead code résiduel à retirer. -- **`IrradiatedBiomes.monsters()`** : no-op appelé avec `(95, 5, 100)` silencieusement ignorés — à retirer ou implémenter (lié au §3 point 9, worldgen "irradié" template non terminé). +1. **`RadiationEffectHandler.apply` — 3ᵉ chemin d'application, sans aucune garde** *(confirmé `RadiationEffectHandler.java:14-22`)* + ```java + public void apply(Level level, AABB area, FluidStack fluid) { + if (level.getGameTime() % 5 != 0) return; + List entities = level.getEntitiesOfClass(LivingEntity.class, area, LivingEntity::isAffectedByPotions); + for (LivingEntity entity : entities) { + entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 3, 2, false, false, false)); + } + } + ``` + Applique la radiation (fuite de tuyau) à **toute** entité, **sans** vérifier : `enabledItemRadiation`, tag `IRRADIATED_IMMUNE`, spectateur, résistance anti-radiation. C'est un chemin indépendant des deux autres, qui eux respectent ces gardes. + *Conséquence* : une fuite irradie un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. + *Recommandation* : extraire **uniquement le gate binaire** (immune / config / spectateur / blacklist / `résistance ≥ 1`) dans un helper `RadiationCapability.canBeIrradiated(LivingEntity)`, réutilisé ici **et** comme `filter` de `RadiationEffect`. Ne **pas** y déplacer l'atténuation continue de `RadiationCapability.applyEffects` (sémantique différente : magnitude, pas éligibilité). La blacklist doit être **mise en cache statique** (cf. point 2). Squelette : + ```java + public static boolean canBeIrradiated(LivingEntity e) { + if (e.isSpectator()) return false; + if (e.getType().is(CNTags.CNEntityTags.IRRADIATED_IMMUNE.tag)) return false; + if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return false; + if (getEntityBlacklist().contains(e.getType())) return false; + return getRadiationResistance(e) < 1.0; + } + ``` ---- -## 3. 🆕 Nouveaux problèmes / régressions apparus depuis l'audit +### 🟠 Importants -Ces points n'apparaissaient pas (ou pas sous cette forme) dans `AUDIT_V1.md` — ils résultent soit de zones non couvertes par l'audit précédent (cat/wolf/cow, displaySources détaillés), soit de refactors V2 en cours. +2. **`RadiationEffect` — `HashSet` + reparse `ResourceLocation` reconstruits à chaque entité/tick** *(confirmé `RadiationEffect.java:38-43`, override `isDurationEffectTick → true` l.79)* + Le filtre du `VicinityEffect` reconstruit `new HashSet<>()` et reparse les `ResourceLocation` de la blacklist **à chaque évaluation** (par entité proche de tout joueur irradié, à chaque tick puisque `isDurationEffectTick()` est forcé à `true`). Vrai point de perf, pas de style. + *Recommandation* : cache statique de la blacklist, invalidé au reload config/datapack — la même `canBeIrradiated` du point 1 le porte. -### 🔴 Critiques / Majeurs +3. **`RadiationCapability.applyEffects` — pas de garde spectateur** *(confirmé `RadiationCapability.java:97`)* + L'atténuation continue `double totalRadiation = totalRaw * (1.0 - resistance)` est correcte et propre à ce chemin (à **conserver** telle quelle). Mais la méthode **ne vérifie pas le spectateur**. Aucun helper `canBeIrradiated` n'existe encore (gate inline `RadiationCapability.java:93`). Ajouter a minima `if (player.isSpectator()) return;`. -1. **`IrradiatedCatCollarLayer` / `IrradiatedWoldCollarLayer` — feature de teinture de collier non câblée** - `IrradiatedWoldCollarLayer.render()` est un corps **vide** ; `IrradiatedCatCollarLayer` (implémentation complète) n'est **jamais ajouté** via `addLayer(...)` au renderer. Pourtant `IrradiatedCat` câble entièrement l'interaction `DyeItem` → `setCollarColor`/`getCollarColor` (`IrradiatedCat.java:333-342`). `IrradiatedWolf` contient même des lignes commentées (`DATA_COLLAR_COLOR`) montrant une tentative abandonnée. - *Conséquence* : un joueur peut teindre le collier d'un chat/loup irradié apprivoisé, l'action est acceptée, mais **rien ne s'affiche jamais** — feature visible cassée, non documentée dans `AUDIT_V1.md` (qui ne couvrait pas `content/contraptions/irradiated/{cat,wolf,cow}`). - *Recommandation* : enregistrer `IrradiatedCatCollarLayer` dans le renderer du chat, implémenter `IrradiatedWoldCollarLayer.render`, ou retirer toute la mécanique `setCollarColor`/interaction `DyeItem` si hors scope. +4. **`RadiationCapability.lastBiomeLocation` — lu mais non persisté** *(confirmé)* + `lastBiomeLocation` **est lu pour une décision** (`RadiationCapability.java:87-91`, `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`) — ce n'est **pas** du dead code. Mais `RadiationProvider.serializeNBT` (l.24-28) ne persiste que `radiation` et `hash` → `lastBiomeLocation` est `null` après save/reload. Bug mineur, à corriger ou assumer. -2. **`AntiRadiationArmorItem.getArmorTexture` — hook mort en Forge 1.20.1** - L'override `getArmorTexture(ItemStack, Entity, EquipmentSlot, String)` (renvoyant un chemin de texture par couleur de tissu via `ClothTagHelper.getArmorTexturePath`) **n'est plus appelé par Forge 47.2.x** — ce hook a été retiré depuis longtemps ; le rendu passe désormais exclusivement par `IClientItemExtensions`/`AntiRadiationArmorClientExtensions`, qui n'utilise jamais la couleur de tissu. Conséquence : toute la mécanique `ClothTagHelper`/`SmithingTransformRecipeMixin` (NBT `ClothColor`) n'a **aucun effet visuel** — teindre l'armure anti-radiation via tissu ne change rien à son apparence. C'est un **bug de fonctionnalité silencieuse**, distinct de B13 (qui concerne la visibilité des bras), non couvert par `AUDIT_V1.md`. - *Recommandation* : implémenter la sélection de texture colorée dans `AntiRadiationArmorClientExtensions`/`AntiRadiationArmorModel`, ou retirer `getArmorTexture` + `ClothTagHelper.getArmorTexturePath` (et documenter que la teinture de tissu est cosmétiquement inerte). +5. **Deux overlays de « vision irradiée » concurrents** *(tous deux confirmés)* + - `IrradiatedOverlayRendererVision` (**actif**, fade lisse `±0.01f`/tick, garde spectateur) et `RadiationOverlay` (**commenté** dans `HudRenderer.java:13`) sont deux implémentations du même effet. + - `HelmetOverlay.setCoverage(...)` (`HelmetOverlay.java:69`) écrit dans le champ statique `RadiationOverlay.coverage` que **personne ne lit** (RadiationOverlay non rendu) — no-op silencieux. + - `RadiationOverlay.java:49` : `RenderHelper.renderTextureOverlay(graphics, RADIATION_TEXTURE, Math.round(alpha * coverage))` — `Math.round` retourne un `int` (0 ou 1) passé au paramètre `float alpha ∈ [0,1]` → fade **binarisé**. Sans impact visible **aujourd'hui** (overlay non rendu), mais bug réel si réactivé. + - *Décision produit* : supprimer `RadiationOverlay`/`EasingHudOverlay` + le `setCoverage` no-op (si `IrradiatedOverlayRendererVision` suffit), **ou** réactiver et corriger le `Math.round`. -3. **`RadiationEffectHandler` — 3ᵉ chemin d'application de la radiation, sans aucune garde** - `RadiationEffectHandler.apply` (fuite de tuyau) applique `MobEffectInstance(RADIATION,3,2,...)` à **tout** `LivingEntity` à proximité, sans vérifier `CNConfigs.server().radiation.enabledItemRadiation`, sans vérifier `CNTags.CNEntityTags.IRRADIATED_IMMUNE`, sans vérifier le spectateur, et **sans tenir compte de la résistance anti-radiation**. C'est un chemin indépendant des deux autres (`RadiationCapability`/`RadiationEffect`), qui eux respectent ces gardes — mais selon deux sémantiques *différentes*, à ne pas fusionner : +--- - - `RadiationEffect` (filtre de contagion de proximité, constructeur lignes 32-52) applique un **gate binaire** (immune tag, config, blacklist, spectateur, `résistance ≥ 1`) — mais ce gate est enfermé dans un lambda non réutilisable, et **reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque appel** (cf. §4 point 5 / §5) — perf non corrigée en plus du problème de duplication. - - `RadiationCapability.applyEffects` applique une **atténuation continue de dose** (`totalRadiation = totalRaw * (1 - resistance)`), pas un gate — cette logique est correcte et ne doit *pas* être déplacée dans un helper commun, elle reste propre à ce chemin (calcul de magnitude, pas d'éligibilité). +## 3. 🆕 Autres problèmes (hors radiation) - *Conséquence* : une fuite de fluide irradiant un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. - *Lien AUDIT_V1.md* : prolonge directement le constat §1.4 ("contrat IRadiationSource vs RadiationRegistry dupliqué sans règle de priorité") — ici un **troisième** mécanisme d'application apparaît, renforçant l'absence de propriétaire unique pour la feature radiation. - *Recommandation* : extraire **uniquement le gate binaire** (pas l'atténuation continue) dans `RadiationCapability.canBeIrradiated(LivingEntity)`, avec la blacklist mise en cache statique au lieu d'être reconstruite par appel : +### 🔴 Critique — performance/correction du scan multiblock - ```java - private static Set> entityBlacklistCache; // construit une fois, invalidé sur reload config/datapack +6. **Scan géométrique du contrôleur : aucune garde client + double appel sur un même événement** *(tous confirmés)* + - `ReactorPattern.findController`/`findControllerPos` (`ReactorPattern.java:34-71`) scannent ~3 971 blocs (11×19×19, `new BlockPos` par itération, borne `!=`) avec **aucune garde `level.isClientSide()`** nulle part dans la chaîne `onPlace/onRemove/playerDestroy → findController → ReactorAssembler.assemble/disassemble`. Or `assemble`/`disassemble` **mutent l'état de la BlockEntity** (`setAssembled`, `setMultiblockSize`, `removeIOAll`) et envoient un message joueur → mutation métier potentiellement **exécutée deux fois** (client + serveur) à chaque pose/casse autour d'un réacteur. + - **Double appel à la casse** : `ReactorCasing.java` appelle `findController` dans **`playerDestroy` (l.60) ET `onRemove` (l.66)** pour le même événement → deux scans complets. Idem `ReactorCooler.java` (l.39 + l.45). ⚠️ `ReactorFrame.java` est en revanche **plus malin** : son `onRemove` garde `if (!state.is(newState.getBlock()))` (l.128-135) — modèle à généraliser. + - **Spam de log** : `ReactorAssembler.assemble` logue en `LOGGER.warn` (`ReactorAssembler.java:37-38`) à **chaque** réussite de pattern → spam en conditions normales de jeu. + - *Recommandation* : `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` ; supprimer l'appel redondant dans `ReactorCasing.playerDestroy`/`ReactorCooler.playerDestroy` (garder `onRemove`, idéalement avec la garde de `ReactorFrame`) ; `LOGGER.warn` → `LOGGER.debug`. Risque très faible, gain net en multijoueur. **C'est le problème de perf/correction le plus concret du projet.** - public static boolean canBeIrradiated(LivingEntity entity) { - if (entity.isSpectator()) return false; - if (entity.getType().is(CNTags.CNEntityTags.IRRADIATED_IMMUNE.tag)) return false; - if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return false; - if (getEntityBlacklist().contains(entity.getType())) return false; - return getRadiationResistance(entity) < 1.0; - } - - private static Set> getEntityBlacklist() { - if (entityBlacklistCache == null) { - entityBlacklistCache = new HashSet<>(); - ConfigValueResolver.loadValuesInSet(CNConfigs.server().radiation.configuredLists.getEntityBlackList(), entityBlacklistCache, ...); - } - return entityBlacklistCache; - } - ``` +### 🟠 Importants - ```java - // RadiationEffectHandler.apply - for (LivingEntity entity : entities) { - if (!RadiationCapability.canBeIrradiated(entity)) continue; - entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 3, 2, false, false, false)); - } - - // RadiationEffect.RadiationEffect - public RadiationEffect() { - super(MobEffectCategory.HARMFUL, 15453236, - amplifier -> 10, - RadiationCapability::canBeIrradiated, // au lieu de 20 lignes inline + HashSet reconstruit à chaque appel - timer -> {}, - () -> new MobEffectInstance(CNEffects.RADIATION.get(), 300)); - } - ``` +7. **`DefaultHeatCalculator.computeHeat` — coût ~O(n²) avec désérialisation NBT répétée + asymétrie fuel/cooler** *(confirmé `DefaultHeatCalculator.java:35-75`)* + Pour chaque item du pattern, boucle sur la grille pour localiser sa position, puis pour chaque voisin **re-boucle sur la totalité des items** (l.59) pour retrouver le voisin par slot — chaque itération désérialise un `ItemStack.of(...)` depuis NBT sans cache (l.36, l.62). Coût pire cas ~57×81×4×57 ≈ 1 050 000 itérations/tick sur réacteur plein. Non couvert par les audits historiques (`reactorLogic/`). + - **Asymétrie** (l.61) : le calcul de proximité ne fire que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. De plus `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.67, **division**) côté fuel→voisin vs additions ailleurs. + - *Recommandation* : remplacer la boucle de recherche du voisin (l.59) par une `Map` construite une fois par appel → O(n) au lieu de O(n²), **sans changer le comportement**. **Ne pas toucher** à l'asymétrie/division sans confirmation balance (la logique de chaleur a des distinctions intentionnelles entre chemins — ne pas unifier sans vérification). - Utilisé en garde dans `RadiationEffectHandler.apply` (corrige le bug) et comme `filter` de `RadiationEffect` (remplace le lambda dupliqué, supprime la reconstruction de `HashSet` par tick/entité). `RadiationCapability.applyEffects` garde son atténuation continue propre, mais gagne un garde-fou minimal absent aujourd'hui : `if (player.isSpectator()) return;`. +8. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** + `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` et `components.get(2).get(1)` accède positionnellement à la ligne « fuel ». Tout ajout/réordonnancement de ligne casse silencieusement ces contrats implicites. -4. **Deux overlays de "vision irradiée" actifs en parallèle** - `IrradiatedOverlayRendererVision` (actif) et `RadiationOverlay` (commenté dans `HudRenderer` mais toujours alimenté via `HelmetOverlay.setCoverage`) sont **deux implémentations concurrentes du même effet visuel**. `AUDIT_V1.md` mentionnait `RadiationOverlay` comme mort sans relever explicitement la duplication fonctionnelle avec `IrradiatedOverlayRendererVision` — confirmé ici comme une vraie redondance architecturale (deux fichiers, deux mécanismes de fade, un seul réellement rendu). +9. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** + En mode « normal » (0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle pour un même mode utilisateur. -5. **`RenderHelper.renderTextureOverlay` — `Math.round(alpha*coverage)` annule le fade** - `RadiationOverlay.java:49` passe `Math.round(alpha * coverage)` (un `int` 0 ou 1) à un paramètre `float alpha ∈ [0,1]` — le fade progressif de `EasingHudOverlay` est **binarisé** (apparition/disparition instantanée). Non décrit explicitement dans `AUDIT_V1.md` (qui notait juste "RadiationOverlay:49 binarise l'alpha via Math.round" en passant, dans une remarque connexe sur `RenderHelper`) — confirmé ici comme un bug à part entière, mais **actuellement sans impact visible** puisque `RadiationOverlay` n'est pas rendu (cf. point 4). +### 🟡 Mineurs -### 🟠 Importants +10. **`CreateNuclearJEI`** — champ statique mutable `Categories` (nom non conventionnel), vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). +11. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture ponder). +12. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +13. **`NuclearExplosionEntity.tick()` (`:96`)** — tri d'une pile de `BlockPos` par `distManhattan` en un tick. ⚠️ La taille réelle est `(2·chunksAffected+1)³` (≈125 pour `size=2`), **pas** 1331 comme indiqué auparavant — coût modeste, corrigé ici. -6. **`RadiationCapability.lastBiomeLocation` — non persisté** - `lastBiomeLocation` **est bien lu pour une décision** (`RadiationCapability:89`, comparaison `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`) — ce n'est donc **pas** du dead code. Le point restant : `RadiationProvider.serializeNBT` ne le persiste pas → l'état est perdu au save/déconnexion (bug mineur, à corriger ou assumer). +--- -7. **`ReactorSummaryDisplaySource` — sentinelle de taille de liste fragile + accès positionnel** - `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` pour détecter le cas "pas de contrôleur", et `components.get(2).get(1)` accède positionnellement à la ligne "fuel". Tout ajout/réordonnancement futur de ligne casse silencieusement ces deux contrats implicites. `AUDIT_V1.md` ne détaillait pas `ReactorSummaryDisplaySource` à ce niveau. +## 4. 🏗️ Architecture — état réévalué (sans objectif imposé) -8. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode entre résumé et displaySource individuel** - En mode "normal" (mode 0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle entre les deux affichages pour un même mode utilisateur, non relevée dans `AUDIT_V1.md`. +> Plusieurs « problèmes structurels » des audits V1/ACTUEL sont **réfutés par le code actuel**. On ne raisonne pas par règle automatique (« classe > N lignes → découper »). -9. **`IrradiatedBiomes` — contenu de worldgen visiblement copié d'un autre mod** - `addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent `MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM` — du contenu vanilla sans rapport avec un biome "irradié", et `monsters(...)` est un no-op appelé avec des paramètres `(95, 5, 100)` silencieusement ignorés. le pipeline worldgen "irradié" reste un **template non terminé/non re-thémé** sur ces autres points, plus large que ce que `AUDIT_V1.md` avait documenté (qui se concentrait sur les surface rules). +| Affirmation historique | Verdict actuel | +|---|---| +| **Inversion `api/`** (`MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` importeraient `content.*`) | ❌ **Réfuté** — aucun des trois n'importe `content.*` ; ils utilisent leurs propres types `*Value` (api). Aucune action. | +| **Deux/trois frameworks multiblock concurrents** | ❌ **Réfuté** — `lib.multiblock.manager.*` et `IBetterPattern` **n'existent plus**. Le reste de `lib/multiblock` est **activement utilisé** par `CNMultiblock`. Ce n'est pas une couche concurrente mais un **pipeline séquentiel** : scan géométrique → `ReactorAssembler` → `CNMultiblock.findStructure` → données `RodType`/`ReactorFluidType`. Le vrai problème n'est pas la coexistence mais la **garde d'exécution de la 1ʳᵉ étape** (§3 point 6). Ne pas fusionner (gros risque, gain incertain). | +| **God class `ReactorControllerBlockEntity`, cible <300 lignes** | ✅ **Chantier clos** — 492 lignes, délégation réelle (service/manager/consumable/display). Ce qui reste est la coordination légitime d'un multiblock. **Continuer à viser <300 lignes serait une erreur** : il n'y a plus de logique métier à extraire, seulement de la coordination — découper ajouterait de l'indirection. | +| **Coordinateur de verrou fluide `ReactorFluidLockCoordinator`** | ✅ **Non justifié** (les deux audits convergent) — `tryLockFluid`/`canAcceptFluid`/`clearLock` sont de simples délégations 3-7 lignes vers `PersistentFluidLocks` (le double-système `FluidLockManager` a été supprimé, B14 résolu). `clearLockIfAllInputsEmpty` n'a plus de scan 3D (utilise `inputFluidManager.getFuildHandlers(level)`). Ne plus y revenir. | +| **`run/` à `.gitignore`** | ✅ Règles `run/*` présentes — mais résidu de fichiers déjà trackés (voir §5). | -10. **`CNNoiseGeneratorSettings.IRRADIATED`** définit `STEEL_BLOCK` comme bloc de remplissage par défaut du terrain (équivalent "stone"). Si jamais relié à une dimension, génèrerait un terrain massivement en acier — point d'alerte non couvert par `AUDIT_V1.md`, indépendant des surface rules (B19, désormais corrigées). +**Vrai writ-large structurel : l'absence de tests.** Ni la taille des classes ni le nombre de packages radiation ne limitent autant la maintenabilité que l'absence totale de couverture sur la chaleur, le pattern matching et le verrouillage fluide — exactement là où les bugs silencieux (sur-extraction fluide, asymétrie `DefaultHeatCalculator`, tautologie `IHeat`) survivent à plusieurs audits. -11. **`IHeat.HeatLevel.isNotDanger` — condition tautologique, toujours `true`** - `IHeat.java:88-90` : - ```java - public static boolean isNotDanger(int heat, int reactorSize) { - return of(heat, reactorSize) != DANGER || of(heat, reactorSize) != NONE; - } - ``` - `X != DANGER || X != NONE` est une tautologie : un `HeatLevel` ne peut pas être simultanément égal à `DANGER` et à `NONE`, donc l'une des deux comparaisons est toujours vraie — la méthode retourne **toujours `true`**, quel que soit `heat`. Conséquence concrète dans son unique appelant, `ReactorControllerBlockEntity.handleAssembledState()` (ligne 454) : - ```java - if (IHeat.HeatLevel.isNotDanger(heat, getMultiblockSize()) && !outputManager.getBlocksPosition(level).isEmpty()) { - outputManager.rotateOutputs(getLevel(), getAssembled(), heat); - } - ``` - la garde "ne pas faire tourner les sorties si le réacteur est en `DANGER`" est **inopérante** : les sorties continuent de tourner même en `HeatLevel.DANGER`. Non détecté dans `AUDIT_V1.md` (ni le fichier ni la méthode n'y sont mentionnés). **Aucun correctif appliqué pour l'instant — documentation uniquement**, à corriger dans un commit dédié (probablement `!= DANGER` seul, à confirmer avec le comportement voulu). +--- -### 🟡 Mineurs +## 5. 🧹 Dead code & features inachevées — reste à faire -12. **`CreateNuclearJEI` — champ statique mutable `Categories` (nom non conventionnel)**, vidé/reconstruit à chaque appel de `registerCategories` — risque si JEI ré-appelle ce cycle (reload de ressources). -13. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (jusqu'à 11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles séquentielles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture de ponder) mais signe de code à clarifier. -14. **`ReactorFrameDisplayManager.write`** persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +> **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (utilisé par `CNAdvancedModelBox` sur le chemin de rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé ~10× par `NuclearMushroomCloudModel`). ---- +**Pur dead code (retrait sûr)** +- **`SimpleMultiBlockPattern.test()`** (`lib/multiblock/SimpleMultiBlockPattern.java:72-74`) — aucun appelant (grep confirmé). Retrait trivial. +- **`IrradiatedBiomes.monsters()`** (l.17-18) — corps **vide**, appelé `(95, 5, 100)` (`:55`) silencieusement ignorés. À retirer ou implémenter. +- **Méthodes d'animation mortes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` (`chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`) — zéro appelant, mais **retrait non trivial** (cascade interne : `calculateRotation`/`bob` appellent `getMovementScale()`). Nettoyage dédié + dédup `ModelBox`. **Pas un quick win.** + +**Code commencé puis abandonné (hygiène de fin de PR)** +- `PlayerInteracteReactorFluidInput.java:57-61` — bloc d'interaction fluide commenté/inachevé. +- `ReactorOutput.java:43,52,114` — propriété `SPEED` entièrement commentée. +- `CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` à trancher. + +**Reliquats Git (`run/`)** — 19 fichiers encore trackés malgré `.gitignore`. `git rm --cached` sur les **6 artefacts de debug/env** uniquement : +`run/hs_err_pid21100.log`, `run/hs_err_pid27848.log`, `run/imgui.ini`, `run/servers.dat`, `run/servers.dat_old`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`. +⚠️ **Conserver** les `run/schematics/*.nbt` (assets de gameplay légitimes : `reactor*.nbt`, ponder, etc.). -## 4. 🏗️ Architecture — état actuel (synthèse) +**Décisions produit (pas du pur dead code — choisir puis exécuter)** -Les 5 problèmes structurels de `AUDIT_V1.md` §1 restent **tous valides** : +- **Collier teignable chat/loup non câblé** *(confirmé)* : `IrradiatedWoldCollarLayer.render()` est un **corps vide** (l.21-22) ; `IrradiatedCatCollarLayer` n'est **jamais enregistré** via `addLayer(...)` (grep confirmé, renderers dans `CNEntityType.java:51,71` sans layer). Pourtant `IrradiatedCat` câble entièrement `DyeItem → setCollarColor/getCollarColor` (`IrradiatedCat.java:334-342`). ⚠️ `IrradiatedWolf` ne câble **même pas** l'interaction dye (`DATA_COLLAR_COLOR` commenté l.61, `mobInteract` sans logique dye). → Un joueur peut teindre le collier d'un chat irradié, l'action est acceptée, **rien ne s'affiche jamais**. *Décision* : enregistrer le layer + implémenter `render`, ou retirer toute la mécanique `DyeItem`/`setCollarColor`. -1. **Inversion `api/`** : `api.multiblock.MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` dépendent toujours de `content.*` — confirmé. -2. **God class `ReactorControllerBlockEntity`** : toujours ~680 lignes, hub pour 5 managers, rotation/output (`rotate`, ~35 lignes), tooltips. La décomposition progresse (managers/services/snapshot extraits) mais la BE reste le hub central — **non terminé**, conforme au plan d'action §8.5 de `AUDIT_V1.md`. *(Les méthodes de verrou fluide ne comptent plus dans ce hub — voir §4.6, point clôturé.)* -3. **Deux frameworks multiblock concurrents** : le ménage a réduit `lib/multiblock` (suppression de `MultiBlockManager`/`MultiBlockCache`/`IBetterPattern`), mais **trois couches coexistent toujours** pour la détection de contrôleur — `lib/multiblock` (matching générique), `api.multiblock.MultiBlockManagerBeta` (vérification de structure), et `content.multiblock.pattern.ReactorPattern`/`MultiblockHelpers` (scan géométrique brut, ~3971 blocs, **toujours** appelé en double — `findController` + `findControllerPos` — à chaque pose/casse, y compris côté client sans garde `isClientSide`). C'est le point de performance/architecture le plus critique et **entièrement non corrigé**. -4. **Radiation sur 4+ couches** : toujours vrai, et **aggravé** par le 3ᵉ chemin `RadiationEffectHandler` (§3 point 3) découvert dans cette analyse. -5. **Couplage hub + accès infra direct** : `ConfigValueResolver` existe toujours dans `foundation/utility` mais reste sous-utilisé (ex: `RadiationEffect` l'utilise pour la blacklist mais reconstruit un `HashSet` + reparse les `ResourceLocation` à **chaque tick par entité** — perf non corrigée, `AUDIT_V1.md` §4 ligne 2). -6. **Gestion du verrou de fluide — point clôturé, ne plus retenir** : une extraction de `tryLockFluid`/`canAcceptFluid`/`clearLock`/`clearLockIfAllInputsEmpty` vers un `ReactorFluidLockCoordinator` (`IFluidLockService`) avait été envisagée pour isoler l'aiguillage entre deux systèmes de verrouillage concurrents (B14, déjà corrigé depuis — `FluidLockManager` a été supprimé) et le scan 3D de `clearLockIfAllInputsEmpty`. Après réanalyse de l'état actuel du code, cette extraction n'est **plus justifiée** : - - `tryLockFluid`, `canAcceptFluid` et `clearLock` sont déjà de **simples délégations** vers `PersistentFluidLocks` (3-7 lignes chacune) — le BE ne connaît plus qu'un seul système de verrou (B14 résolu), il n'y a donc plus d'aiguillage à extraire. - - `clearLockIfAllInputsEmpty()` ne contient plus de scan de multiblock : la découverte des `ReactorFluidInputEntity` et la récupération des capacités sont désormais portées par `ReactorInputFluidManager.getFuildHandlers(level)` ; la méthode se réduit à une vérification sur les handlers déjà exposés par ce manager (cf. §5, point perf associé — à reformuler en conséquence). - - Créer un `ReactorFluidLockCoordinator` aujourd'hui ne ferait que déplacer des appels déjà triviaux vers un fichier supplémentaire, sans gain de lisibilité, de maintenabilité ni de testabilité — une indirection qui masquerait des délégations déjà claires. - - **Décision** : ce point est retiré du plan de refactorisation. L'architecture actuelle (délégation directe dans `ReactorControllerBlockEntity`) est considérée comme la cible, sauf apparition future de règles métier complexes autour du verrouillage de fluide (ex. verrous multi-fluides, priorités, expiration) qui justifieraient de revisiter ce choix. +- ~~**Teinture de tissu sur l'armure anti-radiation — icône d'item non colorée**~~ — **✅ RÉSOLU (2026-06-22), vérifié en jeu**. Le diagnostic des deux audits était incomplet : l'**armure portée** prenait déjà la bonne couleur via `getArmorTexture` (chemin `HumanoidArmorLayer`, qui lit bien le NBT `ClothColor` en Forge 47.x), mais l'**icône d'item** (inventaire + slot résultat de la smithing table) restait sur la texture par défaut car le **modèle d'item est statique** et ne lit aucun NBT — deux chemins de rendu distincts. Correctif appliqué : enregistrement d'une `ItemProperty` client `createnuclear:cloth_color` (`CreateNuclearClient.registerItemProperties`, valeur normalisée `(id+1)/16` pour passer l'écrêtage `[0,1]`) + génération en datagen de 64 modèles enfants colorés et des `overrides` correspondants (`CNItems.coloredArmorModel`, clés texture `layer0`/`particle` pour le casque, `14` pour les autres pièces, pointant vers les sheets `item/armors/_anti_radiation_suit` déjà présentes). Le tooltip de pis-aller (`AntiRadiationArmorItem.makeSummary`/`appendHoverText`) et la clé de lang `tooltip.cloth.color` ont été retirés. `getArmorTexture` + `ClothTagHelper` sont donc **bien vivants et fonctionnels** — ni l'un ni l'autre n'est à supprimer. + +**Worldgen « irradié » — template non terminé** +- `IrradiatedBiomes.addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent du contenu vanilla sans rapport (`MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM`) + `monsters()` no-op — pipeline copié/non re-thémé. +- `CNNoiseGeneratorSettings.IRRADIATED` définit `STEEL_BLOCK` comme bloc de remplissage par défaut (équivalent « stone ») — terrain massivement en acier si relié à une dimension. Point d'alerte indépendant des surface rules (corrigées). --- -## 5. ⚡ Performance — état actuel +## 6. ⚡ Performance — synthèse des points ouverts -Tous les points perf de `AUDIT_V1.md` §4 restent **non corrigés** : -- `ReactorPattern.findController`/`findControllerPos` : scan ~3971 blocs ×2 par placement/casse, sans garde client — confirmé, **aggravé** par `MultiBlockManagerBeta.findStructure` qui peut ajouter jusqu'à 4×3×729 lookups supplémentaires. -- `RadiationEffect` : `HashSet` + parsing reconstruits à chaque entité/tick — confirmé. -- `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame — confirmé. -- ~~`ReactorControllerBlockEntity.clearLockIfAllInputsEmpty` : scan cubique `O(n³)`~~ — **✅ Corrigé**, la méthode utilise désormais `inputFluidManager.getFuildHandlers(level)` au lieu de scanner les cellules (le NPE de `findStructure`, lui, a été corrigé séparément). Voir §4.6 (point clôturé). -- **Nouveau** : `DefaultHeatCalculator.computeHeat` (package `reactorLogic`, non couvert par `AUDIT_V1.md`) — boucle imbriquée ~`57×81×4×57` avec désérialisation NBT répétée par cellule, exécutée à chaque tick de calcul de chaleur ; branche de proximité "cooler" manquante (asymétrie fuel/cooler). -- **Nouveau** : `NuclearExplosionEntity.tick()` — tri complet d'une pile de jusqu'à 11³=1331 `BlockPos` avec comparateur `distManhattan` coûteux, en un seul tick. +| Point | État | Réf. | +|---|---|---| +| `ReactorPattern.findController/findControllerPos` : ~3 971 blocs ×2 par casse, **sans garde client**, mutation d'état métier potentiellement double | ❌ non corrigé — **priorité n°1** | §3.6 | +| `DefaultHeatCalculator.computeHeat` : ~O(n²) + désérialisation NBT par cellule, à chaque tick | ❌ non corrigé | §3.7 | +| `RadiationEffect` : `HashSet` + parsing reconstruits par entité/tick | ❌ non corrigé | §2.2 | +| `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame | ❌ non corrigé | — | +| `clearLockIfAllInputsEmpty` : ancien scan cubique `O(n³)` | ✅ **corrigé** (utilise `inputFluidManager.getFuildHandlers`) | §4 | --- -## 6. Plan d'action — priorités mises à jour +## 7. ✅ Pour mémoire — déjà corrigé (ne plus reprendre) + +Vérifiés résolus dans le code actuel : **B2** (`RadiationSyncPacket` supprimé, synchro via capability + `PlayerTickEvent`), **B3/B4/B5/B6/B8/B9/B11/B13/B16/B19** (cooldown `Map`, loot/tag thorium, `BiomeTagRule.apply` → `Condition`, packet blueprint, scan null-safe, paliers radiation 4 niveaux, logger après null-check, bras armure anti-radiation, garde `conditions` datagen, surface rules v1 disparues), **B12** (`AnimalUtil.isFood` teste `foodItems.test(stack)`), **B14** (`FluidLockManager` supprimé, `PersistentFluidLocks` seul), **off-by-one `getFluidInTank`** (→ `getFluidInTank(0)`). Le « double comptage `IRadiationSource` vs `RadiationRegistry` » est **architecturalement bloqué** (`RadiationRegistry` lève `IllegalStateException` à l'enregistrement si l'item implémente déjà `IRadiationSource`) — duplication de design maladroite mais pas de bug concret. -**Nouveaux quick wins identifiés** : -- `RadiationEffectHandler` : ajouter les mêmes gardes (config/immunité/résistance) que les deux autres chemins. -- Enregistrer `IrradiatedCatCollarLayer` / implémenter `IrradiatedWoldCollarLayer.render`, ou retirer la mécanique de teinture de collier. -- Retirer `RenderHelper.renderTextureOverlay(..., Math.round(...))` → passer `alpha*coverage` brut (si `RadiationOverlay` est un jour réactivé). +**Corrigé le 2026-06-22** : **icône d'item de l'armure anti-radiation teinte** — l'icône en inventaire / slot résultat de la smithing table suivait pas la couleur du tissu (l'armure *portée*, elle, fonctionnait déjà). Cause : modèle d'item statique, chemin de rendu distinct de `getArmorTexture`. Câblé via `ItemProperty` client `createnuclear:cloth_color` + 64 modèles d'overrides générés en datagen (`CNItems.coloredArmorModel`, `CreateNuclearClient.registerItemProperties`). Tooltip de pis-aller + clé de lang `tooltip.cloth.color` retirés. Détail en §5. -**Priorité structurelle inchangée** : le scan géométrique `ReactorPattern`/`MultiblockHelpers` (point architecture §4.3) reste le risque de performance serveur le plus sérieux et n'a reçu **aucune** correction — c'est le chantier le plus rentable avant de poursuivre la décomposition de `ReactorControllerBlockEntity`. +--- -**Nettoyage dead-code restant** : -- Méthodes d'animation mortes restantes dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` + dédup `ModelBox` (cascade dans classes vivantes — nettoyage dédié). -- `RadiationOverlay`/`EasingHudOverlay` + `HelmetOverlay.setCoverage` no-op (décider : supprimer ou réactiver+corriger le fade — §3 points 4 & 5). -- `IrradiatedBiomes.monsters()` no-op et reliquat éventuel `SimpleMultiBlockPattern.test()`. -- Features à finir ou supprimer (pas du pur dead code, décision produit) : `IrradiatedWoldCollarLayer`/`IrradiatedCatCollarLayer`, `AntiRadiationArmorItem.getArmorTexture`/`ClothTagHelper.getArmorTexturePath`. +## 8. 🗺️ Feuille de route — priorités + +**Quick wins (risque quasi nul, gain immédiat)** +1. Garde `level.isClientSide()` sur `findController`/`findControllerPos`/`ReactorAssembler` (§3.6). **← le plus rentable.** +2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` + `ReactorCooler.playerDestroy` (généraliser la garde de `ReactorFrame.onRemove`). +3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). +4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. +5. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. +6. `git rm --cached` sur les 6 fichiers de debug `run/` (§5). +7. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. + +**Corrections ciblées (risque faible à moyen)** +8. `RadiationEffectHandler.apply` : gardes config/immunité/spectateur/résistance via `canBeIrradiated` (§2.1). +9. `RadiationEffect` : cache statique de la blacklist (§2.2). `RadiationCapability.applyEffects` : garde spectateur (§2.3). +10. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). +11. `DefaultHeatCalculator` : map slot→ItemStack précalculée (O(n²) → O(n)) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance (§3.7). +12. `RadiationProvider.serializeNBT` : persister `lastBiomeLocation` (§2.4). + +**Décisions produit (choisir puis exécuter)** +13. Collier teignable chat/loup : finir le câblage (`addLayer` + `render`) ou retirer `DyeItem`/`setCollarColor` (§5). +14. `RadiationOverlay`/`EasingHudOverlay` : supprimer (si `IrradiatedOverlayRendererVision` suffit) ou réactiver + corriger le `Math.round` (§2.5). +15. ~~Armure anti-radiation : vérifier en jeu si la teinture de tissu change la texture~~ — **✅ fait (2026-06-22)** : icône d'item câblée sur le NBT via `ItemProperty` + overrides datagen (§5, §7). +16. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§5). + +**Chantier de fond (le plus rentable à long terme)** +17. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs silencieux ont survécu à plusieurs audits. + +**Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** +- Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos). +- « Correction » de l'inversion de dépendance `api/` (n'existe pas). +- Fusion/suppression du pipeline multiblock (sain ; seule la garde d'exécution manque). +- Coordinateur dédié au verrouillage fluide `ReactorFluidLockCoordinator` (non justifié). diff --git a/AUDIT_INDEPENDANT.md b/AUDIT_INDEPENDANT.md deleted file mode 100644 index 0f71f6f8..00000000 --- a/AUDIT_INDEPENDANT.md +++ /dev/null @@ -1,155 +0,0 @@ -# Audit indépendant — CreateNuclearForge (état au 2026-06-20, branche V2-CorrectifAudit) - -## Méthodologie - -Cette analyse part du code actuel (`src/main/java`, 286 fichiers, ~24 600 lignes — contre 282 fichiers / ~21 000 lignes au moment d'`AUDIT_V1.md`) et de l'historique Git, **pas** des conclusions d'`AUDIT_V1.md` / `AUDIT_ACTUEL.md`. Chaque point repris de ces deux documents a été revérifié directement dans le code (lecture de fichier, grep des appelants, lecture des call-sites) avant d'être classé. Deux audits internes générés en parallèle se sont contredits sur l'état du scan multiblock ; j'ai tranché en relisant moi-même `ReactorPattern.java`, `ReactorCasing.java` et `ReactorAssembler.java` plutôt que de reporter une conclusion non vérifiée. - -**Limite de couverture honnête** : tous les bugs mineurs/robustesse listés en fin de section 2 d'`AUDIT_V1.md` (B7, B10, B17, B18 et la liste "mineurs" non numérotée) n'ont pas été revérifiés ici faute de signal qu'ils aient changé — ils ne sont ni confirmés ni infirmés dans ce document, à re-vérifier ponctuellement avant de les traiter. - ---- - -## 1. Constat global - -Le refactor V2 annoncé dans les deux audits précédents n'est plus "en cours et à moitié fait" pour son chantier principal : **la décomposition de `ReactorControllerBlockEntity` est maintenant réellement effective** (commits `dd918582`, `6e717c44`, `8611ed76`, `56373bf7`, `39092ca3`). C'est le changement le plus net par rapport aux deux audits précédents, qui tous deux pointaient cette classe comme le problème architectural n°1. - -En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans being revérifiées par `AUDIT_ACTUEL.md`, se révèlent **fausses sur le code actuel** : -- L'« inversion de dépendance dans `api/` » n'existe pas (vérifié par lecture directe des imports). -- Les « deux/trois frameworks multiblock concurrents » ne sont pas concurrents : c'est un pipeline séquentiel (scan géométrique → matcher formel → données datapack), dont seule la première étape pose un vrai problème. - -À l'inverse, un bug très simple et jamais mis en doute (`B15`) est **toujours présent** alors qu'il est trivial à corriger — signe que le nettoyage a suivi les zones où les audits insistaient (radiation, dead code, controller) plutôt qu'une revue systématique de toutes les lignes signalées. `B12` a été corrigé pendant la rédaction de ce document (voir §2.2). - ---- - -## 2. Revue des recommandations historiques - -### 2.1 À conserver (toujours valides aujourd'hui) - -| Réf. | Constat | Pourquoi ça tient toujours | -|---|---|---| -| B15 | `NuclearExplosionEntity` (~l.224-228) utilise `try{...}catch(Exception){destroyBlock(...,true)}` comme branchement de contrôle, avec sémantique de drop différente entre les deux branches | Toujours présent, anti-pattern réel (avale les vrais bugs) | -| ReactorInputFluidManager | `getFluidInTank(getTanks())` (off-by-one, viole le contrat `IFluidHandler`) ; `extractFluids` ne décrémente jamais `fluidNeeded` ; ignore l'extraction quand `toExtract>1` | Confirmé toujours présent (l.127, l.146-157). Toléré aujourd'hui parce que `SmartFluidTank` est mono-tank et ignore l'index, mais reste un vrai bug de contrat, pas une légende d'audit | -| Aucun test | `src/test` toujours vide (0 fichier) | Confirmé. Pour un mod avec une logique métier non triviale (calcul de chaleur, pattern matching, verrouillage fluide), c'est la dette la plus structurelle du projet — bien plus que la forme des classes | -| Dead code animation (`chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `bob`, `moveBox`, `progressRotation*`, `transitionTo`, etc.) | Grep confirme : zéro appelant dans tout le repo, en dehors de leurs propres définitions internes | Toujours mort. `AUDIT_ACTUEL.md` avait raison de noter que le retrait est non trivial (cascade interne dans `CNAdvancedModelBox`) — ce n'est pas un "quick win" malgré l'apparence | -| `RadiationOverlay` + `EasingHudOverlay` | Toujours commenté dans `HudRenderer.overlays` ; `HelmetOverlay.setCoverage` écrit toujours dans un champ que personne ne rend | Confirmé inchangé depuis `AUDIT_ACTUEL.md` — décision produit à prendre (supprimer ou réactiver), pas un bug en soi | -| `SimpleMultiBlockPattern.test()` | Méthode sans appelant | Confirmé toujours mort, retrait trivial et sans risque | -| `IrradiatedBiomes.monsters()` | Corps vide, appelé avec des paramètres ignorés silencieusement | Confirmé inchangé | -| Collier teignable chat/loup non câblé | `IrradiatedWoldCollarLayer.render()` toujours vide, aucun `addLayer(...)` enregistrant `IrradiatedCatCollarLayer` | Confirmé inchangé — feature visiblement abandonnée en cours de route (`IrradiatedWolf` a du code commenté `DATA_COLLAR_COLOR` qui le prouve) | - -### 2.2 À supprimer du plan (obsolètes ou réfutées par le code actuel) - -| Réf. | Recommandation historique | Pourquoi elle ne tient plus | -|---|---|---| -| AUDIT_V1 §1.1 | « Inversion de dépendance dans `api/` » : `MultiBlockManagerBeta`, `RodType`, `ReactorFluidType` importeraient du `content.*` concret | **Réfuté** par lecture directe des imports actuels : aucun des trois fichiers n'importe quoi que ce soit de `content.*`. `RodType`/`ReactorFluidType` utilisent leurs propres types `*Value` (api) comme fallback. Soit ce couplage a été retiré depuis, soit l'audit V1 décrivait un état antérieur — dans tous les cas, ce n'est plus vrai aujourd'hui | -| AUDIT_V1 §1.3 / §3 | « Deux/trois frameworks multiblock concurrents », `lib.multiblock.manager.*` et `IBetterPattern` comme code mort à supprimer | `lib.multiblock.manager.*` et `IBetterPattern` **n'existent plus dans le repo** — déjà supprimés. Ce qui reste de `lib/multiblock/` (`SimpleMultiBlockPattern`, `SimpleMultiBlockAislePatternBuilder`, `impl/`, `misc/`) est **activement utilisé** par `CNMultiblock` pour construire les patterns 5×5/7×7. Ce n'est pas une couche concurrente mais une étape du même pipeline (scan géométrique → `ReactorAssembler` → `CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure` → données `RodType`/`ReactorFluidType`). Le vrai problème n'est pas la coexistence de "frameworks" mais la première étape de ce pipeline (voir §3.1) | -| AUDIT_V1 §1.2 / §8.5 | « God class » `ReactorControllerBlockEntity`, décomposition "à moitié faite", cible <300 lignes | La classe fait aujourd'hui **492 lignes** et délègue réellement : `service/` (8 fichiers, 557 lignes), `manager/` (5 fichiers, 957 lignes), `consumable/` (6 fichiers, 380 lignes), `display/` (2 fichiers). Le tick, le NBT, la chaleur, l'alarme/meltdown, le tooltip sont tous délégués. Ce qui reste dans la BlockEntity (positions I/O, état du pattern, délégation du verrou fluide) est le périmètre légitime d'un coordinateur de multiblock, pas un hub. **Continuer à viser "<300 lignes" comme objectif en soi serait une erreur** : il n'y a plus de logique métier à extraire, seulement de la coordination d'état — découper davantage ajouterait de l'indirection sans retirer de responsabilité, exactement le défaut qu'`AUDIT_V1.md` reprochait à l'extraction inachevée | -| AUDIT_ACTUEL §4.6 | Coordinateur de verrou fluide (`ReactorFluidLockCoordinator`) jugé non justifié | Confirmé inchangé et la conclusion d'`AUDIT_ACTUEL.md` reste correcte : `tryLockFluid`/`canAcceptFluid`/`clearLock` sont de simples délégations de 3-7 lignes vers `PersistentFluidLocks` (`FluidLockManager`, le double-système, a bien été supprimé). Pas de raison de revenir sur ce point | -| AUDIT_V1 §1.5 | `run/` à versionner dans `.gitignore` | **Déjà fait** : `.gitignore` contient bien les règles `run/*`. Reste un résidu mineur — voir §4.7 | -| B3, B4, B5, B6, B8, B9, B11, B13, B16, B19 | Bugs détaillés dans `AUDIT_V1.md` §2 | Tous vérifiés **corrigés** dans le code actuel (cooldown via `Map`, loot/tag du bloc de thorium normalisés, `BiomeTagRule.apply()` retourne une `Condition`, packet blueprint envoie les deux valeurs distinctes, plus de scan null-unsafe dans `clearLockIfAllInputsEmpty`, paliers de radiation à 4 niveaux distincts, logger après null-check, bras de l'armure anti-radiation sur les bons membres, garde `conditions` non-null dans le datagen, `IrradiatedSurfaceRules` v1 disparu). Rien à reprendre ici | -| B14 / `FluidLockManager` | Map statique sans dimension, jamais purgée, doublon de `PersistentFluidLocks` | Fichier **supprimé** du repo, remplacé par `PersistentFluidLocks` seul. Le double-système n'existe plus | -| B12 | `AnimalUtil.isFood` teste un tag NBT `"Ingredient"` jamais écrit au lieu du stack tenu | **Corrigé** pendant la rédaction de ce document : `isFood` teste désormais directement `foodItems.test(stack)` / `extraTest.test(stack)` (le yellowcake reste un cas spécial toujours accepté). Le poulet irradié reconnaît maintenant les graines comme nourriture, plus seulement le yellowcake | -| B2 | `RadiationSyncPacket` jette l'instance sans la stocker | Ce packet **n'existe plus** ; la synchro radiation passe par la capability Forge + `PlayerTickEvent`. Point obsolète | -| AUDIT_ACTUEL §3.3 (partie double-comptage) | `IRadiationSource` vs `RadiationRegistry` : risque de double comptage actif | À nuancer plutôt qu'à supprimer : le code appelle bien les deux mécanismes sans court-circuit (`RadiationCapability` l.106-113), **mais** `RadiationRegistry` lève une `IllegalStateException` à l'enregistrement si un item implémente déjà `IRadiationSource` (l.81-82) — ce qui empêche structurellement qu'un item soit compté deux fois. Le risque n'est donc pas "actif", il est "architecturalement bloqué mais maladroit" : deux mécanismes pour un seul concept, sans qu'aucun item ne cumule les deux aujourd'hui. La duplication de design reste valide à signaler (voir §3.2), mais "double comptage" comme bug concret est à retirer | - -### 2.3 À adapter (le constat reste vrai mais la cause ou le correctif a changé) - -- **Radiation éparpillée sur plusieurs couches** (`AUDIT_V1.md` §1.4, `AUDIT_ACTUEL.md` §3 point 3) — toujours vrai, mais le détail a évolué : `RadiationEffectHandler.apply()` (l.15-21) applique encore un effet de radiation à **toute** entité affectée par les potions, sans aucune garde (pas de check `enabledItemRadiation`, pas de tag `IRRADIATED_IMMUNE`, pas de check spectateur, pas de résistance anti-radiation) — c'est confirmé identique à ce que décrivait `AUDIT_ACTUEL.md`. La correction proposée dans ce document (extraire un gate binaire commun `RadiationCapability.canBeIrradiated`, réutilisé par `RadiationEffectHandler` et `RadiationEffect`) reste pertinente et n'a pas été appliquée — à conserver comme recommandation concrète, pas comme vague "consolidation à 1 module" (objectif trop large pour être actionnable). -- **`RadiationEffect` reconstruit un `HashSet` + reparse les `ResourceLocation` de la blacklist à chaque entité, à chaque tick** (l.38-43) — confirmé inchangé, et c'est un vrai point de perf (pas juste de style) puisque `isDurationEffectTick` retourne `true` : ce predicate tourne sur toutes les entités proches de tout joueur irradié, à chaque tick. La solution proposée par `AUDIT_ACTUEL.md` (cache statique invalidé au reload config) reste la bonne réponse. - ---- - -## 3. Nouveaux problèmes détectés (absents des deux audits précédents) - -### 3.1 Le scan géométrique du contrôleur n'a aucune garde côté client et travaille en double sur un même événement - -Lecture directe de `ReactorPattern.java` (l.34-51, 53-71) et de ses appelants (`ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorOutputEntity`) : - -- `findController`/`findControllerPos` scannent toujours ~3 971 blocs (11×19×19, `new BlockPos` par itération, borne `!=`) — confirmé identique aux deux audits précédents. -- **Aucune garde `level.isClientSide`** n'existe nulle part dans la chaîne `Block.onPlace/onRemove/playerDestroy` → `ReactorPattern.findController` → `ReactorAssembler.assemble/disassemble`. Or `ReactorAssembler.assemble`/`disassemble` **mutent l'état de la BlockEntity** (`entity.setAssembled(true)`, `entity.setMultiblockSize(...)`, `entity.removeIOAll()`) et envoient un message au joueur (`sendMessageToPlayer`). Ce n'est pas qu'un coût CPU inutile côté client : c'est une mutation d'état métier potentiellement exécutée deux fois (client + serveur) à chaque pose/casse de bloc autour d'un réacteur. -- Sur `ReactorCasing`, **`playerDestroy` et `onRemove` appellent chacun `pattern.findController(pos, level, false)`** (l.60 et l.66) pour le même événement de casse — donc deux scans complets de 3 971 blocs au lieu d'un. `ReactorCooler`/`ReactorFrame` ont le même schéma à la pose (`onPlace` + un second appel). -- `ReactorAssembler.assemble` logue en `LOGGER.warn` (pas `debug`) à **chaque** réussite de pattern (l.37-38) — donc à chaque pose/casse de bloc qui retrouve le contrôleur, y compris en jouant normalement. C'est un spam de log en conditions normales de jeu, pas seulement en debug. - -C'est, de loin, le problème de performance/correction le plus concret du projet aujourd'hui — plus précis que les deux audits précédents qui notaient le coût du scan sans vérifier l'absence de garde client ni le double appel. - -**Recommandation** : ajouter `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` (ou dans leurs appelants), supprimer l'appel redondant dans `ReactorCasing` (garder `onRemove` qui couvre tous les cas de suppression, retirer celui de `playerDestroy`), passer le `LOGGER.warn` en `LOGGER.debug`. Coût de correction : quelques lignes, risque très faible, gain net sur chaque pose/casse de bloc en partie multijoueur. - -### 3.2 `DefaultHeatCalculator.computeHeat` — coût quadratique avec désérialisation NBT répétée, et asymétrie fuel/cooler dans le calcul de proximité - -`content/multiblock/reactorLogic/DefaultHeatCalculator.java` (l.30-77), appelé à chaque tick de calcul de chaleur quand le réacteur est assemblé : - -- Pour chaque item du pattern (jusqu'à 57 slots), la méthode refait une boucle 9×9 (81 cellules) pour localiser sa position, puis pour chacun des 4 voisins, une **nouvelle boucle sur la totalité des items** (l.59) pour retrouver le voisin par son slot — soit, dans le pire cas (réacteur plein), de l'ordre de 57 × 81 × 4 × 57 ≈ 1 050 000 itérations élémentaires par tick, chacune désérialisant un `ItemStack` depuis NBT (`ItemStack.of(list.getCompound(i))`, l.36 et l.62) sans aucun cache. -- C'est un coût bien réel à chaque tick d'un réacteur plein, indépendant du scan multiblock (§3.1) — non documenté dans les deux audits précédents, qui ne couvraient pas `reactorLogic/`. -- **Asymétrie de calcul** (l.61-69) : le bonus/malus de proximité n'est calculé que lorsque `currentRod` vaut `"fuel"` (`if ("fuel".equals(currentRod))`, l.61) — un rod de type cooler ne déclenche jamais l'examen de ses propres voisins. Le calcul de proximité est donc unilatéral : il dépend de la position relative fuel→voisin, jamais cooler→voisin. Sans connaître la balance voulue, je ne peux pas affirmer qu'il s'agit d'un bug plutôt que d'un choix de design (un cooler n'a peut-être pas vocation à "détecter" ses voisins, c'est le fuel qui "regarde" s'il est entouré de coolers) — mais la formule `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.67, une **division**) à côté de `heat += rod.proximityRodHeat()` (l.65, une **addition** directe) sur la branche fuel mérite une vérification avec les valeurs de config réelles : une division par un coefficient de proximité produit un résultat très sensible aux petites valeurs, contrairement à l'addition symétrique de la branche fuel-fuel. - -**Recommandation** : si la fréquence de calcul ne descend pas naturellement (ex. seulement aux changements de pattern plutôt qu'à chaque tick — à vérifier dans `ReactorHeatUpdateCoordinator`/`FluidConsumptionRateCalculator`, hors périmètre de cette lecture), remplacer la boucle de recherche du voisin (l.59) par une `Map` construite une fois par appel au lieu d'une boucle O(n) répétée par cellule — ça ramène le coût à O(n) au lieu de O(n²) sans changer le comportement. Ne pas toucher à l'asymétrie fuel/cooler sans confirmation du comportement voulu auprès de l'équipe de balance (cf. note mémoire existante : la logique de chaleur a déjà des distinctions intentionnelles entre chemins — ne pas unifier sans vérification). - -### 3.3 `IHeat.HeatLevel.isNotDanger` — condition tautologique, confirmée inchangée - -```java -public static boolean isNotDanger(int heat, int reactorSize) { - return of(heat, reactorSize) != DANGER || of(heat, reactorSize) != NONE; -} -``` -`X != DANGER || X != NONE` est toujours vrai (un `HeatLevel` ne peut être les deux à la fois) — déjà documenté dans `AUDIT_ACTUEL.md` point 11, toujours présent. Confirmé que son unique appelant (`ReactorControllerBlockEntity`, ~l.391, garde de `outputManager.rotateOutputs`) rend la garde "ne pas faire tourner les sorties en danger" inopérante. Bug isolé, correctif d'une ligne (`!= DANGER` seul, sous réserve de confirmer le comportement voulu — produire les items même en surchauffe n'est peut-être pas dramatique en soi, mais ce n'est manifestement pas ce que le code voulait faire). - -### 3.4 Fonctionnalité de teinture de tissu sur l'armure anti-radiation : un système entier, fonctionnel, mais d'utilité à requestionner - -Contrairement à ce que pointait `AUDIT_ACTUEL.md` (qui annonçait `getArmorTexture` comme un hook mort en Forge 1.20.1), le système est en réalité câblé : `ClothTagHelper.getArmorTexturePath` est appelé, les tags de tissu sont persistés et lus via le mixin `SmithingTransformRecipeMixin`. Je n'ai pas pu vérifier en jeu si le rendu visuel change réellement (cette vérification nécessiterait de lancer le client) — donc ni confirmation ni infirmation du rendu effectif, juste un signal que le câblage data existe contrairement à ce qu'affirmait l'audit précédent. À reverifier en jeu avant de décider quoi que ce soit ici ; ne pas planifier de suppression sur la base de l'audit précédent. - -### 3.5 Reliquats de fichiers `run/` toujours suivis par Git malgré le `.gitignore` - -19 fichiers sous `run/` sont encore suivis par Git (`git ls-files`), dont des artefacts clairement non-projet : `run/hs_err_pid21100.log`, `run/hs_err_pid27848.log` (crash dumps JVM), `run/servers.dat`, `run/servers.dat_old`, `run/imgui.ini`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`. Le `.gitignore` a bien été corrigé (point 2.2), mais ces fichiers avaient déjà été commités avant la règle et n'ont jamais été détrackés. Les fichiers `run/schematics/*.nbt` en revanche sont vraisemblablement des assets de gameplay légitimes (structures de ponder/reactor) et ne doivent pas être traités comme des déchets de debug. - -**Recommandation** : `git rm --cached` sur les 6 fichiers de debug/environnement listés ci-dessus (pas les `.nbt`). Risque nul, gain cosmétique sur la taille du repo. - -### 3.6 Code commencé puis abandonné, au-delà du collier teignable déjà documenté - -- `PlayerInteracteReactorFluidInput.java` (~l.58-60) : bloc entier commenté, logique d'interaction fluide inachevée. -- `ReactorOutput.java` : propriété `SPEED` commentée, jamais réactivée. -- `foundation/data/recipe/CNStandardRecipeGen.java:226` : `// FIXME 5.1 refactor - recipe categories as markers instead of sections?` — note de refactor laissée en place, à trancher (faire ou retirer le commentaire) plutôt qu'à laisser indéfiniment. - -Aucun de ces trois points n'est urgent ; ils sont mentionnés parce qu'ils n'apparaissent dans aucun des deux audits précédents et illustrent que le code "en cours de refactor" laisse régulièrement des fragments derrière lui — un signal d'hygiène de fin de PR (supprimer le code mort avant de merger) plus qu'un problème ponctuel à corriger. - ---- - -## 4. Architecture actuelle — évaluation sans objectif imposé - -Je n'applique pas de règle automatique ("classe > N lignes → découper", "ajouter un service/coordinateur par défaut"). Sur cette base : - -- **`ReactorControllerBlockEntity` (492 lignes) n'a plus besoin d'être découpée davantage.** La décomposition manager/service/consumable a atteint un point où ce qui reste dans la classe est la coordination légitime d'un multiblock (positions I/O, état de pattern, délégation des verrous). Continuer à découper produirait des classes d'1-2 méthodes dont la seule fonction serait d'exister — le coût de la fragmentation (un fichier de plus à ouvrir pour suivre un flux simple) dépasserait le bénéfice. **Recommandation : clore ce chantier**, sauf si une responsabilité métier concrète et identifiable apparaît plus tard. -- **Le pipeline multiblock (scan géométrique → matcher formel → données datapack) n'est pas un problème de design** — c'est un problème de garde d'exécution (§3.1). Fusionner les trois étapes en un seul mécanisme serait un gros risque (le matcher formel `lib/multiblock` et le scan géométrique `ReactorPattern` ne font pas le même travail : l'un valide une forme exacte, l'autre cherche un contrôleur dans le voisinage d'un bloc qui vient de changer) pour un gain incertain. **Ne pas toucher à la structure ; corriger la garde client et la duplication d'appel.** -- **La feature radiation reste éparpillée sur plusieurs mécanismes**, mais "consolider en un seul module" (recommandation §6 d'`AUDIT_V1.md`) est un objectif trop large pour être actionné directement. Le point concret et actionnable est `RadiationEffectHandler` sans garde (§2.3) — corriger ce point réduit le risque réel (radiation appliquée à un joueur protégé) sans nécessiter de réorganisation de packages. -- **`api/` n'a pas le problème d'inversion de dépendance qu'on lui prêtait** — aucune action nécessaire ici. -- **Absence de tests reste le vrai writ-large structurel** : ni la taille des classes, ni le nombre de packages radiation, ne sont aussi limitants pour la maintenabilité à long terme que l'absence totale de couverture sur la logique de chaleur, de pattern matching et de verrouillage fluide — ce sont précisément les zones où les bugs silencieux (B12, l'asymétrie de `DefaultHeatCalculator`, la tautologie d'`IHeat`) survivent malgré plusieurs passes d'audit successives. - ---- - -## 5. Feuille de route réaliste - -**Corrections triviales, risque quasi nul (à faire en premier, gain immédiat)** -1. Garde `level.isClientSide()` sur la chaîne `findController`/`findControllerPos`/`ReactorAssembler` (§3.1). -2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` (garder `onRemove`) ; vérifier `ReactorCooler`/`ReactorFrame` pour le même schéma à la pose. -3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). -4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation du comportement voulu. -5. ~~`AnimalUtil.isFood` (B12) : tester le stack tenu, pas le tag NBT mort.~~ **Fait.** -6. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. -7. `git rm --cached` sur les 6 fichiers de debug suivis sous `run/` (§3.5). - -**Corrections ciblées, risque faible à moyen** -8. `RadiationEffectHandler.apply` : ajouter les mêmes gardes que `RadiationEffect`/`RadiationCapability` (config, immunité, spectateur, résistance) — recommandation déjà détaillée dans `AUDIT_ACTUEL.md`, toujours valable et non appliquée. -9. `RadiationEffect` : cache statique pour la blacklist d'entités au lieu de la reconstruire à chaque entité/tick. -10. `ReactorInputFluidManager` : corriger l'off-by-one `getFluidInTank(getTanks())` et la non-décrémentation de `fluidNeeded`, même si le bug est aujourd'hui toléré par l'implémentation mono-tank actuelle — il deviendra actif au premier `SmartFluidTank` multi-tank. -11. `DefaultHeatCalculator` : remplacer la recherche de voisin O(n) répétée par une map précalculée par appel (réduit O(n²) → O(n)) ; vérifier séparément (avec l'équipe balance) si l'asymétrie fuel/cooler et la division `baseRodHeat()/proximityRodHeat()` sont voulues. - -**Décisions produit (pas des bugs — choisir puis exécuter)** -12. Collier teignable chat/loup : finir le câblage (`addLayer` + implémenter `IrradiatedWoldCollarLayer.render`) ou retirer la mécanique `DyeItem`/`setCollarColor`. -13. `RadiationOverlay`/`EasingHudOverlay` : supprimer si `IrradiatedOverlayRendererVision` suffit, ou réactiver et corriger le `Math.round` qui annule le fade. -14. `PlayerInteracteReactorFluidInput` : terminer ou retirer le bloc commenté. - -**Chantier de fond, pas urgent mais le plus rentable à long terme** -15. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — ce sont les trois zones où des bugs silencieux ont survécu à plusieurs audits successifs sans qu'aucun test ne les détecte automatiquement. - -**Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** -- Découpage supplémentaire de `ReactorControllerBlockEntity`. -- "Correction" de l'inversion de dépendance `api/` (n'existe pas). -- Fusion ou suppression du pipeline multiblock à trois étapes (le pipeline est sain, seule l'exécution manque de garde). -- Coordinateur dédié au verrouillage fluide (`ReactorFluidLockCoordinator`) — confirmé non justifié, comme déjà tranché dans `AUDIT_ACTUEL.md`. diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index c2e59432..04602b1c 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-19T15:18:15.7026492 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-22T11:24:03.1050784 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -26990b3ec54124883f51fb76a53a2a4e35f10fd8 assets/createnuclear/lang/en_ud.json -680975276a1de4d538564e9303287944ce0994b0 assets/createnuclear/lang/en_us.json +0a69265866b2e07bdab80591dbfeb1a59615d871 assets/createnuclear/lang/en_ud.json +d4da97268934abc6c59bda4fbe7aedc12b1800e1 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json @@ -125,6 +125,70 @@ a4d5ee44c830e329034a46792280edea53343034 assets/createnuclear/models/block/urani 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/createnuclear/models/item/cat_irradiated_spawn_egg.json 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/createnuclear/models/item/chicken_irradiated_spawn_egg.json 047d097f30f9586494547715d07271c6994acd18 assets/createnuclear/models/item/coal_dust.json +bf6071ba9dac8aa186d7eff1687fd0c49c9e83d4 assets/createnuclear/models/item/colored/black_anti_radiation_boots.json +5e5029f1eced6b6588c6bf0a8a24412769be2032 assets/createnuclear/models/item/colored/black_anti_radiation_chestplate.json +c9a0fd5c17d33650f929ea28e753f1524b28df8e assets/createnuclear/models/item/colored/black_anti_radiation_helmet.json +8d35357fdf69ae42b16a529c58f13e3286a36e96 assets/createnuclear/models/item/colored/black_anti_radiation_leggings.json +2e4e4388510043760a1686cf2a535b95e4e11746 assets/createnuclear/models/item/colored/blue_anti_radiation_boots.json +e630329b2f6072a5e03e657f3c7c04f1e19ec6f0 assets/createnuclear/models/item/colored/blue_anti_radiation_chestplate.json +11858d3d90ff03ffb533d33c6a2dc6736f954c1a assets/createnuclear/models/item/colored/blue_anti_radiation_helmet.json +a19e265184d7df73f6c465d24f23a6566d9b08cc assets/createnuclear/models/item/colored/blue_anti_radiation_leggings.json +af2f19bf91ad723971afbe71c93a3fb1ef9e9b80 assets/createnuclear/models/item/colored/brown_anti_radiation_boots.json +9f2490080037e0cc9580e1939957243d7d80f494 assets/createnuclear/models/item/colored/brown_anti_radiation_chestplate.json +5dc65bb458012228b982eebb3b292aaea048f129 assets/createnuclear/models/item/colored/brown_anti_radiation_helmet.json +e6f5233fec76488fed7f01a8fc6dd13e369bb99c assets/createnuclear/models/item/colored/brown_anti_radiation_leggings.json +ccbfebe4c6428606495ec9d95d03cba12f0614c3 assets/createnuclear/models/item/colored/cyan_anti_radiation_boots.json +2922f5f250e65244329fa2e8a9fc063252f1c384 assets/createnuclear/models/item/colored/cyan_anti_radiation_chestplate.json +92b43a2cde30b9485d7abbdadfda5de7df745f27 assets/createnuclear/models/item/colored/cyan_anti_radiation_helmet.json +1899b326e3ae6b628d793a988839e940da7d4184 assets/createnuclear/models/item/colored/cyan_anti_radiation_leggings.json +135d0ef2e307cacde2fc7834ff599f175f708321 assets/createnuclear/models/item/colored/gray_anti_radiation_boots.json +c7a2bcf4933ee6530668468e2d750a766685b6d8 assets/createnuclear/models/item/colored/gray_anti_radiation_chestplate.json +eb475bbcb4fcc6ef33247a8d828a5f7cebc9bd17 assets/createnuclear/models/item/colored/gray_anti_radiation_helmet.json +8dc41293aea1b2b10d3f5ed7cceb1e750211de82 assets/createnuclear/models/item/colored/gray_anti_radiation_leggings.json +32e4183b43020d4adafc0492e3380f582bc1bc96 assets/createnuclear/models/item/colored/green_anti_radiation_boots.json +2ee9cb67f264276d1e43ae867261194d48cf3e2f assets/createnuclear/models/item/colored/green_anti_radiation_chestplate.json +777b11e9079ed656d81d46618abcf0e3180fa211 assets/createnuclear/models/item/colored/green_anti_radiation_helmet.json +4a764228deb8dd3fa9919b96de866a67147dab47 assets/createnuclear/models/item/colored/green_anti_radiation_leggings.json +0b284171834018501d8a8fa033c2f23253410435 assets/createnuclear/models/item/colored/light_blue_anti_radiation_boots.json +aa8b456049ff706bb4f24ad6e9c159f5be97595e assets/createnuclear/models/item/colored/light_blue_anti_radiation_chestplate.json +f920b0e1e5ccd09cf718aed7c4ce877d8b71535c assets/createnuclear/models/item/colored/light_blue_anti_radiation_helmet.json +28a24d909791afb368fef3c9ea62bd8f411294c0 assets/createnuclear/models/item/colored/light_blue_anti_radiation_leggings.json +3f95305d86580f5bcd4565bf212529c0a31df89f assets/createnuclear/models/item/colored/light_gray_anti_radiation_boots.json +fc40ae0592b29adc56b474a1dcfdda3b308338b6 assets/createnuclear/models/item/colored/light_gray_anti_radiation_chestplate.json +ff2b2cd99e3a5f1d73d5a5b85188e166860e840b assets/createnuclear/models/item/colored/light_gray_anti_radiation_helmet.json +504461e53fd0666769900bb4a9203f549516c32a assets/createnuclear/models/item/colored/light_gray_anti_radiation_leggings.json +56db9dc9744caa6cc0d7f447ee779eea7611bcec assets/createnuclear/models/item/colored/lime_anti_radiation_boots.json +c12d3c89f7964fc9891ae1757457f52f5fd42fb4 assets/createnuclear/models/item/colored/lime_anti_radiation_chestplate.json +0e3076492440bd60e320b960e783b87f941b4bca assets/createnuclear/models/item/colored/lime_anti_radiation_helmet.json +0319754a78d26eb0a102410b172847f59b4e3abd assets/createnuclear/models/item/colored/lime_anti_radiation_leggings.json +a67c6bcc52241530e0a6a1b6462815125730f47c assets/createnuclear/models/item/colored/magenta_anti_radiation_boots.json +d1a3620810d13a8d2887b740aa31147d667a76fe assets/createnuclear/models/item/colored/magenta_anti_radiation_chestplate.json +bd51ce1850aeb47e442d9a225f8e1b9c64703668 assets/createnuclear/models/item/colored/magenta_anti_radiation_helmet.json +2237ced4a4e9ce11096fca7832475859f6a63d12 assets/createnuclear/models/item/colored/magenta_anti_radiation_leggings.json +0e8458fba6ef3f70d485e9ef94ad3348b9c9ccc3 assets/createnuclear/models/item/colored/orange_anti_radiation_boots.json +5596d1c4c495809c2642c5e59e697661411f29a6 assets/createnuclear/models/item/colored/orange_anti_radiation_chestplate.json +3f7f545fe4aecd253b1e34c146ee7eb45dc5a4b6 assets/createnuclear/models/item/colored/orange_anti_radiation_helmet.json +854edc540ee421a3da166ebedb95706349e3612b assets/createnuclear/models/item/colored/orange_anti_radiation_leggings.json +db195113d80a009ccdd6db125020dbfc010e81b3 assets/createnuclear/models/item/colored/pink_anti_radiation_boots.json +c435c2b95d5e27fff9fd300218710ce8b4444df5 assets/createnuclear/models/item/colored/pink_anti_radiation_chestplate.json +823b1614c94b8e385449c05225bc8d3dfa214168 assets/createnuclear/models/item/colored/pink_anti_radiation_helmet.json +3ee985f85be75905a3ec5c31750a6093e29332c2 assets/createnuclear/models/item/colored/pink_anti_radiation_leggings.json +c8ae14ec7e445f9f2158ff0ce05addcfe412f8f1 assets/createnuclear/models/item/colored/purple_anti_radiation_boots.json +f62d520b0e16a5800aee9937e50f543d7ae9505f assets/createnuclear/models/item/colored/purple_anti_radiation_chestplate.json +8a4fa7289406f02f82bf52871bdabd7918600ce8 assets/createnuclear/models/item/colored/purple_anti_radiation_helmet.json +a550ea9c2b1f3aaa4b942552993f84f2ac856bff assets/createnuclear/models/item/colored/purple_anti_radiation_leggings.json +804f3448f3b880ce8e43fbb3fcb963c8ace1841c assets/createnuclear/models/item/colored/red_anti_radiation_boots.json +c35ac2019c04d1da881af7e0c48ee5074fa85bfb assets/createnuclear/models/item/colored/red_anti_radiation_chestplate.json +caa15a3ca087a40b33eb78e2156c9697b08f5c5f assets/createnuclear/models/item/colored/red_anti_radiation_helmet.json +b28e064c434b9859f1465c698f97fecd738707d6 assets/createnuclear/models/item/colored/red_anti_radiation_leggings.json +bd8afdb187eaaaf8611c80e43783a3d428d7477d assets/createnuclear/models/item/colored/white_anti_radiation_boots.json +64ddb5bd41f762fae95366dc33e9bb80aee440be assets/createnuclear/models/item/colored/white_anti_radiation_chestplate.json +59333dc66e3d12c84ea8a83dbce5e96048ef179f assets/createnuclear/models/item/colored/white_anti_radiation_helmet.json +7bb3c999d445c237d220267c390e4ef1d6cb605b assets/createnuclear/models/item/colored/white_anti_radiation_leggings.json +fbf21711d9d9196b95f53d10a3d0160e1423e3ef assets/createnuclear/models/item/colored/yellow_anti_radiation_boots.json +96f46592ee8bd686c14d53eabc03ac0223784fd5 assets/createnuclear/models/item/colored/yellow_anti_radiation_chestplate.json +ceefea70488adb5db8c8e2355eb9b59b8262b0fc assets/createnuclear/models/item/colored/yellow_anti_radiation_helmet.json +893789e72874b7b3bb5634df81b374c38177f2f7 assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json 4c5ade8688c0dfd0c3007c6bde5d52fb0a0f44cc assets/createnuclear/models/item/cooled_nitrogen_concentrate.json 0c682ff48601bf7f42c8561819ecede780664fbf assets/createnuclear/models/item/cut_autunite.json 11220bd60ab51e05a978a8322511c224d15bf886 assets/createnuclear/models/item/cut_autunite_bricks.json @@ -139,10 +203,10 @@ de649e8356e85e802df3e64df8fd663ce62ba16d assets/createnuclear/models/item/cyan_c e7121a329daab2859a4fbe971cea9ce1d3ab0b56 assets/createnuclear/models/item/deepslate_nitrate_ore.json 60b37c01bc3e885a25ce9b1aff4f8cb44e98f759 assets/createnuclear/models/item/deepslate_thorium_ore.json 1f160865067749c0bed163a84a61581631294141 assets/createnuclear/models/item/deepslate_uranium_ore.json -bdd9910ec9f3db9829c3ea2d12083126b7c01304 assets/createnuclear/models/item/default_anti_radiation_boots.json -3031c711fcf2b5e9da9662e9367a8d0773ed349c assets/createnuclear/models/item/default_anti_radiation_chestplate.json -a8968e2d92f26957ad91d0d0e5248e65a4cec183 assets/createnuclear/models/item/default_anti_radiation_helmet.json -b67d3df4f90c9efc0308360b6ed502f2d9ad6d06 assets/createnuclear/models/item/default_anti_radiation_leggings.json +7bd18aa55d1f24d6dcbf3f1318e29404c952f270 assets/createnuclear/models/item/default_anti_radiation_boots.json +0a6a0d34bacafb0557c591531e67c1f1dd51779a assets/createnuclear/models/item/default_anti_radiation_chestplate.json +d57ca18c53943f027d2e3cdf5fcd5ab9647fd6d6 assets/createnuclear/models/item/default_anti_radiation_helmet.json +3b9e419198305e6f565189a9949c35d75d5ccded assets/createnuclear/models/item/default_anti_radiation_leggings.json 5a2694d92c4708ca23ddfa67666ea26be66b9a45 assets/createnuclear/models/item/enriched_soul_soil.json 306f5731ab788fa3cf3d75a7edfcc68b9c20613a assets/createnuclear/models/item/enriched_yellowcake.json a3b71025626527be742999a0256e9c2290c9d42e assets/createnuclear/models/item/enriching_campfire.json diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index dd96a369..ee9128fb 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-18T14:21:52.171348 CreateNuclear Generated Registry Entries +// 1.20.1 2026-06-22T11:11:17.7591194 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -20,7 +20,7 @@ b0e1ee7314412507fd7346cb48b29d105f6186ad data/createnuclear/worldgen/configured_ 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/final_density.json 7f5f110a211b82bc22627b2f901c5f3c6a1265dd data/createnuclear/worldgen/noise/irradiated/erosion.json da4ba44d949615000ebce13f04cb97dec24cf192 data/createnuclear/worldgen/noise_settings/irradiated_noise.json -055203794153b01a2ebc956d13b7900e5d3851ca data/createnuclear/worldgen/placed_feature/lead_ore.json +5a035ad45f9039b81e3e55160da3127fe7079ba9 data/createnuclear/worldgen/placed_feature/lead_ore.json e69f61cbb4bf2c50a6123ddc87c024c801bb78d1 data/createnuclear/worldgen/placed_feature/nitrate_ore.json cc85909071cab20eacbe2c34887c6ed6a02dc51e data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json 0762472dada74fb4592de79d598f8d45d955ea2c data/createnuclear/worldgen/placed_feature/thorium_ore.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index ae9ea000..161e70c9 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -294,7 +294,6 @@ "createnuclear.subtitle.reacteur/casing_place": "buısɐƆ ɹoʇɔɐǝᴚ ǝɔɐןԀ", "createnuclear.subtitle.reacteur/casing_step": "buısɐƆ ɹoʇɔɐǝᴚ uo dǝʇS", "createnuclear.tooltip.baseRodHeat": "Ὁ %d :ʇɐǝH poᴚ ǝsɐᗺ", - "createnuclear.tooltip.cloth.color": "%s :ǝɔǝıd ɹoɯɹɐ ɟo ɹoןoƆ", "createnuclear.tooltip.fluid": " %s :pınןℲ", "createnuclear.tooltip.fluid.amount": "qɯ %d", "createnuclear.tooltip.fluid.none": " ǝuoN :pınןℲ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index b73ec243..b0768b63 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -294,7 +294,6 @@ "createnuclear.subtitle.reacteur/casing_place": "Place Reactor Casing", "createnuclear.subtitle.reacteur/casing_step": "Step on Reactor Casing", "createnuclear.tooltip.baseRodHeat": "Base Rod Heat: %d Q", - "createnuclear.tooltip.cloth.color": "Color of armor piece: %s", "createnuclear.tooltip.fluid": "Fluid: %s ", "createnuclear.tooltip.fluid.amount": "%d mb", "createnuclear.tooltip.fluid.none": "Fluid: None ", diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_boots.json new file mode 100644 index 00000000..69119f5f --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/black_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_chestplate.json new file mode 100644 index 00000000..6675fc3e --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/black_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_helmet.json new file mode 100644 index 00000000..8aa9ce75 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/black_anti_radiation_suit", + "particle": "createnuclear:item/armors/black_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_leggings.json new file mode 100644 index 00000000..26b2d81c --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/black_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/black_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_boots.json new file mode 100644 index 00000000..bc00cdaf --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_chestplate.json new file mode 100644 index 00000000..609f89b9 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_helmet.json new file mode 100644 index 00000000..ef9dff51 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/blue_anti_radiation_suit", + "particle": "createnuclear:item/armors/blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_leggings.json new file mode 100644 index 00000000..c17392eb --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/blue_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_boots.json new file mode 100644 index 00000000..25fa3e01 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/brown_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_chestplate.json new file mode 100644 index 00000000..09169bff --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/brown_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_helmet.json new file mode 100644 index 00000000..fa4da840 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/brown_anti_radiation_suit", + "particle": "createnuclear:item/armors/brown_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_leggings.json new file mode 100644 index 00000000..c690923f --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/brown_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/brown_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_boots.json new file mode 100644 index 00000000..a2faeecb --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/cyan_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_chestplate.json new file mode 100644 index 00000000..32883f01 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/cyan_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_helmet.json new file mode 100644 index 00000000..2a0f8c9c --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/cyan_anti_radiation_suit", + "particle": "createnuclear:item/armors/cyan_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_leggings.json new file mode 100644 index 00000000..81e4a602 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/cyan_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/cyan_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_boots.json new file mode 100644 index 00000000..9c16f60a --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_chestplate.json new file mode 100644 index 00000000..c60317b6 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_helmet.json new file mode 100644 index 00000000..eed2cc4b --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/gray_anti_radiation_suit", + "particle": "createnuclear:item/armors/gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_leggings.json new file mode 100644 index 00000000..249fc982 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/gray_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_boots.json new file mode 100644 index 00000000..10953b22 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/green_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_chestplate.json new file mode 100644 index 00000000..58167620 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/green_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_helmet.json new file mode 100644 index 00000000..a8641aae --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/green_anti_radiation_suit", + "particle": "createnuclear:item/armors/green_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_leggings.json new file mode 100644 index 00000000..5bb03c06 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/green_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/green_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_boots.json new file mode 100644 index 00000000..d18e5ee8 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/light_blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_chestplate.json new file mode 100644 index 00000000..02c67b15 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/light_blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_helmet.json new file mode 100644 index 00000000..7c80dea8 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/light_blue_anti_radiation_suit", + "particle": "createnuclear:item/armors/light_blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_leggings.json new file mode 100644 index 00000000..cd611a9e --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_blue_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/light_blue_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_boots.json new file mode 100644 index 00000000..66e56606 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/light_gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_chestplate.json new file mode 100644 index 00000000..afba5c08 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/light_gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_helmet.json new file mode 100644 index 00000000..59708048 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/light_gray_anti_radiation_suit", + "particle": "createnuclear:item/armors/light_gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_leggings.json new file mode 100644 index 00000000..bc1afc65 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/light_gray_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/light_gray_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_boots.json new file mode 100644 index 00000000..0ee29f8b --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/lime_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_chestplate.json new file mode 100644 index 00000000..b4fd6a4a --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/lime_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_helmet.json new file mode 100644 index 00000000..5e7924d5 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/lime_anti_radiation_suit", + "particle": "createnuclear:item/armors/lime_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_leggings.json new file mode 100644 index 00000000..028841ee --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/lime_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/lime_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_boots.json new file mode 100644 index 00000000..f1a1e3d3 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/magenta_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_chestplate.json new file mode 100644 index 00000000..0b9cefd7 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/magenta_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_helmet.json new file mode 100644 index 00000000..412ed6f6 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/magenta_anti_radiation_suit", + "particle": "createnuclear:item/armors/magenta_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_leggings.json new file mode 100644 index 00000000..052a1c32 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/magenta_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/magenta_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_boots.json new file mode 100644 index 00000000..c18a4bbd --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/orange_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_chestplate.json new file mode 100644 index 00000000..1e953336 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/orange_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_helmet.json new file mode 100644 index 00000000..7d9bb28e --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/orange_anti_radiation_suit", + "particle": "createnuclear:item/armors/orange_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_leggings.json new file mode 100644 index 00000000..a71064a5 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/orange_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/orange_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_boots.json new file mode 100644 index 00000000..aab0a59b --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/pink_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_chestplate.json new file mode 100644 index 00000000..8a4f72db --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/pink_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_helmet.json new file mode 100644 index 00000000..43657ec3 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/pink_anti_radiation_suit", + "particle": "createnuclear:item/armors/pink_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_leggings.json new file mode 100644 index 00000000..0d1be27a --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/pink_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/pink_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_boots.json new file mode 100644 index 00000000..8059c669 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/purple_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_chestplate.json new file mode 100644 index 00000000..5a441620 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/purple_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_helmet.json new file mode 100644 index 00000000..6efbf23d --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/purple_anti_radiation_suit", + "particle": "createnuclear:item/armors/purple_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_leggings.json new file mode 100644 index 00000000..5e000c47 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/purple_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/purple_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_boots.json new file mode 100644 index 00000000..516a66fc --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/red_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_chestplate.json new file mode 100644 index 00000000..0dd13c7e --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/red_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_helmet.json new file mode 100644 index 00000000..63e497a1 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/red_anti_radiation_suit", + "particle": "createnuclear:item/armors/red_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_leggings.json new file mode 100644 index 00000000..1b62aaa2 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/red_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/red_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_boots.json new file mode 100644 index 00000000..7d9de83f --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/white_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_chestplate.json new file mode 100644 index 00000000..995ff506 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/white_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_helmet.json new file mode 100644 index 00000000..c89f038d --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/white_anti_radiation_suit", + "particle": "createnuclear:item/armors/white_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_leggings.json new file mode 100644 index 00000000..e99461b6 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/white_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/white_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_boots.json new file mode 100644 index 00000000..d1ecbe8b --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "textures": { + "14": "createnuclear:item/armors/yellow_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_chestplate.json new file mode 100644 index 00000000..6f12a2ff --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "textures": { + "14": "createnuclear:item/armors/yellow_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_helmet.json new file mode 100644 index 00000000..0f97b2b9 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_helmet.json @@ -0,0 +1,7 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "textures": { + "layer0": "createnuclear:item/armors/yellow_anti_radiation_suit", + "particle": "createnuclear:item/armors/yellow_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json new file mode 100644 index 00000000..77b23ea7 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "textures": { + "14": "createnuclear:item/armors/yellow_anti_radiation_suit" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_boots.json b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_boots.json index 77835b78..f318c885 100644 --- a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_boots.json +++ b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_boots.json @@ -1,3 +1,101 @@ { - "parent": "createnuclear:item/default_anti_radiation_boots/item" + "parent": "createnuclear:item/default_anti_radiation_boots/item", + "overrides": [ + { + "model": "createnuclear:item/colored/white_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.0625 + } + }, + { + "model": "createnuclear:item/colored/orange_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.125 + } + }, + { + "model": "createnuclear:item/colored/magenta_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.1875 + } + }, + { + "model": "createnuclear:item/colored/light_blue_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.25 + } + }, + { + "model": "createnuclear:item/colored/yellow_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.3125 + } + }, + { + "model": "createnuclear:item/colored/lime_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.375 + } + }, + { + "model": "createnuclear:item/colored/pink_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.4375 + } + }, + { + "model": "createnuclear:item/colored/gray_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.5 + } + }, + { + "model": "createnuclear:item/colored/light_gray_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.5625 + } + }, + { + "model": "createnuclear:item/colored/cyan_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.625 + } + }, + { + "model": "createnuclear:item/colored/purple_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.6875 + } + }, + { + "model": "createnuclear:item/colored/blue_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.75 + } + }, + { + "model": "createnuclear:item/colored/brown_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.8125 + } + }, + { + "model": "createnuclear:item/colored/green_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.875 + } + }, + { + "model": "createnuclear:item/colored/red_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 0.9375 + } + }, + { + "model": "createnuclear:item/colored/black_anti_radiation_boots", + "predicate": { + "createnuclear:cloth_color": 1.0 + } + } + ] } \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate.json b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate.json index 59511da8..76be7dbd 100644 --- a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate.json +++ b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_chestplate.json @@ -1,3 +1,101 @@ { - "parent": "createnuclear:item/default_anti_radiation_chestplate/item" + "parent": "createnuclear:item/default_anti_radiation_chestplate/item", + "overrides": [ + { + "model": "createnuclear:item/colored/white_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.0625 + } + }, + { + "model": "createnuclear:item/colored/orange_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.125 + } + }, + { + "model": "createnuclear:item/colored/magenta_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.1875 + } + }, + { + "model": "createnuclear:item/colored/light_blue_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.25 + } + }, + { + "model": "createnuclear:item/colored/yellow_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.3125 + } + }, + { + "model": "createnuclear:item/colored/lime_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.375 + } + }, + { + "model": "createnuclear:item/colored/pink_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.4375 + } + }, + { + "model": "createnuclear:item/colored/gray_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.5 + } + }, + { + "model": "createnuclear:item/colored/light_gray_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.5625 + } + }, + { + "model": "createnuclear:item/colored/cyan_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.625 + } + }, + { + "model": "createnuclear:item/colored/purple_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.6875 + } + }, + { + "model": "createnuclear:item/colored/blue_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.75 + } + }, + { + "model": "createnuclear:item/colored/brown_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.8125 + } + }, + { + "model": "createnuclear:item/colored/green_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.875 + } + }, + { + "model": "createnuclear:item/colored/red_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 0.9375 + } + }, + { + "model": "createnuclear:item/colored/black_anti_radiation_chestplate", + "predicate": { + "createnuclear:cloth_color": 1.0 + } + } + ] } \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_helmet.json b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_helmet.json index 6df967d8..4c6a8168 100644 --- a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_helmet.json +++ b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_helmet.json @@ -1,3 +1,101 @@ { - "parent": "createnuclear:item/default_anti_radiation_helmet/item" + "parent": "createnuclear:item/default_anti_radiation_helmet/item", + "overrides": [ + { + "model": "createnuclear:item/colored/white_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.0625 + } + }, + { + "model": "createnuclear:item/colored/orange_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.125 + } + }, + { + "model": "createnuclear:item/colored/magenta_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.1875 + } + }, + { + "model": "createnuclear:item/colored/light_blue_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.25 + } + }, + { + "model": "createnuclear:item/colored/yellow_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.3125 + } + }, + { + "model": "createnuclear:item/colored/lime_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.375 + } + }, + { + "model": "createnuclear:item/colored/pink_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.4375 + } + }, + { + "model": "createnuclear:item/colored/gray_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.5 + } + }, + { + "model": "createnuclear:item/colored/light_gray_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.5625 + } + }, + { + "model": "createnuclear:item/colored/cyan_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.625 + } + }, + { + "model": "createnuclear:item/colored/purple_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.6875 + } + }, + { + "model": "createnuclear:item/colored/blue_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.75 + } + }, + { + "model": "createnuclear:item/colored/brown_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.8125 + } + }, + { + "model": "createnuclear:item/colored/green_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.875 + } + }, + { + "model": "createnuclear:item/colored/red_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 0.9375 + } + }, + { + "model": "createnuclear:item/colored/black_anti_radiation_helmet", + "predicate": { + "createnuclear:cloth_color": 1.0 + } + } + ] } \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_leggings.json b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_leggings.json index 224fa9f7..335d1f1c 100644 --- a/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_leggings.json +++ b/src/generated/resources/assets/createnuclear/models/item/default_anti_radiation_leggings.json @@ -1,3 +1,101 @@ { - "parent": "createnuclear:item/default_anti_radiation_leggings/item" + "parent": "createnuclear:item/default_anti_radiation_leggings/item", + "overrides": [ + { + "model": "createnuclear:item/colored/white_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.0625 + } + }, + { + "model": "createnuclear:item/colored/orange_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.125 + } + }, + { + "model": "createnuclear:item/colored/magenta_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.1875 + } + }, + { + "model": "createnuclear:item/colored/light_blue_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.25 + } + }, + { + "model": "createnuclear:item/colored/yellow_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.3125 + } + }, + { + "model": "createnuclear:item/colored/lime_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.375 + } + }, + { + "model": "createnuclear:item/colored/pink_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.4375 + } + }, + { + "model": "createnuclear:item/colored/gray_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.5 + } + }, + { + "model": "createnuclear:item/colored/light_gray_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.5625 + } + }, + { + "model": "createnuclear:item/colored/cyan_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.625 + } + }, + { + "model": "createnuclear:item/colored/purple_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.6875 + } + }, + { + "model": "createnuclear:item/colored/blue_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.75 + } + }, + { + "model": "createnuclear:item/colored/brown_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.8125 + } + }, + { + "model": "createnuclear:item/colored/green_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.875 + } + }, + { + "model": "createnuclear:item/colored/red_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 0.9375 + } + }, + { + "model": "createnuclear:item/colored/black_anti_radiation_leggings", + "predicate": { + "createnuclear:cloth_color": 1.0 + } + } + ] } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index ec632bb6..73b2e981 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -4,7 +4,11 @@ import com.tterrag.registrate.util.entry.ItemEntry; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateItemModelProvider; import com.tterrag.registrate.providers.RegistrateRecipeProvider; +import com.tterrag.registrate.util.nullness.NonNullBiConsumer; +import net.minecraftforge.client.model.generators.ItemModelBuilder; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; @@ -44,6 +48,40 @@ @SuppressWarnings({"unused", "deprecation"}) public class CNItems { + /** + * Generates the item model for a dyeable anti-radiation armor piece. + *

+ * Replicates {@link AssetLookup#itemModelWithPartials()} (outer model parenting the + * Blockbench {@code item//item} model) and adds one model override per {@link DyeColor}, + * driven by the client-side {@code createnuclear:cloth_color} item property + * (see {@code CreateNuclearClient}). Each per-color child model reuses the same geometry but + * re-textures it with the matching {@code item/armors/_anti_radiation_suit} sheet. + *

+ * The texture keys differ per slot: the helmet geometry uses {@code layer0}/{@code particle}, + * the other pieces use {@code 14} — hence {@code textureKeys} is passed explicitly. + */ + private static NonNullBiConsumer, RegistrateItemModelProvider> coloredArmorModel(String slot, String... textureKeys) { + return (c, p) -> { + ResourceLocation baseParent = p.modLoc("item/" + c.getName() + "/item"); + ItemModelBuilder outer = p.withExistingParent(c.getName(), baseParent); + // DyeColor.values() is ordered by id (0..15); overrides must be ascending by predicate + // value so vanilla override resolution selects the exact color (returns last match <= value). + // The cloth_color property is clamped to [0,1] (see CreateNuclearClient), hence the + // (id+1)/16 normalization here must match the value returned there exactly. + for (DyeColor color : DyeColor.values()) { + String colorName = color.getSerializedName(); + ItemModelBuilder child = p.withExistingParent("item/colored/" + colorName + "_anti_radiation_" + slot, baseParent); + for (String key : textureKeys) { + child.texture(key, "item/armors/" + colorName + "_anti_radiation_suit"); + } + outer.override() + .predicate(CreateNuclear.asResource("cloth_color"), (color.getId() + 1) / 16f) + .model(child) + .end(); + } + }; + } + public static final ItemEntry YELLOWCAKE = CreateNuclear.REGISTRATE .item("yellowcake", p -> new RadiationItem(p, 4)) @@ -253,7 +291,7 @@ public class CNItems { } }) .lang("Anti Radiation Helmet") - .model(AssetLookup.itemModelWithPartials()) + .model(coloredArmorModel("helmet", "layer0", "particle")) .register(); public static final ItemEntry ANTI_RADIATION_CHESTPLATES = CreateNuclear.REGISTRATE @@ -287,7 +325,7 @@ public class CNItems { } }) .lang("Anti Radiation Chestplate") - .model(AssetLookup.itemModelWithPartials()) + .model(coloredArmorModel("chestplate", "14")) .register(); public static final ItemEntry ANTI_RADIATION_LEGGINGS = CreateNuclear.REGISTRATE @@ -321,7 +359,7 @@ public class CNItems { } }) .lang("Anti Radiation Leggings") - .model(AssetLookup.itemModelWithPartials()) + .model(coloredArmorModel("leggings", "14")) .register(); public static final ItemEntry ANTI_RADIATION_BOOTS = CreateNuclear.REGISTRATE @@ -354,7 +392,7 @@ public class CNItems { } }) .lang("Anti Radiation Boots") - .model(AssetLookup.itemModelWithPartials()) + .model(coloredArmorModel("boots", "14")) .register(); public static final DyedItemsList CLOTHS = new DyedItemsList<>(color -> { diff --git a/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java b/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java index c44faa1f..92700bb0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java +++ b/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java @@ -1,12 +1,17 @@ package net.nuclearteam.createnuclear; import net.createmod.ponder.foundation.PonderIndex; +import net.minecraft.client.renderer.item.ClampedItemPropertyFunction; +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.DyeColor; import net.minecraftforge.client.event.RegisterParticleProvidersEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.nuclearteam.createnuclear.content.particles.NuclearMushroomCloudParticle; import net.nuclearteam.createnuclear.content.particles.SmallNuclearExplosionParticle; import net.nuclearteam.createnuclear.foundation.ponder.CreateNuclearPonderPlugin; +import net.nuclearteam.createnuclear.foundation.utility.ClothTagHelper; @SuppressWarnings("unused") public class CreateNuclearClient { @@ -19,6 +24,30 @@ public static void onCtorClient(IEventBus modEventBus, IEventBus forgeEventBus) public static void clientInit(final FMLClientSetupEvent event) { PonderIndex.addPlugin(new CreateNuclearPonderPlugin()); + event.enqueueWork(CreateNuclearClient::registerItemProperties); + } + + /** + * Registers the {@code createnuclear:cloth_color} item property used by the anti-radiation + * armor item models to pick the right colored icon based on the {@code ClothColor} NBT tag. + *

+ * {@link ItemProperties#register} clamps the value to {@code [0,1]}, so the dyed color id is + * normalized to {@code (id+1)/16} (range {@code 0.0625..1.0}) and undyed maps to {@code 0} — + * below the smallest override threshold, so no override fires and the default icon shows. + * The model overrides in {@code CNItems.coloredArmorModel} use the matching {@code (id+1)/16} + * predicate values. Mirrors the dyed worn-armor texture selected by + * {@code AntiRadiationArmorItem.getArmorTexture}. + */ + private static void registerItemProperties() { + ResourceLocation clothColor = CreateNuclear.asResource("cloth_color"); + ClampedItemPropertyFunction fn = (stack, level, entity, seed) -> { + DyeColor dye = DyeColor.byName(ClothTagHelper.getClothColor(stack, "default"), null); + return dye == null ? 0f : (dye.getId() + 1) / 16f; + }; + ItemProperties.register(CNItems.ANTI_RADIATION_HELMETS.get(), clothColor, fn); + ItemProperties.register(CNItems.ANTI_RADIATION_CHESTPLATES.get(), clothColor, fn); + ItemProperties.register(CNItems.ANTI_RADIATION_LEGGINGS.get(), clothColor, fn); + ItemProperties.register(CNItems.ANTI_RADIATION_BOOTS.get(), clothColor, fn); } public static void setupParticles(RegisterParticleProvidersEvent registry) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java index 8468d500..72e27518 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java @@ -2,12 +2,7 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; -import com.simibubi.create.AllKeys; -import net.minecraft.ChatFormatting; import net.minecraft.Util; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.CommonComponents; -import net.minecraft.network.chat.Component; import net.minecraft.world.entity.*; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; @@ -19,11 +14,8 @@ import net.nuclearteam.createnuclear.CNAttributes; import net.nuclearteam.createnuclear.CNItems; -import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; import net.nuclearteam.createnuclear.foundation.utility.ClothTagHelper; -import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; -import javax.annotation.Nullable; import java.util.*; import java.util.function.Consumer; @@ -59,34 +51,6 @@ public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot return ClothTagHelper.getArmorTexturePath(stack, "anti_radiation_suit.png"); } - @Override - public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List tooltip, TooltipFlag pIsAdvanced) { - if (AllKeys.shiftDown()) return; - - List makeSummary = makeSummary(pStack); - if (makeSummary.isEmpty()) return; - - tooltip.add(CommonComponents.SPACE); - tooltip.addAll(makeSummary); - } - - - public List makeSummary(ItemStack item) { - if (!item.hasTag()) return Collections.emptyList(); - - CompoundTag tag = item.getTag(); - ItemStack cloth = ItemStack.of(tag.getCompound(ClothTagHelper.ITEM)); - if (!(cloth.getItem() instanceof ClothItem clothItem)) return Collections.emptyList(); - - List list = new ArrayList<>(); - CreateNuclearLang.translate("tooltip.cloth.color", clothItem.getColor().getSerializedName()) - .color(clothItem.getColor().getTextColor()) - .style(ChatFormatting.ITALIC) - .addTo(list); - - return list; - } - @Override public void initializeClient(Consumer consumer) { consumer.accept(new AntiRadiationArmorClientExtensions()); diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index 65c91739..5ba948b8 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -54,7 +54,6 @@ "createnuclear.tooltip.rodTimer": "Rod Duration: %d tick", "createnuclear.tooltip.heatRatio": "Heat Ratio: %d", "createnuclear.tooltip.typeRod": "Rod Type: %s", - "createnuclear.tooltip.cloth.color": "Color of armor piece: %s", "tag.item.c.coal_dusts": "Coal Dusts", From 80411903a24e42f73bae5de87df48ce11a67daf6 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 22 Jun 2026 13:35:40 +0200 Subject: [PATCH 064/171] chore: update mod version to 2.0.8 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5c1237d6..a1bd3117 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.5.4-alpha +mod_version=2.0.8 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html From 89374937eb07bdc587404bdfcfba2f936a25e805 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 22 Jun 2026 15:15:26 +0200 Subject: [PATCH 065/171] feat: add reactor sound events and implement client-side sound handling --- .../09bd1f7b209874b6c29086df91c49669495dd477 | 4 +- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +- .../assets/createnuclear/lang/en_ud.json | 3 + .../assets/createnuclear/lang/en_us.json | 3 + .../assets/createnuclear/sounds.json | 27 ++++++++ .../createnuclear/CNSoundEvents.java | 15 +++++ .../controller/ReactorControllerBlock.java | 4 ++ .../ReactorControllerBlockEntity.java | 39 +++++++++++- .../ReactorRunningSoundInstance.java | 61 +++++++++++++++++++ 9 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorRunningSoundInstance.java diff --git a/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 b/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 index 7d13fd79..fdae2c9e 100644 --- a/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 +++ b/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 @@ -1,2 +1,2 @@ -// 1.20.1 2026-05-18T15:36:13.3470841 CreateNuclear's Custom Sounds -7875d9fd3f2fcdd2b8d4d80e6309406b19c133e1 assets/createnuclear/sounds.json +// 1.20.1 2026-06-22T14:19:43.5342033 CreateNuclear's Custom Sounds +b698e29669f03e4d5baba058a24194333d16ebf6 assets/createnuclear/sounds.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 04602b1c..b08948a2 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-22T11:24:03.1050784 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-22T14:19:43.5352126 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -0a69265866b2e07bdab80591dbfeb1a59615d871 assets/createnuclear/lang/en_ud.json -d4da97268934abc6c59bda4fbe7aedc12b1800e1 assets/createnuclear/lang/en_us.json +dd5e0621e9cff50676e24afb7d2e3413da6ddda5 assets/createnuclear/lang/en_ud.json +b30fbb26f774c04e65ed5a4f37f1fdc5b4a6b271 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 161e70c9..c00e7d4d 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -288,11 +288,14 @@ "createnuclear.subtitle.geiger/high": "ɥbıH ɹǝbıǝ⅁", "createnuclear.subtitle.geiger/low": "ʍoꞀ ɹǝbıǝ⅁", "createnuclear.subtitle.geiger/medium": "ɯnıpǝW ɹǝ⅁ıǝ⅁", + "createnuclear.subtitle.reacteur/activation": "uoıʇɐʌıʇɔⱯ ɹoʇɔɐǝᴚ", "createnuclear.subtitle.reacteur/casing_break": "buısɐƆ ɹoʇɔɐǝᴚ ʞɐǝɹᗺ", "createnuclear.subtitle.reacteur/casing_fall": "ןןɐℲ buısɐƆ ɹoʇɔɐǝᴚ", "createnuclear.subtitle.reacteur/casing_hit": "buısɐƆ ɹoʇɔɐǝᴚ ʇıH", "createnuclear.subtitle.reacteur/casing_place": "buısɐƆ ɹoʇɔɐǝᴚ ǝɔɐןԀ", "createnuclear.subtitle.reacteur/casing_step": "buısɐƆ ɹoʇɔɐǝᴚ uo dǝʇS", + "createnuclear.subtitle.reacteur/running": "buıuunᴚ ɹoʇɔɐǝᴚ", + "createnuclear.subtitle.reacteur/shut_off": "ɟɟO ʇnɥS ɹoʇɔɐǝᴚ", "createnuclear.tooltip.baseRodHeat": "Ὁ %d :ʇɐǝH poᴚ ǝsɐᗺ", "createnuclear.tooltip.fluid": " %s :pınןℲ", "createnuclear.tooltip.fluid.amount": "qɯ %d", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index b0768b63..f870e342 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -288,11 +288,14 @@ "createnuclear.subtitle.geiger/high": "Geiger High", "createnuclear.subtitle.geiger/low": "Geiger Low", "createnuclear.subtitle.geiger/medium": "GeiGer Medium", + "createnuclear.subtitle.reacteur/activation": "Reactor Activation", "createnuclear.subtitle.reacteur/casing_break": "Break Reactor Casing", "createnuclear.subtitle.reacteur/casing_fall": "Reactor Casing Fall", "createnuclear.subtitle.reacteur/casing_hit": "Hit Reactor Casing", "createnuclear.subtitle.reacteur/casing_place": "Place Reactor Casing", "createnuclear.subtitle.reacteur/casing_step": "Step on Reactor Casing", + "createnuclear.subtitle.reacteur/running": "Reactor Running", + "createnuclear.subtitle.reacteur/shut_off": "Reactor Shut Off", "createnuclear.tooltip.baseRodHeat": "Base Rod Heat: %d Q", "createnuclear.tooltip.fluid": "Fluid: %s ", "createnuclear.tooltip.fluid.amount": "%d mb", diff --git a/src/generated/resources/assets/createnuclear/sounds.json b/src/generated/resources/assets/createnuclear/sounds.json index a43d66a7..23537568 100644 --- a/src/generated/resources/assets/createnuclear/sounds.json +++ b/src/generated/resources/assets/createnuclear/sounds.json @@ -107,6 +107,15 @@ ], "subtitle": "createnuclear.subtitle.geiger/medium" }, + "reacteur/activation": { + "sounds": [ + { + "type": "file", + "name": "createnuclear:reacteur/activation" + } + ], + "subtitle": "createnuclear.subtitle.reacteur/activation" + }, "reacteur/casing_break": { "sounds": [ { @@ -151,5 +160,23 @@ } ], "subtitle": "createnuclear.subtitle.reacteur/casing_step" + }, + "reacteur/running": { + "sounds": [ + { + "type": "file", + "name": "createnuclear:reacteur/running" + } + ], + "subtitle": "createnuclear.subtitle.reacteur/running" + }, + "reacteur/shut_off": { + "sounds": [ + { + "type": "file", + "name": "createnuclear:reacteur/shut_off" + } + ], + "subtitle": "createnuclear.subtitle.reacteur/shut_off" } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java b/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java index c3516515..dd04aaf8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java @@ -60,6 +60,21 @@ public class CNSoundEvents { .category(SoundSource.BLOCKS) .build(), + REACTOR_ACTIVATION = create("reacteur/activation") + .subtitle("Reactor Activation") + .category(SoundSource.BLOCKS) + .build(), + + REACTOR_RUNNING = create("reacteur/running") + .subtitle("Reactor Running") + .category(SoundSource.BLOCKS) + .build(), + + REACTOR_SHUT_OFF = create("reacteur/shut_off") + .subtitle("Reactor Shut Off") + .category(SoundSource.BLOCKS) + .build(), + REACTOR_ALARM = create("alarm/reactor", "alarm") .subtitle("Reactor Alarm") .category(SoundSource.BLOCKS) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index b64760cc..d0f8299d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -9,6 +9,7 @@ import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; @@ -104,6 +105,8 @@ public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Play player.setItemInHand(handIn, ItemStack.EMPTY); }); + // One-shot played server-side (null player) so it broadcasts to nearby clients. + worldIn.playSound(null, pos, CNSoundEvents.REACTOR_ACTIVATION.getMainEvent(), SoundSource.BLOCKS, 1.0f, 1.0f); return InteractionResult.SUCCESS; } @@ -120,6 +123,7 @@ else if (heldItem.isEmpty() && !controllerBlockEntity.getInventoryObject().getIt be.getOutputManager().rotateOutputs(be.getLevel(), be.getAssembled(), 0); be.notifyUpdate(); }); + worldIn.playSound(null, pos, CNSoundEvents.REACTOR_SHUT_OFF.getMainEvent(), SoundSource.BLOCKS, 1.0f, 1.0f); state.setValue(ASSEMBLED, false); return InteractionResult.SUCCESS; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 6b2c574e..e6efc3e0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -4,6 +4,7 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.IInteractionChecker; +import net.minecraft.client.Minecraft; import net.minecraft.core.*; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -14,9 +15,12 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.IItemHandler; +import net.nuclearteam.createnuclear.CNSoundEvents; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.multiblock.IMultiblockController; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; @@ -57,6 +61,10 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private int heat; private boolean isExploding = false; + /** Client-only looping "running" sound instance; never accessed server-side. */ + @OnlyIn(Dist.CLIENT) + private ReactorRunningSoundInstance runningSound; + private final ConsumptionCycleManager cycleManager = new ConsumptionCycleManager(); private double liquidLife; private ItemStack configuredPattern; @@ -316,7 +324,11 @@ private void updateReactorStateVisibility() { @Override public void tick() { super.tick(); - if (level.isClientSide || isExploding) + if (level.isClientSide) { + tickRunningSound(); + return; + } + if (isExploding) return; // Heat value written by the previous tick's handleAssembledState(); this tick's recalculated // heat is not visible here yet, so the alarm/meltdown danger flag is intentionally 1 tick behind. @@ -351,6 +363,31 @@ public void tick() { handleAssembledState(); } + /** + * Client-side: keep the looping "running" sound alive while the reactor is producing energy. + * Driven by the {@code ACTIVE} blockstate property, which the server recomputes every tick in + * {@link #updateReactorStateVisibility()} and vanilla syncs to the client automatically. + */ + @OnlyIn(Dist.CLIENT) + private void tickRunningSound() { + BlockState state = getBlockState(); + boolean active = state.hasProperty(ReactorControllerBlock.ACTIVE) + && state.getValue(ReactorControllerBlock.ACTIVE); + + if (!active) { + if (runningSound != null) { + runningSound.stopSound(); + runningSound = null; + } + return; + } + + if (runningSound == null || runningSound.isStopped()) { + runningSound = new ReactorRunningSoundInstance(level, worldPosition, CNSoundEvents.REACTOR_RUNNING.getMainEvent()); + Minecraft.getInstance().getSoundManager().play(runningSound); + } + } + // --- extracted sub-steps to keep single responsibility per method --- private void resolveEntitiesIfNeeded() { if (!needsToResolveEntities) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorRunningSoundInstance.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorRunningSoundInstance.java new file mode 100644 index 00000000..52f39cb0 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorRunningSoundInstance.java @@ -0,0 +1,61 @@ +package net.nuclearteam.createnuclear.content.multiblock.controller; + +import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance; +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.nuclearteam.createnuclear.CreateNuclear; + +/** + * Client-side looping sound played while a reactor is actively producing energy. + *

+ * Mirrors {@code ReactorAlarmSoundInstance}: the instance stops itself once the block at + * {@code pos} is no longer a running reactor controller (the {@code ACTIVE} blockstate property + * is synced from the server), so it survives the controller block being broken or the reactor + * shutting down even if the owning block entity's tick stops driving it. + */ +public class ReactorRunningSoundInstance extends AbstractTickableSoundInstance { + private final BlockPos pos; + private final Level level; + + public ReactorRunningSoundInstance(Level level, BlockPos pos, SoundEvent sound) { + super(sound, SoundSource.BLOCKS, level != null ? level.random : null); + this.level = level; + this.pos = pos; + if (pos != null) { + this.x = pos.getX(); + this.y = pos.getY(); + this.z = pos.getZ(); + } + this.looping = true; + this.delay = 0; + this.volume = 1.0F; + } + + @Override + public void tick() { + try { + if (level == null || pos == null) { + stop(); + return; + } + + BlockState state = level.getBlockState(pos); + if (!(state.getBlock() instanceof ReactorControllerBlock) + || !state.hasProperty(ReactorControllerBlock.ACTIVE) + || !state.getValue(ReactorControllerBlock.ACTIVE)) { + stop(); + } + } catch (Exception e) { + stop(); + CreateNuclear.LOGGER.warn(e.getMessage()); + } + } + + /** Public entry point so the owning block entity can stop the loop ({@link #stop()} is protected). */ + public void stopSound() { + stop(); + } +} From 676adbc777455869392a6aaae5e0da6a0da9f1ee Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 22 Jun 2026 15:39:48 +0200 Subject: [PATCH 066/171] feat: implement fluid input capacity distribution for reactors --- .../content/multiblock/ReactorAssembler.java | 29 ++++++++++++++++++- .../input/fluid/ReactorFluidInputEntity.java | 12 ++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 4295485f..202f376d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -20,6 +20,9 @@ import net.nuclearteam.createnuclear.foundation.utility.NotifyUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; +import java.util.ArrayList; +import java.util.List; + public final class ReactorAssembler { public static final int configRadius = CNConfigs.server().notify.distanceOfWarning.get(); @@ -81,6 +84,10 @@ public static void findAndRegisterSpecialBlocks(BoundingBox reactorPos, ReactorC int frameMinY = Integer.MAX_VALUE; int frameMaxY = Integer.MIN_VALUE; + // Collected here and assigned their capacity after the scan: the reactor-size capacity is a + // single TOTAL shared across every fluid input, so we split it once we know how many there are. + List fluidInputs = new ArrayList<>(); + for (int y = yMin; y <= yMax; y++) { boolean isYBoundary = (y == yMin || y == yMax); for (int x = xMin; x <= xMax; x++) { @@ -100,7 +107,7 @@ public static void findAndRegisterSpecialBlocks(BoundingBox reactorPos, ReactorC } else if (blockState.is(reactorInputFluidBlock)) { entity.addInputFluid(mutablePos.immutable()); if (level.getBlockEntity(mutablePos) instanceof ReactorFluidInputEntity fluidInput) { - fluidInput.applyReactorTierCapacity(entity.getMultiblockSize()); + fluidInputs.add(fluidInput); } } else if (blockState.is(reactorAlarmBlock)) { entity.addAlarm(mutablePos.immutable()); @@ -118,6 +125,26 @@ public static void findAndRegisterSpecialBlocks(BoundingBox reactorPos, ReactorC if (frameMinY != Integer.MAX_VALUE) { entity.getFrameDisplayManager().setFrameColumn(frameMinY, frameMaxY, entity::notifyUpdate); } + + distributeFluidInputCapacity(fluidInputs, entity.getMultiblockSize()); + } + + /** + * Splits the reactor-size total fluid capacity evenly across all fluid inputs so the combined + * max capacity always equals the configured value, regardless of how many inputs were placed. + * The integer remainder is spread one unit at a time over the first inputs so the sum stays exact. + */ + private static void distributeFluidInputCapacity(List fluidInputs, int reactorSize) { + int count = fluidInputs.size(); + if (count == 0) return; + + int total = ReactorFluidInputEntity.getCapacityForReactorSize(reactorSize); + int base = total / count; + int remainder = total % count; + + for (int i = 0; i < count; i++) { + fluidInputs.get(i).applyCapacity(base + (i < remainder ? 1 : 0)); + } } private static ReactorControllerBlockEntity getBlockEntity(Level level, BlockPos pos) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java index 58f24c4e..1533b2b6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java @@ -56,9 +56,15 @@ public static int getCapacityForReactorSize(int reactorSize) { }; } - /** Applies the tank capacity matching the size of the reactor this input belongs to. */ - public void applyReactorTierCapacity(int reactorSize) { - int capacity = getCapacityForReactorSize(reactorSize); + /** + * Applies an explicit tank capacity to this input. + *

+ * The per-reactor-size capacity ({@link #getCapacityForReactorSize(int)}) is the TOTAL the + * reactor should hold, split across all fluid inputs by {@code ReactorAssembler}, so the sum + * of every input's capacity stays equal to the configured value no matter how many inputs the + * player places. + */ + public void applyCapacity(int capacity) { if (internalTank.getCapacity() == capacity) return; internalTank.setCapacity(capacity); if (level != null && !level.isClientSide) { From 5089bf0b9fde356788f07c27d1a2a9d2769556b4 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Mon, 22 Jun 2026 16:39:46 +0200 Subject: [PATCH 067/171] fix: update advancement backgrounds and reinforce glass properties --- .../abc32a97b4e744838610c53dbbbaaf9f7d29a557 | 4 ++-- .../data/createnuclear/advancements/root.json | 2 +- .../net/nuclearteam/createnuclear/CNBlocks.java | 2 +- .../advancement/CreateNuclearAdvancement.java | 2 +- .../backgrounds/background_advancement.png | Bin 0 -> 442 bytes 5 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/createnuclear/textures/gui/advancements/backgrounds/background_advancement.png diff --git a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 index 794d02fc..5390619f 100644 --- a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 +++ b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-21T16:18:31.9417877 Create Nuclear Advancements +// 1.20.1 2026-06-22T16:27:02.1133601 Create Nuclear Advancements 605607e2254e01df3e30839921ddd33635250d04 data/createnuclear/advancements/absolute_zero.json b6aa52d55ebb681fa0784c5419667c88a4b0e6db data/createnuclear/advancements/anti_radiation_armor.json fe81bbd052ebe4a70c48912b47e12ed4e4523d1d data/createnuclear/advancements/automatic_uranium.json @@ -31,7 +31,7 @@ f88401b0664256c3b2cb35c018f8f738b60bc3e9 data/createnuclear/advancements/reactor 6cf2ef6ff239288243f69d8763e01eadc1b3f343 data/createnuclear/advancements/reactor_liquid_input.json b19a554150aa4d9dee594574e310c436d7bfc66d data/createnuclear/advancements/reactor_output.json 91aab6f0a18aee167c63a3aece5fa9778cf52b0b data/createnuclear/advancements/reinforced_glass.json -a7b50865e9c0a441d749bf386f38e0a9dd69e5c8 data/createnuclear/advancements/root.json +734a40badf33a911d1e0adb9a2b18688d5cb5401 data/createnuclear/advancements/root.json 79e11acd6d9c16e92bf10d417251a9d6859399c3 data/createnuclear/advancements/silence_the_core.json a44ae76ec00fae36f7df13e43f20ebe389b416d5 data/createnuclear/advancements/steel_ingot.json 6db13694145ff3bbff4abfb58e857f404f0add73 data/createnuclear/advancements/t1.json diff --git a/src/generated/resources/data/createnuclear/advancements/root.json b/src/generated/resources/data/createnuclear/advancements/root.json index 25c8d91c..5bf58859 100644 --- a/src/generated/resources/data/createnuclear/advancements/root.json +++ b/src/generated/resources/data/createnuclear/advancements/root.json @@ -7,7 +7,7 @@ }, "display": { "announce_to_chat": false, - "background": "createnuclear:textures/block/steel_block.png", + "background": "createnuclear:textures/gui/advancements/backgrounds/background_advancement.png", "description": { "color": "#DBA213", "translate": "advancement.createnuclear.root.desc" diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index ebfb23f5..d2e87f60 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -210,7 +210,7 @@ public class CNBlocks { public static final BlockEntry REINFORCED_GLASS = CreateNuclear.REGISTRATE .block("reinforced_glass", ReinforcedGlassBlock::new) .initialProperties(() -> Blocks.GLASS) - .properties(p -> p.explosionResistance(7.0F).destroyTime(2F)) + .properties(p -> p.explosionResistance(1200.0F).destroyTime(2F)) .onRegister(CreateRegistrate.connectedTextures(() -> new EncasedCTBehaviour(CNSpriteShifts.REACTOR_GLASS))) .onRegister(casingConnectivity((block,cc) -> cc.makeCasing(block, CNSpriteShifts.REACTOR_GLASS))) .loot(RegistrateBlockLootTables::dropWhenSilkTouch) diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CreateNuclearAdvancement.java b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CreateNuclearAdvancement.java index 6643a481..83fcc72c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CreateNuclearAdvancement.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CreateNuclearAdvancement.java @@ -23,7 +23,7 @@ @SuppressWarnings("unused") public class CreateNuclearAdvancement { - static final ResourceLocation BACKGROUND = CreateNuclear.asResource("textures/block/steel_block.png"); + static final ResourceLocation BACKGROUND = CreateNuclear.asResource("textures/gui/advancements/backgrounds/background_advancement.png"); static final String LANG = "advancement." + CreateNuclear.MOD_ID + "."; static final String SECRET_SUFFIX = "\n\u00A77(Hidden Advancement)"; diff --git a/src/main/resources/assets/createnuclear/textures/gui/advancements/backgrounds/background_advancement.png b/src/main/resources/assets/createnuclear/textures/gui/advancements/backgrounds/background_advancement.png new file mode 100644 index 0000000000000000000000000000000000000000..d869a9823794e69944fdf8f28a527b96cb0b3c9f GIT binary patch literal 442 zcmV;r0Y(0aP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0Z&OpK~y+TT~f=o zgdhy#FA?OSqmH89|6lf=RKjpvR7z>nG}YvksG3z*>z zF#?bc8ReYBpb$l%9mY`;F-{CYlTgI&us0*KE=xlOt>ZWp(7B-{ru1~hsT!moE3@yr zc3wUo6?0h@xvr~eKw}f$$;e<{bORG;!MVrL{}lJ`iKoY(rl&jJ4ORh%^Jzk*hj>48 zFCy~|912CC9&q$t+%QNv4qZ2lP1+iX+FKtdeHFCE=o@^%fI_*-s27hu$DoJ`K!?QU_lQ_g+ZO8C0~4T+bDf5BqA=G40^yD~#>oag>JT^l kS^7ep{Xf8tjByOuKec8aNLN)$y#N3J07*qoM6N<$f~pg@D*ylh literal 0 HcmV?d00001 From 11b1108a11f842463c9271c095e0aeae179dd539 Mon Sep 17 00:00:00 2001 From: Dimitri Date: Mon, 22 Jun 2026 16:39:56 +0200 Subject: [PATCH 068/171] fix potential bug in the explosion exception catching part --- AUDIT_ACTUEL.md | 1 - .../explosion/NuclearExplosionEntity.java | 20 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f450b290..7a0f54da 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -24,7 +24,6 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi | Réf. | Fichier:ligne | Gravité | Détail (vérifié) | |---|---|---|---| -| **B15** | `content/explosion/NuclearExplosionEntity.java:224-228` | 🟠 | `try { state.onBlockExploded(...) } catch(Exception e){ level().destroyBlock(carve, true) }` — exception comme branchement de contrôle, avale les vrais bugs, sémantiques de drop différentes entre les deux branches. Trivial à corriger (vérification explicite), jamais fait. | | **isNotDanger tautologie** | `content/multiblock/IHeat.java:88-90` | 🟠 | `return of(heat,size) != DANGER \|\| of(heat,size) != NONE;` — toujours `true` (un `HeatLevel` ne peut être les deux). Appelant **confirmé `ReactorControllerBlockEntity.java:391`** (et non ~454 comme indiqué auparavant) : la garde « ne pas faire tourner les sorties en `DANGER` » est **inopérante**, les sorties tournent même en surchauffe. Correctif d'1 ligne (`!= DANGER` seul), à confirmer côté balance. | | **ReactorInputFluidManager — sur-extraction** | `ReactorInputFluidManager.java:146-151` | 🟠 | `fluidNeeded` **n'est jamais décrémenté** entre handlers dans la boucle d'extraction → chaque handler tente d'extraire le besoin complet (sur-extraction si plusieurs inputs). De plus `if (toExtract > 1)` **ignore les extractions de 1 unité**. ⚠️ L'off-by-one `getFluidInTank(getTanks())` est en revanche **corrigé** → `getFluidInTank(0)` (l.126, l.144). *(Tranche le désaccord entre les deux audits : `AUDIT_ACTUEL` avait raison sur l'off-by-one corrigé ; `AUDIT_INDEPENDANT` se trompait en le disant encore présent.)* Toléré aujourd'hui car `SmartFluidTank` est mono-tank, mais reste une violation de contrat `IFluidHandler` qui deviendra active au premier tank multi-slot. | | **InventoryHashUtil — resync durabilité** | `InventoryHashUtil` | 🟡 | Toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité d'un item. | diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java index 6d98a1f6..c6ea3416 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java @@ -210,21 +210,25 @@ private void removeChunk(int radius) { carveBelow.set(carve.getX(), carve.getY() - 1, carve.getZ()); canSetToFire = true; - // GESTION SPAWN MOBS / compat Alex's Caves + // ALEX'S CAVES compatibility handling boolean handledByAlex = false; if (Mods.ALEXS_CAVE.isLoaded() && alexscaveHandler != null){ handledByAlex = ((AlexscaveCompat) alexscaveHandler).MobSpawn(state, level(), carve, itemDropModifier, dummyExplosion); } - // Si Alex a géré (oeuf éclot), on skip if (handledByAlex) continue; - // Nouveau : destruction standard quand Alex's Caves n'est pas présent - // On essaye d'abord d'appeler le comportement d'explosion du block, sinon fallback sur destroyBlock - try { - state.onBlockExploded(level(), carve, dummyExplosion); - } catch (Exception e) { - level().destroyBlock(carve, true); + // 1. Create an immutable copy of the position + BlockPos immutablePos = carve.immutable(); + + // 2. Call the explosion behavior + state.onBlockExploded(level(), immutablePos, dummyExplosion); + + // 3. FIX: If the block is still there (vanilla blocks like Stone/Dirt), force removal + if (level().getBlockState(immutablePos).is(state.getBlock())) { + // false = do not drop standard mining items, let the explosion logic handle drops if needed + // or set to true if you want items to drop like before + level().destroyBlock(immutablePos, true); } } } From 87451431a60c292bbc77c44deef60e462b3456a7 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 22 Jun 2026 20:12:37 +0200 Subject: [PATCH 069/171] feat: chain reactor-part advancements into a linear build sequence Previously most reactor multiblock-part advancements (cooler, frame, liquid input, output) all pointed directly at reactor_casing, so they unlocked in any order. Re-chain them into the actual build order: reactor_core -> reactor_cooler -> reactor_frame, and reactor_input -> reactor_liquid_input -> reactor_output. Also make cryogenic_baptism a hidden/goal-framed secret advancement (instead of an always-visible task) and remove the now-redundant first_thorium and first_nitrate advancements, since raw_thorium/chemistry_101 already cover those triggers earlier in the tree. Fix ReactorPattern.findController(...) to call ReactorAssembler.assemble(newBlock, level) when it locates the controller, so the structure is (re-)assembled as part of the search instead of only being checked for range. Regenerate the corresponding advancement/lang datagen JSONs to match. --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +-- .../abc32a97b4e744838610c53dbbbaaf9f7d29a557 | 14 +++-- .../assets/createnuclear/lang/en_ud.json | 6 +-- .../assets/createnuclear/lang/en_us.json | 6 +-- .../advancements/cryogenic_baptism.json | 6 +-- .../advancements/first_nitrate.json | 39 -------------- .../advancements/first_thorium.json | 39 -------------- .../advancements/reactor_cooler.json | 2 +- .../advancements/reactor_frame.json | 2 +- .../advancements/reactor_liquid_input.json | 2 +- .../advancements/reactor_output.json | 2 +- .../multiblock/pattern/ReactorPattern.java | 1 + .../foundation/advancement/CNAdvancement.java | 52 ++++++++----------- 13 files changed, 40 insertions(+), 137 deletions(-) delete mode 100644 src/generated/resources/data/createnuclear/advancements/first_nitrate.json delete mode 100644 src/generated/resources/data/createnuclear/advancements/first_thorium.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index b08948a2..8353a659 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-22T14:19:43.5352126 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-22T19:57:09.3633092 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -dd5e0621e9cff50676e24afb7d2e3413da6ddda5 assets/createnuclear/lang/en_ud.json -b30fbb26f774c04e65ed5a4f37f1fdc5b4a6b271 assets/createnuclear/lang/en_us.json +eebc6410ccfd3db94f243835ec8dca003fff1932 assets/createnuclear/lang/en_ud.json +2375a0eeb9d2056358e3630ee7aece46a1836b12 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 index 5390619f..411d2de5 100644 --- a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 +++ b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-22T16:27:02.1133601 Create Nuclear Advancements +// 1.20.1 2026-06-22T19:57:09.3552703 Create Nuclear Advancements 605607e2254e01df3e30839921ddd33635250d04 data/createnuclear/advancements/absolute_zero.json b6aa52d55ebb681fa0784c5419667c88a4b0e6db data/createnuclear/advancements/anti_radiation_armor.json fe81bbd052ebe4a70c48912b47e12ed4e4523d1d data/createnuclear/advancements/automatic_uranium.json @@ -8,11 +8,9 @@ fe81bbd052ebe4a70c48912b47e12ed4e4523d1d data/createnuclear/advancements/automat 2e8127a4546d680ab502c6e3c71f49d8df2b1b18 data/createnuclear/advancements/coal_dust.json a0d591c0cfa26fbd3ea83da54cdd9f900d58926c data/createnuclear/advancements/craft_enriching_campfire.json 826cf04c3b3768dd1a5834ce24dc4301435fed75 data/createnuclear/advancements/crunchy_uranium.json -c38eb7205068a048d614ce503305430b036bc756 data/createnuclear/advancements/cryogenic_baptism.json +f85ce01405f65f942bbc2960442677ef5a3863d9 data/createnuclear/advancements/cryogenic_baptism.json efcd55929d60b9925ac4833ad1171ddb81dd47a0 data/createnuclear/advancements/dye_anti_radiation_armor.json eda669191bc6149e3feee4a2b9b25b64e1d7da60 data/createnuclear/advancements/enriched_yellowcake.json -f22c294470c3f9d49ff0c61bb73d844758026cd5 data/createnuclear/advancements/first_nitrate.json -b4f188861589d34efa3a3b8eaba23a21a7b0905d data/createnuclear/advancements/first_thorium.json 68d2b2361f527a1d9fbe48da95f3f313654c6761 data/createnuclear/advancements/getting_concentrated.json bffbc5007ddb20829768a122cc514f84c2dee1e0 data/createnuclear/advancements/graphene.json 8e89393b2e396243d12cf5b29e283ab97c814519 data/createnuclear/advancements/graphite_rod.json @@ -24,12 +22,12 @@ e9f9668d36ebd431502b20296f774c83a1d050f0 data/createnuclear/advancements/raw_lea e9d8bd7f04cac0f3ea72a02a5cdc4cc98f728d98 data/createnuclear/advancements/reactor_blueprint.json 46f6044ed5c777f9fe08f7957c3d26e39d69f3c5 data/createnuclear/advancements/reactor_casing.json bf6947708102180f9cd08e31305253774187d763 data/createnuclear/advancements/reactor_controller.json -842add59177cc7aec1b55102ec0495a522ced05c data/createnuclear/advancements/reactor_cooler.json +74363604b80b4a402fb582711f5967b9f68051e1 data/createnuclear/advancements/reactor_cooler.json f88401b0664256c3b2cb35c018f8f738b60bc3e9 data/createnuclear/advancements/reactor_core.json -07047ca35a1e75dfe3f7885ad8b5a63ce53e1b34 data/createnuclear/advancements/reactor_frame.json +eb2975b0ff5956717aa1737794258d4ed7d7528f data/createnuclear/advancements/reactor_frame.json 4f963ff2f6c09a0272c25ebdb46423700e5256eb data/createnuclear/advancements/reactor_input.json -6cf2ef6ff239288243f69d8763e01eadc1b3f343 data/createnuclear/advancements/reactor_liquid_input.json -b19a554150aa4d9dee594574e310c436d7bfc66d data/createnuclear/advancements/reactor_output.json +e8d320e7680173b5d7d320672fca004ffc45c6d3 data/createnuclear/advancements/reactor_liquid_input.json +e045547fcf9e7f98141755ebed8b1466c8122161 data/createnuclear/advancements/reactor_output.json 91aab6f0a18aee167c63a3aece5fa9778cf52b0b data/createnuclear/advancements/reinforced_glass.json 734a40badf33a911d1e0adb9a2b18688d5cb5401 data/createnuclear/advancements/root.json 79e11acd6d9c16e92bf10d417251a9d6859399c3 data/createnuclear/advancements/silence_the_core.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index c00e7d4d..1eff9b32 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -18,15 +18,11 @@ "advancement.createnuclear.crunchy_uranium": "ʇɔǝdxƎ noʎ pıᗡ ʇɐɥM", "advancement.createnuclear.crunchy_uranium.desc": ")ʇuǝɯǝɔuɐʌpⱯ uǝppıH(ㄥ§\n¿¿ ʇɐɥʍ pıp noʎ ˙˙˙˙˙oɹᗺ", "advancement.createnuclear.cryogenic_baptism": "ǝɹoɯʎuɐ ʇǝǝɟ ʎɯ ןǝǝɟ ʇ,uɐɔ I", - "advancement.createnuclear.cryogenic_baptism.desc": "ǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ uǝboɹʇıu pınbıן ǝɥʇ uı ɯıʍS", + "advancement.createnuclear.cryogenic_baptism.desc": ")ʇuǝɯǝɔuɐʌpⱯ uǝppıH(ㄥ§\nǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ uǝboɹʇıu pınbıן ǝɥʇ uı ɯıʍS", "advancement.createnuclear.dye_anti_radiation_armor": "ɹoɯɹⱯ ʎW dɯıԀ", "advancement.createnuclear.dye_anti_radiation_armor.desc": "ɹoןoɔ ʎuɐ oʇ ɹoɯɹɐ uoıʇɐıpɐɹ ıʇuɐ ɹnoʎ ǝʎᗡ", "advancement.createnuclear.enriched_yellowcake": "ǝʞɐɔʍoןןǝʎ buıɔuɐɥuƎ", "advancement.createnuclear.enriched_yellowcake.desc": "ןnɟɹǝʍod ǝɹoɯ ʇı ǝʞɐɯ puɐ ǝʞɐɔʍoןןǝʎ ɥɔıɹuǝ oʇ uɐɟ ɐ ǝs∩", - "advancement.createnuclear.first_nitrate": "ǝʇɐɹʇıN ʇsɹıℲ", - "advancement.createnuclear.first_nitrate.desc": "ǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ ǝʇɐɹʇıN doɹᗡ", - "advancement.createnuclear.first_thorium": "ɯnıɹoɥ⟘ ʇsɹıℲ", - "advancement.createnuclear.first_thorium.desc": "ǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ ɯnıɹoɥʇ ʍɐɹ ɐ doɹᗡ", "advancement.createnuclear.getting_concentrated": "pǝʇɐɹʇuǝɔuoƆ buıʇʇǝ⅁", "advancement.createnuclear.getting_concentrated.desc": "ǝʇɐɹʇuǝɔuoɔ uǝboɹʇıu uıɐʇqo oʇ ǝɔɐuɹnɟ ʇsɐןq ɐ uı ǝʇɐɹʇıu ʇןǝɯS", "advancement.createnuclear.graphene": "ǝuǝɥdɐɹ⅁", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index f870e342..d2ceff90 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -18,15 +18,11 @@ "advancement.createnuclear.crunchy_uranium": "What Did You Expect", "advancement.createnuclear.crunchy_uranium.desc": "Bro..... you did what ??\n§7(Hidden Advancement)", "advancement.createnuclear.cryogenic_baptism": "I can't feel my feet anymore", - "advancement.createnuclear.cryogenic_baptism.desc": "Swim in the liquid nitrogen for the first time", + "advancement.createnuclear.cryogenic_baptism.desc": "Swim in the liquid nitrogen for the first time\n§7(Hidden Advancement)", "advancement.createnuclear.dye_anti_radiation_armor": "Pimp My Armor", "advancement.createnuclear.dye_anti_radiation_armor.desc": "Dye your anti radiation armor to any color", "advancement.createnuclear.enriched_yellowcake": "Enhancing Yellowcake", "advancement.createnuclear.enriched_yellowcake.desc": "Use a fan to enrich yellowcake and make it more powerful", - "advancement.createnuclear.first_nitrate": "First Nitrate", - "advancement.createnuclear.first_nitrate.desc": "Drop Nitrate for the first time", - "advancement.createnuclear.first_thorium": "First Thorium", - "advancement.createnuclear.first_thorium.desc": "Drop a raw thorium for the first time", "advancement.createnuclear.getting_concentrated": "Getting Concentrated", "advancement.createnuclear.getting_concentrated.desc": "Smelt nitrate in a blast furnace to obtain nitrogen concentrate", "advancement.createnuclear.graphene": "Graphene", diff --git a/src/generated/resources/data/createnuclear/advancements/cryogenic_baptism.json b/src/generated/resources/data/createnuclear/advancements/cryogenic_baptism.json index 75b74fd5..80219e67 100644 --- a/src/generated/resources/data/createnuclear/advancements/cryogenic_baptism.json +++ b/src/generated/resources/data/createnuclear/advancements/cryogenic_baptism.json @@ -7,13 +7,13 @@ } }, "display": { - "announce_to_chat": false, + "announce_to_chat": true, "description": { "color": "#DBA213", "translate": "advancement.createnuclear.cryogenic_baptism.desc" }, - "frame": "task", - "hidden": false, + "frame": "goal", + "hidden": true, "icon": { "item": "createnuclear:nitrogen_bucket" }, diff --git a/src/generated/resources/data/createnuclear/advancements/first_nitrate.json b/src/generated/resources/data/createnuclear/advancements/first_nitrate.json deleted file mode 100644 index 0c046338..00000000 --- a/src/generated/resources/data/createnuclear/advancements/first_nitrate.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "parent": "createnuclear:root", - "criteria": { - "0": { - "conditions": { - "items": [ - { - "items": [ - "createnuclear:nitrate" - ] - } - ] - }, - "trigger": "minecraft:inventory_changed" - } - }, - "display": { - "announce_to_chat": false, - "description": { - "color": "#DBA213", - "translate": "advancement.createnuclear.first_nitrate.desc" - }, - "frame": "task", - "hidden": false, - "icon": { - "item": "createnuclear:nitrate" - }, - "show_toast": true, - "title": { - "translate": "advancement.createnuclear.first_nitrate" - } - }, - "requirements": [ - [ - "0" - ] - ], - "sends_telemetry_event": true -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/advancements/first_thorium.json b/src/generated/resources/data/createnuclear/advancements/first_thorium.json deleted file mode 100644 index 8680354a..00000000 --- a/src/generated/resources/data/createnuclear/advancements/first_thorium.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "parent": "createnuclear:root", - "criteria": { - "0": { - "conditions": { - "items": [ - { - "items": [ - "createnuclear:raw_thorium" - ] - } - ] - }, - "trigger": "minecraft:inventory_changed" - } - }, - "display": { - "announce_to_chat": false, - "description": { - "color": "#DBA213", - "translate": "advancement.createnuclear.first_thorium.desc" - }, - "frame": "task", - "hidden": false, - "icon": { - "item": "createnuclear:raw_thorium" - }, - "show_toast": true, - "title": { - "translate": "advancement.createnuclear.first_thorium" - } - }, - "requirements": [ - [ - "0" - ] - ], - "sends_telemetry_event": true -} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_cooler.json b/src/generated/resources/data/createnuclear/advancements/reactor_cooler.json index c5234f2a..64513899 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_cooler.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_cooler.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_casing", + "parent": "createnuclear:reactor_core", "criteria": { "0": { "conditions": { diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_frame.json b/src/generated/resources/data/createnuclear/advancements/reactor_frame.json index 133a61b9..36c137e8 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_frame.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_frame.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_casing", + "parent": "createnuclear:reactor_cooler", "criteria": { "0": { "conditions": { diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json b/src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json index ef11058b..a2ae7ed4 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_casing", + "parent": "createnuclear:reactor_input", "criteria": { "0": { "conditions": { diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_output.json b/src/generated/resources/data/createnuclear/advancements/reactor_output.json index 54b8e4b8..651c4a18 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_output.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_output.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_casing", + "parent": "createnuclear:reactor_liquid_input", "criteria": { "0": { "conditions": { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java index 08654013..4b5f949b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java @@ -59,6 +59,7 @@ public BlockPos findControllerPos(BlockPos blockPos, Level level){ newBlock = new BlockPos(x, y, z); if (level.getBlockState(newBlock).is(CNBlocks.REACTOR_CONTROLLER.get())) { if (level.getBlockEntity(newBlock) instanceof ReactorControllerBlockEntity entity) { + ReactorAssembler.assemble(newBlock, level); if (isInReactorRange(entity.getMultiblockPos(), blockPos)) { return newBlock; } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java index 161ea81c..bcaeb5e1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java @@ -65,20 +65,6 @@ public class CNAdvancement implements DataProvider { .after(ROOT) ), - FIRST_THORIUM = create("first_thorium", b -> b.icon(CNItems.RAW_THORIUM.asItem()) - .title("First Thorium") - .description("Drop a raw thorium for the first time") - .whenIconCollected() - .after(ROOT) - ), - - FIRST_NITRATE = create("first_nitrate", b -> b.icon(CNItems.NITRATE.asItem()) - .title("First Nitrate") - .description("Drop Nitrate for the first time") - .whenIconCollected() - .after(ROOT) - ), - RAW_URANIUM = create("raw_uranium", b -> b.icon(CNItems.RAW_URANIUM) .title("The Raw Power") .description("Mine uranium ore to obtain raw uranium for further processing") @@ -203,6 +189,7 @@ public class CNAdvancement implements DataProvider { .title("I can't feel my feet anymore") .description("Swim in the liquid nitrogen for the first time") .after(ABSOLUTE_ZERO) + .special(SECRET) ), COAL_DUST = create("coal_dust", b -> b.icon(CNItems.COAL_DUST) @@ -330,20 +317,6 @@ public class CNAdvancement implements DataProvider { .whenIconCollected() ), - REACTOR_COOLER = create("reactor_cooler", b -> b.icon(CNBlocks.REACTOR_COOLER) - .title("Cooling The Reactor") - .description("Craft a reactor cooler to cool your reactor") - .after(REACTOR_CASING) - .whenIconCollected() - ), - - REACTOR_FRAME = create("reactor_frame", b -> b.icon(CNBlocks.REACTOR_FRAME) - .title("Reactor Frame") - .description("Craft a reactor frame to build your nuclear reactor") - .after(REACTOR_CASING) - .whenIconCollected() - ), - REACTOR_INPUT = create("reactor_input", b -> b.icon(CNBlocks.REACTOR_INPUT) .title("Fueling The Reactor") .description("Craft a reactor input to feed uranium and graphite rods into your reactor") @@ -354,22 +327,39 @@ public class CNAdvancement implements DataProvider { REACTOR_LIQUID_INPUT = create("reactor_liquid_input", b -> b.icon(CNBlocks.REACTOR_LIQUID_INPUT) .title("Liquid Fuel") .description("Craft a reactor liquid input to feed liquid coolant into your reactor") - .after(REACTOR_CASING) + .after(REACTOR_INPUT) .whenIconCollected() ), REACTOR_OUTPUT = create("reactor_output", b -> b.icon(CNBlocks.REACTOR_OUTPUT) .title("Power Output") .description("Craft a reactor output to transfer the energy produced by your reactor") - .after(REACTOR_CASING) + .after(REACTOR_LIQUID_INPUT) .whenIconCollected() ), + REACTOR_CORE = create("reactor_core", b -> b.icon(CNBlocks.REACTOR_CORE) .title("Core Of Power") .description("Craft the reactor core to harness the full energy of your nuclear reactor") .after(REACTOR_CASING) .whenIconCollected() - ); + ), + + REACTOR_COOLER = create("reactor_cooler", b -> b.icon(CNBlocks.REACTOR_COOLER) + .title("Cooling The Reactor") + .description("Craft a reactor cooler to cool your reactor") + .after(REACTOR_CORE) + .whenIconCollected() + ), + + REACTOR_FRAME = create("reactor_frame", b -> b.icon(CNBlocks.REACTOR_FRAME) + .title("Reactor Frame") + .description("Craft a reactor frame to build your nuclear reactor") + .after(REACTOR_COOLER) + .whenIconCollected() + ) + + ; private final PackOutput output; From 57c47869f536bea204d4336680fa4c7e228d5702 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 22 Jun 2026 20:13:13 +0200 Subject: [PATCH 070/171] chore: bump mod version to 2.0.9-alpha --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a1bd3117..48925c77 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.8 +mod_version=2.0.9-alpha # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html From 49467b82998347cef2253ac9c780de1434511113 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:07:59 +0200 Subject: [PATCH 071/171] fix: resolve radiation issues by consolidating eligibility checks and improving performance --- AUDIT_ACTUEL.md | 126 ++++++------------ .../content/radiation/RadiationEffect.java | 31 +---- .../radiation/RadiationEffectHandler.java | 2 + .../capability/RadiationCapability.java | 39 +++++- .../capability/RadiationProvider.java | 7 + .../radiation/client/RadiationOverlay.java | 61 --------- .../foundation/events/HudRenderer.java | 1 - .../events/overlay/EasingHudOverlay.java | 41 ------ .../events/overlay/HelmetOverlay.java | 5 - 9 files changed, 88 insertions(+), 225 deletions(-) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EasingHudOverlay.java diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 7a0f54da..90fde951 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -2,7 +2,9 @@ **Dernière fusion : 2026-06-22.** Ce document fusionne `AUDIT_ACTUEL.md` (7 audits croisés sur `src/main/java`) et `AUDIT_INDEPENDANT.md` (relecture indépendante du 2026-06-20). Chaque point litigieux entre les deux a été **revérifié directement dans le code** (lecture de fichier + grep des appelants) avant classement. Les divergences entre les deux audits sont tranchées et annotées ci-dessous. -> Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §7 pour mémoire, puis ne sont plus repris. +> **Mise à jour 2026-06-23** : tous les problèmes radiation (ancienne §2) ont été corrigés et déplacés en §6 « pour mémoire ». Les sections et les points ont été renumérotés en conséquence. + +> Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §6 pour mémoire, puis ne sont plus repris. **Périmètre** : `src/main/java` (286 fichiers, ~24 600 lignes), hors `src/generated` et `src/main/resources`. Recoupé avec l'historique Git. @@ -12,9 +14,9 @@ ## 0. Constat global -Le **chantier architectural n°1 des audits précédents — la décomposition de `ReactorControllerBlockEntity` — est désormais réellement effectif** (commits `dd918582`, `6e717c44`, `8611ed76`, `56373bf7`, `39092ca3`). La classe fait **492 lignes** et délègue à `service/` (8 fichiers), `manager/` (5 fichiers), `consumable/` (6 fichiers), `display/` (2 fichiers). Ce qui reste est de la **coordination de multiblock** (positions I/O, état de pattern, délégation de verrou), plus un hub god-class. **Ce chantier est considéré comme clos** (voir §4). +Le **chantier architectural n°1 des audits précédents — la décomposition de `ReactorControllerBlockEntity` — est désormais réellement effectif** (commits `dd918582`, `6e717c44`, `8611ed76`, `56373bf7`, `39092ca3`). La classe fait **492 lignes** et délègue à `service/` (8 fichiers), `manager/` (5 fichiers), `consumable/` (6 fichiers), `display/` (2 fichiers). Ce qui reste est de la **coordination de multiblock** (positions I/O, état de pattern, délégation de verrou), plus un hub god-class. **Ce chantier est considéré comme clos** (voir §3). -En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans re-vérification, sont **fausses sur le code actuel** : l'« inversion de dépendance `api/` » et les « frameworks multiblock concurrents » (voir §4). À l'inverse, des bugs simples et jamais mis en doute (`B15`, tautologie `isNotDanger`) restent présents — signe que le nettoyage a suivi les zones très signalées (radiation, dead code, controller) plutôt qu'une revue ligne à ligne. +En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans re-vérification, sont **fausses sur le code actuel** : l'« inversion de dépendance `api/` » et les « frameworks multiblock concurrents » (voir §3). À l'inverse, des bugs simples et jamais mis en doute (`B15`, tautologie `isNotDanger`) restent présents — signe que le nettoyage a suivi les zones très signalées (radiation, dead code, controller) plutôt qu'une revue ligne à ligne. La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vide) sur une logique métier non triviale (chaleur, pattern matching, verrouillage fluide) — précisément les zones où des bugs silencieux survivent à plusieurs passes d'audit. @@ -30,61 +32,11 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi --- -## 2. 🆕 Problèmes radiation (revérifiés en détail) - -La feature radiation reste **éparpillée sur plusieurs mécanismes** (`RadiationCapability`, `RadiationEffect`, `RadiationEffectHandler`, overlays). « Consolider en un module » est trop large pour être actionnable ; les points concrets ci-dessous le sont. - -### 🔴 Critique - -1. **`RadiationEffectHandler.apply` — 3ᵉ chemin d'application, sans aucune garde** *(confirmé `RadiationEffectHandler.java:14-22`)* - ```java - public void apply(Level level, AABB area, FluidStack fluid) { - if (level.getGameTime() % 5 != 0) return; - List entities = level.getEntitiesOfClass(LivingEntity.class, area, LivingEntity::isAffectedByPotions); - for (LivingEntity entity : entities) { - entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 3, 2, false, false, false)); - } - } - ``` - Applique la radiation (fuite de tuyau) à **toute** entité, **sans** vérifier : `enabledItemRadiation`, tag `IRRADIATED_IMMUNE`, spectateur, résistance anti-radiation. C'est un chemin indépendant des deux autres, qui eux respectent ces gardes. - *Conséquence* : une fuite irradie un joueur en armure anti-radiation complète, ou un mob immunisé, même avec `enabledItemRadiation=false`. - *Recommandation* : extraire **uniquement le gate binaire** (immune / config / spectateur / blacklist / `résistance ≥ 1`) dans un helper `RadiationCapability.canBeIrradiated(LivingEntity)`, réutilisé ici **et** comme `filter` de `RadiationEffect`. Ne **pas** y déplacer l'atténuation continue de `RadiationCapability.applyEffects` (sémantique différente : magnitude, pas éligibilité). La blacklist doit être **mise en cache statique** (cf. point 2). Squelette : - ```java - public static boolean canBeIrradiated(LivingEntity e) { - if (e.isSpectator()) return false; - if (e.getType().is(CNTags.CNEntityTags.IRRADIATED_IMMUNE.tag)) return false; - if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return false; - if (getEntityBlacklist().contains(e.getType())) return false; - return getRadiationResistance(e) < 1.0; - } - ``` - - -### 🟠 Importants - -2. **`RadiationEffect` — `HashSet` + reparse `ResourceLocation` reconstruits à chaque entité/tick** *(confirmé `RadiationEffect.java:38-43`, override `isDurationEffectTick → true` l.79)* - Le filtre du `VicinityEffect` reconstruit `new HashSet<>()` et reparse les `ResourceLocation` de la blacklist **à chaque évaluation** (par entité proche de tout joueur irradié, à chaque tick puisque `isDurationEffectTick()` est forcé à `true`). Vrai point de perf, pas de style. - *Recommandation* : cache statique de la blacklist, invalidé au reload config/datapack — la même `canBeIrradiated` du point 1 le porte. - -3. **`RadiationCapability.applyEffects` — pas de garde spectateur** *(confirmé `RadiationCapability.java:97`)* - L'atténuation continue `double totalRadiation = totalRaw * (1.0 - resistance)` est correcte et propre à ce chemin (à **conserver** telle quelle). Mais la méthode **ne vérifie pas le spectateur**. Aucun helper `canBeIrradiated` n'existe encore (gate inline `RadiationCapability.java:93`). Ajouter a minima `if (player.isSpectator()) return;`. - -4. **`RadiationCapability.lastBiomeLocation` — lu mais non persisté** *(confirmé)* - `lastBiomeLocation` **est lu pour une décision** (`RadiationCapability.java:87-91`, `!Objects.equals(biomeLoc, cap.getLastBiomeLocation())`) — ce n'est **pas** du dead code. Mais `RadiationProvider.serializeNBT` (l.24-28) ne persiste que `radiation` et `hash` → `lastBiomeLocation` est `null` après save/reload. Bug mineur, à corriger ou assumer. - -5. **Deux overlays de « vision irradiée » concurrents** *(tous deux confirmés)* - - `IrradiatedOverlayRendererVision` (**actif**, fade lisse `±0.01f`/tick, garde spectateur) et `RadiationOverlay` (**commenté** dans `HudRenderer.java:13`) sont deux implémentations du même effet. - - `HelmetOverlay.setCoverage(...)` (`HelmetOverlay.java:69`) écrit dans le champ statique `RadiationOverlay.coverage` que **personne ne lit** (RadiationOverlay non rendu) — no-op silencieux. - - `RadiationOverlay.java:49` : `RenderHelper.renderTextureOverlay(graphics, RADIATION_TEXTURE, Math.round(alpha * coverage))` — `Math.round` retourne un `int` (0 ou 1) passé au paramètre `float alpha ∈ [0,1]` → fade **binarisé**. Sans impact visible **aujourd'hui** (overlay non rendu), mais bug réel si réactivé. - - *Décision produit* : supprimer `RadiationOverlay`/`EasingHudOverlay` + le `setCoverage` no-op (si `IrradiatedOverlayRendererVision` suffit), **ou** réactiver et corriger le `Math.round`. - ---- - -## 3. 🆕 Autres problèmes (hors radiation) +## 2. 🆕 Autres problèmes (hors radiation) ### 🔴 Critique — performance/correction du scan multiblock -6. **Scan géométrique du contrôleur : aucune garde client + double appel sur un même événement** *(tous confirmés)* +1. **Scan géométrique du contrôleur : aucune garde client + double appel sur un même événement** *(tous confirmés)* - `ReactorPattern.findController`/`findControllerPos` (`ReactorPattern.java:34-71`) scannent ~3 971 blocs (11×19×19, `new BlockPos` par itération, borne `!=`) avec **aucune garde `level.isClientSide()`** nulle part dans la chaîne `onPlace/onRemove/playerDestroy → findController → ReactorAssembler.assemble/disassemble`. Or `assemble`/`disassemble` **mutent l'état de la BlockEntity** (`setAssembled`, `setMultiblockSize`, `removeIOAll`) et envoient un message joueur → mutation métier potentiellement **exécutée deux fois** (client + serveur) à chaque pose/casse autour d'un réacteur. - **Double appel à la casse** : `ReactorCasing.java` appelle `findController` dans **`playerDestroy` (l.60) ET `onRemove` (l.66)** pour le même événement → deux scans complets. Idem `ReactorCooler.java` (l.39 + l.45). ⚠️ `ReactorFrame.java` est en revanche **plus malin** : son `onRemove` garde `if (!state.is(newState.getBlock()))` (l.128-135) — modèle à généraliser. - **Spam de log** : `ReactorAssembler.assemble` logue en `LOGGER.warn` (`ReactorAssembler.java:37-38`) à **chaque** réussite de pattern → spam en conditions normales de jeu. @@ -92,43 +44,43 @@ La feature radiation reste **éparpillée sur plusieurs mécanismes** (`Radiatio ### 🟠 Importants -7. **`DefaultHeatCalculator.computeHeat` — coût ~O(n²) avec désérialisation NBT répétée + asymétrie fuel/cooler** *(confirmé `DefaultHeatCalculator.java:35-75`)* +2. **`DefaultHeatCalculator.computeHeat` — coût ~O(n²) avec désérialisation NBT répétée + asymétrie fuel/cooler** *(confirmé `DefaultHeatCalculator.java:35-75`)* Pour chaque item du pattern, boucle sur la grille pour localiser sa position, puis pour chaque voisin **re-boucle sur la totalité des items** (l.59) pour retrouver le voisin par slot — chaque itération désérialise un `ItemStack.of(...)` depuis NBT sans cache (l.36, l.62). Coût pire cas ~57×81×4×57 ≈ 1 050 000 itérations/tick sur réacteur plein. Non couvert par les audits historiques (`reactorLogic/`). - **Asymétrie** (l.61) : le calcul de proximité ne fire que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. De plus `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.67, **division**) côté fuel→voisin vs additions ailleurs. - *Recommandation* : remplacer la boucle de recherche du voisin (l.59) par une `Map` construite une fois par appel → O(n) au lieu de O(n²), **sans changer le comportement**. **Ne pas toucher** à l'asymétrie/division sans confirmation balance (la logique de chaleur a des distinctions intentionnelles entre chemins — ne pas unifier sans vérification). -8. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** +3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` et `components.get(2).get(1)` accède positionnellement à la ligne « fuel ». Tout ajout/réordonnancement de ligne casse silencieusement ces contrats implicites. -9. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** +4. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** En mode « normal » (0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle pour un même mode utilisateur. ### 🟡 Mineurs -10. **`CreateNuclearJEI`** — champ statique mutable `Categories` (nom non conventionnel), vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). -11. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture ponder). -12. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. -13. **`NuclearExplosionEntity.tick()` (`:96`)** — tri d'une pile de `BlockPos` par `distManhattan` en un tick. ⚠️ La taille réelle est `(2·chunksAffected+1)³` (≈125 pour `size=2`), **pas** 1331 comme indiqué auparavant — coût modeste, corrigé ici. +5. **`CreateNuclearJEI`** — champ statique mutable `Categories` (nom non conventionnel), vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). +6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture ponder). +7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +8. **`NuclearExplosionEntity.tick()` (`:96`)** — tri d'une pile de `BlockPos` par `distManhattan` en un tick. ⚠️ La taille réelle est `(2·chunksAffected+1)³` (≈125 pour `size=2`), **pas** 1331 comme indiqué auparavant — coût modeste, corrigé ici. --- -## 4. 🏗️ Architecture — état réévalué (sans objectif imposé) +## 3. 🏗️ Architecture — état réévalué (sans objectif imposé) > Plusieurs « problèmes structurels » des audits V1/ACTUEL sont **réfutés par le code actuel**. On ne raisonne pas par règle automatique (« classe > N lignes → découper »). | Affirmation historique | Verdict actuel | |---|---| | **Inversion `api/`** (`MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` importeraient `content.*`) | ❌ **Réfuté** — aucun des trois n'importe `content.*` ; ils utilisent leurs propres types `*Value` (api). Aucune action. | -| **Deux/trois frameworks multiblock concurrents** | ❌ **Réfuté** — `lib.multiblock.manager.*` et `IBetterPattern` **n'existent plus**. Le reste de `lib/multiblock` est **activement utilisé** par `CNMultiblock`. Ce n'est pas une couche concurrente mais un **pipeline séquentiel** : scan géométrique → `ReactorAssembler` → `CNMultiblock.findStructure` → données `RodType`/`ReactorFluidType`. Le vrai problème n'est pas la coexistence mais la **garde d'exécution de la 1ʳᵉ étape** (§3 point 6). Ne pas fusionner (gros risque, gain incertain). | +| **Deux/trois frameworks multiblock concurrents** | ❌ **Réfuté** — `lib.multiblock.manager.*` et `IBetterPattern` **n'existent plus**. Le reste de `lib/multiblock` est **activement utilisé** par `CNMultiblock`. Ce n'est pas une couche concurrente mais un **pipeline séquentiel** : scan géométrique → `ReactorAssembler` → `CNMultiblock.findStructure` → données `RodType`/`ReactorFluidType`. Le vrai problème n'est pas la coexistence mais la **garde d'exécution de la 1ʳᵉ étape** (§2 point 1). Ne pas fusionner (gros risque, gain incertain). | | **God class `ReactorControllerBlockEntity`, cible <300 lignes** | ✅ **Chantier clos** — 492 lignes, délégation réelle (service/manager/consumable/display). Ce qui reste est la coordination légitime d'un multiblock. **Continuer à viser <300 lignes serait une erreur** : il n'y a plus de logique métier à extraire, seulement de la coordination — découper ajouterait de l'indirection. | | **Coordinateur de verrou fluide `ReactorFluidLockCoordinator`** | ✅ **Non justifié** (les deux audits convergent) — `tryLockFluid`/`canAcceptFluid`/`clearLock` sont de simples délégations 3-7 lignes vers `PersistentFluidLocks` (le double-système `FluidLockManager` a été supprimé, B14 résolu). `clearLockIfAllInputsEmpty` n'a plus de scan 3D (utilise `inputFluidManager.getFuildHandlers(level)`). Ne plus y revenir. | -| **`run/` à `.gitignore`** | ✅ Règles `run/*` présentes — mais résidu de fichiers déjà trackés (voir §5). | +| **`run/` à `.gitignore`** | ✅ Règles `run/*` présentes — mais résidu de fichiers déjà trackés (voir §4). | **Vrai writ-large structurel : l'absence de tests.** Ni la taille des classes ni le nombre de packages radiation ne limitent autant la maintenabilité que l'absence totale de couverture sur la chaleur, le pattern matching et le verrouillage fluide — exactement là où les bugs silencieux (sur-extraction fluide, asymétrie `DefaultHeatCalculator`, tautologie `IHeat`) survivent à plusieurs audits. --- -## 5. 🧹 Dead code & features inachevées — reste à faire +## 4. 🧹 Dead code & features inachevées — reste à faire > **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (utilisé par `CNAdvancedModelBox` sur le chemin de rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé ~10× par `NuclearMushroomCloudModel`). @@ -158,52 +110,54 @@ La feature radiation reste **éparpillée sur plusieurs mécanismes** (`Radiatio --- -## 6. ⚡ Performance — synthèse des points ouverts +## 5. ⚡ Performance — synthèse des points ouverts | Point | État | Réf. | |---|---|---| -| `ReactorPattern.findController/findControllerPos` : ~3 971 blocs ×2 par casse, **sans garde client**, mutation d'état métier potentiellement double | ❌ non corrigé — **priorité n°1** | §3.6 | -| `DefaultHeatCalculator.computeHeat` : ~O(n²) + désérialisation NBT par cellule, à chaque tick | ❌ non corrigé | §3.7 | -| `RadiationEffect` : `HashSet` + parsing reconstruits par entité/tick | ❌ non corrigé | §2.2 | +| `ReactorPattern.findController/findControllerPos` : ~3 971 blocs ×2 par casse, **sans garde client**, mutation d'état métier potentiellement double | ❌ non corrigé — **priorité n°1** | §2.1 | +| `DefaultHeatCalculator.computeHeat` : ~O(n²) + désérialisation NBT par cellule, à chaque tick | ❌ non corrigé | §2.2 | | `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame | ❌ non corrigé | — | -| `clearLockIfAllInputsEmpty` : ancien scan cubique `O(n³)` | ✅ **corrigé** (utilise `inputFluidManager.getFuildHandlers`) | §4 | +| `clearLockIfAllInputsEmpty` : ancien scan cubique `O(n³)` | ✅ **corrigé** (utilise `inputFluidManager.getFuildHandlers`) | §3 | --- -## 7. ✅ Pour mémoire — déjà corrigé (ne plus reprendre) +## 6. ✅ Pour mémoire — déjà corrigé (ne plus reprendre) Vérifiés résolus dans le code actuel : **B2** (`RadiationSyncPacket` supprimé, synchro via capability + `PlayerTickEvent`), **B3/B4/B5/B6/B8/B9/B11/B13/B16/B19** (cooldown `Map`, loot/tag thorium, `BiomeTagRule.apply` → `Condition`, packet blueprint, scan null-safe, paliers radiation 4 niveaux, logger après null-check, bras armure anti-radiation, garde `conditions` datagen, surface rules v1 disparues), **B12** (`AnimalUtil.isFood` teste `foodItems.test(stack)`), **B14** (`FluidLockManager` supprimé, `PersistentFluidLocks` seul), **off-by-one `getFluidInTank`** (→ `getFluidInTank(0)`). Le « double comptage `IRadiationSource` vs `RadiationRegistry` » est **architecturalement bloqué** (`RadiationRegistry` lève `IllegalStateException` à l'enregistrement si l'item implémente déjà `IRadiationSource`) — duplication de design maladroite mais pas de bug concret. -**Corrigé le 2026-06-22** : **icône d'item de l'armure anti-radiation teinte** — l'icône en inventaire / slot résultat de la smithing table suivait pas la couleur du tissu (l'armure *portée*, elle, fonctionnait déjà). Cause : modèle d'item statique, chemin de rendu distinct de `getArmorTexture`. Câblé via `ItemProperty` client `createnuclear:cloth_color` + 64 modèles d'overrides générés en datagen (`CNItems.coloredArmorModel`, `CreateNuclearClient.registerItemProperties`). Tooltip de pis-aller + clé de lang `tooltip.cloth.color` retirés. Détail en §5. +**Corrigé le 2026-06-22** : **icône d'item de l'armure anti-radiation teinte** — l'icône en inventaire / slot résultat de la smithing table suivait pas la couleur du tissu (l'armure *portée*, elle, fonctionnait déjà). Cause : modèle d'item statique, chemin de rendu distinct de `getArmorTexture`. Câblé via `ItemProperty` client `createnuclear:cloth_color` + 64 modèles d'overrides générés en datagen (`CNItems.coloredArmorModel`, `CreateNuclearClient.registerItemProperties`). Tooltip de pis-aller + clé de lang `tooltip.cloth.color` retirés. Détail en §4. + +**Corrigé le 2026-06-23** : **tous les problèmes radiation (ancienne §2)**. Cause racine commune des 3 chemins d'application : la logique d'éligibilité était dupliquée et divergente. +- **Point de vérité unique** : nouveau `RadiationCapability.canBeIrradiated(LivingEntity)` (spectateur → tag `IRRADIATED_IMMUNE` → config `enabledItemRadiation` → blacklist → résistance < 1.0), réutilisé par les trois chemins. +- **`RadiationEffectHandler.apply`** (fuite de tuyau, 3ᵉ chemin) : appliquait la radiation **sans aucune garde** → filtre désormais via `canBeIrradiated`. +- **`RadiationEffect`** : le filtre du `VicinityEffect` reconstruisait un `HashSet` + reparsait la blacklist **par entité/tick** → réduit à `canBeIrradiated(e) && !e.hasEffect(...)`. La blacklist est mise en **cache statique** dans `RadiationCapability`, reconstruite uniquement quand l'instance de liste de config change (auto-invalidée au reload, sans event ni couplage `config → content`). Élimine le point de perf §5. +- **`RadiationCapability.applyEffects`** : pas de garde spectateur → `onPlayerTick` gate désormais sur `canBeIrradiated(player)`. L'atténuation continue par résistance reste séparée (non touchée). +- **`RadiationCapability.lastBiomeLocation`** : lu mais non persisté → sérialisé/désérialisé en NBT (`RadiationProvider`). +- **Overlays concurrents** : `RadiationOverlay` (jamais rendu, fade binarisé par `Math.round`) + `EasingHudOverlay` + l'appel no-op `HelmetOverlay.setCoverage`/`COVERAGE_FACTORS` **supprimés** ; `IrradiatedOverlayRendererVision` (fade lisse, garde spectateur) reste seul. Compilation vérifiée (`gradlew compileJava`). --- -## 8. 🗺️ Feuille de route — priorités +## 7. 🗺️ Feuille de route — priorités **Quick wins (risque quasi nul, gain immédiat)** -1. Garde `level.isClientSide()` sur `findController`/`findControllerPos`/`ReactorAssembler` (§3.6). **← le plus rentable.** +1. Garde `level.isClientSide()` sur `findController`/`findControllerPos`/`ReactorAssembler` (§2.1). **← le plus rentable.** 2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` + `ReactorCooler.playerDestroy` (généraliser la garde de `ReactorFrame.onRemove`). 3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. 5. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. -6. `git rm --cached` sur les 6 fichiers de debug `run/` (§5). +6. `git rm --cached` sur les 6 fichiers de debug `run/` (§4). 7. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. **Corrections ciblées (risque faible à moyen)** -8. `RadiationEffectHandler.apply` : gardes config/immunité/spectateur/résistance via `canBeIrradiated` (§2.1). -9. `RadiationEffect` : cache statique de la blacklist (§2.2). `RadiationCapability.applyEffects` : garde spectateur (§2.3). -10. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). -11. `DefaultHeatCalculator` : map slot→ItemStack précalculée (O(n²) → O(n)) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance (§3.7). -12. `RadiationProvider.serializeNBT` : persister `lastBiomeLocation` (§2.4). +8. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). +9. `DefaultHeatCalculator` : map slot→ItemStack précalculée (O(n²) → O(n)) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance (§2.2). **Décisions produit (choisir puis exécuter)** -13. Collier teignable chat/loup : finir le câblage (`addLayer` + `render`) ou retirer `DyeItem`/`setCollarColor` (§5). -14. `RadiationOverlay`/`EasingHudOverlay` : supprimer (si `IrradiatedOverlayRendererVision` suffit) ou réactiver + corriger le `Math.round` (§2.5). -15. ~~Armure anti-radiation : vérifier en jeu si la teinture de tissu change la texture~~ — **✅ fait (2026-06-22)** : icône d'item câblée sur le NBT via `ItemProperty` + overrides datagen (§5, §7). -16. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§5). +10. Collier teignable chat/loup : finir le câblage (`addLayer` + `render`) ou retirer `DyeItem`/`setCollarColor` (§4). +11. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). **Chantier de fond (le plus rentable à long terme)** -17. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs silencieux ont survécu à plusieurs audits. +12. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs silencieux ont survécu à plusieurs audits. **Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** - Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos). diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java index 283506a9..af366613 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java @@ -1,24 +1,15 @@ package net.nuclearteam.createnuclear.content.radiation; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.nuclearteam.createnuclear.CNEffects; -import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.content.effects.VicinityEffect; import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.nuclearteam.createnuclear.foundation.damageTypes.CNDamageSources; -import net.nuclearteam.createnuclear.foundation.utility.ConfigValueResolver; -import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; - -import java.util.HashSet; -import java.util.Set; public class RadiationEffect extends VicinityEffect { @@ -29,27 +20,7 @@ public class RadiationEffect extends VicinityEffect { public RadiationEffect() { super(MobEffectCategory.HARMFUL, 15453236, amplifier -> 10, - e -> { - boolean isWearingAntiRadiationArmor = false; - - double resistance = RadiationCapability.getRadiationResistance(e); - if (resistance >= 1) isWearingAntiRadiationArmor = true; - - Set> target = new HashSet<>(); - - ConfigValueResolver.loadValuesInSet(CNConfigs.server().radiation.configuredLists.getEntityBlackList(), target, entity -> { - ResourceLocation location = ResourceLocation.tryParse(entity); - return BuiltInRegistries.ENTITY_TYPE.get(location); - }); - - return !e.getType().is(CNTags.CNEntityTags.IRRADIATED_IMMUNE.tag) - && !e.hasEffect(CNEffects.RADIATION.get()) - && !isWearingAntiRadiationArmor - && CNConfigs.server().radiation.enabledItemRadiation.get() - && !target.contains(e.getType()) - && !e.isSpectator() - ; - }, + e -> RadiationCapability.canBeIrradiated(e) && !e.hasEffect(CNEffects.RADIATION.get()), timer -> {}, () -> new MobEffectInstance(CNEffects.RADIATION.get(), 300)); // Custom color (hex value) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java index b231bfe0..53a72c3d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java @@ -7,6 +7,7 @@ import net.minecraft.world.phys.AABB; import net.minecraftforge.fluids.FluidStack; import net.nuclearteam.createnuclear.CNEffects; +import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import java.util.List; @@ -17,6 +18,7 @@ public void apply(Level level, AABB area, FluidStack fluid) { List entities = level.getEntitiesOfClass(LivingEntity.class, area, LivingEntity::isAffectedByPotions); for (LivingEntity entity : entities) { + if (!RadiationCapability.canBeIrradiated(entity)) continue; entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 3, 2, false, false, false)); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java index 13b3ad7d..d476469a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java @@ -1,11 +1,13 @@ package net.nuclearteam.createnuclear.content.radiation.capability; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.player.Player; @@ -17,16 +19,21 @@ import net.minecraftforge.event.TickEvent.PlayerTickEvent; import net.nuclearteam.createnuclear.CNAttributes; import net.nuclearteam.createnuclear.CNEffects; +import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.radiation.IRadiationSource; import net.nuclearteam.createnuclear.api.radiation.RadiationRegistry; import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; +import net.nuclearteam.createnuclear.foundation.utility.ConfigValueResolver; import net.nuclearteam.createnuclear.foundation.utility.InventoryHashUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import static net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem.RADIATION_VALUE; +import java.util.HashSet; +import java.util.List; import java.util.Objects; +import java.util.Set; public class RadiationCapability implements IRadiationCapability { private double radiation; @@ -90,7 +97,7 @@ public static void onPlayerTick(PlayerTickEvent event) { cap.setLastBiomeLocation(biomeLoc); } - if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return; + if (!canBeIrradiated(player)) return; double totalRaw = cap.getRadiation() + getRawBiomeRadiation(biomeKey); double resistance = getRadiationResistance(player); @@ -120,6 +127,36 @@ private static double getRawBiomeRadiation(ResourceKey biomeKey) { return RadiationRegistry.get(biomeKey); } + /** + * Single source of truth for radiation eligibility, shared by every application path + * (item/biome tick, vicinity effect, open-pipe leak). Covers eligibility only — + * the continuous attenuation by resistance lives in {@link #applyEffects} / the effect tick. + */ + public static boolean canBeIrradiated(LivingEntity entity) { + if (entity.isSpectator()) return false; + if (entity.getType().is(CNTags.CNEntityTags.IRRADIATED_IMMUNE.tag)) return false; + if (!CNConfigs.server().radiation.enabledItemRadiation.get()) return false; + if (getEntityBlacklist().contains(entity.getType())) return false; + return getRadiationResistance(entity) < 1.0; + } + + // Cached, parsed entity blacklist. Rebuilt only when the underlying config list instance + // changes (ForgeConfigSpec returns a fresh list on reload), so no per-tick parsing. + private static List cachedBlacklistSource; + private static Set> cachedBlacklist = Set.of(); + + private static Set> getEntityBlacklist() { + List source = CNConfigs.server().radiation.configuredLists.getEntityBlackList(); + if (source != cachedBlacklistSource) { + Set> resolved = new HashSet<>(); + ConfigValueResolver.loadValuesInSet(source, resolved, + entry -> BuiltInRegistries.ENTITY_TYPE.get(ResourceLocation.tryParse(entry))); + cachedBlacklist = resolved; + cachedBlacklistSource = source; + } + return cachedBlacklist; + } + public static double getRadiationResistance(LivingEntity entity) { double resistance = 0d; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java index 05cfaca2..a9fea11d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationProvider.java @@ -2,6 +2,7 @@ import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityToken; @@ -25,6 +26,9 @@ public CompoundTag serializeNBT() { CompoundTag tag = new CompoundTag(); tag.putDouble("radiation", instance.getRadiation()); tag.putLong("hash", instance.getInventoryHash()); + if (instance.getLastBiomeLocation() != null) { + tag.putString("lastBiome", instance.getLastBiomeLocation().toString()); + } return tag; } @@ -32,5 +36,8 @@ public CompoundTag serializeNBT() { public void deserializeNBT(CompoundTag nbt) { instance.setRadiation(nbt.getDouble("radiation")); instance.setInventoryHash(nbt.getLong("hash")); + instance.setLastBiomeLocation(nbt.contains("lastBiome") + ? ResourceLocation.tryParse(nbt.getString("lastBiome")) + : null); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java deleted file mode 100644 index 17a1ad11..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/client/RadiationOverlay.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.nuclearteam.createnuclear.content.radiation.client; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.gui.overlay.IGuiOverlay; -import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; -import net.nuclearteam.createnuclear.CNEffects; -import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.foundation.events.overlay.EasingHudOverlay; -import net.nuclearteam.createnuclear.foundation.utility.RenderHelper; - -/** - * HUD overlay for radiation effect when the player is irradiated. - */ -public class RadiationOverlay extends EasingHudOverlay { - private static final ResourceLocation RADIATION_TEXTURE = - CreateNuclear.asResource("textures/misc/irradiated_vision/irradiated_vision.png"); - private static float coverage = 1f; - - /** - * Updates the coverage scale for the radiation effect. - * @param newCoverage scale factor (1.0 = normal size) - */ - public static void setCoverage(float newCoverage) { - coverage = newCoverage; - } - - @Override - public ResourceLocation getAfterOverlay() { - return VanillaGuiOverlay.HELMET.id(); - } - - @Override - public String getOverlayId() { - return "radiation_overlay"; - } - - @Override - public boolean isActive() { - LocalPlayer player = Minecraft.getInstance().player; - return player != null && player.hasEffect(CNEffects.RADIATION.get()); - } - - @Override - protected void renderWithAlpha(GuiGraphics graphics, float partialTicks, float alpha) { - // Render radiation overlay with dynamic coverage and alpha - RenderHelper.renderTextureOverlay(graphics, RADIATION_TEXTURE, Math.round(alpha * coverage)); - } - - @Override - public int getPriority() { - return 100; // Fixed background priority for radiation effect - } - - @Override - public IGuiOverlay getOverlay() { - return this::render; - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java index e8913694..4d94e48c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/HudRenderer.java @@ -10,7 +10,6 @@ public class HudRenderer { private static final List overlays = List.of( new HelmetOverlay() - //new RadiationOverlay(), ); public void onHudRender(RegisterGuiOverlaysEvent event) { diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EasingHudOverlay.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EasingHudOverlay.java deleted file mode 100644 index 217e8592..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/EasingHudOverlay.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.nuclearteam.createnuclear.foundation.events.overlay; - -import net.minecraft.client.gui.GuiGraphics; -import net.minecraftforge.client.gui.overlay.ForgeGui; - -/** - * Abstract HUD overlay with a smooth fade-in/out (ease-in-out) effect. - */ -public abstract class EasingHudOverlay implements HudOverlay { - private float progress = 0f; - protected float fadeSpeed = 0.03f; - - @Override - public void render(ForgeGui gui, GuiGraphics graphics, float partialTicks, int width, int height) { - // Update progress based on the active state - progress = isActive() - ? Math.min(1f, progress + fadeSpeed) - : Math.max(0f, progress - fadeSpeed); - if (progress > 0f) { - renderWithAlpha(graphics, partialTicks, ease(progress)); - } - } - - /** - * Smoothstep interpolation (ease-in-out). - * @param t linear progress [0,1] - * @return eased value - */ - private float ease(float t) { - return t * t * (3f - 2f * t); - } - - /** - * Renders the overlay with a specific alpha. - * Subclasses implement the actual drawing here. - * @param graphics the GUI graphics context - * @param partialTicks frame interpolation value - * @param alpha transparency level [0,1] - */ - protected abstract void renderWithAlpha(GuiGraphics graphics, float partialTicks, float alpha); -} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java index 8a878acb..0eb8e35f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/HelmetOverlay.java @@ -12,7 +12,6 @@ import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.content.radiation.client.RadiationOverlay; import net.nuclearteam.createnuclear.foundation.utility.RenderHelper; /** @@ -26,7 +25,6 @@ public class HelmetOverlay implements HudOverlay { CreateNuclear.asResource("textures/misc/helmet_vision/helmet_crack2.png"), CreateNuclear.asResource("textures/misc/helmet_vision/helmet_almost_broken.png") }; - private static final float[] COVERAGE_FACTORS = {.5f, 1f, 1.05f, 1.45f, 1.98f}; private static final int BASE_PRIORITY = 50; @Override @@ -65,9 +63,6 @@ public void render(ForgeGui gui, GuiGraphics graphics, float partialTicks, int w : durabilityRatio >= 0.25f ? 3 : 4; - // Update radiation coverage based on helmet condition - RadiationOverlay.setCoverage(COVERAGE_FACTORS[index]); - // Render helmet overlay texture RenderHelper.renderFirstPersonOverlay(graphics, HELMET_TEXTURES[index], 1f, 1f); // Render the hotbar behind the helmet overlay From f895755bc93f44761e4a1935a1da08513437c76f Mon Sep 17 00:00:00 2001 From: Dimitri Date: Tue, 23 Jun 2026 14:16:03 +0200 Subject: [PATCH 072/171] adding the real alarm recipe --- .../708b1206ce73e235f43eb2a5fd72b93671cfba4e | 3 +- .../mechanical_crafting/reactor_alarm.json | 28 +++++++++++++++++++ .../recipe/CNMechanicalCraftingRecipeGen.java | 13 +++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_alarm.json diff --git a/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e b/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e index 82b5bc84..edb7063e 100644 --- a/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e +++ b/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e @@ -1,5 +1,6 @@ -// 1.20.1 2026-05-12T11:08:49.9141357 createnuclear's mechanical crafting recipes +// 1.20.1 2026-06-23T14:13:44.403459 createnuclear's mechanical crafting recipes 0a56332199941d1db61ee7512130d2664fd73e46 data/createnuclear/recipes/mechanical_crafting/graphite_rod.json +13bbcaa279d141281856ee7dbed5d3ea105e2389 data/createnuclear/recipes/mechanical_crafting/reactor_alarm.json 85f68439da9d4bb70d1308b7b64db0e30fec9e51 data/createnuclear/recipes/mechanical_crafting/reactor_controller.json 11b4c4d65d4f6981c34e7f97e0e8dc3468376b05 data/createnuclear/recipes/mechanical_crafting/reactor_cooler.json 8228bb2d850dfd474e2ce142ac9a0ff6ab707f07 data/createnuclear/recipes/mechanical_crafting/reactor_core.json diff --git a/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_alarm.json b/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_alarm.json new file mode 100644 index 00000000..01ad04cb --- /dev/null +++ b/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_alarm.json @@ -0,0 +1,28 @@ +{ + "type": "create:mechanical_crafting", + "acceptMirrored": true, + "key": { + "C": { + "item": "createnuclear:reactor_casing" + }, + "L": { + "item": "minecraft:clock" + }, + "N": { + "item": "minecraft:note_block" + }, + "R": { + "item": "minecraft:repeater" + } + }, + "pattern": [ + "CCCCC", + "CNRNC", + "CRLRC", + "CNRNC", + "CCCCC" + ], + "result": { + "item": "createnuclear:reactor_alarm" + } +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java index 238e2edd..eedc2df3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java @@ -95,6 +95,19 @@ public class CNMechanicalCraftingRecipeGen extends MechanicalCraftingRecipeGen { .patternLine("CSBSC") .patternLine("CPSPC") .patternLine("CCCCC") + ), + + REACTOR_ALARM = create(CNBlocks.REACTOR_ALARM::get) + .recipe(b -> b + .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) + .key('N', Ingredient.of(Blocks.NOTE_BLOCK)) + .key('R', Ingredient.of(Blocks.REPEATER)) + .key('L', Ingredient.of(Items.CLOCK)) + .patternLine("CCCCC") + .patternLine("CNRNC") + .patternLine("CRLRC") + .patternLine("CNRNC") + .patternLine("CCCCC") ); From 3778b6f15f5cc988f2d3a5aae948252e4adba262 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:48:12 +0200 Subject: [PATCH 073/171] feat: add reactor liquid input recipe and adjust ore placement settings --- .../15812fa7bc190aa8f0a8644088c7ff563925e506 | 7 +++--- .../fed443662143001aeb5341375f6f5ef31d10baea | 8 +++---- .../recipes/crushing/raw_thorium.json | 5 ++--- .../recipes/crushing/raw_thorium_block.json | 6 +++--- ...ut_from_fluid_pipe_and_reactor_casing.json | 16 ++++++++++++++ .../worldgen/placed_feature/lead_ore.json | 2 +- .../striated_ores_overworld.json | 6 +++--- .../worldgen/placed_feature/thorium_ore.json | 4 ++-- .../data/recipe/CNCrushingRecipeGen.java | 20 +++++++++--------- .../recipe/CNItemApplicationRecipeGen.java | 7 ++++++ .../worldgen/CNPlacedFeatures.java | 6 +++--- .../item/armors/anti_radiation_boots.png | Bin 232 -> 0 bytes .../boots/black_anti_radiation_boots.png | Bin 387 -> 0 bytes .../boots/blue_anti_radiation_boots.png | Bin 402 -> 0 bytes .../boots/brown_anti_radiation_boots.png | Bin 416 -> 0 bytes .../boots/cyan_anti_radiation_boots.png | Bin 404 -> 0 bytes .../boots/gray_anti_radiation_boots.png | Bin 408 -> 0 bytes .../boots/green_anti_radiation_boots.png | Bin 409 -> 0 bytes .../boots/light_blue_anti_radiation_boots.png | Bin 415 -> 0 bytes .../boots/light_gray_anti_radiation_boots.png | Bin 392 -> 0 bytes .../boots/lime_anti_radiation_boots.png | Bin 395 -> 0 bytes .../boots/magenta_anti_radiation_boots.png | Bin 399 -> 0 bytes .../boots/orange_anti_radiation_boots.png | Bin 409 -> 0 bytes .../boots/pink_anti_radiation_boots.png | Bin 400 -> 0 bytes .../boots/purple_anti_radiation_boots.png | Bin 401 -> 0 bytes .../armors/boots/red_anti_radiation_boots.png | Bin 407 -> 0 bytes .../boots/white_anti_radiation_boots.png | Bin 411 -> 0 bytes .../boots/yellow_anti_radiation_boots.png | Bin 410 -> 0 bytes .../black_anti_radiation_chestplate.png | Bin 363 -> 0 bytes .../blue_anti_radiation_chestplate.png | Bin 405 -> 0 bytes .../brown_anti_radiation_chestplate.png | Bin 400 -> 0 bytes .../cyan_anti_radiation_chestplate.png | Bin 398 -> 0 bytes .../gray_anti_radiation_chestplate.png | Bin 398 -> 0 bytes .../green_anti_radiation_chestplate.png | Bin 396 -> 0 bytes .../light_blue_anti_radiation_chestplate.png | Bin 416 -> 0 bytes .../light_gray_anti_radiation_chestplate.png | Bin 395 -> 0 bytes .../lime_anti_radiation_chestplate.png | Bin 391 -> 0 bytes .../magenta_anti_radiation_chestplate.png | Bin 405 -> 0 bytes .../orange_anti_radiation_chestplate.png | Bin 417 -> 0 bytes .../pink_anti_radiation_chestplate.png | Bin 410 -> 0 bytes .../purple_anti_radiation_chestplate.png | Bin 412 -> 0 bytes .../red_anti_radiation_chestplate.png | Bin 384 -> 0 bytes .../white_anti_radiation_chestplate.png | Bin 359 -> 0 bytes .../yellow_anti_radiation_chestplate.png | Bin 402 -> 0 bytes .../helmets/black_anti_radiation_helmet.png | Bin 387 -> 0 bytes .../helmets/blue_anti_radiation_helmet.png | Bin 402 -> 0 bytes .../helmets/brown_anti_radiation_helmet.png | Bin 416 -> 0 bytes .../helmets/cyan_anti_radiation_helmet.png | Bin 404 -> 0 bytes .../helmets/gray_anti_radiation_helmet.png | Bin 408 -> 0 bytes .../helmets/green_anti_radiation_helmet.png | Bin 409 -> 0 bytes .../light_blue_anti_radiation_helmet.png | Bin 415 -> 0 bytes .../light_gray_anti_radiation_helmet.png | Bin 392 -> 0 bytes .../helmets/lime_anti_radiation_helmet.png | Bin 395 -> 0 bytes .../helmets/magenta_anti_radiation_helmet.png | Bin 399 -> 0 bytes .../helmets/orange_anti_radiation_helmet.png | Bin 409 -> 0 bytes .../helmets/pink_anti_radiation_helmet.png | Bin 400 -> 0 bytes .../helmets/purple_anti_radiation_helmet.png | Bin 401 -> 0 bytes .../helmets/red_anti_radiation_helmet.png | Bin 407 -> 0 bytes .../helmets/white_anti_radiation_helmet.png | Bin 411 -> 0 bytes .../helmets/yellow_anti_radiation_helmet.png | Bin 410 -> 0 bytes .../black_anti_radiation_leggings.png | Bin 311 -> 0 bytes .../leggings/blue_anti_radiation_leggings.png | Bin 345 -> 0 bytes .../brown_anti_radiation_leggings.png | Bin 334 -> 0 bytes .../leggings/cyan_anti_radiation_leggings.png | Bin 335 -> 0 bytes .../leggings/gray_anti_radiation_leggings.png | Bin 334 -> 0 bytes .../green_anti_radiation_leggings.png | Bin 334 -> 0 bytes .../light_blue_anti_radiation_leggings.png | Bin 356 -> 0 bytes .../light_gray_anti_radiation_leggings.png | Bin 341 -> 0 bytes .../leggings/lime_anti_radiation_leggings.png | Bin 347 -> 0 bytes .../magenta_anti_radiation_leggings.png | Bin 351 -> 0 bytes .../orange_anti_radiation_leggings.png | Bin 347 -> 0 bytes .../leggings/pink_anti_radiation_leggings.png | Bin 358 -> 0 bytes .../purple_anti_radiation_leggings.png | Bin 346 -> 0 bytes .../leggings/red_anti_radiation_leggings.png | Bin 334 -> 0 bytes .../white_anti_radiation_leggings.png | Bin 324 -> 0 bytes .../yellow_anti_radiation_leggings.png | Bin 354 -> 0 bytes 76 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/black_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/blue_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/brown_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/cyan_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/gray_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/green_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/light_blue_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/light_gray_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/lime_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/magenta_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/orange_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/pink_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/purple_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/red_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/white_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/boots/yellow_anti_radiation_boots.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/black_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/blue_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/brown_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/cyan_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/gray_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/green_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/light_blue_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/light_gray_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/lime_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/magenta_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/orange_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/pink_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/purple_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/red_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/white_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/chestplates/yellow_anti_radiation_chestplate.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/black_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/blue_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/brown_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/cyan_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/gray_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/green_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/light_blue_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/light_gray_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/lime_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/magenta_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/orange_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/pink_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/purple_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/red_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/white_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/helmets/yellow_anti_radiation_helmet.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/black_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/blue_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/brown_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/cyan_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/gray_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/green_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/light_blue_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/light_gray_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/lime_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/magenta_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/orange_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/pink_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/purple_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/red_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/white_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/leggings/yellow_anti_radiation_leggings.png diff --git a/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 b/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 index 5014de95..94ddd2ad 100644 --- a/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 +++ b/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-12T10:26:06.6419648 CreateNuclear's Processing Recipes +// 1.20.1 2026-06-24T09:46:27.9556309 CreateNuclear's Processing Recipes bccfe326d6c91bd2df207a38225fbca413e1013f data/createnuclear/recipes/compacting/thorium_fluid_to_thorium_ingot.json c711d032a04e1a9350ad9bc4d9c4d74f54689862 data/createnuclear/recipes/compacting/uranium_fluid_to_yellowcake.json 33becbc558bd2fbe277be096b292c0093f84e44c data/createnuclear/recipes/crushing/coal.json @@ -6,13 +6,14 @@ c711d032a04e1a9350ad9bc4d9c4d74f54689862 data/createnuclear/recipes/compacting/u 57154e35ebb09170bb39f5b3a72ecd49182697f2 data/createnuclear/recipes/crushing/granite.json 682ceb2386fe56cd47e46d7ebb3d8185ac78515b data/createnuclear/recipes/crushing/nitrate.json 4feb59d85e86e34ed565c18b6a4df120fe050bc7 data/createnuclear/recipes/crushing/raw_copper.json -e79a01c53e63fe0c0b8519a6b9b76a2044179efa data/createnuclear/recipes/crushing/raw_thorium.json -78ba5a2791f2f30bd22d6a1111447d1a39928277 data/createnuclear/recipes/crushing/raw_thorium_block.json +c0e1f33d8e91a3133e5acf6e4d3eb5ea5cd23471 data/createnuclear/recipes/crushing/raw_thorium.json +169c09c5947ddf8bdc8727af3c71368880b0c128 data/createnuclear/recipes/crushing/raw_thorium_block.json 26d2787e831b9986ed6f90f8ea803d5fdc544bf5 data/createnuclear/recipes/crushing/raw_zinc.json e42be7d17c5e057e62c4b1176cbf43319a157f51 data/createnuclear/recipes/enriched/enriched_yellowcake.json 74555eb2cce0827f99dc5c4ff91362bdaecad725 data/createnuclear/recipes/enriched/enriching_campfire.json d0a30a8942f3e81d11afa21a93037916601c38cb data/createnuclear/recipes/item_application/reactor_casing_from_steel_and_brass_casing.json f2d3a2dbcb9135e31261cc8408f11cd07038a826 data/createnuclear/recipes/item_application/reactor_input_from_hopper_and_reactor_casing.json +a98e78b74b8755c320ffaf30ba16631bd11240f6 data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json 91c07d7804d0960aaa17a6258f00f1731ca458f5 data/createnuclear/recipes/item_application/reactor_output_from_shaft_and_reactor_casing.json a9d114da800657c53caabcb1369137ede6746362 data/createnuclear/recipes/mixing/liquid_nitrogen.json 7fc7695cd03577131096e9695170193044f8bc1a data/createnuclear/recipes/mixing/steel.json diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index ee9128fb..66034ea2 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-22T11:11:17.7591194 CreateNuclear Generated Registry Entries +// 1.20.1 2026-06-24T09:46:27.9570941 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -20,8 +20,8 @@ b0e1ee7314412507fd7346cb48b29d105f6186ad data/createnuclear/worldgen/configured_ 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/final_density.json 7f5f110a211b82bc22627b2f901c5f3c6a1265dd data/createnuclear/worldgen/noise/irradiated/erosion.json da4ba44d949615000ebce13f04cb97dec24cf192 data/createnuclear/worldgen/noise_settings/irradiated_noise.json -5a035ad45f9039b81e3e55160da3127fe7079ba9 data/createnuclear/worldgen/placed_feature/lead_ore.json +f11d981e79cf92130a47ad564925d7be26ffbc0b data/createnuclear/worldgen/placed_feature/lead_ore.json e69f61cbb4bf2c50a6123ddc87c024c801bb78d1 data/createnuclear/worldgen/placed_feature/nitrate_ore.json -cc85909071cab20eacbe2c34887c6ed6a02dc51e data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json -0762472dada74fb4592de79d598f8d45d955ea2c data/createnuclear/worldgen/placed_feature/thorium_ore.json +6b777b9b4e02bd55236cbeaff12529309b939c17 data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json +403caabb9eefec1012db63d6cbd5c1f22ac9e88d data/createnuclear/worldgen/placed_feature/thorium_ore.json a18aa32c139932d0023abe6caa722992b167114b data/createnuclear/worldgen/placed_feature/uranium_ore.json diff --git a/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium.json b/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium.json index a92abf02..618069e9 100644 --- a/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium.json +++ b/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium.json @@ -11,9 +11,8 @@ "item": "createnuclear:thorium_dust" }, { - "chance": 0.5, - "count": 8, - "item": "createnuclear:thorium_dust" + "chance": 0.75, + "item": "create:experience_nugget" } ] } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium_block.json b/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium_block.json index bb8e02ca..b786a807 100644 --- a/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium_block.json +++ b/src/generated/resources/data/createnuclear/recipes/crushing/raw_thorium_block.json @@ -12,9 +12,9 @@ "item": "createnuclear:thorium_dust" }, { - "chance": 0.5, - "count": 72, - "item": "createnuclear:thorium_dust" + "chance": 0.75, + "count": 9, + "item": "create:experience_nugget" } ] } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json b/src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json new file mode 100644 index 00000000..2a95d6b8 --- /dev/null +++ b/src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json @@ -0,0 +1,16 @@ +{ + "type": "create:item_application", + "ingredients": [ + { + "item": "createnuclear:reactor_casing" + }, + { + "item": "create:fluid_pipe" + } + ], + "results": [ + { + "item": "createnuclear:reactor_liquid_input" + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/lead_ore.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/lead_ore.json index 11ba3bd9..0cc2bfab 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/lead_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/lead_ore.json @@ -13,7 +13,7 @@ "height": { "type": "minecraft:trapezoid", "max_inclusive": { - "absolute": 112 + "absolute": 60 }, "min_inclusive": { "absolute": -16 diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json index 7af13976..a6ca8578 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:rarity_filter", - "chance": 18 + "chance": 5 }, { "type": "minecraft:in_square" @@ -13,10 +13,10 @@ "height": { "type": "minecraft:uniform", "max_inclusive": { - "absolute": 70 + "absolute": 16 }, "min_inclusive": { - "absolute": -30 + "absolute": -63 } } }, diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json index 2b260667..4eaee977 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:count", - "count": 16 + "count": 8 }, { "type": "minecraft:in_square" @@ -13,7 +13,7 @@ "height": { "type": "minecraft:trapezoid", "max_inclusive": { - "absolute": 112 + "absolute": 55 }, "min_inclusive": { "absolute": -16 diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNCrushingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNCrushingRecipeGen.java index 7b5ad12a..1f5bdfde 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNCrushingRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNCrushingRecipeGen.java @@ -32,11 +32,11 @@ public class CNCrushingRecipeGen extends CrushingRecipeGen { COAL_DUST = create("coal", b -> b .duration(250) .require(ItemTags.COALS) - .output(.50f, CNItems.COAL_DUST) + .output(0.50f, CNItems.COAL_DUST) ), GRANITE_URANIUM_POWDER = create(() -> Items.GRANITE, b -> b.duration(250) - .output(.5f, CNItems.URANIUM_POWDER) + .output(0.5f, CNItems.URANIUM_POWDER) .output(1f, Blocks.RED_SAND) ), @@ -48,32 +48,32 @@ public class CNCrushingRecipeGen extends CrushingRecipeGen { RAW_THORIUM_BLOCK = create(() -> CNBlocks.RAW_THORIUM_BLOCK, b -> b .duration(250) .output(1, CNItems.THORIUM_DUST, 9) - .output(0.5f, CNItems.THORIUM_DUST, 72) + .output(0.75f, AllItems.EXP_NUGGET, 9) ), RAW_THORIUM_ITEM = create(() -> CNItems.RAW_THORIUM, b -> b .duration(125) .output(1, CNItems.THORIUM_DUST, 1) - .output(0.5f, CNItems.THORIUM_DUST, 8) + .output(0.75f, AllItems.EXP_NUGGET, 1) ), RAW_ZINC = create(() -> AllItems.RAW_ZINC, b -> b.duration(250) .output(1, AllItems.CRUSHED_ZINC, 1) - .output(.75f, AllItems.EXP_NUGGET, 1) - .output(.25f, CNItems.LEAD_NUGGET,1) + .output(0.75f, AllItems.EXP_NUGGET, 1) + .output(0.25f, CNItems.LEAD_NUGGET,1) ), RAW_COPPER = create(() -> Items.RAW_COPPER, b -> b.duration(250) .output(1, AllItems.CRUSHED_COPPER, 1) - .output(.75f, AllItems.EXP_NUGGET, 1) - .output(.15f, CNItems.LEAD_NUGGET,1) + .output(0.75f, AllItems.EXP_NUGGET, 1) + .output(0.15f, CNItems.LEAD_NUGGET,1) ), NITRATE = create("nitrate", b -> b .require(AllPaletteStoneTypes.LIMESTONE.materialTag) .duration(250) - .output(.6f, CNItems.NITRATE, 1) - .output(.4f, CNItems.LEAD_NUGGET, 1) + .output(0.6f, CNItems.NITRATE, 1) + .output(0.4f, CNItems.LEAD_NUGGET, 1) ) ; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java index 7e2b2014..961bc126 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java @@ -1,6 +1,7 @@ package net.nuclearteam.createnuclear.foundation.data.recipe; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.api.data.recipe.ItemApplicationRecipeGen; import net.minecraft.data.PackOutput; @@ -33,6 +34,12 @@ public class CNItemApplicationRecipeGen extends ItemApplicationRecipeGen { CNBlocks.REACTOR_INPUT.get() ); + GeneratedRecipe REACTOR_LIQUID_INPUT = itemApplication("reactor_liquid_input_from_fluid_pipe_and_reactor_casing", + AllBlocks.FLUID_PIPE.asItem(), + CNBlocks.REACTOR_CASING.get(), + CNBlocks.REACTOR_LIQUID_INPUT.get() + ); + protected GeneratedRecipe itemApplication(String name, Ingredient ingredient, ItemLike input, ItemLike output) { return create(CreateNuclear.asResource(name), b -> b.require(input) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java index 85c73ce7..b2620591 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java @@ -36,10 +36,10 @@ public static void bootstrap(BootstapContext ctx) { Holder> striatedOresOverworld = featureLookup.getOrThrow(CNConfiguredFeatures.STRIATED_ORES_OVERWORLD); register(ctx, URANIUM_ORE, uraniumOre, placementOres(CountPlacement.of(7), -63, 16)); - register(ctx, LEAD_ORE, leadOre, placementOres(CountPlacement.of(10), -16, 112)); - register(ctx, THORIUM_ORE, thoriumOre, placementOres(CountPlacement.of(16), -16, 112)); + register(ctx, LEAD_ORE, leadOre, placementOres(CountPlacement.of(10), -16, 60)); + register(ctx, THORIUM_ORE, thoriumOre, placementOres(CountPlacement.of(8), -16, 55)); register(ctx, NITRATE_ORE, nitrateOre, placementOres(CountPlacement.of(6), -63, 64)); - register(ctx, STRIATED_ORES_OVERWORLD, striatedOresOverworld, placement(RarityFilter.onAverageOnceEvery(18), -30, 70)); + register(ctx, STRIATED_ORES_OVERWORLD, striatedOresOverworld, placement(RarityFilter.onAverageOnceEvery(5), -63, 16)); } diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/anti_radiation_boots.png deleted file mode 100644 index 5e2aafa41a0e3df91580b5ef6d1133095a741426..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9FlS3sCCF7+t~P;i!~ zi(`mI@7+m;LPr!hTDrBel-W}av(hGKrBCCs|55ORX@B2Z)m2qJ zN9TP0w)Werqf>&OEET!4lJ$YJ%?!zRcD7f~Ja|{|eFh)H?;9FQ3X3=kmijkbs|k;1 zns-DfA?-Zls;V!u_ca-PK6$Nn&z)_yZMzSjQBYF%xN$?xWOW#W(kwQX1=pmK-WS)$ d{XJpdVV;^5yr5Rb@i)+w44$rjF6*2UngIMjUP%A| diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/black_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/black_anti_radiation_boots.png deleted file mode 100644 index 98a0676a2861106c799a75ce89384e2c724c97c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 387 zcmV-}0et?6P)i!fFk8~!T!_J8t>#{oQ=W_joH*HsyeJ;#`4c^5^8V2oM5)*8Fr zw*v|O3MNyQwYU@kt6=8#d9L;2?@R08py2nnj}U zaIXQ-;A}TFIFC`TmJXm?Ex~zgPDYu4eptv**B>U3ot;~N>ix}pr|As3)mT?$V9miS zn>!Oo%I6mV`diZbz41e!pK;yx3!}TXL}A@(B+1c@DSWMyyan%LVxhl` hao7tWh|l*u=N}yAl(17x%<%vK002ovPDHLkV1l4tqp$z~ diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/blue_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/blue_anti_radiation_boots.png deleted file mode 100644 index 5aa8e9707ad5fbe51f8c3191baffc0e60996aaea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmV;D0d4+?P)0 z$98?*xP>tWtK}eYy3)G1_a=~ZdG!F`@JgvktzQBTGj5DQYSQ9cJEE{L2DRF0+m=A0 wQbG~301D?vnf**c2o_KbvjBo{KKGq}0ds^9_j^~@`}0Bn z)pPYq5<*yQRP+G=7J!O`5Rg*-$9DrrQcA>~1aT+PUhQH7CxD8o!RnecAN1c006U5l z0F<+-aaklDM*3x_Rs(2oR+BM!7-2EYEWl!zfrk-RlQF6pMjIA1Q9M5AKL@!u6APM7Kt1dP5X9xXzVi<{jf}2S4!4Q`0000_Ibt<+*~AQlS2WI_b-3>M-E z1U-X-CkQEWh7d4F76MvWB#?FvkOYzKl3CNNMR>!`&eOk|`Fa1xyqPx+7}e^HjPpnF z&?$PBQL8tyYIPsw?Xuyof7VEnZwuo56<*9|2EY$O7P3`50fk?lpA7&0;Sqii>ix~_ z-9fk0{wi_3lAdN{2lH!Ex6@7x zfaiG`04(M+12$2#-UBcb@BP}t^@Vv zr2&ZFUiJF)>>R057{x=!n1c(^vL=w!y1E9id8L(FYQF?*W;|62E43`XwIK?pO5yP6 z_(ZorqE>d?T^2y${3x@Zsp7gUpcrNW1mS${JO2X6tc-*qyJ{`~0000 zC+itTz2heCNf8H!dz%0K^#lJSG$77j;pJkj0l3Gkkp1ilDE$05)cpIW7P!aM{_f$j z-0RL(Ia{wJA%xLJN)Z4U04fqfKuY-^-wq&2DbZ|K(QH?hm$_JG1yE5sm|l~5-PxxG zIOa$IV7XXpmqp?pQ!hic3P6K19sA%O!>B(u0HgjK++&!IeWWuEZ3?A4-i9j`XxvmZ z!0XGqTGv`-L_v(nz<0DcXk1r}2_#+Jo&ngsQn=YFKL_k)JPKljn{D>3HBmSUVqBb` z)>I25YNdE&3@8AoaC(%jpQ%vFTLIay6+jT1Z~M-_ePoPy%y6Lt00000NkvXXu0mjf D`iQ9J diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/light_blue_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/light_blue_anti_radiation_boots.png deleted file mode 100644 index 1b9a7c1c846a1b242c1bb1be784e90afeb8d0686..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 415 zcmV;Q0bu@#P)jE_NYU2hs>) zND&BmfhG6?OGqj$w6vCx2S{ZTEYgjT#zHXQ{y>P`T7*07%#L`fxo78m?47w|!Jx)? znwtDcw{GcP&S;FM>G9Da?7dyZPu3f}FF$e+>#y*9Arye;kP)(@{{e>w=M}{tyb5>@ z$vSxZtn}ULSHaXPi-?puS#PrC4*=uSRV7^cfi{&{aZ-)0u01wV=UFcd|vLpK|HD>Nmm&{zoljCk&lF(NJ|ONV@f zhb*Dg#ThenHu)H%HFW7vkg%XzI)o=IS*3T_JoVGoIbB3zgjQ~}(1Lq8Fd%`diQIVzzj>iuh*leC1z<&Q`*URM-wC+*Y zP2|i$S*}MDNZM{+09K@i5j3wE&x=b?qM3G51~u874|*QSf6Q@JkK zN!}oZZx94uAfTOikB};F5O5E!Nty^*(gf_*LU!Fh6F)duzMJ{&%*qHL=UyTBPbj=w>Tx>^O0=uq;anmd4urOagR}ooKJMhTVyD z07(i30E=pljO9T>#&UBrI@YKt+bT(+k`(G?d2iPKXaCc~7HL2$ZsP6n(?G|sZWYtJ zzqz=5zQj)MF&nHS2N0jc!36r+poZK^184xhGrp61$gTA6`e5=6d$=+!*k_?Dp=9r@ pJ@PTN;wB03lSzPvP(JmXe*iB~l^quP4dnm;002ovPDHLkV1kN4sQ3T? diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/magenta_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/magenta_anti_radiation_boots.png deleted file mode 100644 index 79eccd875ad425d9fdc5b92961adda87aa5d6dfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 399 zcmV;A0dW3_P)g5HF-4n&%XFH@HUk1cE6i${a1>gm~6>_BSfWoy=UGbCgC%nKH^Y{3z z*620AOSWD~j4`7PNjU%*04idPfph*J-wq&g&Jniy2wQ#OX$M=j0;ot1%41Ta*Zffc zw`bP{03^$ma#$oU@WstgtpL!&nJi*>fsa8nGysEW2ruw4S;UYt4o%8#1y8TfA~3#> z6u{`^L5v^oLTs`%+Ow{s08Xpt#tYQ7&vwYutpJpOzc;?g*2vSXe%A-X^&562S|G_g tu}NN;JnLsFyA>-y4_g5QvH7;|{0n-vk)c4d8k+zB002ovPDHLkV1oaOtlPo!JuBVnw$Lg zU~Z|NX7rlX{LJ0K-mWeAU*ErYkAF0XwJ97;QV9@vjuEn@o`Axq_e05#9zz74!}p&L zCvLejj%^hn%J+S(4M8aYXaFkmeIJam|M+GAi7|#&qmEXi&OPN~OGW?{i9vBqDtE>o z5}>xfodZBLNu|po1)jrShH5#02B$k(A@Cf8{iy~B`%?s-gYIYrF=NrDQY_%^E#`rj z>mvzp^E%_}rwbR$Btv^Jx1>3EzB<$4FEN41Q5jJo4)fO&;X2VVLHK700000NkvXXu0mjf D^cSPA diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/pink_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/pink_anti_radiation_boots.png deleted file mode 100644 index 26955cd54ff3d16a4316b11bac55520f56db1099..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wk0|TRz zr;B5VMQ?J-0j9oVA%Bjm-FaNs4fgJkJKAvOo}0yPZL`@A{~qV(x#n#p5y&r!Uoo?iBu00MZ5U}gRQZX0vihHw6USH z*l*Z^51_Hsf&v;!W5-8KM{Hz63=LtHtXT{4CObQWx0<L)lL% zu3lL}2&;{P6aZKNE)qgOO8Fn(4PZ$r(QOaVZ4b0py4YhUfQyR3;+i#-{T~BxR=v&v zAlW3wWw9tE{W4su0X#VK)dUn0ri+mUm@Y=3kT73OP|SF|srvywzu$GB(|R%hv#(dZ zzBzqBnkkHzk!Q@o-T9+6fvo$>X8`+G+Ga}o6<|N(X{NBvRQat9aX8HsE>2okx&;=u va^we20EdgC?EFmi1Auba31EoJcYWtS(<_Zzu}nF700000NkvXXu0mjfcp0V| diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/red_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/red_anti_radiation_boots.png deleted file mode 100644 index baadfee21c4cfe901c1760648f105e54abcdc5dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 407 zcmV;I0cie-P)c5)&ng3(nyf+LQ^*p!G`GZ-+%3j6j zd2VrPS=ciT#sAK7ysuUj2-_AOEmH;HJGK_GQ$7KOZ(ra3%%Z^a^%Z=_7S_}GncE#t zBBKnD#W~-clZi4Ur2tR?&?e3~f*|;huLqEVAV8A$-TiFrGusF#4#Q23|hDMBu*J zPymnNhgjbn9U{qc3}z8i=HSk2R3?!0aMA>@?$RRr5xxPeXFS>bDD_$qg_A7DMQ#65 zlt7|V4$R7c0)Pn1qpW>Q^(|$T!&(4AbiVF6{{jQ?j*$xZ?zsQ}002ovPDHLkV1gKw BvRwcG diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/white_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/white_anti_radiation_boots.png deleted file mode 100644 index 95283572329fc11a0c75442a63cf20be5a80224d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F3${@^GvDChdfq~K3 z)5S5wqPKPO-rU0m0&eonQ!?*t2wQqCVQLVAdck7WkZLa9hq^4x^Bfw~16H%L#0YME zIpdJktSL`^tnS$T``*Xr8BQE)u9n_4`!QkVYb*X1ffu{#v>#T~p7VTWq67m^ zLz7*&?4q6Tf9pKld))H40gt0%bwh?;ms0ol+WznJmh5JI^7v>ZqsHl?;vSd%4AKo^ zQ&Ue`^!@+%opDv6Oy;b%WtmAir5odSGw6EtzLdHU{`(|D?rpXc`r1>!+wJqYz3pLz z4b%B>4(~_04#nQiird6ExGtd4$tTIA@m;`ObR;)1<#=E5s3y*>Z= zjES$|ItFE>!hi9OSN4?r_hXF6Ha;=$%9}aH-+#|twQ3%NU?q3pXA|F$(62Xs{W6cr zu4E0|+`-Uq|B>CobFsO&^HVEenDV7Yc&7RKGH3zW96$^Lmx3pQC{I^Emvv4FO#sm^ BsKfvO diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/boots/yellow_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/boots/yellow_anti_radiation_boots.png deleted file mode 100644 index 518fb040a2561e2e9c76a2b37e569a0acd3a9542..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wk0|TRv zr;B5VMQ?J-0j6nNv;QAglMAh!Dj3V-oDjMDTYasl92=vZn8-)|`Tq=J_IzeNEZ`P1 zi+|qlhNOnQ6B)vs1J))cG-QVr$95>y6_ndF0|n>&f4pR|MElQw;XXJ1a4~0PWl7v~ zV6vA00t21~&7k1mbn2_TlTA;9KomvKd^i)j)R?9jG5G&~RBLH#jnQQZ2s{_a zv{TwdqjyDK?mgTY9`Hx0@nOCQ0`T$v#%I&0OXeHrY9)j?002^jN$#RB;*B6 zUB?$C008GbRdtAvESr&KvlyTlg&!QKoo_)NoFF+K)Mzeg@O{})|HRo6SxTYA};$P zg@SzoAHkK|{@8-xLR>eC7L%sqLNa#JR1iI@;m$oDhdX!Rj}rBv+v^*E_qPX%k4Mqg z92{Mlh}7^mTIbdUj(WI?^oWBa$>@yTlRayLP!xtA%~eB`#3juTTF6{*&D2HuE8@`KmLaA2 z4cs3{SJ)+e{J*WTxaGN%ZWuze8woA9|s_Y-+u|qp3pO|lqz@c$L4x_z$pRN+d~FQva2vc uUh)sLEu+xi>@t8n11AA_NLl6Zzvu&gv2GfDK*c5i0000TlgmoOKp2I;$xSe+Oh5<`+Q)I_Lu573E&@JDp^F9z zLLb7FkJEx62nn?nOcUdxW^!pOh#m<1OwRc@lbOIDCF;SACKbT@(<9aMN}M#`jH=7q zI{iw8y9ort4uiHUL%-b|7vvsjMIbz;J9# z*VACD9t_83pQcC^lPzXkMPm)If{@KJL8_R2nqvFD2IvL=w(pa#S4b7JStdBc5zcU= z!})sE33nRwB~?uJFo&{0s`#9(+u%rL@#E_s0oh`PRI&ahzXD{*v{PHEm@Ju|1PB0e z9dyoJj_*&m>Ord47tu6uF2FPa_{{f5VZCOW2k*C(^b07*qoM6N<$g2V@<$^ZZW diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/gray_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/gray_anti_radiation_chestplate.png deleted file mode 100644 index 7981b59096c015d6d7a7de2bef11f05e16aa2b9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 398 zcmV;90df9`P)TlU+{2Koo_)4ozVIlRD`Gun7}g00}%brq!kL69ST8 z;sP{r6TllyL{WlMAIOZfltiQFsXaO8>%G$!{wT*>v^(7t;Q8s1BuSj2uGvwL9HZ>lCE|DpJ~vFoCM9;gvlAlnOGCcBh*v6#(FsJ*u*1 z!4}|^J(6Ta7{$z{6ALlr*>pk}#U#nfJ}3j&?|9B~F}ILLvqhuXvgPGsj_;pmR&$Hb z7Q!gzZZt&elrV}<#j+FRrS;KS{v0qK4hW-|Fp3!u2fqW1`n}B9VH7j!_X+_HK)rsJ znf3bSwlJKBtk*A&oxpWV2(iE2er%7*#uGx|x+Uw|x3JrNTJvr5dIT_@)*7vID;&yv sffXq;{`+PFeE$O{0f&&h^5uWg7rza40s6zyQ~&?~07*qoM6N<$f^5gCkN^Mx diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/green_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/green_anti_radiation_chestplate.png deleted file mode 100644 index 707258c9847c1e05a8365d0a05b50e7392ca0227..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 396 zcmV;70dxL|P)Tlg&=TKomw#TS{rckRc%?hCYHXP&cmXzU~?ykC3>) zJ;VhYeE}b#goF)*h$w1X7R^k50FBXab^Fb|XYQSu!XKr{zzakQ@cg*qWs&}aMD?k!|xB3HMGK}y;SDneP0OLVaYTFN8#)IP! z4Z!J8y7%kb<1<$w+a;Rnz%Wr?AG^chrKjmxu9Uik_%k=(UcU|i(n}MFlgbE1$rspg q%##1U&32Igz)3(6QdPD1U$h6ojcP9cP&Oz40000Tk}+$-KmdhbvH&&32b4b5F@+kydlU7q@WOeGBt* zwMhWD7w$bA_J4<~#Do0t6pXy&uUB6HfYIZv)JXuMkhtRIi|7YrK!3doua=7d0000< KMNUMnLSTY8C9Z}5 diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/light_gray_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/light_gray_anti_radiation_chestplate.png deleted file mode 100644 index 6f37af532bd5e6672b7ff96e5d64e1e340e8ba48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 395 zcmV;60d)R}P)TlTT{GKpcg?n3By%vZ$LT%vN%k;w^++AkYDqfrvsE zS%}bENDmV{z;t65O5F%Ux+s}CF$%@LRd{*t%WwV!?v&R)WZAR<*lga>`orrB$MI7$ znLGoqUcY$&gSH%oL!?YF##q?7vTWKIV~{c-42L!|Xai9cA%p-x%EW;yp&;QKxR$K&y$+tves$2dSeFH5rdmSr~=u`jz002ovPDHLkV1k!fsBHiM diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/lime_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/lime_anti_radiation_chestplate.png deleted file mode 100644 index 6f8da44655ad7918911e9b36b5ddc29f3934ead5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 391 zcmV;20eJq2P)Tk}+$8Kp2LfByARlhBJ^QE`me03|TVeCpfuO{2_tR zN$3yAPbf}K{)9{}*)s$>b?KnALzham!*SP~i7kb^Ae`U5@AKWK2iH=RO`9m2Hsd)> zmuEbuQ9f1ctMEuzxSm5@$@fbQ>Iz)XVI(Z==_`Y<1ruCAnoc26Hf>zb0bqiQu!RO| zzyy~=u_sPLwn45TD!dJH;xyz?>~$jp05G!`7WeamUPF7^B^EeXuwU zdALugE4l7czjFtutKWA20BnMUI1P!@kWG;M53u$VTlD}%gP#DF33B@F$UWI_*;F1?8LT4wJjzS+n+;p){ z>7;#t#HsWVgpR&MLHYtN4o(HDE!Eqhw^J^;@edR{Pn9230muml z*UxLP2IPdpcCjW7BL|WJnxFY!_>NkO2TF1r=8FrH0fRb!v^eF0bZGNK)SjK% zn=7Q1{DB2gH2km4CjhrEcSh#`kcMQHEnh@`)ANDHHJMS)00000NkvXXu0mjf+~uvi diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/orange_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/orange_anti_radiation_chestplate.png deleted file mode 100644 index b83a217c88ccee3cb19fe91c6ab6bd7d56a13af1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 417 zcmV;S0bc%zP)Tld(#}P!xv0n>3+q1`D=nB|^s{KQ`~R2`F2VfE;{ zb_&vO*J9tb0Vov=s*b6_IaQPj2BWzo3_MPHQwE&_4e?!@&R|9uc#P(fM%mH;?Es)r zwiu2Vgn>tAFr!(|)2!$9@^HLJEvFo06$T!sS5suPs&~oQ*#TtqUH1pTNpDIRc>0_C z3ef6KQntguqt%^k1qgupUM_X-H|K|2hqI9J%ZJboik84KR{?x}-+Xy>W|@MbwGOJj zg*Ul2@$kCb0H`y$jFE}TlD}%gKpe-v#>!DbGzrovA|?-@d#CQcfZ*Uza1J4sy^pxS`O;=;W>sAmUm|+9FayFQ(I7bI}L|zvK75-_QN-4{$Ec`;&CupQPPt zBQ45wtBq9Vq-V&oQ?ua(K13pr4P-YEiGUaQaB8;77&2hiT@cFx0C<6~LFWBQ>IFUk zfLIpHx~sqnKr9QoLW8&7=&YR%D^eZARPY>(3_65u{mYvO-Dxo zB>=d&ywcwN<>BdQI1hRKek=X`g9-sL$^d|PyFDmNj~Hc`6{39g3cH_JnY;Js03f}1 zpCH~R`Vq2{KhUY!n*Z_j2>`f$e$+Y#fGi}heEBT;1&TlTAv)Kp2Lf{E$p2w6l<8A;R3it#}4E273cnS-JBJ z-E~zEdIL*!(KCo!ZxAUi8r-x{YKzIZ&qSPsvGrmp>w2=_^vP>yEFu@z;iqRq>wd8 zH|l9ABmkb{5xByD-SXf$9`p5rSS5_p0T(CN1|o%IG941Dg!y_w$8Q^eX#mji+hog( zSS3uRL&8=_*a}TJTV}OztwB?`V^;00001R5*>Tlfh~NF%(5ll4(#uu%(EE%-X-{clZf`t_7hxSN)Fu zjce^FrL=`Ym8mgZj7gnQp{2d6NqG0n&C3h?Q6hef2K@l=@bXGgeu`7YMqh-Rt4jdx zS5E>!Msrt5a;@$y6g_K~H6LRJF{tu0ckFe#o^3pra%`l_hWj zbd;nhOPn=Km#YMc=IL^UvxcH9(~oL^>WrG%dXpf-c8g)VmCUpC2D48Rm2pPS8txvK z_z-Z`oGYs*Xv&A9Uj7^~Srj;HaMmzc6u$$E=S3~Hvxf2fG(-SgXIU-lZGQU9O~~_h zD^db21!_NkAAWaaj(bW}wNdF7%H4N}H@~HMLDe4kP;c(h%*P4rs(O3g_X*+~I14z0 eG}Sc!i@pHB2Xfrqz3%z|0000DNF diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/white_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/white_anti_radiation_chestplate.png deleted file mode 100644 index 581bbbd3764f4ac6d49fe1931bf25df2ff9cbd96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 359 zcmV-t0hs=YP)Tk}IymFc3vgsuvPwVkxvRiZm>wBnt@aG7YnUkRe?_ zU}>e2vXTKQvK1$7r6=_w>&~6y@dtjT5W*5dSlYH-K4sdrU1BbJhuG}BM?^3))`9f~ zW`>C1y-%4#4Agava}EFz$si$wMMMB_&QaHO0{_K@bB=kQQB_W-6XQ50h=?!@1FFhA z&ooW52LLop!!%6^qN)ICJxvpR-)Be50Bfl#ecxkd3G_~fj}^eozLmcN;@I&x{{nPf zmyNBebY1rrPyif{$L!rNm&@Dm7IM8_i!?!1Rg`53z~k}QHAk;3ORB0$etL!H^O?-s z?Y09%&&;yREw;h002ovPDHLk FV1n}pmFEBe diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/yellow_anti_radiation_chestplate.png b/src/main/resources/assets/createnuclear/textures/item/armors/chestplates/yellow_anti_radiation_chestplate.png deleted file mode 100644 index 8429f5dc65cffceebdec21b44f930cbb76ec268d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmV;D0d4+?P)TlD|sBP#lH7gfx^8N=l(nCtI?#0RwUDpo_b+TL%Yc zC!e5`PmsYavyYGtj;$a_$2utpVsR+N1h0eKYi`maLeF$LIlnLG{()U783!U62V&53 z#J0?!=LngTo+*dhO`Fhn$#Ow4Q2arb3qs$e-LzH4lz~pm#%ovrgubgml5rqH-vz*H zSae#p0$Xz7H7w?f6=@uCd_Lp$`anTK-{ti3fi#YoFIM!sP89&q?>bCoO9e^e2tchT zvn5B7r)^CG6qUviCl~i*xlo`@GPiyKvV7}>{0)$`<#zrB7>=e|?KF-Uj;0#{2EhJa zUF&*xbGR{FhCDs54b{M@o75}=faOPC8J1qnGH~j@#nmmW)?dnedHbvYq?hGFJ6xk2 wl#i#~v^D?r{ReP%^{CBM07Xby<>8&^8+$)|<|j(q^#A|>07*qoM6N<$fi!fFk8~!T!_J8t>#{oQ=W_joH*HsyeJ;#`4c^5^8V2oM5)*8Fr zw*v|O3MNyQwYU@kt6=8#d9L;2?@R08py2nnj}U zaIXQ-;A}TFIFC`TmJXm?Ex~zgPDYu4eptv**B>U3ot;~N>ix}pr|As3)mT?$V9miS zn>!Oo%I6mV`diZbz41e!pK;yx3!}TXL}A@(B+1c@DSWMyyan%LVxhl` hao7tWh|l*u=N}yAl(17x%<%vK002ovPDHLkV1l4tqp$z~ diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/blue_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/blue_anti_radiation_helmet.png deleted file mode 100644 index 5aa8e9707ad5fbe51f8c3191baffc0e60996aaea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmV;D0d4+?P)0 z$98?*xP>tWtK}eYy3)G1_a=~ZdG!F`@JgvktzQBTGj5DQYSQ9cJEE{L2DRF0+m=A0 wQbG~301D?vnf**c2o_KbvjBo{KKGq}0ds^9_j^~@`}0Bn z)pPYq5<*yQRP+G=7J!O`5Rg*-$9DrrQcA>~1aT+PUhQH7CxD8o!RnecAN1c006U5l z0F<+-aaklDM*3x_Rs(2oR+BM!7-2EYEWl!zfrk-RlQF6pMjIA1Q9M5AKL@!u6APM7Kt1dP5X9xXzVi<{jf}2S4!4Q`0000_Ibt<+*~AQlS2WI_b-3>M-E z1U-X-CkQEWh7d4F76MvWB#?FvkOYzKl3CNNMR>!`&eOk|`Fa1xyqPx+7}e^HjPpnF z&?$PBQL8tyYIPsw?Xuyof7VEnZwuo56<*9|2EY$O7P3`50fk?lpA7&0;Sqii>ix~_ z-9fk0{wi_3lAdN{2lH!Ex6@7x zfaiG`04(M+12$2#-UBcb@BP}t^@Vv zr2&ZFUiJF)>>R057{x=!n1c(^vL=w!y1E9id8L(FYQF?*W;|62E43`XwIK?pO5yP6 z_(ZorqE>d?T^2y${3x@Zsp7gUpcrNW1mS${JO2X6tc-*qyJ{`~0000 zC+itTz2heCNf8H!dz%0K^#lJSG$77j;pJkj0l3Gkkp1ilDE$05)cpIW7P!aM{_f$j z-0RL(Ia{wJA%xLJN)Z4U04fqfKuY-^-wq&2DbZ|K(QH?hm$_JG1yE5sm|l~5-PxxG zIOa$IV7XXpmqp?pQ!hic3P6K19sA%O!>B(u0HgjK++&!IeWWuEZ3?A4-i9j`XxvmZ z!0XGqTGv`-L_v(nz<0DcXk1r}2_#+Jo&ngsQn=YFKL_k)JPKljn{D>3HBmSUVqBb` z)>I25YNdE&3@8AoaC(%jpQ%vFTLIay6+jT1Z~M-_ePoPy%y6Lt00000NkvXXu0mjf D`iQ9J diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/light_blue_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/light_blue_anti_radiation_helmet.png deleted file mode 100644 index 1b9a7c1c846a1b242c1bb1be784e90afeb8d0686..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 415 zcmV;Q0bu@#P)jE_NYU2hs>) zND&BmfhG6?OGqj$w6vCx2S{ZTEYgjT#zHXQ{y>P`T7*07%#L`fxo78m?47w|!Jx)? znwtDcw{GcP&S;FM>G9Da?7dyZPu3f}FF$e+>#y*9Arye;kP)(@{{e>w=M}{tyb5>@ z$vSxZtn}ULSHaXPi-?puS#PrC4*=uSRV7^cfi{&{aZ-)0u01wV=UFcd|vLpK|HD>Nmm&{zoljCk&lF(NJ|ONV@f zhb*Dg#ThenHu)H%HFW7vkg%XzI)o=IS*3T_JoVGoIbB3zgjQ~}(1Lq8Fd%`diQIVzzj>iuh*leC1z<&Q`*URM-wC+*Y zP2|i$S*}MDNZM{+09K@i5j3wE&x=b?qM3G51~u874|*QSf6Q@JkK zN!}oZZx94uAfTOikB};F5O5E!Nty^*(gf_*LU!Fh6F)duzMJ{&%*qHL=UyTBPbj=w>Tx>^O0=uq;anmd4urOagR}ooKJMhTVyD z07(i30E=pljO9T>#&UBrI@YKt+bT(+k`(G?d2iPKXaCc~7HL2$ZsP6n(?G|sZWYtJ zzqz=5zQj)MF&nHS2N0jc!36r+poZK^184xhGrp61$gTA6`e5=6d$=+!*k_?Dp=9r@ pJ@PTN;wB03lSzPvP(JmXe*iB~l^quP4dnm;002ovPDHLkV1kN4sQ3T? diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/magenta_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/magenta_anti_radiation_helmet.png deleted file mode 100644 index 79eccd875ad425d9fdc5b92961adda87aa5d6dfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 399 zcmV;A0dW3_P)g5HF-4n&%XFH@HUk1cE6i${a1>gm~6>_BSfWoy=UGbCgC%nKH^Y{3z z*620AOSWD~j4`7PNjU%*04idPfph*J-wq&g&Jniy2wQ#OX$M=j0;ot1%41Ta*Zffc zw`bP{03^$ma#$oU@WstgtpL!&nJi*>fsa8nGysEW2ruw4S;UYt4o%8#1y8TfA~3#> z6u{`^L5v^oLTs`%+Ow{s08Xpt#tYQ7&vwYutpJpOzc;?g*2vSXe%A-X^&562S|G_g tu}NN;JnLsFyA>-y4_g5QvH7;|{0n-vk)c4d8k+zB002ovPDHLkV1oaOtlPo!JuBVnw$Lg zU~Z|NX7rlX{LJ0K-mWeAU*ErYkAF0XwJ97;QV9@vjuEn@o`Axq_e05#9zz74!}p&L zCvLejj%^hn%J+S(4M8aYXaFkmeIJam|M+GAi7|#&qmEXi&OPN~OGW?{i9vBqDtE>o z5}>xfodZBLNu|po1)jrShH5#02B$k(A@Cf8{iy~B`%?s-gYIYrF=NrDQY_%^E#`rj z>mvzp^E%_}rwbR$Btv^Jx1>3EzB<$4FEN41Q5jJo4)fO&;X2VVLHK700000NkvXXu0mjf D^cSPA diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/pink_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/pink_anti_radiation_helmet.png deleted file mode 100644 index 26955cd54ff3d16a4316b11bac55520f56db1099..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wk0|TRz zr;B5VMQ?J-0j9oVA%Bjm-FaNs4fgJkJKAvOo}0yPZL`@A{~qV(x#n#p5y&r!Uoo?iBu00MZ5U}gRQZX0vihHw6USH z*l*Z^51_Hsf&v;!W5-8KM{Hz63=LtHtXT{4CObQWx0<L)lL% zu3lL}2&;{P6aZKNE)qgOO8Fn(4PZ$r(QOaVZ4b0py4YhUfQyR3;+i#-{T~BxR=v&v zAlW3wWw9tE{W4su0X#VK)dUn0ri+mUm@Y=3kT73OP|SF|srvywzu$GB(|R%hv#(dZ zzBzqBnkkHzk!Q@o-T9+6fvo$>X8`+G+Ga}o6<|N(X{NBvRQat9aX8HsE>2okx&;=u va^we20EdgC?EFmi1Auba31EoJcYWtS(<_Zzu}nF700000NkvXXu0mjfcp0V| diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/red_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/red_anti_radiation_helmet.png deleted file mode 100644 index baadfee21c4cfe901c1760648f105e54abcdc5dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 407 zcmV;I0cie-P)c5)&ng3(nyf+LQ^*p!G`GZ-+%3j6j zd2VrPS=ciT#sAK7ysuUj2-_AOEmH;HJGK_GQ$7KOZ(ra3%%Z^a^%Z=_7S_}GncE#t zBBKnD#W~-clZi4Ur2tR?&?e3~f*|;huLqEVAV8A$-TiFrGusF#4#Q23|hDMBu*J zPymnNhgjbn9U{qc3}z8i=HSk2R3?!0aMA>@?$RRr5xxPeXFS>bDD_$qg_A7DMQ#65 zlt7|V4$R7c0)Pn1qpW>Q^(|$T!&(4AbiVF6{{jQ?j*$xZ?zsQ}002ovPDHLkV1gKw BvRwcG diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/white_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/white_anti_radiation_helmet.png deleted file mode 100644 index 95283572329fc11a0c75442a63cf20be5a80224d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F3${@^GvDChdfq~K3 z)5S5wqPKPO-rU0m0&eonQ!?*t2wQqCVQLVAdck7WkZLa9hq^4x^Bfw~16H%L#0YME zIpdJktSL`^tnS$T``*Xr8BQE)u9n_4`!QkVYb*X1ffu{#v>#T~p7VTWq67m^ zLz7*&?4q6Tf9pKld))H40gt0%bwh?;ms0ol+WznJmh5JI^7v>ZqsHl?;vSd%4AKo^ zQ&Ue`^!@+%opDv6Oy;b%WtmAir5odSGw6EtzLdHU{`(|D?rpXc`r1>!+wJqYz3pLz z4b%B>4(~_04#nQiird6ExGtd4$tTIA@m;`ObR;)1<#=E5s3y*>Z= zjES$|ItFE>!hi9OSN4?r_hXF6Ha;=$%9}aH-+#|twQ3%NU?q3pXA|F$(62Xs{W6cr zu4E0|+`-Uq|B>CobFsO&^HVEenDV7Yc&7RKGH3zW96$^Lmx3pQC{I^Emvv4FO#sm^ BsKfvO diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/helmets/yellow_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/helmets/yellow_anti_radiation_helmet.png deleted file mode 100644 index 518fb040a2561e2e9c76a2b37e569a0acd3a9542..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wk0|TRv zr;B5VMQ?J-0j6nNv;QAglMAh!Dj3V-oDjMDTYasl92=vZn8-)|`Tq=J_IzeNEZ`P1 zi+|qlhNOnQ6B)vs1J))cG-QVr$95>y6_ndF0|n>&f4pR|MElQw;XXJ1a4~0PWl7v~ zV6vA00t21~&7k1mbn2_Lkx@&-KoEq#y*ANUi;x)8^br65zp9i}L=>bJo3qXO z5Ijkmm$8NXf$2kca6s6T9xdEVB zue?x1SlTB5_VqWfFO}C#L$Rv$$_u(^wCQmt1|RQlpz6hc0wX5$Pv0QTa;~ouFLtg5 zU}7djQ9NwWjp|(OyB4L@XiNftP4(QSxqleN_tvOQ+gptB>pI5+oJ=Rpazq3XALlD$g9P#A`vb7B%Ip=up8jZi39baQg>5(3@zUOM(t z3cUj_p@WlC2@ZjPKa)R81rw6vAUQ4**E% zp;U=dB>=tSYrZ}o$$u8w+iMntQB1dcz{%+)$#OMz&@!oT|ZaYW%ZpeCPZE^@eONHJV9w00000NkvXXu0mjfUaN`= diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/brown_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/brown_anti_radiation_leggings.png deleted file mode 100644 index 4935e7a68434f5228b37833a02a2eaaba034049a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 334 zcmV-U0kQsxP)Lkv~hrKp4h6+h|S>``nik00ITIfthLF z2fEMG%Y^5u_QZfR4x6L>T>yrou?3Y6*B561yuMdtd0{yvl{FlVEwCtKjN| diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/cyan_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/cyan_anti_radiation_leggings.png deleted file mode 100644 index 7aaed8489d21927aa023a2db5626f26fad20e274..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335 zcmV-V0kHmwP)LkugdGK@^6+apDHDaqT1K1~#$s0s$d~M_90Oy-mO^ z0>U1`$_rST#v2Gm>>_3Zt~-v!kRf4S$V&cd-pBm^yf+W_l-ekIeH)z(sGgr3h}vLk zFvgYV7gR4(?Ce#E0dbny=(G>Od@}Y%wC4Ew7J#4G8)cDuUrTChJ{fz%x~%yP*hawe z@qwkOy?JF&`apUo4Co9;9QIDUx&C-}0o@~7Ng@V_(JOOVLkxNU%Komw#ZnCgoA)AW2P<-rzN%w&Siu!X~Fd!t5 zy${^`K$liZHX0Yr#D#RI%#=p@?dD_7na70<<18J;RaH4wL7b%R?%qBC*<`Fi5n*(33BYvvPFdud^K943CSwgOr)iYY{SiFe-EyyP zG`s*@S8V5)f*_0-40bd;n|%PV)$7sU?pp;`^#U%7+$oFP`L643HvqWKt^hb24mA>{b}87>kYwwU~A$e gZQ~?uyY?IB2U@sqk8EJu5dZ)H07*qoM6N<$f(Ag13;+NC diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/green_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/green_anti_radiation_leggings.png deleted file mode 100644 index ab34ea48c8833d92dc3154f0548d05d1afeb5cc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 334 zcmV-U0kQsxP)Lk-bX9Koo_)NesC02L_836+0Ut*e4+3BSi2Kx3I_q zY++}55p3*S6h&kTF%dKwiE_IQ=iWOPR+O4PYz?vdM85c(4h;cr6 gwT)A4`}!;E7yiy-##q9skpKVy07*qoM6N<$f^mn42LJ#7 diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/light_blue_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/light_blue_anti_radiation_leggings.png deleted file mode 100644 index 5230cf8dfa606189b801131044657e91dad27eac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 356 zcmV-q0h|7bP)Lk*`a{U>t{^SKZ)1{1q&w193r2nup0S2EqmH13_>L z{sV?3%cYxOvKh1qW5Fb5t6?Y_jE2)g5O&iUWG^TC%I&yMdmrBC^Zxk4m{Eg^8Ed0h z-r6C(Is;&`G0k_LQS>tatZk3S>q~m+oe~S&C@I$0Rsd*wEiEd;y#O#bKg-hMf>a$NuM$`kA$L>VT^FtLMhC>Niw*Et8! zA2^JQpEydyg4b?O+$`}*!6>pAH%baON{YIC?EC=94RriaSBA3y0000Lkv(bxK^TUg&19{D)i$vT7Qrr91TV2n@DK|_3R8H9 zEyN<-z#c-7TtZSvE+7GksaI0%GHi;lgJC~$#kZS>dEWW?;KBrli(c=x8V(;=t=<9X zbUHZaaLxfR8a=XJf3Vwq2V#LSNi`VU1CXXOFDj*&PG11nY(B9z^WL>|tu&o^;V@-c zHrT&{GTdAt1rpxeD6iXyS#N`kd)Z5CLY1^fL^yBh$^ z=dS>a$4{+zV~j;n0DmK_$90T1o}hJ%QVOLMTE{23_=L&i8Nh$wDK38EIS~u;JQp`h nyistDEXJ6mGA60o@{98ez&UaoWKhIN00000NkvXXu0mjfL%oS? diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/lime_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/lime_anti_radiation_leggings.png deleted file mode 100644 index ed28ad85b95df7a8c354d763862ee6cf2c331169..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 347 zcmV-h0i^zkP)LkugidP!xr~7~8>sh<1E~OF^)LYbQqu4w*7^$kx@_ zr65@Z|3kM>I&{h);=d475DG44)KCgK7}7Y@zP7w8P3hU*dG9;--gjX`S&N6-DaBFC z=Bb+lP;p?ALH;wnKWW>%_H#ZS=iE|25UZkDKLeoS_cUl%;c9RW!1M5h$V)W0Ew$D0 zdm32OH)F$F3b?;cxXb474A@~;s$&MYp`uYg*6`c#9e}-k2X$~L25d>@4350SioC=c zrC;Sb0J!xZ0JykOrF>(J*Cfz*WBZiR(xV tNIz5YvE&;8>%gLdSQSC6in9L3`UL_iWsXK|6GH$1002ovPDHLkV1krcl_3BC diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/magenta_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/magenta_anti_radiation_leggings.png deleted file mode 100644 index e0db666ad7179158d76d435178d5d4baa7a3076c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 351 zcmV-l0igbgP)Lk+Dj{P#A^38$=SR)Jd>|dj}DG0jGk=7!3Fju_dj8 z570@fEu10pwMv$Zwb^#h^rb$OLk-bU-K@>*MxETqFV6h4tMJz?IvKF>XVI_;Cu-Mnw zNANMSg+-9X$_MZTtODW#tge5Z5y_Yxi;y8QGbEC)+mAVCFZaTV5%V91TT-7Mw7DLB z0??8IRfC#n0M3s#xP2V)@UDbYkSCEo*>3{S?Ux3Wf#Bw17l8YxZ_=VNT*Eb1w_h4y zKI5O->i!5W?>9Pcy@JbWDku-y*W+mud$Q$2&zq7rFQiMP?j zJAoxQyDI4oo~?(z-a6x#nr^-&g*lh6w`VNu={6(#!TM=NI%darB}5-Lk-bX8P#A`vB-RW<)lCO+aOtKlB4qFeO2Ek>0XujF z#UW>q;*{Ki;3CAqNs!)vLqJ?yyC{f`;vaOVO^k!&P{}7v>ARhW^StNhgDGQ-E}Hd~ zyt%o}#qBi!b2XbZOBsA;0PJn;(7n5%`}t&u1&JTzYa8nTv^s4q+NQ;+3ITZR^>E@y zdo$9tTAj8QMw1P{O6*TTcy&&Cd8Xw;uxhi?IpqT7daO1YT7JHN0AO)`f%@{2SYS%9 zkexU(oH#PxKHjU{0N@~0037Y^SK_5H_J;%DcZ9{b{^O-5DA&U_Eo{?5x!zbVKH=o> z7(jpEI4*wTBoPbxFR$WeiI)l{k;No_kSBhSSLIXZ2NVT#S*}F#zW@LL07*qoM6N<$ Ef-TINVgLXD diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/purple_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/purple_anti_radiation_leggings.png deleted file mode 100644 index a2fa6ec29d0708bd862bd55ca21f9a6933d01588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 346 zcmV-g0j2(lP)Lk+Dj{P#A^3o5tAGy4bWGq}?3EQ3nb720{tgH;}$U zpP?_%!B+@WdIqzS<^Vb8(XKdgUs3=S9FIH%{M+TlR=K$>6RqA^+F+hw?;V>GiFdC}g z)w0|V03P4(0k~@3mhy9FOqaKnYtB{V=PLMKfQ5sFgYN|!eX+t#=MKOOxXCZRPf3XZ si-Of9KNqkKEUMog>3(~p%lbQO4HE%usGhg<<^TWy07*qoM6N<$g1wfH+W-In diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/red_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/red_anti_radiation_leggings.png deleted file mode 100644 index 8f4ac0519feb44e81f2aeab2f986eb101d03fddd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 334 zcmV-U0kQsxP)Lk~>brKomvKvmFPBQrJY6la7j-id|S@7p^E+MJj5q zgI!Q%2^2)easfzDkYeHtg_TjzyeNrsySX#x>U{>zlpF07*qoM6N<$f{Koa;{X5v diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/leggings/white_anti_radiation_leggings.png b/src/main/resources/assets/createnuclear/textures/item/armors/leggings/white_anti_radiation_leggings.png deleted file mode 100644 index 1763c81fde856575986a3c514cfc4fd9190270da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 324 zcmV-K0lWT*P)Lkuj=-KoCUB<%8e>jAfEej7^Nq3=AgnG@iz&0|PTp zA$WpG1esWn3Hk>gWtSQMvTSAj=qj2n;7di%L!Rf-G!6Q`2LL2V0_Pl@a{z$0Z7~c3 zmSu_jC;-eX)>^UF3K5A?N|aJUL}H8)V~jAfJbQjZL1kHDnkJ7Q$KkP;fUfJ{oV(1Y zA&%qV#le80C@%9n&j5flO_60;FyIk_r&((qX|1De+ioxL0;;M)UDw{?9rtS7_Z`4r zg=bxN+!Hek5eX5!)OE*!K#k)#0>JgacRcvSPZSJT*EP5t;$FZf=Af9_d(?mYYyAQV W#*d8d#>3qJ0000LkugZaKp2I;3rP(bLTeMgA_MIPzq>J$L2q-{XYRh%8J0B~8p6Q`x&TxqOU z(l)@Lx?kUx_a|Wg=z+aT8@LZNCLHMMq+P$$Z*7;VAozLHY2fkzKs`IT0vLwWF6`rfel5nUGLX9T}%K&D9 z!~FVwMwA%v_$qH*@~wdXz@myg(nTKWQT?&?10Qg7DYFSo`v3p{07*qoM6N<$f}$aj Au>b%7 From 814c7af9d826b95a716177829f7bd9c1eee09419 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:52:04 +0200 Subject: [PATCH 074/171] fix: update reactor crafting recipes to use bucket instead of uranium fluid --- .../recipe/CNMechanicalCraftingRecipeGen.java | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java index eedc2df3..ec898cce 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNMechanicalCraftingRecipeGen.java @@ -47,7 +47,7 @@ public class CNMechanicalCraftingRecipeGen extends MechanicalCraftingRecipeGen { .recipe(b -> b .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) .key('G', Ingredient.of(CNBlocks.REINFORCED_GLASS)) - .key('B', Ingredient.of(CNFluids.URANIUM.get().getBucket())) + .key('B', Ingredient.of(Items.BUCKET)) .key('S', Ingredient.of(CNTags.forgeItemTag("ingots/steel"))) .patternLine("CCCCC") .patternLine("CSGSC") @@ -56,59 +56,59 @@ public class CNMechanicalCraftingRecipeGen extends MechanicalCraftingRecipeGen { .patternLine("CCCCC") ), - REACTOR_CONTROLLER = create(CNBlocks.REACTOR_CONTROLLER::get) - .recipe(b -> b - .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) - .key('V', Ingredient.of(AllBlocks.ITEM_VAULT)) - .key('O', Ingredient.of(AllBlocks.SMART_OBSERVER)) - .key('T', Ingredient.of(AllItems.ELECTRON_TUBE)) - .key('N', Ingredient.of(Items.NETHERITE_INGOT)) - .key('X', Ingredient.of(Items.NETHER_STAR)) - .patternLine("CCCCC") - .patternLine("CNONC") - .patternLine("CTXTC") - .patternLine("CNVNC") - .patternLine("CCCCC") - ), + REACTOR_CONTROLLER = create(CNBlocks.REACTOR_CONTROLLER::get) + .recipe(b -> b + .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) + .key('V', Ingredient.of(AllBlocks.ITEM_VAULT)) + .key('O', Ingredient.of(AllBlocks.SMART_OBSERVER)) + .key('T', Ingredient.of(AllItems.ELECTRON_TUBE)) + .key('N', Ingredient.of(Items.NETHERITE_INGOT)) + .key('X', Ingredient.of(Items.NETHER_STAR)) + .patternLine("CCCCC") + .patternLine("CNONC") + .patternLine("CTXTC") + .patternLine("CNVNC") + .patternLine("CCCCC") + ), - REACTOR_COOLING_FRAME= create(CNBlocks.REACTOR_COOLER::get) - .recipe(b -> b - .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) - .key('I', Ingredient.of(Blocks.BLUE_ICE)) - .key('G', Ingredient.of(CNBlocks.REINFORCED_GLASS)) - .key('S', Ingredient.of(CNTags.forgeItemTag("ingots/steel"))) - .patternLine("CCCCC") - .patternLine("CSGSC") - .patternLine("CIGIC") - .patternLine("CSGSC") - .patternLine("CCCCC") - ), + REACTOR_COOLING_FRAME= create(CNBlocks.REACTOR_COOLER::get) + .recipe(b -> b + .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) + .key('I', Ingredient.of(Blocks.BLUE_ICE)) + .key('G', Ingredient.of(CNBlocks.REINFORCED_GLASS)) + .key('S', Ingredient.of(CNTags.forgeItemTag("ingots/steel"))) + .patternLine("CCCCC") + .patternLine("CSGSC") + .patternLine("CIGIC") + .patternLine("CSGSC") + .patternLine("CCCCC") + ), - REACTOR_CORE = create(CNBlocks.REACTOR_CORE::get) - .recipe(b -> b - .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) - .key('P', Ingredient.of(AllItems.PRECISION_MECHANISM)) - .key('B', Ingredient.of(CNFluids.URANIUM.get().getBucket())) - .key('S', Ingredient.of(CNTags.forgeItemTag("ingots/steel"))) - .patternLine("CCCCC") - .patternLine("CPSPC") - .patternLine("CSBSC") - .patternLine("CPSPC") - .patternLine("CCCCC") - ), + REACTOR_CORE = create(CNBlocks.REACTOR_CORE::get) + .recipe(b -> b + .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) + .key('P', Ingredient.of(AllItems.PRECISION_MECHANISM)) + .key('B', Ingredient.of(CNFluids.URANIUM.get().getBucket())) + .key('S', Ingredient.of(CNTags.forgeItemTag("ingots/steel"))) + .patternLine("CCCCC") + .patternLine("CPSPC") + .patternLine("CSBSC") + .patternLine("CPSPC") + .patternLine("CCCCC") + ), - REACTOR_ALARM = create(CNBlocks.REACTOR_ALARM::get) - .recipe(b -> b - .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) - .key('N', Ingredient.of(Blocks.NOTE_BLOCK)) - .key('R', Ingredient.of(Blocks.REPEATER)) - .key('L', Ingredient.of(Items.CLOCK)) - .patternLine("CCCCC") - .patternLine("CNRNC") - .patternLine("CRLRC") - .patternLine("CNRNC") - .patternLine("CCCCC") - ); + REACTOR_ALARM = create(CNBlocks.REACTOR_ALARM::get) + .recipe(b -> b + .key('C', Ingredient.of(CNBlocks.REACTOR_CASING)) + .key('N', Ingredient.of(Blocks.NOTE_BLOCK)) + .key('R', Ingredient.of(Blocks.REPEATER)) + .key('L', Ingredient.of(Items.CLOCK)) + .patternLine("CCCCC") + .patternLine("CNRNC") + .patternLine("CRLRC") + .patternLine("CNRNC") + .patternLine("CCCCC") + ); public CNMechanicalCraftingRecipeGen(PackOutput output) { From 0e9bf944797cf54d5f0055f42488e14d17825482 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Wed, 24 Jun 2026 09:55:58 +0200 Subject: [PATCH 075/171] changed version --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 48925c77..1f5643e4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.9-alpha +mod_version=2.0.10-beta # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html @@ -73,4 +73,4 @@ mod_group_id=net.nuclearteam.createnuclear mod_authors=Create Nuclear Team # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. mod_description=Create nuclear is a mod that adds a whole nuclear system to the create mod. An optimized reactor produces over two millions SU. -mixin_config = 'createnuclear.forge.mixins.json' \ No newline at end of file +mixin_config = 'createnuclear.forge.mixins.json' From 91e5e997f436a97be8f6600ebfb4d7f4d893dcc8 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:57:38 +0200 Subject: [PATCH 076/171] fix: skip irradiated vision overlay for creative and spectator modes --- .../events/overlay/IrradiatedOverlayRendererVision.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java index 61f0ca61..09565686 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/overlay/IrradiatedOverlayRendererVision.java @@ -20,7 +20,13 @@ public class IrradiatedOverlayRendererVision { public static void renderOverlay(ForgeGui gui, GuiGraphics graphics, float partialTicks, int width, int height) { Minecraft mc = Minecraft.getInstance(); - if (mc.options.hideGui || mc.gameMode.getPlayerMode() == GameType.SPECTATOR) return; + GameType playerMode = mc.gameMode.getPlayerMode(); + // Skip the irradiated vision overlay in creative/spectator: the effect icon still + // shows in the HUD so the player stays aware, but the screen overlay is not applied. + if (mc.options.hideGui || playerMode == GameType.SPECTATOR || playerMode == GameType.CREATIVE) { + irradiatedVisionAlpha = 0.0f; + return; + } LocalPlayer localPlayer = mc.player; if (localPlayer == null) return; RenderSystem.enableBlend(); From 2d8f7454499f112256ebd23065d8dd6914178fd3 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 10:17:47 +0200 Subject: [PATCH 077/171] fix: adjust ore generation rates for thorium and uranium ores --- .../infrastructure/worldgen/CNConfiguredFeatures.java | 2 +- .../infrastructure/worldgen/CNPlacedFeatures.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java index 314120c2..a79a9ac9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java @@ -52,7 +52,7 @@ public static void bootstrap(BootstapContext> ctx) { OreConfiguration.target(stoneOreReplaceable, CNBlocks.THORIUM_ORE.getDefaultState()), OreConfiguration.target(deepslateOreReplaceable, CNBlocks.DEEPSLATE_THORIUM_ORE.getDefaultState()) ); - register(ctx, THORIUM_ORE, Feature.ORE, new OreConfiguration(thoriumTargetStates, 16)); + register(ctx, THORIUM_ORE, Feature.ORE, new OreConfiguration(thoriumTargetStates, 12)); List nitrateTargetStates = List.of( OreConfiguration.target(stoneOreReplaceable, CNBlocks.NITRATE_ORE.getDefaultState()), diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java index b2620591..a4427c23 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java @@ -35,11 +35,11 @@ public static void bootstrap(BootstapContext ctx) { Holder> nitrateOre = featureLookup.getOrThrow(CNConfiguredFeatures.NITRATE_ORE); Holder> striatedOresOverworld = featureLookup.getOrThrow(CNConfiguredFeatures.STRIATED_ORES_OVERWORLD); - register(ctx, URANIUM_ORE, uraniumOre, placementOres(CountPlacement.of(7), -63, 16)); + register(ctx, URANIUM_ORE, uraniumOre, placementOres(CountPlacement.of(5), -63, 16)); register(ctx, LEAD_ORE, leadOre, placementOres(CountPlacement.of(10), -16, 60)); register(ctx, THORIUM_ORE, thoriumOre, placementOres(CountPlacement.of(8), -16, 55)); register(ctx, NITRATE_ORE, nitrateOre, placementOres(CountPlacement.of(6), -63, 64)); - register(ctx, STRIATED_ORES_OVERWORLD, striatedOresOverworld, placement(RarityFilter.onAverageOnceEvery(5), -63, 16)); + register(ctx, STRIATED_ORES_OVERWORLD, striatedOresOverworld, placement(RarityFilter.onAverageOnceEvery(1), -63, 16)); } From 0daa590fcd7b86d5d23d569ecd23987bfa90d69c Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 10:51:37 +0200 Subject: [PATCH 078/171] fix: rename irradiated biome and add new irradiated land configuration --- .../biome/{irradiated_plain.json => irradiated_land.json} | 2 +- .../worldgen/noise_settings/irradiated_noise.json | 6 +++--- .../infrastructure/worldgen/biome/CNBiomes.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/generated/resources/data/createnuclear/worldgen/biome/{irradiated_plain.json => irradiated_land.json} (99%) diff --git a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_plain.json b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json similarity index 99% rename from src/generated/resources/data/createnuclear/worldgen/biome/irradiated_plain.json rename to src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json index 7570a5c4..1a39be70 100644 --- a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_plain.json +++ b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json @@ -48,4 +48,4 @@ "water_creature": [] }, "temperature": 2.0 -} \ No newline at end of file +} diff --git a/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json b/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json index d705b8a8..b59dbcfe 100644 --- a/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json +++ b/src/generated/resources/data/createnuclear/worldgen/noise_settings/irradiated_noise.json @@ -169,7 +169,7 @@ "if_true": { "type": "minecraft:biome", "biome_is": [ - "createnuclear:irradiated_plain" + "createnuclear:irradiated_land" ] }, "then_run": { @@ -264,7 +264,7 @@ "if_true": { "type": "minecraft:biome", "biome_is": [ - "createnuclear:irradiated_plain" + "createnuclear:irradiated_land" ] }, "then_run": { @@ -289,7 +289,7 @@ "if_true": { "type": "minecraft:biome", "biome_is": [ - "createnuclear:irradiated_plain" + "createnuclear:irradiated_land" ] }, "then_run": { diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java index e20dbd6b..c8b562e8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java @@ -12,7 +12,7 @@ public class CNBiomes { public static final class Irradiated { - public static final ResourceKey PLAIN = key("irradiated_plain"); + public static final ResourceKey PLAIN = key("irradiated_land"); } public static void bootstrapRegistries(BootstapContext context) { @@ -25,4 +25,4 @@ public static void bootstrapRegistries(BootstapContext context) { public static @NotNull ResourceKey key(String id) { return ResourceKey.create(Registries.BIOME, CreateNuclear.asResource(id)); } -} \ No newline at end of file +} From 069951bbca2a6aeb08910aa343c265da50ddae09 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:15:25 +0200 Subject: [PATCH 079/171] fix: update cloth dyeing recipe to prevent dyeing with the same color --- src/main/java/net/nuclearteam/createnuclear/CNItems.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 73b2e981..781da4b9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -403,7 +403,12 @@ private static NonNullBiConsumer, Regis .tag(CNItemTags.CLOTH.tag) .recipe((c, p) -> ShapelessRecipeBuilder.shapeless(RecipeCategory.BUILDING_BLOCKS, c.get()) .unlockedBy("has_white_cloth", RegistrateRecipeProvider.has(ClothItem.Cloths.WHITE_CLOTH.getItem())) - .requires(CNItemTags.CLOTH.tag) + // Accept any cloth EXCEPT one already of the target colour, otherwise the + // recipe would let you "dye" a cloth into the colour it already is. + .requires(Ingredient.of(Arrays.stream(DyeColor.values()) + .filter(other -> other != color) + .map(other -> ClothItem.Cloths.getByColor(other).get()) + .toArray(ClothItem[]::new))) .requires(ingredients.get(color.ordinal())) .save(p, CreateNuclear.asResource("shapeless/cloth/" + c.getName())) ) From 8aef32a9ccc167c92da3da89849590690a967f86 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:47:19 +0200 Subject: [PATCH 080/171] fix: update cloth crafting recipes to use specific colored cloth items --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 34 ++++++------- .../708b1206ce73e235f43eb2a5fd72b93671cfba4e | 4 +- .../fed443662143001aeb5341375f6f5ef31d10baea | 12 ++--- .../mechanical_crafting/reactor_frame.json | 2 +- .../recipes/shapeless/cloth/black_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/blue_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/brown_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/cyan_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/gray_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/green_cloth.json | 50 +++++++++++++++++-- .../shapeless/cloth/light_blue_cloth.json | 50 +++++++++++++++++-- .../shapeless/cloth/light_gray_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/lime_cloth.json | 50 +++++++++++++++++-- .../shapeless/cloth/magenta_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/orange_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/pink_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/purple_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/red_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/white_cloth.json | 50 +++++++++++++++++-- .../recipes/shapeless/cloth/yellow_cloth.json | 50 +++++++++++++++++-- .../worldgen/biome/irradiated_land.json | 2 +- .../configured_feature/thorium_ore.json | 2 +- .../striated_ores_overworld.json | 2 +- .../worldgen/placed_feature/uranium_ore.json | 2 +- .../nuclearteam/createnuclear/CNItems.java | 2 +- .../output/ReactorOutputEntity.java | 2 +- 26 files changed, 784 insertions(+), 80 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 8353a659..ed796bc8 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-22T19:57:09.3633092 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-24T11:17:44.2114024 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -507,22 +507,22 @@ af81c9ed277e6f3d0d9e48d413247debcc7b64be data/createnuclear/recipes/polished_cut 9cd62ff9cbce5c4a5293c7bfcb9c8c35d68ea91e data/createnuclear/recipes/polished_cut_autunite_stairs_from_stone_types_autunite_stonecutting.json e74d31ed68a39baca7d719338fdfeb71a9cea9a4 data/createnuclear/recipes/polished_cut_autunite_wall.json bd7dd55600eb9ddebb17ac6932cf77f0538bfe02 data/createnuclear/recipes/polished_cut_autunite_wall_from_stone_types_autunite_stonecutting.json -1713ce33da8ce2fd0145e9921cab615d31fa5e66 data/createnuclear/recipes/shapeless/cloth/black_cloth.json -0d0c71a2b494a34439cb2d7873b31083b07877b0 data/createnuclear/recipes/shapeless/cloth/blue_cloth.json -e6ec8d394df502aa1dcebd16d1ed0275f92e9d2a data/createnuclear/recipes/shapeless/cloth/brown_cloth.json -8d0f363323584bcdefe7803e9057f252b63fd12d data/createnuclear/recipes/shapeless/cloth/cyan_cloth.json -fff014f30a041fad100ceefcf70ed9e8a00c318c data/createnuclear/recipes/shapeless/cloth/gray_cloth.json -cdd6de83eccb34f7bc4f38c6a92a32a74b7b3ff7 data/createnuclear/recipes/shapeless/cloth/green_cloth.json -fe147f38895f8b99412c53a6f7530a1e9575003c data/createnuclear/recipes/shapeless/cloth/light_blue_cloth.json -ab94d1c13af2e4bef0c92b8486108940180d3f9d data/createnuclear/recipes/shapeless/cloth/light_gray_cloth.json -2cd96d4f78b81393bff120448e9a14235cf2376b data/createnuclear/recipes/shapeless/cloth/lime_cloth.json -a22692736ff403a44bca8ef34b5f97a855eb0a7a data/createnuclear/recipes/shapeless/cloth/magenta_cloth.json -bbc2714fa8586db7d42db2c1e4375accd7c264d2 data/createnuclear/recipes/shapeless/cloth/orange_cloth.json -d6be8ab92dd0caa9df946afb83868ce278c2c437 data/createnuclear/recipes/shapeless/cloth/pink_cloth.json -fa041c5a7e252bed6dc4636a45e5857d7e14dcb1 data/createnuclear/recipes/shapeless/cloth/purple_cloth.json -c863e58a1e11f9b8a925b08b321d45f76cb96de4 data/createnuclear/recipes/shapeless/cloth/red_cloth.json -2d315d82efde22d511e339baec628babdce5767f data/createnuclear/recipes/shapeless/cloth/white_cloth.json -fac232af7ba0edf6cf8e0f018cf53678457e652e data/createnuclear/recipes/shapeless/cloth/yellow_cloth.json +7d07afbab06c52adaf8463f256c238eb59e2969a data/createnuclear/recipes/shapeless/cloth/black_cloth.json +4f14ccebaae840b99856155c779da52cc820c0fd data/createnuclear/recipes/shapeless/cloth/blue_cloth.json +14d9c62de0aa59106b31785092acd2d1f4f5fa78 data/createnuclear/recipes/shapeless/cloth/brown_cloth.json +481f0fcad9e386443f4abb193572be6dea20c50a data/createnuclear/recipes/shapeless/cloth/cyan_cloth.json +8cb32e458634f2217f7b8fc0cb785cbbddb3e98d data/createnuclear/recipes/shapeless/cloth/gray_cloth.json +b67355b2e6d9b792cc18ed12a95487277c27469c data/createnuclear/recipes/shapeless/cloth/green_cloth.json +66de7a4a6f768e68b6a81a1510c3b4f1ae62b2fe data/createnuclear/recipes/shapeless/cloth/light_blue_cloth.json +b04f0b6f3875abf2207f19951f6a078e7445bb83 data/createnuclear/recipes/shapeless/cloth/light_gray_cloth.json +9f43e08955d8c269ec514e4bb66d186f1b60f34f data/createnuclear/recipes/shapeless/cloth/lime_cloth.json +5a3bd7aeee574101cff4ab42aadfcc697ac05a16 data/createnuclear/recipes/shapeless/cloth/magenta_cloth.json +b282815b9b858c78ba00870d4e795bc50d1c0380 data/createnuclear/recipes/shapeless/cloth/orange_cloth.json +7e40f80880139ffd26def352e1f0c17b2b05872c data/createnuclear/recipes/shapeless/cloth/pink_cloth.json +1cb11c3bbe8393116da50ac4e181ac1b68fbc7ee data/createnuclear/recipes/shapeless/cloth/purple_cloth.json +389c841c99a2ef68a4eba3dca414952d3c3d9099 data/createnuclear/recipes/shapeless/cloth/red_cloth.json +3a63377f0de2473803fe4b81b2fce121443faa42 data/createnuclear/recipes/shapeless/cloth/white_cloth.json +0e075da2b474cc1ffb430fb612feaca8c5426932 data/createnuclear/recipes/shapeless/cloth/yellow_cloth.json 8e194709b50fd2ca2ef2138b5d2528e092b45e4f data/createnuclear/recipes/shapeless/reactor_blueprint_item_clear.json bf49ba3e1332f0742e933d81ddd0dd9462f175db data/createnuclear/recipes/small_autunite_brick_from_stone_types_autunite_stonecutting.json 01e0af5e7139dc9d887ee026e4d319d5063415e5 data/createnuclear/recipes/small_autunite_brick_slab.json diff --git a/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e b/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e index edb7063e..de59cc55 100644 --- a/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e +++ b/src/generated/resources/.cache/708b1206ce73e235f43eb2a5fd72b93671cfba4e @@ -1,9 +1,9 @@ -// 1.20.1 2026-06-23T14:13:44.403459 createnuclear's mechanical crafting recipes +// 1.20.1 2026-06-24T11:17:44.2189222 createnuclear's mechanical crafting recipes 0a56332199941d1db61ee7512130d2664fd73e46 data/createnuclear/recipes/mechanical_crafting/graphite_rod.json 13bbcaa279d141281856ee7dbed5d3ea105e2389 data/createnuclear/recipes/mechanical_crafting/reactor_alarm.json 85f68439da9d4bb70d1308b7b64db0e30fec9e51 data/createnuclear/recipes/mechanical_crafting/reactor_controller.json 11b4c4d65d4f6981c34e7f97e0e8dc3468376b05 data/createnuclear/recipes/mechanical_crafting/reactor_cooler.json 8228bb2d850dfd474e2ce142ac9a0ff6ab707f07 data/createnuclear/recipes/mechanical_crafting/reactor_core.json -48db9006423a3762a24c7cae7a3534f124aa0e4c data/createnuclear/recipes/mechanical_crafting/reactor_frame.json +9b2a4dee0019fa8506cc26fdd20802e0f5baba1b data/createnuclear/recipes/mechanical_crafting/reactor_frame.json f6eda56d293f771067b1d5b661284ed1ce9e8f93 data/createnuclear/recipes/mechanical_crafting/thorium_rod.json 0a1d26105f14cb2a01b18b9f050c900412f917fb data/createnuclear/recipes/mechanical_crafting/uranium_rod.json diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 66034ea2..2fcb7256 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T09:46:27.9570941 CreateNuclear Generated Registry Entries +// 1.20.1 2026-06-24T11:17:44.2094021 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -10,18 +10,18 @@ afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids 72173023e6a31748692e750db0f5fa8c555d1009 data/createnuclear/forge/biome_modifier/striated_ores_overworld.json 1d15657126bab7c0b4355d0dcb9addc2d417ed01 data/createnuclear/forge/biome_modifier/thorium_ore.json fa32145101dc12ec914684fec8c5cbb995d2c051 data/createnuclear/forge/biome_modifier/uranium_ore.json -738687a49c3cd8473d1c511f55e274637fe44478 data/createnuclear/worldgen/biome/irradiated_plain.json +738687a49c3cd8473d1c511f55e274637fe44478 data/createnuclear/worldgen/biome/irradiated_land.json 211d1391981d173b8bc490e5af1471441e1df37f data/createnuclear/worldgen/configured_feature/lead_ore.json c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_feature/nitrate_ore.json 4f11c0a518c0de7857919983fc638ba551c6630a data/createnuclear/worldgen/configured_feature/striated_ores_overworld.json -8b44cc21bf02cb04704f081ccef4f7114ea59ae8 data/createnuclear/worldgen/configured_feature/thorium_ore.json +aaa284a4e57635bf05f4539125b33a2f9176ed5b data/createnuclear/worldgen/configured_feature/thorium_ore.json b0e1ee7314412507fd7346cb48b29d105f6186ad data/createnuclear/worldgen/configured_feature/uranium_ore.json 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/erosion.json 59d61c02881d710b0426a0955f6945b7a12d219f data/createnuclear/worldgen/density_function/irradiated/final_density.json 7f5f110a211b82bc22627b2f901c5f3c6a1265dd data/createnuclear/worldgen/noise/irradiated/erosion.json -da4ba44d949615000ebce13f04cb97dec24cf192 data/createnuclear/worldgen/noise_settings/irradiated_noise.json +ea836bafce53bcb743cb2de5ba38271291483865 data/createnuclear/worldgen/noise_settings/irradiated_noise.json f11d981e79cf92130a47ad564925d7be26ffbc0b data/createnuclear/worldgen/placed_feature/lead_ore.json e69f61cbb4bf2c50a6123ddc87c024c801bb78d1 data/createnuclear/worldgen/placed_feature/nitrate_ore.json -6b777b9b4e02bd55236cbeaff12529309b939c17 data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json +b46fca88702d24526baa96e08b6b09b7c43e0563 data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json 403caabb9eefec1012db63d6cbd5c1f22ac9e88d data/createnuclear/worldgen/placed_feature/thorium_ore.json -a18aa32c139932d0023abe6caa722992b167114b data/createnuclear/worldgen/placed_feature/uranium_ore.json +3ecef6758d08745789d07e23377e348cf1ddb126 data/createnuclear/worldgen/placed_feature/uranium_ore.json diff --git a/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_frame.json b/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_frame.json index a9e6a52b..c29d711a 100644 --- a/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_frame.json +++ b/src/generated/resources/data/createnuclear/recipes/mechanical_crafting/reactor_frame.json @@ -3,7 +3,7 @@ "acceptMirrored": true, "key": { "B": { - "item": "createnuclear:uranium_bucket" + "item": "minecraft:bucket" }, "C": { "item": "createnuclear:reactor_casing" diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/black_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/black_cloth.json index c97772db..823df287 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/black_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/black_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + } + ], { "item": "minecraft:black_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/blue_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/blue_cloth.json index 7a88326c..338c24c0 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/blue_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/blue_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:blue_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/brown_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/brown_cloth.json index 7c298c77..b7fade83 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/brown_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/brown_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:brown_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/cyan_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/cyan_cloth.json index ea1f9bb7..eec2232e 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/cyan_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/cyan_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:cyan_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/gray_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/gray_cloth.json index 2a9a5180..02839f6b 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/gray_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/gray_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:gray_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/green_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/green_cloth.json index 9de6a6ef..ac547d0e 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/green_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/green_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:green_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_blue_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_blue_cloth.json index b650cede..d7a5328f 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_blue_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_blue_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:light_blue_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_gray_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_gray_cloth.json index 7ad40ccc..659206ec 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_gray_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/light_gray_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:light_gray_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/lime_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/lime_cloth.json index 5f5fed5f..de11efb5 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/lime_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/lime_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:lime_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/magenta_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/magenta_cloth.json index d150ae22..24afa28d 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/magenta_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/magenta_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:magenta_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/orange_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/orange_cloth.json index 7e4cf94b..3cd48ac6 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/orange_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/orange_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:orange_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/pink_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/pink_cloth.json index 4274a3ae..641842e4 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/pink_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/pink_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:pink_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/purple_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/purple_cloth.json index ccedaffe..a5c90635 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/purple_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/purple_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:purple_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/red_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/red_cloth.json index 71820997..3d8bc1cf 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/red_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/red_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:red_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/white_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/white_cloth.json index f479aa89..94e55ede 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/white_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/white_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:yellow_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:white_dye" } diff --git a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/yellow_cloth.json b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/yellow_cloth.json index 34bda8f1..9d97f8ab 100644 --- a/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/yellow_cloth.json +++ b/src/generated/resources/data/createnuclear/recipes/shapeless/cloth/yellow_cloth.json @@ -2,9 +2,53 @@ "type": "minecraft:crafting_shapeless", "category": "building", "ingredients": [ - { - "tag": "createnuclear:cloth" - }, + [ + { + "item": "createnuclear:white_cloth" + }, + { + "item": "createnuclear:orange_cloth" + }, + { + "item": "createnuclear:magenta_cloth" + }, + { + "item": "createnuclear:light_blue_cloth" + }, + { + "item": "createnuclear:lime_cloth" + }, + { + "item": "createnuclear:pink_cloth" + }, + { + "item": "createnuclear:gray_cloth" + }, + { + "item": "createnuclear:light_gray_cloth" + }, + { + "item": "createnuclear:cyan_cloth" + }, + { + "item": "createnuclear:purple_cloth" + }, + { + "item": "createnuclear:blue_cloth" + }, + { + "item": "createnuclear:brown_cloth" + }, + { + "item": "createnuclear:green_cloth" + }, + { + "item": "createnuclear:red_cloth" + }, + { + "item": "createnuclear:black_cloth" + } + ], { "item": "minecraft:yellow_dye" } diff --git a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json index 1a39be70..7570a5c4 100644 --- a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json +++ b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json @@ -48,4 +48,4 @@ "water_creature": [] }, "temperature": 2.0 -} +} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/worldgen/configured_feature/thorium_ore.json b/src/generated/resources/data/createnuclear/worldgen/configured_feature/thorium_ore.json index a0af6e82..f0e17e28 100644 --- a/src/generated/resources/data/createnuclear/worldgen/configured_feature/thorium_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/configured_feature/thorium_ore.json @@ -2,7 +2,7 @@ "type": "minecraft:ore", "config": { "discard_chance_on_air_exposure": 0.0, - "size": 16, + "size": 12, "targets": [ { "state": { diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json index a6ca8578..c217fb10 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:rarity_filter", - "chance": 5 + "chance": 1 }, { "type": "minecraft:in_square" diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json index f5af6eb0..fa2d9e57 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:count", - "count": 7 + "count": 5 }, { "type": "minecraft:in_square" diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 781da4b9..55f38239 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -65,7 +65,7 @@ private static NonNullBiConsumer, Regis ResourceLocation baseParent = p.modLoc("item/" + c.getName() + "/item"); ItemModelBuilder outer = p.withExistingParent(c.getName(), baseParent); // DyeColor.values() is ordered by id (0..15); overrides must be ascending by predicate - // value so vanilla override resolution selects the exact color (returns last match <= value). + // value so vanilla override resolution selects the exact color (returns last match <= value).cloth // The cloth_color property is clamped to [0,1] (see CreateNuclearClient), hence the // (id+1)/16 normalization here must match the value returned there exactly. for (DyeColor color : DyeColor.values()) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java index 6d200c3c..727f35f4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java @@ -31,7 +31,7 @@ public class ReactorOutputEntity extends GeneratingKineticBlockEntity { - public int speed = 1; + public int speed = 0; public float heat = 0; protected ReactorPattern pattern = new ReactorPattern(); From d020976a30c16effab353b5abef20f2b89daf6d7 Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Wed, 24 Jun 2026 11:48:55 +0200 Subject: [PATCH 081/171] heat problem corrected --- .../fed443662143001aeb5341375f6f5ef31d10baea | 2 +- .../ReactorControllerBlockEntity.java | 2 +- .../service/DefaultHeatService.java | 5 ++- .../controller/service/IHeatService.java | 3 +- .../IReactorHeatUpdateCoordinator.java | 2 +- .../service/ReactorHeatUpdateCoordinator.java | 6 +-- .../reactorLogic/DefaultHeatCalculator.java | 44 ++++++++++++++----- .../multiblock/reactorLogic/HeatManager.java | 5 ++- .../reactorLogic/IHeatCalculator.java | 3 +- 9 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 2fcb7256..3e1f0c7a 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T11:17:44.2094021 CreateNuclear Generated Registry Entries +// 1.20.1 2026-06-24T11:36:24.8723899 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index e6efc3e0..0ea986a7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -421,7 +421,7 @@ private void handleAssembledState() { notifyUpdate(); BigFluidStack fluidStack = currentFluidStack(); - heat = heatCoordinator.calculateAndWriteHeat(configuredPattern, fluidStack, totalHeatRatio, inventory, level); + heat = heatCoordinator.calculateAndWriteHeat(configuredPattern, fluidStack, totalHeatRatio, inventory, level, displayState); fluidBuffer = fluidRateCalculator.tick(fluidStack, reactorSize, level, inputFluidManager, fluidBuffer); cycleManager.update(configuredPattern, level, inputManager, level.getGameTime() % 20 == 0); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java index 38202af7..28498b29 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/DefaultHeatService.java @@ -3,6 +3,7 @@ import net.minecraft.world.level.Level; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.HeatManager; public class DefaultHeatService implements IHeatService { @@ -18,7 +19,7 @@ public int getLiquidTimer() { } @Override - public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { - return impl.calculateHeat(bigFluidStack, totalHeatRatio, inventory, level); + public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level, ReactorDisplayState displayState) { + return impl.calculateHeat(bigFluidStack, totalHeatRatio, inventory, level, displayState); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java index c56fa4e8..74478641 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IHeatService.java @@ -3,9 +3,10 @@ import net.minecraft.world.level.Level; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; public interface IHeatService { int getLiquidTimer(); - double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level); + double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level, ReactorDisplayState displayState); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java index 15b93596..90a3c3e1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/IReactorHeatUpdateCoordinator.java @@ -40,5 +40,5 @@ int updateHeatOnly(ItemStack configuredPattern, ReactorDisplayState displayState * @return the calculated heat */ int calculateAndWriteHeat(ItemStack configuredPattern, BigFluidStack fluidStack, int totalHeatRatio, - ReactorControllerInventory inventory, Level level); + ReactorControllerInventory inventory, Level level, ReactorDisplayState displayState); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java index 7710aa97..206d455b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java @@ -86,7 +86,7 @@ public int updateHeatOnly(ItemStack configuredPattern, ReactorDisplayState displ boolean allAvailable = checkPatternAvailability(configuredPattern, displayState, (item, requiredCount, availableCount) -> availableCount >= requiredCount); if (allAvailable) { - heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level); + heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level, displayState); } } configuredPattern.getOrCreateTag().putDouble("heat", heat); @@ -95,8 +95,8 @@ public int updateHeatOnly(ItemStack configuredPattern, ReactorDisplayState displ @Override public int calculateAndWriteHeat(ItemStack configuredPattern, BigFluidStack fluidStack, int totalHeatRatio, - ReactorControllerInventory inventory, Level level) { - int heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level); + ReactorControllerInventory inventory, Level level, ReactorDisplayState displayState) { + int heat = (int) heatService.calculateHeat(fluidStack, totalHeatRatio, inventory, level, displayState); configuredPattern.getOrCreateTag().putDouble("heat", heat); return heat; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index 1e29c0c8..aaf4ba69 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -4,6 +4,7 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Item; import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; @@ -11,6 +12,10 @@ import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; + +import java.util.HashMap; +import java.util.Map; public class DefaultHeatCalculator implements IHeatCalculator { private final int[][] formattedPattern = new int[][]{ @@ -27,13 +32,30 @@ public class DefaultHeatCalculator implements IHeatCalculator { private final int[][] offsets = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} }; @Override - public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat) { + public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat, ReactorDisplayState displayState) { double heat = 0; ListTag list = inventory.getStackInSlot(0).getOrCreateTag().getCompound("pattern").getList("Items", Tag.TAG_COMPOUND); + + Map availableItems = displayState != null && displayState.items() != null + ? new HashMap<>(displayState.items()) + : new HashMap<>(); + + Map actualRods = new HashMap<>(); for (int i = 0; i < list.size(); i++) { ItemStack currentStack = ItemStack.of(list.getCompound(i)); + Item rodItem = currentStack.getItem(); + + if (availableItems.getOrDefault(rodItem, 0) > 0) { + availableItems.put(rodItem, availableItems.get(rodItem) - 1); + actualRods.put(list.getCompound(i).getInt("Slot"), currentStack); + } + } + + for (Map.Entry entry : actualRods.entrySet()) { + int slot = entry.getKey(); + ItemStack currentStack = entry.getValue(); RodType rod = ItemRodTypesValue.getRodType(currentStack.getItem()); String currentRod = ""; if (currentStack.is(CNTags.CNItemTags.FUEL.tag) || (rod.items().size() > 0 && rod.type() == RodType.TypeRod.FUEL)) { @@ -48,7 +70,7 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re for (int j = 0; j < formattedPattern.length; j++) { for (int k = 0; k < formattedPattern[j].length; k++) { if (formattedPattern[j][k] == 99) continue; - if (list.getCompound(i).getInt("Slot") != formattedPattern[j][k]) continue; + if (slot != formattedPattern[j][k]) continue; for (int[] offset : offsets) { int nj = j + offset[0]; @@ -56,16 +78,14 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re if (nj < 0 || nj >= formattedPattern.length || nk < 0 || nk >= formattedPattern[j].length) continue; int neighborSlot = formattedPattern[nj][nk]; - for (int l = 0; l < list.size(); l++) { - if (list.getCompound(l).getInt("Slot") == neighborSlot) { - if ("fuel".equals(currentRod)) { - ItemStack stack = ItemStack.of(list.getCompound(l)); - RodType neighborRod = ItemRodTypesValue.getRodType(stack.getItem()); - if (stack.is(CNTags.CNItemTags.FUEL.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL)) { - heat += rod.proximityRodHeat(); - } else if (stack.is(CNTags.CNItemTags.COOLER.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER)) { - heat += rod.baseRodHeat() / neighborRod.proximityRodHeat(); - } + if (actualRods.containsKey(neighborSlot)) { + if ("fuel".equals(currentRod)) { + ItemStack stack = actualRods.get(neighborSlot); + RodType neighborRod = ItemRodTypesValue.getRodType(stack.getItem()); + if (stack.is(CNTags.CNItemTags.FUEL.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL)) { + heat += rod.proximityRodHeat(); + } else if (stack.is(CNTags.CNItemTags.COOLER.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER)) { + heat += rod.baseRodHeat() / neighborRod.proximityRodHeat(); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java index 75340cb5..d47b1450 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java @@ -8,6 +8,7 @@ import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; /** @@ -26,11 +27,11 @@ public HeatManager() { this(new DefaultHeatCalculator(), new DefaultOverheatController()); } - public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level) { + public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, ReactorControllerInventory inventory, Level level, ReactorDisplayState displayState) { ReactorFluidType type = bigFluidStack == null ? null : bigFluidStack.getFluidtype(level); overheatController.updateState(totalHeatRatio, bigFluidStack, type); - return calculator.computeHeat(bigFluidStack, type, inventory, overheatController.getOverHeat()); + return calculator.computeHeat(bigFluidStack, type, inventory, overheatController.getOverHeat(), displayState); } public int getLiquidTimer() { return overheatController.getLiquidTimer();} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java index 2a32d5a4..ba200fe6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java @@ -3,7 +3,8 @@ import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; public interface IHeatCalculator { - double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat); + double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat, ReactorDisplayState displayState); } From f974d43cddc7bfee706bc285de7b154b9eb965c6 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 13:59:16 +0200 Subject: [PATCH 082/171] fix: improve block removal handling to prevent item loss during state changes --- .../multiblock/input/item/ReactorInput.java | 20 ++++++++----------- .../output/ReactorOutputEntity.java | 5 ----- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java index d0cd83ff..74169e16 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java @@ -16,7 +16,6 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; @@ -79,20 +78,17 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L } - @Override - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - withBlockEntityDo(level, pos, be -> ItemHelper.dropContents(level, pos, be.inventory)); - MultiblockHelpers.handleRemoval(pos, level, ReactorControllerBlockEntity::removeInput); - } - @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { + // Only act when the block is actually removed/replaced, not on a mere state change + // (e.g. a FACING update) — otherwise rotating the block would spill its rods. + if (!pState.is(pNewState.getBlock())) { + // Drop the contents BEFORE super removes the block entity: super.onRemove() + // calls level.removeBlockEntity(pos), after which the inventory is gone. + withBlockEntityDo(pLevel, pPos, be -> ItemHelper.dropContents(pLevel, pPos, be.inventory)); + MultiblockHelpers.handleRemoval(pPos, pLevel, ReactorControllerBlockEntity::removeInput); + } super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); - - withBlockEntityDo(pLevel, pPos, be -> ItemHelper.dropContents(pLevel, pPos, be.inventory)); - pLevel.removeBlockEntity(pPos); - MultiblockHelpers.handleRemoval(pPos, pLevel, ReactorControllerBlockEntity::removeInput); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java index 727f35f4..2ae41883 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutputEntity.java @@ -51,11 +51,6 @@ public ReactorOutputEntity(BlockEntityType type, BlockPos pos, BlockState sta @Override public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); - // generatedSpeed = new KineticScrollValueBehaviour(CreateNuclearLang.translateDirect("kinetics.reactor_output.rotation_speed"), this, new ReactorOutputValue()); - // generatedSpeed.between(-1500000, 1500000); - // generatedSpeed.setValue(speed); - // generatedSpeed.withCallback(i -> this.updateGeneratedRotation()); - // behaviours.add(generatedSpeed); } From e647955151d5f5790b4aa64b498ee228ae16082c Mon Sep 17 00:00:00 2001 From: matteo vocanson Date: Wed, 24 Jun 2026 14:01:21 +0200 Subject: [PATCH 083/171] updated overheat system to match new missing rod system --- .../ReactorControllerBlockEntity.java | 2 +- .../service/ReactorHeatUpdateCoordinator.java | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 0ea986a7..924e39f4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -351,7 +351,7 @@ public void tick() { int heat = (int) this.getConfiguredPatternTag().getDouble("heat"); countCoolerRod = this.getConfiguredPatternTag().getInt("countCoolerRod"); countFuelRod = this.getConfiguredPatternTag().getInt("countFuelRod"); - totalHeatRatio = this.getConfiguredPatternTag().getInt("totalHeatRatio"); + totalHeatRatio = ReactorHeatUpdateCoordinator.calculateActualTotalHeatRatio(configuredPattern, displayState, level); } resolveEntitiesIfNeeded(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java index 206d455b..4bb0f5ec 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java @@ -25,6 +25,28 @@ public ReactorHeatUpdateCoordinator(IHeatService heatService) { this.heatService = heatService; } + public static int calculateActualTotalHeatRatio(ItemStack configuredPattern, ReactorDisplayState displayState, Level level) { + Map patternCounts = PatternReader.readItemCounts(configuredPattern); + Map currentItems = displayState != null && displayState.items() != null + ? displayState.items() : Collections.emptyMap(); + + int totalHeatRatio = 0; + for (Map.Entry entry : patternCounts.entrySet()) { + Item item = entry.getKey(); + int requiredCount = entry.getValue(); + int availableCount = currentItems.getOrDefault(item, 0); + int countToUse = Math.min(requiredCount, availableCount); + + if (countToUse > 0) { + RodType rodType = RodType.resolveRodType(item, level); + if (rodType != null && rodType.isNotEmptyItem()) { + totalHeatRatio += rodType.heatRatio() * countToUse; + } + } + } + return totalHeatRatio; + } + /** Predicate applied to each pattern entry when checking availability. */ @FunctionalInterface private interface PatternEntryCheck { From c87f5a810d22f370d13a12ac05ce897b0aabfbe6 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:19:39 +0200 Subject: [PATCH 084/171] fix: optimize reactor structure rendering to reduce lag for larger tiers --- .../ponder/scenes/CNPonderReactorScenes.java | 150 +++++++++++------- 1 file changed, 89 insertions(+), 61 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 2c4e861b..2b591a3a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -38,6 +38,11 @@ private static class Positions { this.alarm = alarm; this.output = output; } + + /** All blocks that carry an explanatory callout, so a section-based reveal can show them per layer. */ + BlockPos[] specials() { + return new BlockPos[] { controller, input1, input2, liquidInput, alarm, output }; + } } /** * Map statique – remplis/ajuste les coordonnées ici pour chaque taille (multiblockSize). * Exemple : clef = 5 pour S_T1 (5x5), 7 pour S_T2, 9 pour S_T3. * * Règle : x/z en 0..plate-1, y en 1..H ; adapte ces valeurs exactement comme dans ton NBT. */ @@ -97,13 +102,17 @@ private static Positions positionsFor(int multiblockSize, int height) { } private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil util, int S, int H, int plate) { + showReactorStructure(scene, util, S, H, plate, false); + } + + /** + * @param bySections when true, each floor is revealed as a single render section instead of + * block-by-block. Block-by-block creates one {@code WorldSectionElement} per cell + * ({@code H * plate^2}, e.g. 1859 for T3) and they all keep rendering every frame, which + * is what makes the larger tiers lag past ~2/3 of the scene. T1/T2 stay block-by-block. + */ + private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil util, int S, int H, int plate, boolean bySections) { Positions pos = positionsFor(S, H); - BlockPos controller = pos.controller; - BlockPos output = pos.output; - BlockPos input1 = pos.input1; - BlockPos input2 = pos.input2; - BlockPos liquidInput = pos.liquidInput; - BlockPos alarm = pos.alarm; for (int y = 1; y <= H; y++) { scene.overlay().showText(8) @@ -111,59 +120,21 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u .attachKeyFrame() .placeNearTarget(); - for (int x = 0; x < plate; x++) { - for (int z = 0; z < plate; z++) { - scene.world().showSection(util.select().position(x, y, z), Direction.NORTH); - scene.idle(4); - - if (x == input1.getX() && y == input1.getY() && z == input1.getZ()) { - scene.overlay().showText(90) - .text("Input: stores one stack of rod (free placing : can replace any casing not in the edge)") - .pointAt(util.vector().blockSurface(input1, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(80); - } - if (x == input2.getX() && y == input2.getY() && z == input2.getZ()) { - scene.overlay().showText(110) - .text("Second input: needed because you will likely have one input " + - "of fuel rod and one for coolant (free placing)") - .pointAt(util.vector().blockSurface(input2, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(80); - } - if (x == liquidInput.getX() && y == liquidInput.getY() && z == liquidInput.getZ()) { - scene.overlay().showText(90) - .text("Liquid Input: cooling fluid inlet (free placing)") - .pointAt(util.vector().blockSurface(liquidInput, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(80); - } - if (x == alarm.getX() && y == alarm.getY() && z == alarm.getZ()) { - scene.overlay().showText(90) - .text("Alarm: will sound if reactor overheats (free placing)") - .pointAt(util.vector().blockSurface(alarm, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(80); - } - if (x == output.getX() && y == output.getY() && z == output.getZ()) { - scene.overlay().showText(90) - .text("Output: where the generated power is extracted (free placing)") - .pointAt(util.vector().blockSurface(output, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(80); + if (bySections) { + // One section for the whole floor: same visual build-up, a fraction of the draws. + scene.world().showSection(util.select().layer(y), Direction.NORTH); + scene.idle(4); + for (BlockPos sp : pos.specials()) { + if (sp.getY() == y) { + tryShowCallout(scene, util, pos, sp.getX(), sp.getY(), sp.getZ()); } - if (x == controller.getX() && y == controller.getY() && z == controller.getZ()) { - scene.overlay().showText(110) - .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") - .pointAt(util.vector().blockSurface(controller, Direction.DOWN)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(80); + } + } else { + for (int x = 0; x < plate; x++) { + for (int z = 0; z < plate; z++) { + scene.world().showSection(util.select().position(x, y, z), Direction.NORTH); + scene.idle(4); + tryShowCallout(scene, util, pos, x, y, z); } } } @@ -173,12 +144,68 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u scene.overlay() .showText(110) .text("To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand"); - Vec3 topSide = util.vector().blockSurface(controller, Direction.EAST); + Vec3 topSide = util.vector().blockSurface(pos.controller, Direction.EAST); scene.overlay() .showControls(topSide, Pointing.UP, 60) .withItem(CNItems.REACTOR_BLUEPRINT.asStack()) .rightClick(); - scene.world().modifyBlock(controller, s -> s.setValue(ReactorControllerBlock.ASSEMBLED, true), true); + scene.world().modifyBlock(pos.controller, s -> s.setValue(ReactorControllerBlock.ASSEMBLED, true), true); + } + + /** Shows the explanatory callout for the special block at (x,y,z), if any. Shared by both reveal modes. */ + private static void tryShowCallout(SceneBuilder scene, SceneBuildingUtil util, Positions pos, int x, int y, int z) { + BlockPos input1 = pos.input1, input2 = pos.input2, liquidInput = pos.liquidInput, + alarm = pos.alarm, output = pos.output, controller = pos.controller; + + if (x == input1.getX() && y == input1.getY() && z == input1.getZ()) { + scene.overlay().showText(90) + .text("Input: stores one stack of rod (free placing : can replace any casing not in the edge)") + .pointAt(util.vector().blockSurface(input1, Direction.UP)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(80); + } + if (x == input2.getX() && y == input2.getY() && z == input2.getZ()) { + scene.overlay().showText(110) + .text("Second input: needed because you will likely have one input " + + "of fuel rod and one for coolant (free placing)") + .pointAt(util.vector().blockSurface(input2, Direction.UP)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(80); + } + if (x == liquidInput.getX() && y == liquidInput.getY() && z == liquidInput.getZ()) { + scene.overlay().showText(90) + .text("Liquid Input: cooling fluid inlet (free placing)") + .pointAt(util.vector().blockSurface(liquidInput, Direction.UP)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(80); + } + if (x == alarm.getX() && y == alarm.getY() && z == alarm.getZ()) { + scene.overlay().showText(90) + .text("Alarm: will sound if reactor overheats (free placing)") + .pointAt(util.vector().blockSurface(alarm, Direction.UP)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(80); + } + if (x == output.getX() && y == output.getY() && z == output.getZ()) { + scene.overlay().showText(90) + .text("Output: where the generated power is extracted (free placing)") + .pointAt(util.vector().blockSurface(output, Direction.UP)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(80); + } + if (x == controller.getX() && y == controller.getY() && z == controller.getZ()) { + scene.overlay().showText(110) + .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") + .pointAt(util.vector().blockSurface(controller, Direction.DOWN)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(80); + } } public static void t1(SceneBuilder scene, SceneBuildingUtil util) { @@ -214,6 +241,7 @@ public static void t3(SceneBuilder scene, SceneBuildingUtil util) { scene.showBasePlate(); scene.rotateCameraY(180); scene.scaleSceneView(0.35f); - showReactorStructure(scene, util, S, H, plate); + // T3 reveals floor-by-floor (section-based) so the largest tier doesn't lag; T1/T2 stay block-by-block. + showReactorStructure(scene, util, S, H, plate, true); } } \ No newline at end of file From 8e2321f0b2f1733deec3e3336459e29d33f26800 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:32:06 +0200 Subject: [PATCH 085/171] fix: adjust overlay text display timing for improved clarity in reactor scenes --- .../ponder/scenes/CNPonderReactorScenes.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 2b591a3a..57d0586e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -115,7 +115,7 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u Positions pos = positionsFor(S, H); for (int y = 1; y <= H; y++) { - scene.overlay().showText(8) + scene.overlay().showText(bySections ? 25 : 8) .text("Floor " + y) .attachKeyFrame() .placeNearTarget(); @@ -123,7 +123,10 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u if (bySections) { // One section for the whole floor: same visual build-up, a fraction of the draws. scene.world().showSection(util.select().layer(y), Direction.NORTH); - scene.idle(4); + // Block-by-block got its per-floor pacing from plate^2 * idle(4). With a single + // section per floor we must idle explicitly, otherwise callout-free floors flash + // by instantly and their "Floor N" labels overlap each other. + scene.idle(30); for (BlockPos sp : pos.specials()) { if (sp.getY() == y) { tryShowCallout(scene, util, pos, sp.getX(), sp.getY(), sp.getZ()); From 505f5ac2ac40afa5c04c96472691ac4cd1ca8804 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Wed, 24 Jun 2026 14:48:50 +0200 Subject: [PATCH 086/171] added tooltips --- gradle.properties | 2 +- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 28 +++++++++---------- .../assets/createnuclear/lang/en_ud.json | 15 ++++++---- .../assets/createnuclear/lang/en_us.json | 15 ++++++---- .../createnuclear/lang/default/tooltips.json | 12 +++++--- .../assets/createnuclear/lang/fr_fr.json | 10 +++++-- 6 files changed, 48 insertions(+), 34 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1f5643e4..d14b78cf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.10-beta +mod_version=2.0.12-beta # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index ed796bc8..446bda8b 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,11 +1,11 @@ -// 1.20.1 2026-06-24T11:17:44.2114024 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-24T14:44:24.181898 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json -f402fda858988cbb5e1a6a623cb15a6c76ac7f54 assets/createnuclear/blockstates/cut_autunite_bricks.json b88d65e7a3393caeaed8d504bf6c4615767371aa assets/createnuclear/blockstates/cut_autunite_brick_slab.json 7f788334258cfb67dfbf716dbaf1b126376d1a14 assets/createnuclear/blockstates/cut_autunite_brick_stairs.json 7bfc6778893ef6552c10e17e3489e201758d3a75 assets/createnuclear/blockstates/cut_autunite_brick_wall.json +f402fda858988cbb5e1a6a623cb15a6c76ac7f54 assets/createnuclear/blockstates/cut_autunite_bricks.json 1e246d1862a801b2253595d7fac7717a0110ce79 assets/createnuclear/blockstates/cut_autunite_slab.json 56c308e675a047a3d28757377e61e5f79c6384e3 assets/createnuclear/blockstates/cut_autunite_stairs.json 98d386985f7c185f1acab25b9d606828f788769f assets/createnuclear/blockstates/cut_autunite_wall.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -eebc6410ccfd3db94f243835ec8dca003fff1932 assets/createnuclear/lang/en_ud.json -2375a0eeb9d2056358e3630ee7aece46a1836b12 assets/createnuclear/lang/en_us.json +7dfd52e7242ade4050069bf3077d995ce731f8c4 assets/createnuclear/lang/en_ud.json +dbca9de714fcfdef3b7d84c49b829ed76f01bd7f assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json @@ -57,15 +57,15 @@ a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autun 2f6b85682c569527f9f538dae16526505ce5655a assets/createnuclear/models/block/autunite_pillar.json 4a04692c39cfad137877258b4443eb4bf5298423 assets/createnuclear/models/block/autunite_pillar_horizontal.json a48d579af38beab6fc87d3b02a7ed902b25bdf16 assets/createnuclear/models/block/cut_autunite.json -4d49f9151293582741edc0d935f3130547cf5360 assets/createnuclear/models/block/cut_autunite_bricks.json -6729240e3a6cbda812d3feb8e287f743bd6b6de5 assets/createnuclear/models/block/cut_autunite_bricks_wall_post.json -244715a4f0f6a21d055b1de3307c303a5a885c1d assets/createnuclear/models/block/cut_autunite_bricks_wall_side.json -f8d6743895a633a45eb0c565cb7f79aae9172175 assets/createnuclear/models/block/cut_autunite_bricks_wall_side_tall.json c470ac7f3b34c8da456f221d81b45292f0657e36 assets/createnuclear/models/block/cut_autunite_brick_slab.json d4084e8b32d197db311b575a06023bb5fd5d8aba assets/createnuclear/models/block/cut_autunite_brick_slab_top.json e4a795c7efcfa306ac6772e2b8a23a3afc52c0ec assets/createnuclear/models/block/cut_autunite_brick_stairs.json 90a9c051a0c72398a1f052542620029275e6a676 assets/createnuclear/models/block/cut_autunite_brick_stairs_inner.json 4bb891d8f069cf043de74c0cc9d16fcbcb49ee07 assets/createnuclear/models/block/cut_autunite_brick_stairs_outer.json +4d49f9151293582741edc0d935f3130547cf5360 assets/createnuclear/models/block/cut_autunite_bricks.json +6729240e3a6cbda812d3feb8e287f743bd6b6de5 assets/createnuclear/models/block/cut_autunite_bricks_wall_post.json +244715a4f0f6a21d055b1de3307c303a5a885c1d assets/createnuclear/models/block/cut_autunite_bricks_wall_side.json +f8d6743895a633a45eb0c565cb7f79aae9172175 assets/createnuclear/models/block/cut_autunite_bricks_wall_side_tall.json d9ae523c08cbbe274a598736a8a9fd510d78d484 assets/createnuclear/models/block/cut_autunite_slab.json 14043cfcb42894ebb0db2501929ba4cae9d8bd7d assets/createnuclear/models/block/cut_autunite_slab_top.json f66edf8ef01d16ee116ac71e742bea54e98e1724 assets/createnuclear/models/block/cut_autunite_stairs.json @@ -191,10 +191,10 @@ ceefea70488adb5db8c8e2355eb9b59b8262b0fc assets/createnuclear/models/item/colore 893789e72874b7b3bb5634df81b374c38177f2f7 assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json 4c5ade8688c0dfd0c3007c6bde5d52fb0a0f44cc assets/createnuclear/models/item/cooled_nitrogen_concentrate.json 0c682ff48601bf7f42c8561819ecede780664fbf assets/createnuclear/models/item/cut_autunite.json -11220bd60ab51e05a978a8322511c224d15bf886 assets/createnuclear/models/item/cut_autunite_bricks.json d43ffb4c5491fcd8c98451649c3f4ceb271e8875 assets/createnuclear/models/item/cut_autunite_brick_slab.json dfea56e99288e64e5061c621e860fa314fc31e9d assets/createnuclear/models/item/cut_autunite_brick_stairs.json 95e992c1e1c881d0f00a234a5e6906b1a5dbf149 assets/createnuclear/models/item/cut_autunite_brick_wall.json +11220bd60ab51e05a978a8322511c224d15bf886 assets/createnuclear/models/item/cut_autunite_bricks.json 5027aa166900571aa2e4f50ad53869b595ff3426 assets/createnuclear/models/item/cut_autunite_slab.json bd832947d219746d3264422bc4c82f6acdc5cc3e assets/createnuclear/models/item/cut_autunite_stairs.json 4c0b115eb2a2f8d6e74c612fa6e1aa5b357e9185 assets/createnuclear/models/item/cut_autunite_wall.json @@ -272,12 +272,12 @@ fe44d1ed2b4100ec32dda43274a085166706485d assets/createnuclear/models/item/thoriu ea04609e8b5c12a7805b1c564bca07fefd6d38ba assets/createnuclear/models/item/uranium_rod.json 4d85657105612ca5525a14791c3e07cf6bd239b8 assets/createnuclear/models/item/white_cloth.json 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/createnuclear/models/item/wolf_irradiated_spawn_egg.json -8bdc2fabbfc9fcc7c2ad4a3273897659d90b95ab assets/createnuclear/models/item/yellowcake.json a1970879fd57836f5ae5d23352cdca277095bc7d assets/createnuclear/models/item/yellow_cloth.json +8bdc2fabbfc9fcc7c2ad4a3273897659d90b95ab assets/createnuclear/models/item/yellowcake.json +d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json 72b0cec0c98e9ead9562ff0cc1231a5028e2a22f data/createnuclear/advancements/recipes/building_blocks/autunite_from_stone_types_autunite_stonecutting.json e7967751f132676cb1d523743adaac3aea1f0814 data/createnuclear/advancements/recipes/building_blocks/autunite_pillar_from_stone_types_autunite_stonecutting.json 8e9cfc8ab1ddd7b818cb52cbd0fb60c0c4713bad data/createnuclear/advancements/recipes/building_blocks/crafting/enriched_soul_soil.json -1ec4bd12e3fd4303800a758a2b791e30a04e5960 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json 801940038556c52d0e10aec6d16430a99f31a385 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_slab.json d0f97d467c8a00a57ece37990ece8601a32c431d data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_slab_from_stone_types_autunite_stonecutting.json 913dfa33a312cd9a08d6d1194d0f7af40d4c5856 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_slab_recycling.json @@ -285,6 +285,7 @@ d0f97d467c8a00a57ece37990ece8601a32c431d data/createnuclear/advancements/recipes 1a35a3a0cf6a0202eb8244d26647e8e277cf8fd3 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_stairs_from_stone_types_autunite_stonecutting.json 4fae09cee3ae86760906501da0dba47acb035cf4 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_wall.json f893c5dec42faf470d493c4b1c5c184cad842c32 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_wall_from_stone_types_autunite_stonecutting.json +1ec4bd12e3fd4303800a758a2b791e30a04e5960 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json c53fd5df1d52d6e9919c9600e483697e8db75f4d data/createnuclear/advancements/recipes/building_blocks/cut_autunite_from_stone_types_autunite_stonecutting.json 8ded4051daf417cb802b5327ef0e92d361dcb298 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_slab.json 1b0fefdf4f489b3e6c389c45ffd3918b10a50de0 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_slab_from_stone_types_autunite_stonecutting.json @@ -413,10 +414,10 @@ f38e19487233203d7135f35a7afe65d6b19a5aa7 data/createnuclear/advancements/recipes a021646becb7b6411eddd86644e5b17c8365582c data/createnuclear/loot_tables/blocks/autunite.json 62b7087350b0a9af9007b848c7f619a730e90693 data/createnuclear/loot_tables/blocks/autunite_pillar.json 771b416236bcc21f380e0f312c61803224987616 data/createnuclear/loot_tables/blocks/cut_autunite.json -3b81b5b58b7ef985348cf511e609064a7171d7dc data/createnuclear/loot_tables/blocks/cut_autunite_bricks.json feae7c8978bcce63f2eeb2ad6ed6a7ef53cbc13e data/createnuclear/loot_tables/blocks/cut_autunite_brick_slab.json 1fa4418198a079b6236b2f3e4b11a7f7d0fc6962 data/createnuclear/loot_tables/blocks/cut_autunite_brick_stairs.json db666ffaca36edc9e246e225f225c1e87604dd88 data/createnuclear/loot_tables/blocks/cut_autunite_brick_wall.json +3b81b5b58b7ef985348cf511e609064a7171d7dc data/createnuclear/loot_tables/blocks/cut_autunite_bricks.json 10aff7424eefd85e50269c66e60ae343043193cd data/createnuclear/loot_tables/blocks/cut_autunite_slab.json e6e624e978fdacfa3cdd123d23d021f504308149 data/createnuclear/loot_tables/blocks/cut_autunite_stairs.json f28efa9fb383b86c770b8c7344fc30f6ab9200d3 data/createnuclear/loot_tables/blocks/cut_autunite_wall.json @@ -482,7 +483,6 @@ ae6d07dc30751bfa39edbcdb8758a2faababa5da data/createnuclear/recipes/crafting/ste 5fb04284d66de4bf54471a3db0d9a3bfa6b7a18c data/createnuclear/recipes/crafting/steel_nugget_from_decompacting.json 047c50559746a9ffb5835ff960ba500400e7e299 data/createnuclear/recipes/crafting/thorium_ingot_from_decompacting.json 428e74b7762c3b5b74e80850a5c75d27960c73c9 data/createnuclear/recipes/crafting/thorium_nugget_from_decompacting.json -ebfe438f4284101e07538accdf15789d06140c94 data/createnuclear/recipes/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json 4b86d48cdf03dcfaa383552881a7f52b7bebe9c5 data/createnuclear/recipes/cut_autunite_brick_slab.json b9d828959c4614caa4a0f3ac82f322dd538c6219 data/createnuclear/recipes/cut_autunite_brick_slab_from_stone_types_autunite_stonecutting.json bb8a46365f31a2e4b5440a47d1d22d122d0e973b data/createnuclear/recipes/cut_autunite_brick_slab_recycling.json @@ -490,6 +490,7 @@ bb8a46365f31a2e4b5440a47d1d22d122d0e973b data/createnuclear/recipes/cut_autunite 65ae0b709f14ec4c018ab5548d91c3a53657f612 data/createnuclear/recipes/cut_autunite_brick_stairs_from_stone_types_autunite_stonecutting.json f16b4fafe9693a2d4eaea0616aa1c01042430154 data/createnuclear/recipes/cut_autunite_brick_wall.json e40db55eb02cdbedc6f4dc52786069c74b267ada data/createnuclear/recipes/cut_autunite_brick_wall_from_stone_types_autunite_stonecutting.json +ebfe438f4284101e07538accdf15789d06140c94 data/createnuclear/recipes/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json b68221950ba50e3c11cdd6b58de2aafea83b07b5 data/createnuclear/recipes/cut_autunite_from_stone_types_autunite_stonecutting.json 0bfedb8324af8797150b1faf2c2b50856d1b4ace data/createnuclear/recipes/cut_autunite_slab.json f04d6df381ea8dfbcae8d4387a5a58e25ed325e9 data/createnuclear/recipes/cut_autunite_slab_from_stone_types_autunite_stonecutting.json @@ -609,7 +610,6 @@ bce34f53cb2d00f7dee84683e8fdd429dabbcc1d data/createnuclear/tags/items/anti_radi 8e6598f14a72a61cbe1e5ed2aaea229fb2dd74e6 data/createnuclear/tags/items/cooler.json c5587bb72c54f59e9f9a4cd2c3e6bedb78ee198d data/createnuclear/tags/items/fuel.json 1a438d724641b4899f18b4abeef0b0708c76ea70 data/createnuclear/tags/items/stone_types/autunite.json -d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json 75f0600da4891d0f4a3329fb44cac6c4945a0b49 data/forge/tags/blocks/glass.json 1fd17be1d553e7ddf20494ee1e98084f02137cc8 data/forge/tags/blocks/ores.json 925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/forge/tags/blocks/ores/lead.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 1eff9b32..0ddc47cd 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -132,10 +132,13 @@ "block.createnuclear.reactor_frame": "ǝɯɐɹℲ ɹoʇɔɐǝᴚ", "block.createnuclear.reactor_frame.tooltip.summary": "‾ɹoʇɔɐǝɹ‾ ǝɥʇ pןınq oʇ pǝsn ‾ʞɔoןᗺ‾", "block.createnuclear.reactor_input": "ʇnduI ɹoʇɔɐǝᴚ", - "block.createnuclear.reactor_input.tooltip.behaviour1": " ‾ɹoʇɔɐǝɹ ǝɥʇ‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı spoɹ ‾ǝuǝɥdɐɹb‾ puɐ ‾ɯnıuɐɹn‾ ʇɹǝsuI", - "block.createnuclear.reactor_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝᴚ ǝɥʇ uǝɥM", - "block.createnuclear.reactor_input.tooltip.summary": "‾ɹoʇɔɐǝᴚ‾ ǝɥʇ oʇuı spoɹ ‾ǝuǝɥdɐɹ⅁‾ puɐ ‾ɯnıuɐɹ∩‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI ɹoʇɔɐǝᴚ ǝɥ⟘‾", + "block.createnuclear.reactor_input.tooltip.behaviour1": "˙‾ɹoʇɔɐǝᴚ ǝɥ⟘‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı spoɹ )‾ǝʇıɥdɐɹ⅁‾ ǝʞıן( ‾buıןooƆ‾ puɐ )‾ɯnıɹoɥ⟘‾ ɹo ‾ɯnıuɐɹ∩‾ ǝʞıן( ‾buıʇɐǝH‾ ʇɹǝsuI", + "block.createnuclear.reactor_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", + "block.createnuclear.reactor_input.tooltip.summary": "˙ɹoʇɔɐǝᴚ ǝɥʇ oʇuı spoɹ ‾buıןooƆ‾ ɹo ‾buıʇɐǝH‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI poᴚ ɹoʇɔɐǝᴚ ǝɥ⟘‾", "block.createnuclear.reactor_liquid_input": "ʇnduI pınbıꞀ ɹoʇɔɐǝᴚ", + "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "˙‾buıʇɐǝɥɹǝʌo‾ pıoʌɐ puɐ ‾ɹoʇɔɐǝᴚ ǝɥ⟘‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı ‾uǝboɹʇıN pınbıꞀ‾ ɹo ‾ɹǝʇɐM‾ ʇɹǝsuI", + "block.createnuclear.reactor_liquid_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", + "block.createnuclear.reactor_liquid_input.tooltip.summary": "˙ɹoʇɔɐǝᴚ ǝɥʇ oʇuı ‾uǝboɹʇıN pınbıꞀ‾ ɹo ‾ɹǝʇɐM‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI pınןℲ ɹoʇɔɐǝᴚ ǝɥ⟘‾", "block.createnuclear.reactor_output": "ʇndʇnO ɹoʇɔɐǝᴚ", "block.createnuclear.reactor_output.tooltip.behaviour1": "‾ʇndʇno ɹoʇɔɐǝɹ‾ ǝɥʇ oʇ ‾ʇɟɐɥs‾ buıɥɔɐʇʇɐ ʎq ɹoʇɔɐǝɹ ǝɥʇ ʎq ǝɔnpoɹd ‾ʎbɹǝuǝ ǝɥʇ ʇɔɐɹʇxǝ‾ uɐɔ noʎ", "block.createnuclear.reactor_output.tooltip.condition1": "ʎbɹǝuǝ ǝɔnpoɹd ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", @@ -246,8 +249,8 @@ "createnuclear.ponder.reactor_t2.text_9": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", "createnuclear.ponder.reactor_t3.header": "Ɛ⟘ ɹoʇɔɐǝᴚ", "createnuclear.ponder.reactor_t3.text_1": "Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_10": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", - "createnuclear.ponder.reactor_t3.text_11": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t3.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t3.text_11": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", "createnuclear.ponder.reactor_t3.text_12": ")buıɔɐןd ǝǝɹɟ( sʇɐǝɥɹǝʌo ɹoʇɔɐǝɹ ɟı punos ןןıʍ :ɯɹɐןⱯ", "createnuclear.ponder.reactor_t3.text_13": "ㄥ ɹooןℲ", "createnuclear.ponder.reactor_t3.text_14": "8 ɹooןℲ", @@ -367,7 +370,7 @@ "item.createnuclear.reactor_blueprint_item": "ʇuıɹdǝnןᗺ ɹoʇɔɐǝᴚ", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour1": "˙ʇı ןןıɟ oʇ ʞɔıןɔ ‾ʇɥbıᴚ‾", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour2": "˙ʇı uǝdo oʇ ɹǝןןoɹʇuoɔ ɹoʇɔɐǝɹ ǝɥʇ uo ʞɔıןɔ ‾ʇɥbıᴚ‾", - "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "spoɹ ןǝnɟ puɐ buıןooɔ ɥʇıʍ pǝןןıℲ", + "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "spoɹ buıʇɐǝɥ puɐ buıןooɔ ɥʇıʍ pǝןןıℲ", "item.createnuclear.reactor_blueprint_item.tooltip.condition2": "pǝןqɯǝssɐ ǝq ʇsnɯ ɹoʇɔɐǝɹ ǝɥ⟘", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "˙uɹǝʇʇɐd uʍo ɹnoʎ ǝɹnbıɟuoɔ oʇ noʎ sʍoןןɐ ʇI", "item.createnuclear.red_cloth": "ɥʇoןƆ pǝᴚ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index d2ceff90..457fc7ca 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -132,10 +132,13 @@ "block.createnuclear.reactor_frame": "Reactor Frame", "block.createnuclear.reactor_frame.tooltip.summary": "_Block_ used to build the _reactor_", "block.createnuclear.reactor_input": "Reactor Input", - "block.createnuclear.reactor_input.tooltip.behaviour1": "Insert _uranium_ and _graphene_ rods in large quantities to power _the reactor_ ", - "block.createnuclear.reactor_input.tooltip.condition1": "When the Reactor is assembled", - "block.createnuclear.reactor_input.tooltip.summary": "_The Reactor Input_ is a _block_ that can be used to insert _Uranium_ and _Graphene_ rods into the _Reactor_", + "block.createnuclear.reactor_input.tooltip.behaviour1": "Insert _Heating_ (like _Uranium_ or _Thorium_) and _Cooling_ (like _Graphite_) rods in large quantities to power _The Reactor_.", + "block.createnuclear.reactor_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_input.tooltip.summary": "_The Reactor Rod Input_ is a _block_ that can be used to insert _Heating_ or _Cooling_ rods into the Reactor.", "block.createnuclear.reactor_liquid_input": "Reactor Liquid Input", + "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "Insert _Water_ or _Liquid Nitrogen_ in large quantities to power _The Reactor_ and avoid _overheating_.", + "block.createnuclear.reactor_liquid_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_liquid_input.tooltip.summary": "_The Reactor Fluid Input_ is a _block_ that can be used to insert _Water_ or _Liquid Nitrogen_ into the Reactor.", "block.createnuclear.reactor_output": "Reactor Output", "block.createnuclear.reactor_output.tooltip.behaviour1": "You can _extract the energy_ produce by the reactor by attaching _shaft_ to the _reactor output_", "block.createnuclear.reactor_output.tooltip.condition1": "When the reactor produce energy", @@ -246,8 +249,8 @@ "createnuclear.ponder.reactor_t2.text_9": "Liquid Input: cooling fluid inlet (free placing)", "createnuclear.ponder.reactor_t3.header": "Reactor T3", "createnuclear.ponder.reactor_t3.text_1": "Floor 1", - "createnuclear.ponder.reactor_t3.text_10": "Liquid Input: cooling fluid inlet (free placing)", - "createnuclear.ponder.reactor_t3.text_11": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t3.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t3.text_11": "Liquid Input: cooling fluid inlet (free placing)", "createnuclear.ponder.reactor_t3.text_12": "Alarm: will sound if reactor overheats (free placing)", "createnuclear.ponder.reactor_t3.text_13": "Floor 7", "createnuclear.ponder.reactor_t3.text_14": "Floor 8", @@ -367,7 +370,7 @@ "item.createnuclear.reactor_blueprint_item": "Reactor Blueprint", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour1": "_Right_ click to fill it.", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour2": "_Right_ click on the reactor controller to open it.", - "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and fuel rods", + "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and heating rods", "item.createnuclear.reactor_blueprint_item.tooltip.condition2": "The reactor must be assembled", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", "item.createnuclear.red_cloth": "Red Cloth", diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index 5ba948b8..e122efa7 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -4,9 +4,13 @@ "tag.item.createnuclear.fuel": "Fuel", - "block.createnuclear.reactor_input.tooltip.summary": "_The Reactor Input_ is a _block_ that can be used to insert _Uranium_ and _Graphene_ rods into the _Reactor_", - "block.createnuclear.reactor_input.tooltip.condition1": "When the Reactor is assembled", - "block.createnuclear.reactor_input.tooltip.behaviour1": "Insert _uranium_ and _graphene_ rods in large quantities to power _the reactor_ ", + "block.createnuclear.reactor_input.tooltip.summary": "_The Reactor Rod Input_ is a _block_ that can be used to insert _Heating_ or _Cooling_ rods into the Reactor.", + "block.createnuclear.reactor_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_input.tooltip.behaviour1": "Insert _Heating_ (like _Uranium_ or _Thorium_) and _Cooling_ (like _Graphite_) rods in large quantities to power _The Reactor_.", + + "block.createnuclear.reactor_liquid_input.tooltip.summary": "_The Reactor Fluid Input_ is a _block_ that can be used to insert _Water_ or _Liquid Nitrogen_ into the Reactor.", + "block.createnuclear.reactor_liquid_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "Insert _Water_ or _Liquid Nitrogen_ in large quantities to power _The Reactor_ and avoid _overheating_.", "block.createnuclear.reactor_controller.tooltip.summary": " The _Reactor Controller_ is the _most important_ block for operating the reactor", @@ -36,7 +40,7 @@ "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", - "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and fuel rods", + "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and heating rods", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour1": "_Right_ click to fill it.", "item.createnuclear.reactor_blueprint_item.tooltip.condition2": "The reactor must be assembled", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour2": "_Right_ click on the reactor controller to open it.", diff --git a/src/main/resources/assets/createnuclear/lang/fr_fr.json b/src/main/resources/assets/createnuclear/lang/fr_fr.json index 8b0faf76..4a8b8e7a 100644 --- a/src/main/resources/assets/createnuclear/lang/fr_fr.json +++ b/src/main/resources/assets/createnuclear/lang/fr_fr.json @@ -95,9 +95,13 @@ "block.createnuclear.reactor_frame": "Structure de réacteur", "block.createnuclear.reactor_frame.tooltip.summary": "_Bloc_ utilisé pour construire le _réacteur_", "block.createnuclear.reactor_input": "Entrée de réacteur", - "block.createnuclear.reactor_input.tooltip.behaviour1": "Insérer des barres _d'uranium_ et de _graphene_ en grandes quantités pour alimenter _le réacteur_ ", + "block.createnuclear.reactor_input.tooltip.behaviour1": "Insérer des barres de _chauffage_ (comme l'_uranium_ ou le _thorium_) et de _refroidissement_ (comme le _graphite_) en grandes quantités pour alimenter _le réacteur_.", "block.createnuclear.reactor_input.tooltip.condition1": "Quand le réacteur est assemblé", - "block.createnuclear.reactor_input.tooltip.summary": "_L'entrée du réacteur_ est un _bloc_ qui peut être utilisé pour insérer des barres _d'Uranium_ et de _Graphene_ dans le _Réacteur_", + "block.createnuclear.reactor_input.tooltip.summary": "_L'entrée de barre de réacteur_ est un _bloc_ qui peut être utilisé pour insérer des barres de _chauffage_ ou de _refroidissement_ dans le réacteur.", + + "block.createnuclear.reactor_liquid_input.tooltip.summary": "_L'entrée de fluide de réacteur_ est un _bloc_ qui peut être utilisé pour insérer de l'_eau_ ou de l'_azote liquide_ dans le réacteur.", + "block.createnuclear.reactor_liquid_input.tooltip.condition1": "Quand le réacteur est assemblé", + "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "Insérer de l'_eau_ ou de l'_azote liquide_ en grandes quantités pour alimenter _le réacteur_ et éviter la _surchauffe_.", "block.createnuclear.reactor_output": "Sortie de réacteur", "block.createnuclear.reactor_output.tooltip.behaviour1": "Vous pouvez _extraire l'énergie_ produite par le réacteur en attachant un _rotor_ à la sortie du _réacteur_", "block.createnuclear.reactor_output.tooltip.condition1": "Quand le réacteur produit de l'énergie", @@ -211,7 +215,7 @@ "item.createnuclear.reactor_blueprint_item": "Plan du réacteur", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour1": "Faites un clic _droit_ pour le remplir.", "item.createnuclear.reactor_blueprint_item.tooltip.behaviour2": "Faites un clic _droit_ sur le contrôleur de réacteur pour l'ouvrir.", - "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Rempli de graphite et de barres d'uranium", + "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Rempli de barres de refroidissement et de chauffage", "item.createnuclear.reactor_blueprint_item.tooltip.condition2": "Le réacteur doit être assemblé", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "Il vous permet de configurer votre propre paterne.", "item.createnuclear.red_anti_radiation_chestplate": "Plastron anti-radiations rouge", From 80119844a49fd2311864d11a76f4e3e73e1e9e0c Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:49:27 +0200 Subject: [PATCH 087/171] fix: update callout display durations for special blocks based on reactor tier --- .../ponder/scenes/CNPonderReactorScenes.java | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 57d0586e..cb233201 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -129,7 +129,7 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u scene.idle(30); for (BlockPos sp : pos.specials()) { if (sp.getY() == y) { - tryShowCallout(scene, util, pos, sp.getX(), sp.getY(), sp.getZ()); + tryShowCallout(scene, util, pos, sp.getX(), sp.getY(), sp.getZ(), bySections); } } } else { @@ -137,7 +137,7 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u for (int z = 0; z < plate; z++) { scene.world().showSection(util.select().position(x, y, z), Direction.NORTH); scene.idle(4); - tryShowCallout(scene, util, pos, x, y, z); + tryShowCallout(scene, util, pos, x, y, z, bySections); } } } @@ -155,59 +155,63 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u scene.world().modifyBlock(pos.controller, s -> s.setValue(ReactorControllerBlock.ASSEMBLED, true), true); } - /** Shows the explanatory callout for the special block at (x,y,z), if any. Shared by both reveal modes. */ - private static void tryShowCallout(SceneBuilder scene, SceneBuildingUtil util, Positions pos, int x, int y, int z) { + /** + * Shows the explanatory callout for the special block at (x,y,z), if any. Shared by both reveal + * modes. When {@code reduced} is true (T3), these block-explanation texts run 15% shorter + * (90->77, 110->94, hold 80->68); the other tiers keep the original durations. + */ + private static void tryShowCallout(SceneBuilder scene, SceneBuildingUtil util, Positions pos, int x, int y, int z, boolean reduced) { BlockPos input1 = pos.input1, input2 = pos.input2, liquidInput = pos.liquidInput, alarm = pos.alarm, output = pos.output, controller = pos.controller; if (x == input1.getX() && y == input1.getY() && z == input1.getZ()) { - scene.overlay().showText(90) + scene.overlay().showText(reduced ? 77 : 90) .text("Input: stores one stack of rod (free placing : can replace any casing not in the edge)") .pointAt(util.vector().blockSurface(input1, Direction.UP)) .attachKeyFrame() .placeNearTarget(); - scene.idle(80); + scene.idle(reduced ? 68 : 80); } if (x == input2.getX() && y == input2.getY() && z == input2.getZ()) { - scene.overlay().showText(110) + scene.overlay().showText(reduced ? 94 : 110) .text("Second input: needed because you will likely have one input " + "of fuel rod and one for coolant (free placing)") .pointAt(util.vector().blockSurface(input2, Direction.UP)) .attachKeyFrame() .placeNearTarget(); - scene.idle(80); + scene.idle(reduced ? 68 : 80); } if (x == liquidInput.getX() && y == liquidInput.getY() && z == liquidInput.getZ()) { - scene.overlay().showText(90) + scene.overlay().showText(reduced ? 77 : 90) .text("Liquid Input: cooling fluid inlet (free placing)") .pointAt(util.vector().blockSurface(liquidInput, Direction.UP)) .attachKeyFrame() .placeNearTarget(); - scene.idle(80); + scene.idle(reduced ? 68 : 80); } if (x == alarm.getX() && y == alarm.getY() && z == alarm.getZ()) { - scene.overlay().showText(90) + scene.overlay().showText(reduced ? 77 : 90) .text("Alarm: will sound if reactor overheats (free placing)") .pointAt(util.vector().blockSurface(alarm, Direction.UP)) .attachKeyFrame() .placeNearTarget(); - scene.idle(80); + scene.idle(reduced ? 68 : 80); } if (x == output.getX() && y == output.getY() && z == output.getZ()) { - scene.overlay().showText(90) + scene.overlay().showText(reduced ? 77 : 90) .text("Output: where the generated power is extracted (free placing)") .pointAt(util.vector().blockSurface(output, Direction.UP)) .attachKeyFrame() .placeNearTarget(); - scene.idle(80); + scene.idle(reduced ? 68 : 80); } if (x == controller.getX() && y == controller.getY() && z == controller.getZ()) { - scene.overlay().showText(110) + scene.overlay().showText(reduced ? 94 : 110) .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") .pointAt(util.vector().blockSurface(controller, Direction.DOWN)) .attachKeyFrame() .placeNearTarget(); - scene.idle(80); + scene.idle(reduced ? 68 : 80); } } From 4dd322a884b279ba74e4904341f2402d6cde1864 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Wed, 24 Jun 2026 15:30:56 +0200 Subject: [PATCH 088/171] feat: add "Irradiated Land" biome to language files --- .../.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +++--- .../resources/assets/createnuclear/lang/en_ud.json | 1 + .../resources/assets/createnuclear/lang/en_us.json | 1 + .../assets/createnuclear/lang/default/interface.json | 1 + src/main/resources/assets/createnuclear/lang/en_US.json | 1 + src/main/resources/assets/createnuclear/lang/fr_fr.json | 1 + 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 446bda8b..d12d064b 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T14:44:24.181898 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-24T15:26:20.46308 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -7dfd52e7242ade4050069bf3077d995ce731f8c4 assets/createnuclear/lang/en_ud.json -dbca9de714fcfdef3b7d84c49b829ed76f01bd7f assets/createnuclear/lang/en_us.json +a9e8446211ce417590bcea40563af1088714c500 assets/createnuclear/lang/en_ud.json +e1ce05db404d639722ef62790f5720378d749967 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 0ddc47cd..3a8404ed 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -88,6 +88,7 @@ "advancement.createnuclear.yellowcake": "ssǝɔoɹԀ ǝʞɐɔʍoןןǝʎ ǝɥ⟘", "advancement.createnuclear.yellowcake.desc": "ǝʞɐɔʍoןןǝʎ ǝʇɐǝɹɔ oʇ pınbıן ɯnıuɐɹn ʇɔɐdɯoƆ", "attribute.name.createnuclear.generic.irradiated_resistance": "ǝɔuɐʇsısǝᴚ uoıʇɐıpɐᴚ", + "biome.createnuclear.irradiated_land": "puɐꞀ pǝʇɐıpɐɹɹI", "block.createnuclear.autunite": "ǝʇıunʇnⱯ", "block.createnuclear.autunite_pillar": "ɹɐןןıԀ ǝʇıunʇnⱯ", "block.createnuclear.cut_autunite": "ǝʇıunʇnⱯ ʇnƆ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 457fc7ca..6f84ef95 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -88,6 +88,7 @@ "advancement.createnuclear.yellowcake": "The Yellowcake Process", "advancement.createnuclear.yellowcake.desc": "Compact uranium liquid to create yellowcake", "attribute.name.createnuclear.generic.irradiated_resistance": "Radiation Resistance", + "biome.createnuclear.irradiated_land": "Irradiated Land", "block.createnuclear.autunite": "Autunite", "block.createnuclear.autunite_pillar": "Autunite Pillar", "block.createnuclear.cut_autunite": "Cut Autunite", diff --git a/src/main/resources/assets/createnuclear/lang/default/interface.json b/src/main/resources/assets/createnuclear/lang/default/interface.json index 8b659cd7..6a27be52 100644 --- a/src/main/resources/assets/createnuclear/lang/default/interface.json +++ b/src/main/resources/assets/createnuclear/lang/default/interface.json @@ -1,6 +1,7 @@ { "itemGroup.createnuclear.main": "Create Nuclear", "itemgroup.uranium": "Uranium Group", + "biome.createnuclear.irradiated_land": "Irradiated Land", "createnuclear.enriched.fan.recipe": "Bulk Enriching", "emi.category.createnuclear.fan_enriched": "Bulk Enriching", diff --git a/src/main/resources/assets/createnuclear/lang/en_US.json b/src/main/resources/assets/createnuclear/lang/en_US.json index cf682674..b01ee4c7 100644 --- a/src/main/resources/assets/createnuclear/lang/en_US.json +++ b/src/main/resources/assets/createnuclear/lang/en_US.json @@ -1,4 +1,5 @@ { + "biome.createnuclear.irradiated_land": "Irradiated Land", "block.createnuclear.deepslate_lead_ore": "Deepslate Lead Ore", "block.createnuclear.deepslate_uranium_ore": "Deepslate Uranium Ore", "block.createnuclear.enriched_soul_soil": "Enriched Soul Soil", diff --git a/src/main/resources/assets/createnuclear/lang/fr_fr.json b/src/main/resources/assets/createnuclear/lang/fr_fr.json index 4a8b8e7a..edfa8581 100644 --- a/src/main/resources/assets/createnuclear/lang/fr_fr.json +++ b/src/main/resources/assets/createnuclear/lang/fr_fr.json @@ -1,4 +1,5 @@ { + "biome.createnuclear.irradiated_land": "Terres irradiées", "advancement.createnuclear.anti_radiation_armor": "Armure anti-radiation", "advancement.createnuclear.anti_radiation_armor.desc": "Fabriquez votre première pièce d'armure anti-radiation pour vous protéger des radiations", "advancement.createnuclear.automatic_uranium": "Automatisation de l'uranium", From c3e5ecbbd7dfe41a2217e4db96fbf244e1119e0f Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Wed, 24 Jun 2026 15:39:58 +0200 Subject: [PATCH 089/171] refactor: remove unused interaction logic from ReactorOutput --- .../multiblock/output/ReactorOutput.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java index 05d72021..e2169e6f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java @@ -54,26 +54,6 @@ protected void createBlockStateDefinition(StateDefinition.Builder Date: Wed, 24 Jun 2026 15:44:08 +0200 Subject: [PATCH 090/171] fix: correct text formatting in reactor controller overlay --- .../infrastructure/ponder/scenes/CNPonderReactorScenes.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index cb233201..186b09af 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -207,7 +207,7 @@ private static void tryShowCallout(SceneBuilder scene, SceneBuildingUtil util, P } if (x == controller.getX() && y == controller.getY() && z == controller.getZ()) { scene.overlay().showText(reduced ? 94 : 110) - .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") + .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") .pointAt(util.vector().blockSurface(controller, Direction.DOWN)) .attachKeyFrame() .placeNearTarget(); @@ -251,4 +251,4 @@ public static void t3(SceneBuilder scene, SceneBuildingUtil util) { // T3 reveals floor-by-floor (section-based) so the largest tier doesn't lag; T1/T2 stay block-by-block. showReactorStructure(scene, util, S, H, plate, true); } -} \ No newline at end of file +} From ad23acbf56dc33ec1ad31a6766e19b4c84f1851f Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Wed, 24 Jun 2026 15:49:12 +0200 Subject: [PATCH 091/171] fix: update text formatting in reactor controller descriptions and correct fluid density --- .../.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +++--- .../resources/assets/createnuclear/lang/en_ud.json | 6 +++--- .../resources/assets/createnuclear/lang/en_us.json | 6 +++--- src/main/java/net/nuclearteam/createnuclear/CNFluids.java | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index d12d064b..fedefb03 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T15:26:20.46308 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-24T15:46:40.18335 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -a9e8446211ce417590bcea40563af1088714c500 assets/createnuclear/lang/en_ud.json -e1ce05db404d639722ef62790f5720378d749967 assets/createnuclear/lang/en_us.json +afa50b91fc65d9f785afffefbf5aafc9cde32a2a assets/createnuclear/lang/en_ud.json +12a32b876aacfd92504d386d7366003931ddbea1 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 3a8404ed..16edc6ac 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -230,10 +230,10 @@ "createnuclear.ponder.reactor_t1.text_6": ")buıɔɐןd ǝǝɹɟ( ʇuɐןooɔ ɹoɟ ǝuo puɐ poɹ ןǝnɟ ɟo ʇnduı ǝuo ǝʌɐɥ ʎןǝʞıן ןןıʍ noʎ ǝsnɐɔǝq pǝpǝǝu :ʇnduı puoɔǝS", "createnuclear.ponder.reactor_t1.text_7": "ㄣ ɹooןℲ", "createnuclear.ponder.reactor_t1.text_8": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", - "createnuclear.ponder.reactor_t1.text_9": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t1.text_9": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", "createnuclear.ponder.reactor_t2.header": "ᄅ⟘ ɹoʇɔɐǝᴚ", "createnuclear.ponder.reactor_t2.text_1": "Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t2.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", "createnuclear.ponder.reactor_t2.text_11": ")buıɔɐןd ǝǝɹɟ( sʇɐǝɥɹǝʌo ɹoʇɔɐǝɹ ɟı punos ןןıʍ :ɯɹɐןⱯ", "createnuclear.ponder.reactor_t2.text_12": "9 ɹooןℲ", "createnuclear.ponder.reactor_t2.text_13": "ㄥ ɹooןℲ", @@ -250,7 +250,7 @@ "createnuclear.ponder.reactor_t2.text_9": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", "createnuclear.ponder.reactor_t3.header": "Ɛ⟘ ɹoʇɔɐǝᴚ", "createnuclear.ponder.reactor_t3.text_1": "Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t3.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", "createnuclear.ponder.reactor_t3.text_11": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", "createnuclear.ponder.reactor_t3.text_12": ")buıɔɐןd ǝǝɹɟ( sʇɐǝɥɹǝʌo ɹoʇɔɐǝɹ ɟı punos ןןıʍ :ɯɹɐןⱯ", "createnuclear.ponder.reactor_t3.text_13": "ㄥ ɹooןℲ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 6f84ef95..e5ae2885 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -230,10 +230,10 @@ "createnuclear.ponder.reactor_t1.text_6": "Second input: needed because you will likely have one input of fuel rod and one for coolant (free placing)", "createnuclear.ponder.reactor_t1.text_7": "Floor 4", "createnuclear.ponder.reactor_t1.text_8": "Liquid Input: cooling fluid inlet (free placing)", - "createnuclear.ponder.reactor_t1.text_9": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t1.text_9": "Controller: brain of the reactor, and the place where the blueprint goes to start it", "createnuclear.ponder.reactor_t2.header": "Reactor T2", "createnuclear.ponder.reactor_t2.text_1": "Floor 1", - "createnuclear.ponder.reactor_t2.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t2.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", "createnuclear.ponder.reactor_t2.text_11": "Alarm: will sound if reactor overheats (free placing)", "createnuclear.ponder.reactor_t2.text_12": "Floor 6", "createnuclear.ponder.reactor_t2.text_13": "Floor 7", @@ -250,7 +250,7 @@ "createnuclear.ponder.reactor_t2.text_9": "Liquid Input: cooling fluid inlet (free placing)", "createnuclear.ponder.reactor_t3.header": "Reactor T3", "createnuclear.ponder.reactor_t3.text_1": "Floor 1", - "createnuclear.ponder.reactor_t3.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t3.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", "createnuclear.ponder.reactor_t3.text_11": "Liquid Input: cooling fluid inlet (free placing)", "createnuclear.ponder.reactor_t3.text_12": "Alarm: will sound if reactor overheats (free placing)", "createnuclear.ponder.reactor_t3.text_13": "Floor 7", diff --git a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java index 4afb0f22..aadf5b41 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java @@ -95,7 +95,7 @@ public class CNFluids { .lang("Liquid Nitrogen") .tag(CNFluidTags.NITROGEN.tag) .properties(p -> p.viscosity(1000) - .density(0) + .density(1000) .canSwim(true) .sound(SoundActions.BUCKET_FILL, SoundEvents.BUCKET_FILL_AXOLOTL) .sound(SoundActions.BUCKET_EMPTY, SoundEvents.BUCKET_EMPTY_FISH) From f659e9f33df9fe5d9579980ef654c7890cf7cfd9 Mon Sep 17 00:00:00 2001 From: Gio Date: Wed, 24 Jun 2026 18:08:02 +0200 Subject: [PATCH 092/171] docs: reclassify B17 as intentional behavior in audit report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RodsTooltipHandler intentionally skips mod items (already handled via setTooltipModifierFactory) to only process external/datapack items. This is not a bug, but a readability risk — updated documentation with the rationale and a recommendation to add a guard comment. --- AUDIT_ACTUEL.md | 10 ++++++++++ .../java/net/nuclearteam/createnuclear/CNItems.java | 9 ++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 90fde951..fbbdc7c7 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -48,6 +48,7 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi Pour chaque item du pattern, boucle sur la grille pour localiser sa position, puis pour chaque voisin **re-boucle sur la totalité des items** (l.59) pour retrouver le voisin par slot — chaque itération désérialise un `ItemStack.of(...)` depuis NBT sans cache (l.36, l.62). Coût pire cas ~57×81×4×57 ≈ 1 050 000 itérations/tick sur réacteur plein. Non couvert par les audits historiques (`reactorLogic/`). - **Asymétrie** (l.61) : le calcul de proximité ne fire que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. De plus `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.67, **division**) côté fuel→voisin vs additions ailleurs. - *Recommandation* : remplacer la boucle de recherche du voisin (l.59) par une `Map` construite une fois par appel → O(n) au lieu de O(n²), **sans changer le comportement**. **Ne pas toucher** à l'asymétrie/division sans confirmation balance (la logique de chaleur a des distinctions intentionnelles entre chemins — ne pas unifier sans vérification). + - **Dépendance avec le point 9 (tags `FUEL`/`COOLER`)** : `computeHeat` (et l'interface `IHeatCalculator.computeHeat`, `IHeatCalculator.java:9`) ne reçoivent **aucun `Level`**, alors que `HeatManager.calculateHeat` (`HeatManager.java:29`) en a un et ne le propage pas (`HeatManager.java:32`). Tant que ce `Level` n'est pas ajouté à la signature, ce fichier ne peut pas utiliser `TypeRodPredicate.isFuel/isCooled` (qui ont besoin de `RodType.resolveRodType(item, level)`) et reste donc sur le double-check `stack.is(TAG) || rod.type() == X` (l.61, l.64, l.85, l.87) — c'est le site le plus engageant des 4 listés au point 9, car il touche une interface publique et non un simple remplacement local. 3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` et `components.get(2).get(1)` accède positionnellement à la ligne « fuel ». Tout ajout/réordonnancement de ligne casse silencieusement ces contrats implicites. @@ -61,6 +62,12 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture ponder). 7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. 8. **`NuclearExplosionEntity.tick()` (`:96`)** — tri d'une pile de `BlockPos` par `distManhattan` en un tick. ⚠️ La taille réelle est `(2·chunksAffected+1)³` (≈125 pour `size=2`), **pas** 1331 comme indiqué auparavant — coût modeste, corrigé ici. +9. **`CNItemTags.FUEL`/`COOLER` — double source de catégorisation avec `RodType.type()`, déjà désynchronisée** *(assigné Gio, priorité basse)* — Tous les chemins métier (`RodType.TypeRodPredicate.IS_FUEL/IS_COOLED`, `ReactorInputInventory.isItemValid`, `DefaultHeatCalculator`, `ReactorBluePrintMenu`) testent `stack.is(TAG) || rodType.type() == X`, un OR redondant entre deux sources indépendantes. Le tag ne porte aucune stat (juste un `TagKey`) ; toutes les valeurs métier vivent déjà sur `RodType` (registre Java `ItemRodTypesValue` **et** registre dynamique data-driven `CreateNuclearRegistries.ROD_TYPE`, donc déjà extensible par datapack sans tag — confirme le constat positif d'`AUDIT_V1.md:154` sur ce design). Preuve de désync déjà réelle : `THORIUM_ROD` (`CNItems.java:250-258`) a `RodType.fuelRodType()` enregistré mais n'a **pas** le tag `CNItemTags.FUEL` (seulement le tag générique `"rods"`) — ne fonctionne aujourd'hui que grâce au fallback `RodType` dans le OR. + - **Plan concret retenu** : remplacer `TypeRodPredicate.IS_FUEL`/`IS_COOLED` (`RodType.java:301-320`, actuellement `Predicate` basés sur `ItemRodTypesValue.getRodType`, qui ignore le registre dynamique data-driven) par deux méthodes statiques `isFuel(ItemStack stack, Level level)`/`isCooled(ItemStack stack, Level level)` appelant `RodType.resolveRodType(stack.getItem(), level).type() == TypeRod.FUEL/COOLER` — `resolveRodType` interroge le registre dynamique avant de retomber sur le registre Java statique, donc un `RodType` défini uniquement par datapack sera enfin reconnu. Une variante `BiPredicate` a été envisagée mais écartée : aucun appelant actuel ne compose (`and`/`or`/`negate`) ni ne stocke ces prédicats comme valeur, donc le gain fonctionnel d'un type `(Bi)Predicate` est nul ici — une méthode statique nommée `isFuel`/`isCooled` est plus honnête qu'une constante `IS_FUEL` qui dépend en réalité d'un contexte (`Level`) à chaque appel. + - **Sites à migrer une fois `isFuel`/`isCooled` créées** (tous ont déjà un `Level` accessible sauf `DefaultHeatCalculator`, voir point 2) : `ReactorInputInventory.isItemValid` (`:30`, via `be.getLevel()`, ⚠️ nullable hors monde — prévoir fallback), `ReactorBluePrintMenu.saveData` (`:132-133` et `:165-166`, deux boucles dans la même méthode, via `playerInventory.player.level()`), `FuelDisplaySource`/`CoolerDisplaySource`/`ReactorSummaryDisplaySource` (déjà via `context.level()`), `ReactorInputManager.getInventory/extractItems` (déjà un paramètre `Level level`). + - **Déjà conformes au design cible** (aucun tag, déjà `RodType.resolveRodType(item, level)`) : `ReactorHeatUpdateCoordinator.canRun` (`:91`) et `RodsStats.getRodTypeStats` (`:60`) — pas de duplication ici, à ne pas toucher, sert de modèle de référence pour la migration des autres sites. + - *Recommandation* : restreindre les tags `FUEL`/`COOLER` à leur seul usage légitime restant (ingrédients de recettes JSON `Ingredient.of(tag)`, compat datapack/mods tiers côté craft) et ne plus s'y fier dans la logique interne — ne garder que `rodType.type() == X` via `isFuel`/`isCooled`. Risque faible, pas de stats dupliquées à corriger, juste un critère booléen redondant à retirer à 4 endroits (+1 nécessitant d'abord un changement de signature, voir point 2). + - **Pourquoi l'ajouter à l'audit malgré la priorité basse** : c'est une dette qui **s'auto-aggrave silencieusement** — chaque nouvel item fuel/cooler ajouté à `CNItems.java` est un nouveau risque d'oubli du tag (déjà arrivé une fois sur 3 avec `THORIUM_ROD`), et le `||` défensif partout dans le code masque le symptôme sans le corriger. Documenter le plan maintenant évite de redécouvrir le même diagnostic à un audit futur, et fixe le bon modèle de référence (`ReactorHeatUpdateCoordinator`/`RodsStats`) pendant qu'il est encore frais. --- @@ -152,6 +159,9 @@ Vérifiés résolus dans le code actuel : **B2** (`RadiationSyncPacket` supprim 8. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). 9. `DefaultHeatCalculator` : map slot→ItemStack précalculée (O(n²) → O(n)) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance (§2.2). +**Assigné Gio (priorité basse, à faire quand le temps le permet)** +13. Tags `CNItemTags.FUEL`/`COOLER` → créer `TypeRodPredicate.isFuel/isCooled(stack, level)` basés sur `RodType.resolveRodType`, migrer `ReactorInputInventory`, `ReactorBluePrintMenu`, les `*DisplaySource`, `ReactorInputManager` ; restreindre les tags au craft (§2.9). Le site `DefaultHeatCalculator` nécessite d'abord d'ajouter `Level` à `IHeatCalculator.computeHeat` (§2.2) — à faire en premier sur ce fichier précis, indépendamment du chantier perf O(n²) déjà prévu au point 9 ci-dessus. + **Décisions produit (choisir puis exécuter)** 10. Collier teignable chat/loup : finir le câblage (`addLayer` + `render`) ou retirer `DyeItem`/`setCollarColor` (§4). 11. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 55f38239..3de6d721 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -13,7 +13,6 @@ import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.ItemTags; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; @@ -270,7 +269,7 @@ private static NonNullBiConsumer, Regis ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, c.get()) .unlockedBy("has_cloth", RegistrateRecipeProvider.has(CNItemTags.CLOTH.tag)) .define('X', CNTags.forgeItemTag("ingots/lead")) - .define('Y', Ingredient.of(ItemTags.create(new ResourceLocation("forge", "ingots/brass")))) + .define('Y', CNTags.forgeItemTag("ingots/brass")) .define('Z', CNBlocks.REINFORCED_GLASS.asItem()) .pattern("YXY") .pattern("XZX") @@ -304,7 +303,7 @@ private static NonNullBiConsumer, Regis ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, c.get()) .unlockedBy("has_cloth", RegistrateRecipeProvider.has(CNItemTags.CLOTH.tag)) .define('X', CNTags.forgeItemTag("ingots/lead")) - .define('Y', Ingredient.of(ItemTags.create(new ResourceLocation("forge", "ingots/brass")))) + .define('Y', CNTags.forgeItemTag("ingots/brass")) .define('Z', CNItems.GRAPHITE_ROD) .pattern("Y Y") .pattern("XXX") @@ -338,7 +337,7 @@ private static NonNullBiConsumer, Regis ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, c.get()) .unlockedBy("has_cloth", RegistrateRecipeProvider.has(CNItemTags.CLOTH.tag)) .define('X', CNTags.forgeItemTag("ingots/lead")) - .define('Y', Ingredient.of(ItemTags.create(new ResourceLocation("forge", "ingots/brass")))) + .define('Y', CNTags.forgeItemTag("ingots/brass")) .pattern("YXY") .pattern("X X") .pattern("Y Y") @@ -372,7 +371,7 @@ private static NonNullBiConsumer, Regis ShapedRecipeBuilder.shaped(RecipeCategory.COMBAT, c.get()) .unlockedBy("has_cloth", RegistrateRecipeProvider.has(CNItemTags.CLOTH.tag)) .define('X', CNTags.forgeItemTag("ingots/lead")) - .define('Y', Ingredient.of(ItemTags.create(new ResourceLocation("forge", "ingots/brass")))) + .define('Y', CNTags.forgeItemTag("ingots/brass")) .pattern("Y Y") .pattern("X X") .showNotification(true) From 52b122bf3755e5b2b2f4ee2657e6e68de01874d5 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Wed, 24 Jun 2026 20:32:09 +0200 Subject: [PATCH 093/171] perf: merge duplicate multiblock controller scans into one shared loop ReactorPattern.findController and findControllerPos each ran their own ~3,971-block scan around the placed/removed part, and MultiblockHelpers.handleOnPlace/handleRemoval called both of them back to back for the same place/break event, doubling the work. Extract the shared scan into scanControllerCandidates(...) (with a ControllerVisitor callback that can short-circuit once a relevant controller is found), and have findController/findControllerPos reuse it. findControllerPos(pos, level, first) is a new overload that does the assemble/disassemble work findController used to do, while also returning the matching controller position, so handleOnPlace/handleRemoval only need a single scan instead of two. The old 2-arg handleOnPlace(pos, level, boolean) overload is now unused and removed. Also avoid unnecessarily re-assembling/disassembling a neighboring, already-assembled controller whose structure doesn't include the changed block: findController/findControllerPos now only act on a controller when the changed block is in its range, or when it isn't assembled yet (covers first-time assembly), instead of acting on every controller found in the scan radius. Document the fix in AUDIT_ACTUEL.md: the scan/double-call issue is now flagged as partially fixed, with the remaining work (no client-side guard, duplicate playerDestroy+onRemove calls on ReactorCasing/ ReactorCooler, LOGGER.warn spam) still tracked as priority #1. --- AUDIT_ACTUEL.md | 18 ++-- .../content/multiblock/MultiblockHelpers.java | 16 +--- .../multiblock/pattern/ReactorPattern.java | 82 +++++++++++++------ 3 files changed, 71 insertions(+), 45 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index fbbdc7c7..01478db2 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -36,11 +36,13 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi ### 🔴 Critique — performance/correction du scan multiblock -1. **Scan géométrique du contrôleur : aucune garde client + double appel sur un même événement** *(tous confirmés)* - - `ReactorPattern.findController`/`findControllerPos` (`ReactorPattern.java:34-71`) scannent ~3 971 blocs (11×19×19, `new BlockPos` par itération, borne `!=`) avec **aucune garde `level.isClientSide()`** nulle part dans la chaîne `onPlace/onRemove/playerDestroy → findController → ReactorAssembler.assemble/disassemble`. Or `assemble`/`disassemble` **mutent l'état de la BlockEntity** (`setAssembled`, `setMultiblockSize`, `removeIOAll`) et envoient un message joueur → mutation métier potentiellement **exécutée deux fois** (client + serveur) à chaque pose/casse autour d'un réacteur. - - **Double appel à la casse** : `ReactorCasing.java` appelle `findController` dans **`playerDestroy` (l.60) ET `onRemove` (l.66)** pour le même événement → deux scans complets. Idem `ReactorCooler.java` (l.39 + l.45). ⚠️ `ReactorFrame.java` est en revanche **plus malin** : son `onRemove` garde `if (!state.is(newState.getBlock()))` (l.128-135) — modèle à généraliser. - - **Spam de log** : `ReactorAssembler.assemble` logue en `LOGGER.warn` (`ReactorAssembler.java:37-38`) à **chaque** réussite de pattern → spam en conditions normales de jeu. - - *Recommandation* : `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` ; supprimer l'appel redondant dans `ReactorCasing.playerDestroy`/`ReactorCooler.playerDestroy` (garder `onRemove`, idéalement avec la garde de `ReactorFrame`) ; `LOGGER.warn` → `LOGGER.debug`. Risque très faible, gain net en multijoueur. **C'est le problème de perf/correction le plus concret du projet.** +1. **Scan géométrique du contrôleur : aucune garde client + double appel sur un même événement** *(partiellement corrigé, revérifié 2026-06-24)* + - ✅ **Corrigé** — `ReactorPattern.findController`/`findControllerPos` (`ReactorPattern.java`) partagent désormais une seule boucle de scan (`scanControllerCandidates`) avec court-circuit dès qu'un controller pertinent est trouvé. `findController` filtre maintenant via `isInReactorRange` : un controller voisin déjà assemblé dont la structure n'inclut pas `blockPos` n'est plus ré-assemblé/désassemblé inutilement (évitait un risque de double-enregistrement I/O via `ReactorAssembler.findAndRegisterSpecialBlocks`, qui n'est pas idempotent). + - ✅ **Corrigé** — `MultiblockHelpers.handleOnPlace`/`handleRemoval` faisaient **deux scans complets** par pose/casse (`findController` puis `findControllerPos`). Fusionné en un seul scan via une nouvelle surcharge `findControllerPos(pos, level, first)` qui fait le travail d'assemblage **et** retourne le controller pertinent ; la surcharge `handleOnPlace(pos, level, boolean)` (devenue inutilisée) a été supprimée. + - ❌ **Toujours non corrigé** — **aucune garde `level.isClientSide()`** nulle part dans la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler.assemble/disassemble`. Mutation d'état métier toujours potentiellement exécutée côté client en plus du serveur. + - ❌ **Toujours non corrigé** — **double appel à la casse** : `ReactorCasing.java` appelle toujours `pattern.findController` dans **`playerDestroy` (l.60) ET `onRemove` (l.66)** pour le même événement → deux scans complets. Idem `ReactorCooler.java` (l.39 + l.45). `ReactorFrame.java` reste le seul à garder `if (!state.is(newState.getBlock()))` côté `onRemove`. + - ❌ **Toujours non corrigé** — **spam de log** : `ReactorAssembler.assemble` logue toujours en `LOGGER.warn` (`ReactorAssembler.java:40-41`) à chaque réussite de pattern. + - *Reste à faire* : `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` ; supprimer l'appel redondant dans `ReactorCasing.playerDestroy`/`ReactorCooler.playerDestroy` (garder `onRemove`) ; `LOGGER.warn` → `LOGGER.debug`. Risque très faible, gain net en multijoueur — **reste la priorité n°1 du projet**, mais le scan lui-même (le plus coûteux des deux problèmes initiaux) est désormais optimisé et plus sûr sur les multiblocks voisins. ### 🟠 Importants @@ -121,7 +123,7 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi | Point | État | Réf. | |---|---|---| -| `ReactorPattern.findController/findControllerPos` : ~3 971 blocs ×2 par casse, **sans garde client**, mutation d'état métier potentiellement double | ❌ non corrigé — **priorité n°1** | §2.1 | +| `ReactorPattern.findController/findControllerPos` : scan fusionné + court-circuit + filtre `isInReactorRange` (✅), double scan `MultiblockHelpers` éliminé (✅) ; **sans garde client** (❌), double appel `playerDestroy`+`onRemove` sur `ReactorCasing`/`ReactorCooler` (❌) | 🟡 partiellement corrigé — reste **priorité n°1** | §2.1 | | `DefaultHeatCalculator.computeHeat` : ~O(n²) + désérialisation NBT par cellule, à chaque tick | ❌ non corrigé | §2.2 | | `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame | ❌ non corrigé | — | | `clearLockIfAllInputsEmpty` : ancien scan cubique `O(n³)` | ✅ **corrigé** (utilise `inputFluidManager.getFuildHandlers`) | §3 | @@ -147,8 +149,8 @@ Vérifiés résolus dans le code actuel : **B2** (`RadiationSyncPacket` supprim ## 7. 🗺️ Feuille de route — priorités **Quick wins (risque quasi nul, gain immédiat)** -1. Garde `level.isClientSide()` sur `findController`/`findControllerPos`/`ReactorAssembler` (§2.1). **← le plus rentable.** -2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` + `ReactorCooler.playerDestroy` (généraliser la garde de `ReactorFrame.onRemove`). +1. Garde `level.isClientSide()` sur `findController`/`findControllerPos`/`ReactorAssembler` (§2.1). **← le plus rentable, toujours à faire.** +2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` + `ReactorCooler.playerDestroy` (généraliser la garde de `ReactorFrame.onRemove`). *(Toujours à faire — distinct du double-scan `MultiblockHelpers`, déjà corrigé le 2026-06-24.)* 3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. 5. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java index 36c8c241..1bf4928b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java @@ -18,9 +18,7 @@ public class MultiblockHelpers { * invoke provided callbacks to register or remove parts. */ public static void handleOnPlace(BlockPos pos, Level level, BiConsumer register) { - handleOnPlace(pos, level, true); - - BlockPos controllerPos = pattern.findControllerPos(pos, level); + BlockPos controllerPos = pattern.findControllerPos(pos, level, true); if (controllerPos != null) { ReactorControllerBlockEntity controllerBlockEntity = (ReactorControllerBlockEntity) level.getBlockEntity(controllerPos); if (controllerBlockEntity != null) { @@ -29,18 +27,8 @@ public static void handleOnPlace(BlockPos pos, Level level, BiConsumer remover) { - handleOnPlace(pos, level, false); - - BlockPos controllerPos = pattern.findControllerPos(pos, level); + BlockPos controllerPos = pattern.findControllerPos(pos, level, false); if (controllerPos != null) { ReactorControllerBlockEntity controllerBlockEntity = (ReactorControllerBlockEntity) level.getBlockEntity(controllerPos); if (controllerBlockEntity != null) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java index 4b5f949b..cdd5f18a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java @@ -31,18 +31,22 @@ private static Predicate stateIs(Block block) { }; } - public void findController(BlockPos blockPos, Level level, boolean first){ + @FunctionalInterface + private interface ControllerVisitor { + boolean visit(BlockPos controllerPos, ReactorControllerBlockEntity entity); + } + + private void scanControllerCandidates(BlockPos blockPos, Level level, ControllerVisitor visitor) { BlockPos newBlock; Vec3i pos = new Vec3i(blockPos.getX(), blockPos.getY(), blockPos.getZ()); for (int y = pos.getY()-5; y != pos.getY()+6; y+=1) { for (int x = pos.getX()-9; x != pos.getX()+10; x+=1) { for (int z = pos.getZ()-9; z != pos.getZ()+10; z+=1) { newBlock = new BlockPos(x, y, z); - if (level.getBlockState(newBlock).is(CNBlocks.REACTOR_CONTROLLER.get())) { - if (first) { - ReactorAssembler.assemble(newBlock, level); - } else { - ReactorAssembler.disassemble(newBlock, level); + if (level.getBlockState(newBlock).is(CNBlocks.REACTOR_CONTROLLER.get()) + && level.getBlockEntity(newBlock) instanceof ReactorControllerBlockEntity entity) { + if (visitor.visit(newBlock, entity)) { + return; } } } @@ -50,25 +54,57 @@ public void findController(BlockPos blockPos, Level level, boolean first){ } } - public BlockPos findControllerPos(BlockPos blockPos, Level level){ - BlockPos newBlock; - Vec3i pos = new Vec3i(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - for (int y = pos.getY()-5; y != pos.getY()+6; y+=1) { - for (int x = pos.getX()-9; x != pos.getX()+10; x+=1) { - for (int z = pos.getZ()-9; z != pos.getZ()+10; z+=1) { - newBlock = new BlockPos(x, y, z); - if (level.getBlockState(newBlock).is(CNBlocks.REACTOR_CONTROLLER.get())) { - if (level.getBlockEntity(newBlock) instanceof ReactorControllerBlockEntity entity) { - ReactorAssembler.assemble(newBlock, level); - if (isInReactorRange(entity.getMultiblockPos(), blockPos)) { - return newBlock; - } - } - } + public void findController(BlockPos blockPos, Level level, boolean first){ + scanControllerCandidates(blockPos, level, ((controllerPos, entity) -> { + boolean inRange = isInReactorRange(entity.getMultiblockPos(), blockPos); + if (first) { + if (inRange || !entity.isAssembled()) { + ReactorAssembler.assemble(controllerPos, level); } + } else if (inRange) { + ReactorAssembler.disassemble(controllerPos, level); } - } - return null; + + return false; + })); + } + + public BlockPos findControllerPos(BlockPos blockPos, Level level, boolean first){ + BlockPos[] found = {null}; + scanControllerCandidates(blockPos, level, ((controllerPos, entity) -> { + boolean inRange = isInReactorRange(entity.getMultiblockPos(), blockPos); + if (first) { + if (inRange || !entity.isAssembled()) { + ReactorAssembler.assemble(controllerPos, level); + } + } else if (inRange) { + ReactorAssembler.disassemble(controllerPos, level); + } + + if (isInReactorRange(entity.getMultiblockPos(), blockPos)) { + found[0] = controllerPos; + return true; + } + + return false; + })); + + return found[0]; + } + + public BlockPos findControllerPos(BlockPos blockPos, Level level){ + BlockPos[] found = {null}; + scanControllerCandidates(blockPos, level, ((controllerPos, entity) -> { + ReactorAssembler.assemble(controllerPos, level); + if (isInReactorRange(entity.getMultiblockPos(), blockPos)) { + found[0] = controllerPos; + return true; + } + + return false; + })); + + return found[0]; } public boolean isInReactorRange(@Nullable BoundingBox reactorPos, BlockPos blockPos) { From a9b65ed65db86ea2b6912cdd3a653953e88542c3 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 10:33:54 +0200 Subject: [PATCH 094/171] Refactor Reactor inputs and output recipes to be Deployer-only --- .../15812fa7bc190aa8f0a8644088c7ff563925e506 | 8 +-- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 2 +- ..._input_from_hopper_and_reactor_casing.json | 2 +- ...ut_from_fluid_pipe_and_reactor_casing.json | 2 +- ..._output_from_shaft_and_reactor_casing.json | 2 +- .../data/recipe/CNDeployingRecipeGen.java | 52 +++++++++++++++++++ .../recipe/CNItemApplicationRecipeGen.java | 17 ------ .../data/recipe/CNProcessingRecipeGen.java | 2 +- .../data/CreateNuclearDatagen.java | 1 - 9 files changed, 61 insertions(+), 27 deletions(-) rename src/generated/resources/data/createnuclear/recipes/{item_application => deploying}/reactor_input_from_hopper_and_reactor_casing.json (84%) rename src/generated/resources/data/createnuclear/recipes/{item_application => deploying}/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json (85%) rename src/generated/resources/data/createnuclear/recipes/{item_application => deploying}/reactor_output_from_shaft_and_reactor_casing.json (84%) create mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java diff --git a/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 b/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 index 94ddd2ad..06c15daf 100644 --- a/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 +++ b/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T09:46:27.9556309 CreateNuclear's Processing Recipes +// 1.20.1 2026-06-25T10:30:57.471141 CreateNuclear's Processing Recipes bccfe326d6c91bd2df207a38225fbca413e1013f data/createnuclear/recipes/compacting/thorium_fluid_to_thorium_ingot.json c711d032a04e1a9350ad9bc4d9c4d74f54689862 data/createnuclear/recipes/compacting/uranium_fluid_to_yellowcake.json 33becbc558bd2fbe277be096b292c0093f84e44c data/createnuclear/recipes/crushing/coal.json @@ -9,12 +9,12 @@ c711d032a04e1a9350ad9bc4d9c4d74f54689862 data/createnuclear/recipes/compacting/u c0e1f33d8e91a3133e5acf6e4d3eb5ea5cd23471 data/createnuclear/recipes/crushing/raw_thorium.json 169c09c5947ddf8bdc8727af3c71368880b0c128 data/createnuclear/recipes/crushing/raw_thorium_block.json 26d2787e831b9986ed6f90f8ea803d5fdc544bf5 data/createnuclear/recipes/crushing/raw_zinc.json +d2bb94c56fa462ebed3d762a90f6e79d172ffa51 data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json +722c8115413c67402b4c267b1e06c3d761441f9a data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json +04c671106607c2c93c0706f690cd876fb072dd56 data/createnuclear/recipes/deploying/reactor_output_from_shaft_and_reactor_casing.json e42be7d17c5e057e62c4b1176cbf43319a157f51 data/createnuclear/recipes/enriched/enriched_yellowcake.json 74555eb2cce0827f99dc5c4ff91362bdaecad725 data/createnuclear/recipes/enriched/enriching_campfire.json d0a30a8942f3e81d11afa21a93037916601c38cb data/createnuclear/recipes/item_application/reactor_casing_from_steel_and_brass_casing.json -f2d3a2dbcb9135e31261cc8408f11cd07038a826 data/createnuclear/recipes/item_application/reactor_input_from_hopper_and_reactor_casing.json -a98e78b74b8755c320ffaf30ba16631bd11240f6 data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json -91c07d7804d0960aaa17a6258f00f1731ca458f5 data/createnuclear/recipes/item_application/reactor_output_from_shaft_and_reactor_casing.json a9d114da800657c53caabcb1369137ede6746362 data/createnuclear/recipes/mixing/liquid_nitrogen.json 7fc7695cd03577131096e9695170193044f8bc1a data/createnuclear/recipes/mixing/steel.json 4bc858c73385e4309ef250b163cc696244a64767 data/createnuclear/recipes/mixing/thorium_fluid.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index fedefb03..b004f1a5 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T15:46:40.18335 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-25T10:30:57.472976 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json diff --git a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_input_from_hopper_and_reactor_casing.json b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json similarity index 84% rename from src/generated/resources/data/createnuclear/recipes/item_application/reactor_input_from_hopper_and_reactor_casing.json rename to src/generated/resources/data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json index f5690f24..86e5dbc3 100644 --- a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_input_from_hopper_and_reactor_casing.json +++ b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json @@ -1,5 +1,5 @@ { - "type": "create:item_application", + "type": "create:deploying", "ingredients": [ { "item": "createnuclear:reactor_casing" diff --git a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json similarity index 85% rename from src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json rename to src/generated/resources/data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json index 2a95d6b8..a6843872 100644 --- a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json +++ b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json @@ -1,5 +1,5 @@ { - "type": "create:item_application", + "type": "create:deploying", "ingredients": [ { "item": "createnuclear:reactor_casing" diff --git a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_output_from_shaft_and_reactor_casing.json b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_output_from_shaft_and_reactor_casing.json similarity index 84% rename from src/generated/resources/data/createnuclear/recipes/item_application/reactor_output_from_shaft_and_reactor_casing.json rename to src/generated/resources/data/createnuclear/recipes/deploying/reactor_output_from_shaft_and_reactor_casing.json index 9a1e6c11..c31c429f 100644 --- a/src/generated/resources/data/createnuclear/recipes/item_application/reactor_output_from_shaft_and_reactor_casing.json +++ b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_output_from_shaft_and_reactor_casing.json @@ -1,5 +1,5 @@ { - "type": "create:item_application", + "type": "create:deploying", "ingredients": [ { "item": "createnuclear:reactor_casing" diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java new file mode 100644 index 00000000..2aa512af --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java @@ -0,0 +1,52 @@ +package net.nuclearteam.createnuclear.foundation.data.recipe; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.api.data.recipe.DeployingRecipeGen; +import net.minecraft.data.PackOutput; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.ItemLike; +import net.nuclearteam.createnuclear.CNBlocks; +import net.nuclearteam.createnuclear.CreateNuclear; + +public class CNDeployingRecipeGen extends DeployingRecipeGen { + + GeneratedRecipe REACTOR_INPUT = deploying("reactor_input_from_hopper_and_reactor_casing", + Items.HOPPER, + CNBlocks.REACTOR_CASING.get(), + CNBlocks.REACTOR_INPUT.get() + ); + + GeneratedRecipe REACTOR_LIQUID_INPUT = deploying("reactor_liquid_input_from_fluid_pipe_and_reactor_casing", + AllBlocks.FLUID_PIPE.asItem(), + CNBlocks.REACTOR_CASING.get(), + CNBlocks.REACTOR_LIQUID_INPUT.get() + ); + + GeneratedRecipe REACTOR_OUTPUT = deploying("reactor_output_from_shaft_and_reactor_casing", + AllBlocks.SHAFT.asItem(), + CNBlocks.REACTOR_CASING.get(), + CNBlocks.REACTOR_OUTPUT.get() + ); + + protected GeneratedRecipe deploying(String name, Ingredient ingredient, ItemLike input, ItemLike output) { + return create(CreateNuclear.asResource(name), b -> + b.require(input) + .require(ingredient) + .output(output) + ); + } + + protected GeneratedRecipe deploying(String name, Item ingredient, ItemLike input, ItemLike output) { + return create(CreateNuclear.asResource(name), b -> + b.require(input) + .require(ingredient) + .output(output) + ); + } + + public CNDeployingRecipeGen(PackOutput generator) { + super(generator, CreateNuclear.MOD_ID); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java index 961bc126..9fb36a0c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNItemApplicationRecipeGen.java @@ -22,23 +22,6 @@ public class CNItemApplicationRecipeGen extends ItemApplicationRecipeGen { CNBlocks.REACTOR_CASING.get() ); - GeneratedRecipe REACTOR_OUTPUT = itemApplication("reactor_output_from_shaft_and_reactor_casing", - AllBlocks.SHAFT.asItem(), - CNBlocks.REACTOR_CASING.get(), - CNBlocks.REACTOR_OUTPUT.get() - ); - - GeneratedRecipe REACTOR_INPUT = itemApplication("reactor_input_from_hopper_and_reactor_casing", - Items.HOPPER, - CNBlocks.REACTOR_CASING.get(), - CNBlocks.REACTOR_INPUT.get() - ); - - GeneratedRecipe REACTOR_LIQUID_INPUT = itemApplication("reactor_liquid_input_from_fluid_pipe_and_reactor_casing", - AllBlocks.FLUID_PIPE.asItem(), - CNBlocks.REACTOR_CASING.get(), - CNBlocks.REACTOR_LIQUID_INPUT.get() - ); protected GeneratedRecipe itemApplication(String name, Ingredient ingredient, ItemLike input, ItemLike output) { return create(CreateNuclear.asResource(name), b -> diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNProcessingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNProcessingRecipeGen.java index 00adfe31..aa8ea107 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNProcessingRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNProcessingRecipeGen.java @@ -38,7 +38,7 @@ public static void registerAll(DataGenerator gen, PackOutput output) { GENERATORS.add(new CNEnrichedRecipeGen(output)); GENERATORS.add(new CNSnowPowderRecipeGen(output)); GENERATORS.add(new CNWashingRecipeGen(output)); - + GENERATORS.add(new CNDeployingRecipeGen(output)); gen.addProvider(true, new DataProvider() { diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java index d537fd2f..36d9e7b2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/data/CreateNuclearDatagen.java @@ -40,7 +40,6 @@ public static void gatherData(GatherDataEvent event) { generator.addProvider(event.includeClient(), new CNStandardRecipeGen(output)); generator.addProvider(event.includeClient(), new CNMechanicalCraftingRecipeGen(output)); generator.addProvider(event.includeClient(), new CNAdvancement(output)); - /*if (event.includeClient()) { }*/ From 3285a2026052b58c6f700c2196fcd24dfcb3c23d Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 13:08:04 +0200 Subject: [PATCH 095/171] Optimize reactor ponder scenes, add IO placement scene --- .../foundation/ponder/CNPonderIndex.java | 6 +- .../ponder/scenes/CNPonderReactorScenes.java | 169 ++++++++++++------ 2 files changed, 120 insertions(+), 55 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/ponder/CNPonderIndex.java b/src/main/java/net/nuclearteam/createnuclear/foundation/ponder/CNPonderIndex.java index 09369e3d..d3a0f787 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/ponder/CNPonderIndex.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/ponder/CNPonderIndex.java @@ -19,11 +19,13 @@ public static void register(PonderSceneRegistrationHelper help HELPER.forComponents(CNBlocks.REACTOR_CONTROLLER) .addStoryBoard("reactor/reactor_t1_ponder", CNPonderReactorScenes::t1) .addStoryBoard("reactor/reactor_t2_ponder", CNPonderReactorScenes::t2) - .addStoryBoard("reactor/reactor_t3_ponder", CNPonderReactorScenes::t3); + .addStoryBoard("reactor/reactor_t3_ponder", CNPonderReactorScenes::t3) + .addStoryBoard("reactor/reactor_t1_ponder", CNPonderReactorScenes::ioPlacement); HELPER.forComponents(CNItems.REACTOR_BLUEPRINT) .addStoryBoard("reactor/reactor_t1_ponder", CNPonderReactorScenes::t1) .addStoryBoard("reactor/reactor_t2_ponder", CNPonderReactorScenes::t2) - .addStoryBoard("reactor/reactor_t3_ponder", CNPonderReactorScenes::t3); + .addStoryBoard("reactor/reactor_t3_ponder", CNPonderReactorScenes::t3) + .addStoryBoard("reactor/reactor_t1_ponder", CNPonderReactorScenes::ioPlacement); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 186b09af..32037405 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -6,6 +6,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.phys.Vec3; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.nuclearteam.createnuclear.CNBlocks; import net.nuclearteam.createnuclear.CNItems; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock; @@ -114,6 +116,14 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil util, int S, int H, int plate, boolean bySections) { Positions pos = positionsFor(S, H); + scene.world().modifyBlock(pos.input1, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + scene.world().modifyBlock(pos.input2, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + scene.world().modifyBlock(pos.liquidInput, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + scene.world().modifyBlock(pos.alarm, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + scene.world().modifyBlock(pos.output, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + + scene.idle(20); + for (int y = 1; y <= H; y++) { scene.overlay().showText(bySections ? 25 : 8) .text("Floor " + y) @@ -126,7 +136,7 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u // Block-by-block got its per-floor pacing from plate^2 * idle(4). With a single // section per floor we must idle explicitly, otherwise callout-free floors flash // by instantly and their "Floor N" labels overlap each other. - scene.idle(30); + scene.idle(50); for (BlockPos sp : pos.specials()) { if (sp.getY() == y) { tryShowCallout(scene, util, pos, sp.getX(), sp.getY(), sp.getZ(), bySections); @@ -153,65 +163,26 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u .withItem(CNItems.REACTOR_BLUEPRINT.asStack()) .rightClick(); scene.world().modifyBlock(pos.controller, s -> s.setValue(ReactorControllerBlock.ASSEMBLED, true), true); + + scene.idle(120); + scene.overlay() + .showText(120) + .text("Note: Check page 4 for I/O and Alarm blocks (placement & function).") + .attachKeyFrame() + .placeNearTarget(); + scene.idle(130); } - /** - * Shows the explanatory callout for the special block at (x,y,z), if any. Shared by both reveal - * modes. When {@code reduced} is true (T3), these block-explanation texts run 15% shorter - * (90->77, 110->94, hold 80->68); the other tiers keep the original durations. - */ private static void tryShowCallout(SceneBuilder scene, SceneBuildingUtil util, Positions pos, int x, int y, int z, boolean reduced) { - BlockPos input1 = pos.input1, input2 = pos.input2, liquidInput = pos.liquidInput, - alarm = pos.alarm, output = pos.output, controller = pos.controller; + BlockPos controller = pos.controller; - if (x == input1.getX() && y == input1.getY() && z == input1.getZ()) { - scene.overlay().showText(reduced ? 77 : 90) - .text("Input: stores one stack of rod (free placing : can replace any casing not in the edge)") - .pointAt(util.vector().blockSurface(input1, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(reduced ? 68 : 80); - } - if (x == input2.getX() && y == input2.getY() && z == input2.getZ()) { - scene.overlay().showText(reduced ? 94 : 110) - .text("Second input: needed because you will likely have one input " + - "of fuel rod and one for coolant (free placing)") - .pointAt(util.vector().blockSurface(input2, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(reduced ? 68 : 80); - } - if (x == liquidInput.getX() && y == liquidInput.getY() && z == liquidInput.getZ()) { - scene.overlay().showText(reduced ? 77 : 90) - .text("Liquid Input: cooling fluid inlet (free placing)") - .pointAt(util.vector().blockSurface(liquidInput, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(reduced ? 68 : 80); - } - if (x == alarm.getX() && y == alarm.getY() && z == alarm.getZ()) { - scene.overlay().showText(reduced ? 77 : 90) - .text("Alarm: will sound if reactor overheats (free placing)") - .pointAt(util.vector().blockSurface(alarm, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(reduced ? 68 : 80); - } - if (x == output.getX() && y == output.getY() && z == output.getZ()) { - scene.overlay().showText(reduced ? 77 : 90) - .text("Output: where the generated power is extracted (free placing)") - .pointAt(util.vector().blockSurface(output, Direction.UP)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(reduced ? 68 : 80); - } if (x == controller.getX() && y == controller.getY() && z == controller.getZ()) { - scene.overlay().showText(reduced ? 94 : 110) + scene.overlay().showText(reduced ? 110 : 130) .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") .pointAt(util.vector().blockSurface(controller, Direction.DOWN)) .attachKeyFrame() .placeNearTarget(); - scene.idle(reduced ? 68 : 80); + scene.idle(reduced ? 120 : 140); } } @@ -224,7 +195,7 @@ public static void t1(SceneBuilder scene, SceneBuildingUtil util) { scene.showBasePlate(); scene.rotateCameraY(180); scene.scaleSceneView(0.55f); - showReactorStructure(scene, util, S, H, plate); + showReactorStructure(scene, util, S, H, plate, true); } public static void t2(SceneBuilder scene, SceneBuildingUtil util) { @@ -236,7 +207,7 @@ public static void t2(SceneBuilder scene, SceneBuildingUtil util) { scene.showBasePlate(); scene.rotateCameraY(180); scene.scaleSceneView(0.45f); - showReactorStructure(scene, util, S, H, plate); + showReactorStructure(scene, util, S, H, plate, true); } public static void t3(SceneBuilder scene, SceneBuildingUtil util) { @@ -251,4 +222,96 @@ public static void t3(SceneBuilder scene, SceneBuildingUtil util) { // T3 reveals floor-by-floor (section-based) so the largest tier doesn't lag; T1/T2 stay block-by-block. showReactorStructure(scene, util, S, H, plate, true); } + + public static void ioPlacement(SceneBuilder scene, SceneBuildingUtil util) { + int S = S_T1, H = H_T1; + int plate = plateSizeFor(S); + Positions pos = positionsFor(S, H); + + scene.title("reactor_io_placement", "Reactor I/O: Function & Placement"); + scene.configureBasePlate(0, 0, plate); + scene.world().showSection(util.select().layer(0), Direction.UP); + scene.showBasePlate(); + scene.rotateCameraY(180); + scene.scaleSceneView(0.55f); + + // Show the entire T1 structure instantly + scene.world().showSection(util.select().layersFrom(1), Direction.UP); + scene.idle(20); + + // Show Input 1 + scene.overlay().showText(150) + .text("Rod Input: Stores Heating or Cooling Rods. We need one Heating Rod (fuel) to heat the reactor, and one Cooling Rod for stability.") + .pointAt(util.vector().blockSurface(pos.input1, Direction.SOUTH)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(160); + + // Show Input 2 + scene.overlay().showText(150) + .text("Second Rod Input: This is why we need at least two inputs! One for the Heating Rod and one for the Cooling Rod to prevent explosions.") + .pointAt(util.vector().blockSurface(pos.input2, Direction.SOUTH)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(160); + + // Show Fluid Input + scene.overlay().showText(150) + .text("Fluid Input: Fluid is also required to cool the reactor and ensure it does not explode.") + .pointAt(util.vector().blockSurface(pos.liquidInput, Direction.SOUTH)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(160); + + // Show Alarm + scene.overlay().showText(150) + .text("Alarm (Optional): Emits a sound when the reactor becomes unstable and risks exploding.") + .pointAt(util.vector().blockSurface(pos.alarm, Direction.SOUTH)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(160); + + // Show Output + scene.overlay().showText(160) + .text("Output: Necessary to extract generated energy. You can place multiple outputs to dispatch the total energy between them.") + .pointAt(util.vector().blockSurface(pos.output, Direction.SOUTH)) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(170); + + // --- Placement --- + scene.overlay().showText(120) + .text("These blocks can replace ANY Reactor Casing, as long as it is not on an edge.") + .attachKeyFrame() + .placeNearTarget(); + scene.idle(130); + + // Demonstrate moving the blocks to the roof (y=7 for T1) + BlockPos newIn1 = new BlockPos(3, 7, 3); + BlockPos newIn2 = new BlockPos(3, 7, 4); + BlockPos newLiq = new BlockPos(3, 7, 5); + BlockPos newAlm = new BlockPos(5, 7, 3); + BlockPos newOut = new BlockPos(5, 7, 5); + + // Replace old pos with casing + scene.world().modifyBlock(pos.input1, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), true); + scene.world().modifyBlock(pos.input2, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), true); + scene.world().modifyBlock(pos.liquidInput, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), true); + scene.world().modifyBlock(pos.alarm, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), true); + scene.world().modifyBlock(pos.output, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), true); + + // Place I/O on roof + scene.world().modifyBlock(newIn1, s -> CNBlocks.REACTOR_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + scene.world().modifyBlock(newIn2, s -> CNBlocks.REACTOR_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + scene.world().modifyBlock(newLiq, s -> CNBlocks.REACTOR_LIQUID_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + // Note: ReactorAlarm might not have FACING. Using default state. + scene.world().modifyBlock(newAlm, s -> CNBlocks.REACTOR_ALARM.get().defaultBlockState(), true); + scene.world().modifyBlock(newOut, s -> CNBlocks.REACTOR_OUTPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + + scene.overlay().showText(100) + .text("They can be grouped together on the roof or any other flat surface.") + .pointAt(util.vector().blockSurface(newIn2, Direction.UP)) + .placeNearTarget(); + scene.idle(110); + } } From 95289bee303e8b2d8efc96806795fc0c9662405d Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 13:08:59 +0200 Subject: [PATCH 096/171] fix: update text formatting in reactor controller descriptions and correct fluid density --- gradle.properties | 6 +- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +- .../assets/createnuclear/lang/en_ud.json | 74 +++++++++---------- .../assets/createnuclear/lang/en_us.json | 74 +++++++++---------- 4 files changed, 76 insertions(+), 84 deletions(-) diff --git a/gradle.properties b/gradle.properties index d14b78cf..ebd1d0cc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -69,8 +69,8 @@ mod_version=2.0.12-beta # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html mod_group_id=net.nuclearteam.createnuclear -# The authors of the mod. This is a simple text string that is used for display purposes in the mod list. +# The authors of the mod. This is a simple text string used for display purposes in the mod list. mod_authors=Create Nuclear Team -# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. -mod_description=Create nuclear is a mod that adds a whole nuclear system to the create mod. An optimized reactor produces over two millions SU. +# The description of the mod. This is a simple multiline text string used for display purposes in the mod list. +mod_description=Create nuclear is a mod that adds a whole nuclear system to the Create mod. An optimized reactor produces over eight million SU. mixin_config = 'createnuclear.forge.mixins.json' diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index b004f1a5..d4bb0371 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-25T10:30:57.472976 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-25T13:02:58.204367 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -afa50b91fc65d9f785afffefbf5aafc9cde32a2a assets/createnuclear/lang/en_ud.json -12a32b876aacfd92504d386d7366003931ddbea1 assets/createnuclear/lang/en_us.json +5868132972920436bc2de98b9f3c330c8861a180 assets/createnuclear/lang/en_ud.json +0b9be3ebee8773b4969bfa2f6232daaadd104972 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 16edc6ac..4ae6378e 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -216,57 +216,53 @@ "createnuclear.notification.reactor.meltdown_in": " NI NMOᗡ⟘ꞀƎW ƎᴚOƆ", "createnuclear.notification.reactor.overheating": "⅁NI⟘ⱯƎHᴚƎΛO ƎᴚOƆ :⅁NINᴚⱯM", "createnuclear.notification.reactor.stabilized": "ᗡƎZIꞀIᗺⱯ⟘S ƎᴚOƆ", + "createnuclear.ponder.reactor_io_placement.header": "ʇuǝɯǝɔɐןԀ & uoıʇɔunℲ :O/I ɹoʇɔɐǝᴚ", + "createnuclear.ponder.reactor_io_placement.text_1": "˙ʎʇıןıqɐʇs ɹoɟ poᴚ buıןooƆ ǝuo puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ʇɐǝɥ oʇ )ןǝnɟ( poᴚ buıʇɐǝH ǝuo pǝǝu ǝM ˙spoᴚ buıןooƆ ɹo buıʇɐǝH sǝɹoʇS :ʇnduI poᴚ", + "createnuclear.ponder.reactor_io_placement.text_2": "˙suoısoןdxǝ ʇuǝʌǝɹd oʇ poᴚ buıןooƆ ǝɥʇ ɹoɟ ǝuo puɐ poᴚ buıʇɐǝH ǝɥʇ ɹoɟ ǝuO ¡sʇnduı oʍʇ ʇsɐǝן ʇɐ pǝǝu ǝʍ ʎɥʍ sı sıɥ⟘ :ʇnduI poᴚ puoɔǝS", + "createnuclear.ponder.reactor_io_placement.text_3": "˙ǝpoןdxǝ ʇou sǝop ʇı ǝɹnsuǝ puɐ ɹoʇɔɐǝɹ ǝɥʇ ןooɔ oʇ pǝɹınbǝɹ osןɐ sı pınןℲ :ʇnduI pınןℲ", + "createnuclear.ponder.reactor_io_placement.text_4": "˙buıpoןdxǝ sʞsıɹ puɐ ǝןqɐʇsun sǝɯoɔǝq ɹoʇɔɐǝɹ ǝɥʇ uǝɥʍ punos ɐ sʇıɯƎ :)ןɐuoıʇdO( ɯɹɐןⱯ", + "createnuclear.ponder.reactor_io_placement.text_5": "˙ɯǝɥʇ uǝǝʍʇǝq ʎbɹǝuǝ ןɐʇoʇ ǝɥʇ ɥɔʇɐdsıp oʇ sʇndʇno ǝןdıʇןnɯ ǝɔɐןd uɐɔ noʎ ˙ʎbɹǝuǝ pǝʇɐɹǝuǝb ʇɔɐɹʇxǝ oʇ ʎɹɐssǝɔǝN :ʇndʇnO", + "createnuclear.ponder.reactor_io_placement.text_6": "˙ǝbpǝ uɐ uo ʇou sı ʇı sɐ buoן sɐ 'buısɐƆ ɹoʇɔɐǝᴚ ʎNⱯ ǝɔɐןdǝɹ uɐɔ sʞɔoןq ǝsǝɥ⟘", + "createnuclear.ponder.reactor_io_placement.text_7": "˙ǝɔɐɟɹns ʇɐןɟ ɹǝɥʇo ʎuɐ ɹo ɟooɹ ǝɥʇ uo ɹǝɥʇǝboʇ pǝdnoɹb ǝq uɐɔ ʎǝɥ⟘", "createnuclear.ponder.reactor_t1.header": "Ɩ⟘ ɹoʇɔɐǝᴚ", "createnuclear.ponder.reactor_t1.text_1": "Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_10": ")buıɔɐןd ǝǝɹɟ( sʇɐǝɥɹǝʌo ɹoʇɔɐǝɹ ɟı punos ןןıʍ :ɯɹɐןⱯ", - "createnuclear.ponder.reactor_t1.text_11": "ϛ ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_12": "9 ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_13": "ㄥ ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_14": "puɐɥ uı ʇuıɹdǝnןq ǝɥʇ ɥʇıʍ ɹǝןןoɹʇuoɔ ǝɥʇ ʞɔıןɔ ʇɥbıɹ uǝɥʇ 'uɹǝʇʇɐd ǝɥʇ oʇ buıpuodsǝɹɹoɔ spoɹ puɐ pınbıן pǝǝu ןןıʍ noʎ ɹoʇɔɐǝɹ ǝɥʇ ʇɹɐʇs o⟘", + "createnuclear.ponder.reactor_t1.text_10": "˙)uoıʇɔunɟ & ʇuǝɯǝɔɐןd( sʞɔoןq ɯɹɐןⱯ puɐ O/I ɹoɟ ㄣ ǝbɐd ʞɔǝɥƆ :ǝʇoN", "createnuclear.ponder.reactor_t1.text_2": "ᄅ ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_3": ")ǝbpǝ ǝɥʇ uı ʇou buısɐɔ ʎuɐ ǝɔɐןdǝɹ uɐɔ : buıɔɐןd ǝǝɹɟ( poɹ ɟo ʞɔɐʇs ǝuo sǝɹoʇs :ʇnduI", - "createnuclear.ponder.reactor_t1.text_4": ")buıɔɐןd ǝǝɹɟ( pǝʇɔɐɹʇxǝ sı ɹǝʍod pǝʇɐɹǝuǝb ǝɥʇ ǝɹǝɥʍ :ʇndʇnO", - "createnuclear.ponder.reactor_t1.text_5": "Ɛ ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_6": ")buıɔɐןd ǝǝɹɟ( ʇuɐןooɔ ɹoɟ ǝuo puɐ poɹ ןǝnɟ ɟo ʇnduı ǝuo ǝʌɐɥ ʎןǝʞıן ןןıʍ noʎ ǝsnɐɔǝq pǝpǝǝu :ʇnduı puoɔǝS", - "createnuclear.ponder.reactor_t1.text_7": "ㄣ ɹooןℲ", - "createnuclear.ponder.reactor_t1.text_8": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", - "createnuclear.ponder.reactor_t1.text_9": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t1.text_3": "Ɛ ɹooןℲ", + "createnuclear.ponder.reactor_t1.text_4": "ㄣ ɹooןℲ", + "createnuclear.ponder.reactor_t1.text_5": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t1.text_6": "ϛ ɹooןℲ", + "createnuclear.ponder.reactor_t1.text_7": "9 ɹooןℲ", + "createnuclear.ponder.reactor_t1.text_8": "ㄥ ɹooןℲ", + "createnuclear.ponder.reactor_t1.text_9": "puɐɥ uı ʇuıɹdǝnןq ǝɥʇ ɥʇıʍ ɹǝןןoɹʇuoɔ ǝɥʇ ʞɔıןɔ ʇɥbıɹ uǝɥʇ 'uɹǝʇʇɐd ǝɥʇ oʇ buıpuodsǝɹɹoɔ spoɹ puɐ pınbıן pǝǝu ןןıʍ noʎ ɹoʇɔɐǝɹ ǝɥʇ ʇɹɐʇs o⟘", "createnuclear.ponder.reactor_t2.header": "ᄅ⟘ ɹoʇɔɐǝᴚ", "createnuclear.ponder.reactor_t2.text_1": "Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", - "createnuclear.ponder.reactor_t2.text_11": ")buıɔɐןd ǝǝɹɟ( sʇɐǝɥɹǝʌo ɹoʇɔɐǝɹ ɟı punos ןןıʍ :ɯɹɐןⱯ", - "createnuclear.ponder.reactor_t2.text_12": "9 ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_13": "ㄥ ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_14": "8 ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_15": "6 ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_16": "puɐɥ uı ʇuıɹdǝnןq ǝɥʇ ɥʇıʍ ɹǝןןoɹʇuoɔ ǝɥʇ ʞɔıןɔ ʇɥbıɹ uǝɥʇ 'uɹǝʇʇɐd ǝɥʇ oʇ buıpuodsǝɹɹoɔ spoɹ puɐ pınbıן pǝǝu ןןıʍ noʎ ɹoʇɔɐǝɹ ǝɥʇ ʇɹɐʇs o⟘", + "createnuclear.ponder.reactor_t2.text_10": "6 ɹooןℲ", + "createnuclear.ponder.reactor_t2.text_11": "puɐɥ uı ʇuıɹdǝnןq ǝɥʇ ɥʇıʍ ɹǝןןoɹʇuoɔ ǝɥʇ ʞɔıןɔ ʇɥbıɹ uǝɥʇ 'uɹǝʇʇɐd ǝɥʇ oʇ buıpuodsǝɹɹoɔ spoɹ puɐ pınbıן pǝǝu ןןıʍ noʎ ɹoʇɔɐǝɹ ǝɥʇ ʇɹɐʇs o⟘", + "createnuclear.ponder.reactor_t2.text_12": "˙)uoıʇɔunɟ & ʇuǝɯǝɔɐןd( sʞɔoןq ɯɹɐןⱯ puɐ O/I ɹoɟ ㄣ ǝbɐd ʞɔǝɥƆ :ǝʇoN", "createnuclear.ponder.reactor_t2.text_2": "ᄅ ɹooןℲ", "createnuclear.ponder.reactor_t2.text_3": "Ɛ ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_4": ")ǝbpǝ ǝɥʇ uı ʇou buısɐɔ ʎuɐ ǝɔɐןdǝɹ uɐɔ : buıɔɐןd ǝǝɹɟ( poɹ ɟo ʞɔɐʇs ǝuo sǝɹoʇs :ʇnduI", - "createnuclear.ponder.reactor_t2.text_5": ")buıɔɐןd ǝǝɹɟ( pǝʇɔɐɹʇxǝ sı ɹǝʍod pǝʇɐɹǝuǝb ǝɥʇ ǝɹǝɥʍ :ʇndʇnO", - "createnuclear.ponder.reactor_t2.text_6": "ㄣ ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_7": ")buıɔɐןd ǝǝɹɟ( ʇuɐןooɔ ɹoɟ ǝuo puɐ poɹ ןǝnɟ ɟo ʇnduı ǝuo ǝʌɐɥ ʎןǝʞıן ןןıʍ noʎ ǝsnɐɔǝq pǝpǝǝu :ʇnduı puoɔǝS", - "createnuclear.ponder.reactor_t2.text_8": "ϛ ɹooןℲ", - "createnuclear.ponder.reactor_t2.text_9": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", + "createnuclear.ponder.reactor_t2.text_4": "ㄣ ɹooןℲ", + "createnuclear.ponder.reactor_t2.text_5": "ϛ ɹooןℲ", + "createnuclear.ponder.reactor_t2.text_6": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t2.text_7": "9 ɹooןℲ", + "createnuclear.ponder.reactor_t2.text_8": "ㄥ ɹooןℲ", + "createnuclear.ponder.reactor_t2.text_9": "8 ɹooןℲ", "createnuclear.ponder.reactor_t3.header": "Ɛ⟘ ɹoʇɔɐǝᴚ", "createnuclear.ponder.reactor_t3.text_1": "Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_10": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", - "createnuclear.ponder.reactor_t3.text_11": ")buıɔɐןd ǝǝɹɟ( ʇǝןuı pınןɟ buıןooɔ :ʇnduI pınbıꞀ", - "createnuclear.ponder.reactor_t3.text_12": ")buıɔɐןd ǝǝɹɟ( sʇɐǝɥɹǝʌo ɹoʇɔɐǝɹ ɟı punos ןןıʍ :ɯɹɐןⱯ", - "createnuclear.ponder.reactor_t3.text_13": "ㄥ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_14": "8 ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_15": "6 ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_16": "0Ɩ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_17": "ƖƖ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_18": "puɐɥ uı ʇuıɹdǝnןq ǝɥʇ ɥʇıʍ ɹǝןןoɹʇuoɔ ǝɥʇ ʞɔıןɔ ʇɥbıɹ uǝɥʇ 'uɹǝʇʇɐd ǝɥʇ oʇ buıpuodsǝɹɹoɔ spoɹ puɐ pınbıן pǝǝu ןןıʍ noʎ ɹoʇɔɐǝɹ ǝɥʇ ʇɹɐʇs o⟘", + "createnuclear.ponder.reactor_t3.text_10": "6 ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_11": "0Ɩ ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_12": "ƖƖ ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_13": "puɐɥ uı ʇuıɹdǝnןq ǝɥʇ ɥʇıʍ ɹǝןןoɹʇuoɔ ǝɥʇ ʞɔıןɔ ʇɥbıɹ uǝɥʇ 'uɹǝʇʇɐd ǝɥʇ oʇ buıpuodsǝɹɹoɔ spoɹ puɐ pınbıן pǝǝu ןןıʍ noʎ ɹoʇɔɐǝɹ ǝɥʇ ʇɹɐʇs o⟘", + "createnuclear.ponder.reactor_t3.text_14": "˙)uoıʇɔunɟ & ʇuǝɯǝɔɐןd( sʞɔoןq ɯɹɐןⱯ puɐ O/I ɹoɟ ㄣ ǝbɐd ʞɔǝɥƆ :ǝʇoN", "createnuclear.ponder.reactor_t3.text_2": "ᄅ ɹooןℲ", "createnuclear.ponder.reactor_t3.text_3": "Ɛ ɹooןℲ", "createnuclear.ponder.reactor_t3.text_4": "ㄣ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_5": ")ǝbpǝ ǝɥʇ uı ʇou buısɐɔ ʎuɐ ǝɔɐןdǝɹ uɐɔ : buıɔɐןd ǝǝɹɟ( poɹ ɟo ʞɔɐʇs ǝuo sǝɹoʇs :ʇnduI", - "createnuclear.ponder.reactor_t3.text_6": ")buıɔɐןd ǝǝɹɟ( pǝʇɔɐɹʇxǝ sı ɹǝʍod pǝʇɐɹǝuǝb ǝɥʇ ǝɹǝɥʍ :ʇndʇnO", - "createnuclear.ponder.reactor_t3.text_7": "ϛ ɹooןℲ", - "createnuclear.ponder.reactor_t3.text_8": ")buıɔɐןd ǝǝɹɟ( ʇuɐןooɔ ɹoɟ ǝuo puɐ poɹ ןǝnɟ ɟo ʇnduı ǝuo ǝʌɐɥ ʎןǝʞıן ןןıʍ noʎ ǝsnɐɔǝq pǝpǝǝu :ʇnduı puoɔǝS", - "createnuclear.ponder.reactor_t3.text_9": "9 ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_5": "ϛ ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_6": "9 ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_7": "ʇı ʇɹɐʇs oʇ sǝob ʇuıɹdǝnןq ǝɥʇ ǝɹǝɥʍ ǝɔɐןd ǝɥʇ puɐ 'ɹoʇɔɐǝɹ ǝɥʇ ɟo uıɐɹq :ɹǝןןoɹʇuoƆ", + "createnuclear.ponder.reactor_t3.text_8": "ㄥ ɹooןℲ", + "createnuclear.ponder.reactor_t3.text_9": "8 ɹooןℲ", "createnuclear.reactor.debug.label.alarm": "ɯɹɐןⱯ", "createnuclear.reactor.debug.label.fluid_input": "ʇnduI pınןℲ", "createnuclear.reactor.debug.label.input": "ʇnduI", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index e5ae2885..4dd629d1 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -216,57 +216,53 @@ "createnuclear.notification.reactor.meltdown_in": "CORE MELTDOWN IN ", "createnuclear.notification.reactor.overheating": "WARNING: CORE OVERHEATING", "createnuclear.notification.reactor.stabilized": "CORE STABILIZED", + "createnuclear.ponder.reactor_io_placement.header": "Reactor I/O: Function & Placement", + "createnuclear.ponder.reactor_io_placement.text_1": "Rod Input: Stores Heating or Cooling Rods. We need one Heating Rod (fuel) to heat the reactor, and one Cooling Rod for stability.", + "createnuclear.ponder.reactor_io_placement.text_2": "Second Rod Input: This is why we need at least two inputs! One for the Heating Rod and one for the Cooling Rod to prevent explosions.", + "createnuclear.ponder.reactor_io_placement.text_3": "Fluid Input: Fluid is also required to cool the reactor and ensure it does not explode.", + "createnuclear.ponder.reactor_io_placement.text_4": "Alarm (Optional): Emits a sound when the reactor becomes unstable and risks exploding.", + "createnuclear.ponder.reactor_io_placement.text_5": "Output: Necessary to extract generated energy. You can place multiple outputs to dispatch the total energy between them.", + "createnuclear.ponder.reactor_io_placement.text_6": "These blocks can replace ANY Reactor Casing, as long as it is not on an edge.", + "createnuclear.ponder.reactor_io_placement.text_7": "They can be grouped together on the roof or any other flat surface.", "createnuclear.ponder.reactor_t1.header": "Reactor T1", "createnuclear.ponder.reactor_t1.text_1": "Floor 1", - "createnuclear.ponder.reactor_t1.text_10": "Alarm: will sound if reactor overheats (free placing)", - "createnuclear.ponder.reactor_t1.text_11": "Floor 5", - "createnuclear.ponder.reactor_t1.text_12": "Floor 6", - "createnuclear.ponder.reactor_t1.text_13": "Floor 7", - "createnuclear.ponder.reactor_t1.text_14": "To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand", + "createnuclear.ponder.reactor_t1.text_10": "Note: Check page 4 for I/O and Alarm blocks (placement & function).", "createnuclear.ponder.reactor_t1.text_2": "Floor 2", - "createnuclear.ponder.reactor_t1.text_3": "Input: stores one stack of rod (free placing : can replace any casing not in the edge)", - "createnuclear.ponder.reactor_t1.text_4": "Output: where the generated power is extracted (free placing)", - "createnuclear.ponder.reactor_t1.text_5": "Floor 3", - "createnuclear.ponder.reactor_t1.text_6": "Second input: needed because you will likely have one input of fuel rod and one for coolant (free placing)", - "createnuclear.ponder.reactor_t1.text_7": "Floor 4", - "createnuclear.ponder.reactor_t1.text_8": "Liquid Input: cooling fluid inlet (free placing)", - "createnuclear.ponder.reactor_t1.text_9": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t1.text_3": "Floor 3", + "createnuclear.ponder.reactor_t1.text_4": "Floor 4", + "createnuclear.ponder.reactor_t1.text_5": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t1.text_6": "Floor 5", + "createnuclear.ponder.reactor_t1.text_7": "Floor 6", + "createnuclear.ponder.reactor_t1.text_8": "Floor 7", + "createnuclear.ponder.reactor_t1.text_9": "To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand", "createnuclear.ponder.reactor_t2.header": "Reactor T2", "createnuclear.ponder.reactor_t2.text_1": "Floor 1", - "createnuclear.ponder.reactor_t2.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", - "createnuclear.ponder.reactor_t2.text_11": "Alarm: will sound if reactor overheats (free placing)", - "createnuclear.ponder.reactor_t2.text_12": "Floor 6", - "createnuclear.ponder.reactor_t2.text_13": "Floor 7", - "createnuclear.ponder.reactor_t2.text_14": "Floor 8", - "createnuclear.ponder.reactor_t2.text_15": "Floor 9", - "createnuclear.ponder.reactor_t2.text_16": "To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand", + "createnuclear.ponder.reactor_t2.text_10": "Floor 9", + "createnuclear.ponder.reactor_t2.text_11": "To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand", + "createnuclear.ponder.reactor_t2.text_12": "Note: Check page 4 for I/O and Alarm blocks (placement & function).", "createnuclear.ponder.reactor_t2.text_2": "Floor 2", "createnuclear.ponder.reactor_t2.text_3": "Floor 3", - "createnuclear.ponder.reactor_t2.text_4": "Input: stores one stack of rod (free placing : can replace any casing not in the edge)", - "createnuclear.ponder.reactor_t2.text_5": "Output: where the generated power is extracted (free placing)", - "createnuclear.ponder.reactor_t2.text_6": "Floor 4", - "createnuclear.ponder.reactor_t2.text_7": "Second input: needed because you will likely have one input of fuel rod and one for coolant (free placing)", - "createnuclear.ponder.reactor_t2.text_8": "Floor 5", - "createnuclear.ponder.reactor_t2.text_9": "Liquid Input: cooling fluid inlet (free placing)", + "createnuclear.ponder.reactor_t2.text_4": "Floor 4", + "createnuclear.ponder.reactor_t2.text_5": "Floor 5", + "createnuclear.ponder.reactor_t2.text_6": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t2.text_7": "Floor 6", + "createnuclear.ponder.reactor_t2.text_8": "Floor 7", + "createnuclear.ponder.reactor_t2.text_9": "Floor 8", "createnuclear.ponder.reactor_t3.header": "Reactor T3", "createnuclear.ponder.reactor_t3.text_1": "Floor 1", - "createnuclear.ponder.reactor_t3.text_10": "Controller: brain of the reactor, and the place where the blueprint goes to start it", - "createnuclear.ponder.reactor_t3.text_11": "Liquid Input: cooling fluid inlet (free placing)", - "createnuclear.ponder.reactor_t3.text_12": "Alarm: will sound if reactor overheats (free placing)", - "createnuclear.ponder.reactor_t3.text_13": "Floor 7", - "createnuclear.ponder.reactor_t3.text_14": "Floor 8", - "createnuclear.ponder.reactor_t3.text_15": "Floor 9", - "createnuclear.ponder.reactor_t3.text_16": "Floor 10", - "createnuclear.ponder.reactor_t3.text_17": "Floor 11", - "createnuclear.ponder.reactor_t3.text_18": "To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand", + "createnuclear.ponder.reactor_t3.text_10": "Floor 9", + "createnuclear.ponder.reactor_t3.text_11": "Floor 10", + "createnuclear.ponder.reactor_t3.text_12": "Floor 11", + "createnuclear.ponder.reactor_t3.text_13": "To start the reactor you will need liquid and rods corresponding to the pattern, then right click the controller with the blueprint in hand", + "createnuclear.ponder.reactor_t3.text_14": "Note: Check page 4 for I/O and Alarm blocks (placement & function).", "createnuclear.ponder.reactor_t3.text_2": "Floor 2", "createnuclear.ponder.reactor_t3.text_3": "Floor 3", "createnuclear.ponder.reactor_t3.text_4": "Floor 4", - "createnuclear.ponder.reactor_t3.text_5": "Input: stores one stack of rod (free placing : can replace any casing not in the edge)", - "createnuclear.ponder.reactor_t3.text_6": "Output: where the generated power is extracted (free placing)", - "createnuclear.ponder.reactor_t3.text_7": "Floor 5", - "createnuclear.ponder.reactor_t3.text_8": "Second input: needed because you will likely have one input of fuel rod and one for coolant (free placing)", - "createnuclear.ponder.reactor_t3.text_9": "Floor 6", + "createnuclear.ponder.reactor_t3.text_5": "Floor 5", + "createnuclear.ponder.reactor_t3.text_6": "Floor 6", + "createnuclear.ponder.reactor_t3.text_7": "Controller: brain of the reactor, and the place where the blueprint goes to start it", + "createnuclear.ponder.reactor_t3.text_8": "Floor 7", + "createnuclear.ponder.reactor_t3.text_9": "Floor 8", "createnuclear.reactor.debug.label.alarm": "Alarm", "createnuclear.reactor.debug.label.fluid_input": "Fluid Input", "createnuclear.reactor.debug.label.input": "Input", From dba2dc7873c3bebf662192f0db6c782ac7263fdb Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 13:31:24 +0200 Subject: [PATCH 097/171] fix: streamline block model generation to handle translucency directly in PaletteBlockPattern --- .../palettes/PaletteBlockPattern.java | 38 +++++++++++++------ .../palettes/PalettesVariantEntry.java | 7 ++-- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java index f06ddf5f..4ff53e5c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java @@ -140,16 +140,24 @@ private PaletteBlockPattern connectedTextures(Function prov.simpleBlock(ctx.get(), prov.models() - .cubeAll(createName(variant), all)); + return (ctx, prov) -> { + net.minecraftforge.client.model.generators.BlockModelBuilder builder = prov.models() + .cubeAll(createName(variant), all); + if (isTranslucent) builder.renderType("translucent"); + prov.simpleBlock(ctx.get(), builder); + }; } public IBlockStateProvider cubeBottomTop(String variant) { ResourceLocation side = toLocation(variant, textures[0]); ResourceLocation bottom = toLocation(variant, textures[1]); ResourceLocation top = toLocation(variant, textures[2]); - return (ctx, prov) -> prov.simpleBlock(ctx.get(), prov.models() - .cubeBottomTop(createName(variant), side, bottom, top)); + return (ctx, prov) -> { + net.minecraftforge.client.model.generators.BlockModelBuilder builder = prov.models() + .cubeBottomTop(createName(variant), side, bottom, top); + if (isTranslucent) builder.renderType("translucent"); + prov.simpleBlock(ctx.get(), builder); + }; } public IBlockStateProvider pillar(String variant) { @@ -159,15 +167,19 @@ public IBlockStateProvider pillar(String variant) { return (ctx, prov) -> prov.getVariantBuilder(ctx.getEntry()) .forAllStatesExcept(state -> { Axis axis = state.getValue(BlockStateProperties.AXIS); - if (axis == Axis.Y) + net.minecraftforge.client.model.generators.BlockModelBuilder builder; + if (axis == Axis.Y) { + builder = prov.models().cubeColumn(createName(variant), side, end); + if (isTranslucent) builder.renderType("translucent"); return ConfiguredModel.builder() - .modelFile(prov.models() - .cubeColumn(createName(variant), side, end)) + .modelFile(builder) .uvLock(false) .build(); + } + builder = prov.models().cubeColumnHorizontal(createName(variant) + "_horizontal", side, end); + if (isTranslucent) builder.renderType("translucent"); return ConfiguredModel.builder() - .modelFile(prov.models() - .cubeColumnHorizontal(createName(variant) + "_horizontal", side, end)) + .modelFile(builder) .uvLock(false) .rotationX(90) .rotationY(axis == Axis.X ? 90 : 0) @@ -179,8 +191,12 @@ public IBlockStateProvider pillar(String variant) { public IBlockStateProvider cubeColumn(String variant) { ResourceLocation side = toLocation(variant, textures[0]); ResourceLocation end = toLocation(variant, textures[1]); - return (ctx, prov) -> prov.simpleBlock(ctx.get(), prov.models() - .cubeColumn(createName(variant), side, end)); + return (ctx, prov) -> { + net.minecraftforge.client.model.generators.BlockModelBuilder builder = prov.models() + .cubeColumn(createName(variant), side, end); + if (isTranslucent) builder.renderType("translucent"); + prov.simpleBlock(ctx.get(), builder); + }; } // Utility diff --git a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java index f912381d..8a4dcaed 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java @@ -50,10 +50,11 @@ public PalettesVariantEntry(String name, CNPaletteStoneTypes paletteStoneVariant itemBuilder.tag(paletteStoneVariants.materialTag); - if (pattern.isTranslucent()) - builder.addLayer(() -> RenderType::translucent); + if (pattern.isTranslucent()) { + // Le RenderType est maintenant géré directement dans la génération du modèle json (via PaletteBlockPattern) + } pattern.createCTBehaviour(name) - .ifPresent(b -> builder.onRegister(connectedTextures(b))); + .ifPresent(b -> builder.onRegister(CreateRegistrate.connectedTextures(b))); builder.recipe((c, p) -> { p.stonecutting(DataIngredient.tag(paletteStoneVariants.materialTag), RecipeCategory.BUILDING_BLOCKS, c); From a0a86d2bec8aaf28ffa131d4adf5d93401465c20 Mon Sep 17 00:00:00 2001 From: Dimitri Date: Thu, 25 Jun 2026 14:15:35 +0200 Subject: [PATCH 098/171] refactoring the names of the item input and the liquid input --- .../15812fa7bc190aa8f0a8644088c7ff563925e506 | 6 +-- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 44 +++++++++--------- .../abc32a97b4e744838610c53dbbbaaf9f7d29a557 | 8 ++-- .../blockstates/reactor_fluid_input.json | 26 +++++++++++ .../blockstates/reactor_input.json | 26 ----------- .../blockstates/reactor_liquid_input.json | 26 ----------- .../blockstates/reactor_rod_input.json | 26 +++++++++++ .../assets/createnuclear/lang/en_ud.json | 30 ++++++------ .../assets/createnuclear/lang/en_us.json | 30 ++++++------ .../models/item/reactor_fluid_input.json | 3 ++ .../models/item/reactor_input.json | 3 -- .../models/item/reactor_liquid_input.json | 3 -- .../models/item/reactor_rod_input.json | 3 ++ ...id_input.json => reactor_fluid_input.json} | 10 ++-- .../advancements/reactor_output.json | 2 +- ...ctor_input.json => reactor_rod_input.json} | 8 ++-- ...id_input.json => reactor_fluid_input.json} | 4 +- ...ctor_input.json => reactor_rod_input.json} | 4 +- ...t_from_fluid_pipe_and_reactor_casing.json} | 2 +- ...input_from_hopper_and_reactor_casing.json} | 2 +- .../tags/blocks/mineable/pickaxe.json | 4 +- .../tags/blocks/needs_diamond_tool.json | 4 +- .../createnuclear/CNBlockEntityTypes.java | 14 +++--- .../nuclearteam/createnuclear/CNBlocks.java | 28 +++++------ .../nuclearteam/createnuclear/CNMenus.java | 6 +-- .../nuclearteam/createnuclear/CNShapes.java | 4 +- .../content/multiblock/CNMultiblock.java | 4 +- .../content/multiblock/ReactorAssembler.java | 6 +-- .../multiblock/casing/ReactorCasing.java | 4 +- .../manager/ReactorInputManager.java | 4 +- ...iquidInput.java => ReactorFluidInput.java} | 8 ++-- ...r.java => ReactorFluidInputGenerator.java} | 10 ++-- ...ReactorInput.java => ReactorRodInput.java} | 14 +++--- ...Entity.java => ReactorRodInputEntity.java} | 10 ++-- ...tor.java => ReactorRodInputGenerator.java} | 10 ++-- ...ory.java => ReactorRodInputInventory.java} | 6 +-- ...nputMenu.java => ReactorRodInputMenu.java} | 22 ++++----- ...Screen.java => ReactorRodInputScreen.java} | 4 +- .../multiblock/pattern/ReactorPattern.java | 4 +- .../foundation/advancement/CNAdvancement.java | 14 +++--- .../data/recipe/CNDeployingRecipeGen.java | 8 ++-- .../ponder/scenes/CNPonderReactorScenes.java | 6 +-- .../createnuclear/lang/default/tooltips.json | 18 +++---- .../fluid_input.json} | 2 +- .../fluid_input_vertical.json} | 4 +- .../reactor/{input => fluid_input}/item.json | 2 +- .../{liquid_input => rod_input}/item.json | 2 +- .../input.json => rod_input/rod_input.json} | 2 +- .../rod_input_vertical.json} | 4 +- .../input.png => fluid_input/fluid_input.png} | Bin .../input.png => rod_input/rod_input.png} | Bin 51 files changed, 245 insertions(+), 249 deletions(-) create mode 100644 src/generated/resources/assets/createnuclear/blockstates/reactor_fluid_input.json delete mode 100644 src/generated/resources/assets/createnuclear/blockstates/reactor_input.json delete mode 100644 src/generated/resources/assets/createnuclear/blockstates/reactor_liquid_input.json create mode 100644 src/generated/resources/assets/createnuclear/blockstates/reactor_rod_input.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/reactor_fluid_input.json delete mode 100644 src/generated/resources/assets/createnuclear/models/item/reactor_input.json delete mode 100644 src/generated/resources/assets/createnuclear/models/item/reactor_liquid_input.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/reactor_rod_input.json rename src/generated/resources/data/createnuclear/advancements/{reactor_liquid_input.json => reactor_fluid_input.json} (63%) rename src/generated/resources/data/createnuclear/advancements/{reactor_input.json => reactor_rod_input.json} (70%) rename src/generated/resources/data/createnuclear/loot_tables/blocks/{reactor_liquid_input.json => reactor_fluid_input.json} (71%) rename src/generated/resources/data/createnuclear/loot_tables/blocks/{reactor_input.json => reactor_rod_input.json} (72%) rename src/generated/resources/data/createnuclear/recipes/deploying/{reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json => reactor_fluid_input_from_fluid_pipe_and_reactor_casing.json} (79%) rename src/generated/resources/data/createnuclear/recipes/deploying/{reactor_input_from_hopper_and_reactor_casing.json => reactor_rod_input_from_hopper_and_reactor_casing.json} (79%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/{ReactorLiquidInput.java => ReactorFluidInput.java} (93%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/{ReactorLiquidInputGenerator.java => ReactorFluidInputGenerator.java} (68%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/{ReactorInput.java => ReactorRodInput.java} (89%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/{ReactorInputEntity.java => ReactorRodInputEntity.java} (89%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/{ReactorInputGenerator.java => ReactorRodInputGenerator.java} (69%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/{ReactorInputInventory.java => ReactorRodInputInventory.java} (86%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/{ReactorInputMenu.java => ReactorRodInputMenu.java} (80%) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/{ReactorInputScreen.java => ReactorRodInputScreen.java} (86%) rename src/main/resources/assets/createnuclear/models/block/reactor/{liquid_input/liquid_input.json => fluid_input/fluid_input.json} (97%) rename src/main/resources/assets/createnuclear/models/block/reactor/{liquid_input/liquid_input_vertical.json => fluid_input/fluid_input_vertical.json} (98%) rename src/main/resources/assets/createnuclear/models/block/reactor/{input => fluid_input}/item.json (97%) rename src/main/resources/assets/createnuclear/models/block/reactor/{liquid_input => rod_input}/item.json (97%) rename src/main/resources/assets/createnuclear/models/block/reactor/{input/input.json => rod_input/rod_input.json} (98%) rename src/main/resources/assets/createnuclear/models/block/reactor/{input/input_vertical.json => rod_input/rod_input_vertical.json} (98%) rename src/main/resources/assets/createnuclear/textures/block/reactor/{liquid_input/input.png => fluid_input/fluid_input.png} (100%) rename src/main/resources/assets/createnuclear/textures/block/reactor/{input/input.png => rod_input/rod_input.png} (100%) diff --git a/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 b/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 index 06c15daf..e98ca84a 100644 --- a/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 +++ b/src/generated/resources/.cache/15812fa7bc190aa8f0a8644088c7ff563925e506 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-25T10:30:57.471141 CreateNuclear's Processing Recipes +// 1.20.1 2026-06-25T13:51:56.534886 CreateNuclear's Processing Recipes bccfe326d6c91bd2df207a38225fbca413e1013f data/createnuclear/recipes/compacting/thorium_fluid_to_thorium_ingot.json c711d032a04e1a9350ad9bc4d9c4d74f54689862 data/createnuclear/recipes/compacting/uranium_fluid_to_yellowcake.json 33becbc558bd2fbe277be096b292c0093f84e44c data/createnuclear/recipes/crushing/coal.json @@ -9,9 +9,9 @@ c711d032a04e1a9350ad9bc4d9c4d74f54689862 data/createnuclear/recipes/compacting/u c0e1f33d8e91a3133e5acf6e4d3eb5ea5cd23471 data/createnuclear/recipes/crushing/raw_thorium.json 169c09c5947ddf8bdc8727af3c71368880b0c128 data/createnuclear/recipes/crushing/raw_thorium_block.json 26d2787e831b9986ed6f90f8ea803d5fdc544bf5 data/createnuclear/recipes/crushing/raw_zinc.json -d2bb94c56fa462ebed3d762a90f6e79d172ffa51 data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json -722c8115413c67402b4c267b1e06c3d761441f9a data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json +87d2e1022c9eeb986bdc23b068fe7cf473ee42f1 data/createnuclear/recipes/deploying/reactor_fluid_input_from_fluid_pipe_and_reactor_casing.json 04c671106607c2c93c0706f690cd876fb072dd56 data/createnuclear/recipes/deploying/reactor_output_from_shaft_and_reactor_casing.json +58a34e84d942cb4250969388f78282270215c227 data/createnuclear/recipes/deploying/reactor_rod_input_from_hopper_and_reactor_casing.json e42be7d17c5e057e62c4b1176cbf43319a157f51 data/createnuclear/recipes/enriched/enriched_yellowcake.json 74555eb2cce0827f99dc5c4ff91362bdaecad725 data/createnuclear/recipes/enriched/enriching_campfire.json d0a30a8942f3e81d11afa21a93037916601c38cb data/createnuclear/recipes/item_application/reactor_casing_from_steel_and_brass_casing.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index d4bb0371..1137ce38 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,11 +1,11 @@ -// 1.20.1 2026-06-25T13:02:58.204367 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-25T14:01:50.1727214 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json +f402fda858988cbb5e1a6a623cb15a6c76ac7f54 assets/createnuclear/blockstates/cut_autunite_bricks.json b88d65e7a3393caeaed8d504bf6c4615767371aa assets/createnuclear/blockstates/cut_autunite_brick_slab.json 7f788334258cfb67dfbf716dbaf1b126376d1a14 assets/createnuclear/blockstates/cut_autunite_brick_stairs.json 7bfc6778893ef6552c10e17e3489e201758d3a75 assets/createnuclear/blockstates/cut_autunite_brick_wall.json -f402fda858988cbb5e1a6a623cb15a6c76ac7f54 assets/createnuclear/blockstates/cut_autunite_bricks.json 1e246d1862a801b2253595d7fac7717a0110ce79 assets/createnuclear/blockstates/cut_autunite_slab.json 56c308e675a047a3d28757377e61e5f79c6384e3 assets/createnuclear/blockstates/cut_autunite_stairs.json 98d386985f7c185f1acab25b9d606828f788769f assets/createnuclear/blockstates/cut_autunite_wall.json @@ -33,10 +33,10 @@ f628f8c7aa1e150ad2b5a3ce87dbe7f00b462e74 assets/createnuclear/blockstates/polish 0b5bd864f1e3b0c6b0ce868245da96fd8070fb21 assets/createnuclear/blockstates/reactor_controller.json 3c259041f317bb8868fb4f177c457fc12b8d28f5 assets/createnuclear/blockstates/reactor_cooler.json 3cced3f7d35371f1881b0485ee324788adcd2c74 assets/createnuclear/blockstates/reactor_core.json +0d8ab9ccc729b8e78539a2fab7b52b6be0afb24b assets/createnuclear/blockstates/reactor_fluid_input.json ff68065029f7d47434aaf3f60e5ec3319302d2d8 assets/createnuclear/blockstates/reactor_frame.json -bd30dea2e337215430c4510c3eb90e6ec909f4b4 assets/createnuclear/blockstates/reactor_input.json -20c17a81bb3c63d244af9d66da3dc61857900f6c assets/createnuclear/blockstates/reactor_liquid_input.json 36ee5c127b0548502d15bc16a638a5bac40df1b6 assets/createnuclear/blockstates/reactor_output.json +daa6730e5e83972faea54e62eb1cf0fe36aaef0a assets/createnuclear/blockstates/reactor_rod_input.json f7504d5f748fe938bf07d2eb5d0ba46bbfa0499d assets/createnuclear/blockstates/reinforced_glass.json f9dd0a30be6d92e85fd7c3dde4f1b732f63d35ce assets/createnuclear/blockstates/small_autunite_brick.json 533317e2fc9ab18b71dea2fecaec599533a864c4 assets/createnuclear/blockstates/small_autunite_brick_slab.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -5868132972920436bc2de98b9f3c330c8861a180 assets/createnuclear/lang/en_ud.json -0b9be3ebee8773b4969bfa2f6232daaadd104972 assets/createnuclear/lang/en_us.json +0c556267e935b64bc549174c5ad935ce7d390480 assets/createnuclear/lang/en_ud.json +033947c30f5eed0a689b6deb821a68d6d30745fd assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json @@ -57,15 +57,15 @@ a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autun 2f6b85682c569527f9f538dae16526505ce5655a assets/createnuclear/models/block/autunite_pillar.json 4a04692c39cfad137877258b4443eb4bf5298423 assets/createnuclear/models/block/autunite_pillar_horizontal.json a48d579af38beab6fc87d3b02a7ed902b25bdf16 assets/createnuclear/models/block/cut_autunite.json +4d49f9151293582741edc0d935f3130547cf5360 assets/createnuclear/models/block/cut_autunite_bricks.json +6729240e3a6cbda812d3feb8e287f743bd6b6de5 assets/createnuclear/models/block/cut_autunite_bricks_wall_post.json +244715a4f0f6a21d055b1de3307c303a5a885c1d assets/createnuclear/models/block/cut_autunite_bricks_wall_side.json +f8d6743895a633a45eb0c565cb7f79aae9172175 assets/createnuclear/models/block/cut_autunite_bricks_wall_side_tall.json c470ac7f3b34c8da456f221d81b45292f0657e36 assets/createnuclear/models/block/cut_autunite_brick_slab.json d4084e8b32d197db311b575a06023bb5fd5d8aba assets/createnuclear/models/block/cut_autunite_brick_slab_top.json e4a795c7efcfa306ac6772e2b8a23a3afc52c0ec assets/createnuclear/models/block/cut_autunite_brick_stairs.json 90a9c051a0c72398a1f052542620029275e6a676 assets/createnuclear/models/block/cut_autunite_brick_stairs_inner.json 4bb891d8f069cf043de74c0cc9d16fcbcb49ee07 assets/createnuclear/models/block/cut_autunite_brick_stairs_outer.json -4d49f9151293582741edc0d935f3130547cf5360 assets/createnuclear/models/block/cut_autunite_bricks.json -6729240e3a6cbda812d3feb8e287f743bd6b6de5 assets/createnuclear/models/block/cut_autunite_bricks_wall_post.json -244715a4f0f6a21d055b1de3307c303a5a885c1d assets/createnuclear/models/block/cut_autunite_bricks_wall_side.json -f8d6743895a633a45eb0c565cb7f79aae9172175 assets/createnuclear/models/block/cut_autunite_bricks_wall_side_tall.json d9ae523c08cbbe274a598736a8a9fd510d78d484 assets/createnuclear/models/block/cut_autunite_slab.json 14043cfcb42894ebb0db2501929ba4cae9d8bd7d assets/createnuclear/models/block/cut_autunite_slab_top.json f66edf8ef01d16ee116ac71e742bea54e98e1724 assets/createnuclear/models/block/cut_autunite_stairs.json @@ -191,10 +191,10 @@ ceefea70488adb5db8c8e2355eb9b59b8262b0fc assets/createnuclear/models/item/colore 893789e72874b7b3bb5634df81b374c38177f2f7 assets/createnuclear/models/item/colored/yellow_anti_radiation_leggings.json 4c5ade8688c0dfd0c3007c6bde5d52fb0a0f44cc assets/createnuclear/models/item/cooled_nitrogen_concentrate.json 0c682ff48601bf7f42c8561819ecede780664fbf assets/createnuclear/models/item/cut_autunite.json +11220bd60ab51e05a978a8322511c224d15bf886 assets/createnuclear/models/item/cut_autunite_bricks.json d43ffb4c5491fcd8c98451649c3f4ceb271e8875 assets/createnuclear/models/item/cut_autunite_brick_slab.json dfea56e99288e64e5061c621e860fa314fc31e9d assets/createnuclear/models/item/cut_autunite_brick_stairs.json 95e992c1e1c881d0f00a234a5e6906b1a5dbf149 assets/createnuclear/models/item/cut_autunite_brick_wall.json -11220bd60ab51e05a978a8322511c224d15bf886 assets/createnuclear/models/item/cut_autunite_bricks.json 5027aa166900571aa2e4f50ad53869b595ff3426 assets/createnuclear/models/item/cut_autunite_slab.json bd832947d219746d3264422bc4c82f6acdc5cc3e assets/createnuclear/models/item/cut_autunite_stairs.json 4c0b115eb2a2f8d6e74c612fa6e1aa5b357e9185 assets/createnuclear/models/item/cut_autunite_wall.json @@ -246,10 +246,10 @@ ee9b06de6d4e5f722543a83e5d9f7564ac6d7f70 assets/createnuclear/models/item/reacto 7d0b9c3d7301e1f419441b69f152955fc69c5633 assets/createnuclear/models/item/reactor_controller.json 118e595a42c557d4eb97750ba31699a0e3f29ed8 assets/createnuclear/models/item/reactor_cooler.json 7e444d9dc776530d017fc28fe18dad0fabeedcdc assets/createnuclear/models/item/reactor_core.json +3e46c3ff9c6fc0b276549f7f63be2b4690cd3d62 assets/createnuclear/models/item/reactor_fluid_input.json 6726831326d47e5e416216e0ec1d3fd214110e89 assets/createnuclear/models/item/reactor_frame.json -18dc2031fd8aeba588d92e43093fb76e78b2bbe4 assets/createnuclear/models/item/reactor_input.json -bf5bc112f5a1ecb51f6e324c718257eaa3863b9d assets/createnuclear/models/item/reactor_liquid_input.json 69e464d730b826a0c28ed3cfeab28c4c561ec1b0 assets/createnuclear/models/item/reactor_output.json +08b156175821e1ce7820783f2f1ba92924e54a7d assets/createnuclear/models/item/reactor_rod_input.json 4db93da70d6a7549155201b7d9d68355449652ac assets/createnuclear/models/item/red_cloth.json 78a9e80073512a111cb936a516d290a824846ff2 assets/createnuclear/models/item/reinforced_glass.json 60dc6eb917ee1567461f02aca765e061d3d9f55a assets/createnuclear/models/item/small_autunite_brick.json @@ -272,12 +272,12 @@ fe44d1ed2b4100ec32dda43274a085166706485d assets/createnuclear/models/item/thoriu ea04609e8b5c12a7805b1c564bca07fefd6d38ba assets/createnuclear/models/item/uranium_rod.json 4d85657105612ca5525a14791c3e07cf6bd239b8 assets/createnuclear/models/item/white_cloth.json 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/createnuclear/models/item/wolf_irradiated_spawn_egg.json -a1970879fd57836f5ae5d23352cdca277095bc7d assets/createnuclear/models/item/yellow_cloth.json 8bdc2fabbfc9fcc7c2ad4a3273897659d90b95ab assets/createnuclear/models/item/yellowcake.json -d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json +a1970879fd57836f5ae5d23352cdca277095bc7d assets/createnuclear/models/item/yellow_cloth.json 72b0cec0c98e9ead9562ff0cc1231a5028e2a22f data/createnuclear/advancements/recipes/building_blocks/autunite_from_stone_types_autunite_stonecutting.json e7967751f132676cb1d523743adaac3aea1f0814 data/createnuclear/advancements/recipes/building_blocks/autunite_pillar_from_stone_types_autunite_stonecutting.json 8e9cfc8ab1ddd7b818cb52cbd0fb60c0c4713bad data/createnuclear/advancements/recipes/building_blocks/crafting/enriched_soul_soil.json +1ec4bd12e3fd4303800a758a2b791e30a04e5960 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json 801940038556c52d0e10aec6d16430a99f31a385 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_slab.json d0f97d467c8a00a57ece37990ece8601a32c431d data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_slab_from_stone_types_autunite_stonecutting.json 913dfa33a312cd9a08d6d1194d0f7af40d4c5856 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_slab_recycling.json @@ -285,7 +285,6 @@ d0f97d467c8a00a57ece37990ece8601a32c431d data/createnuclear/advancements/recipes 1a35a3a0cf6a0202eb8244d26647e8e277cf8fd3 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_stairs_from_stone_types_autunite_stonecutting.json 4fae09cee3ae86760906501da0dba47acb035cf4 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_wall.json f893c5dec42faf470d493c4b1c5c184cad842c32 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_brick_wall_from_stone_types_autunite_stonecutting.json -1ec4bd12e3fd4303800a758a2b791e30a04e5960 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json c53fd5df1d52d6e9919c9600e483697e8db75f4d data/createnuclear/advancements/recipes/building_blocks/cut_autunite_from_stone_types_autunite_stonecutting.json 8ded4051daf417cb802b5327ef0e92d361dcb298 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_slab.json 1b0fefdf4f489b3e6c389c45ffd3918b10a50de0 data/createnuclear/advancements/recipes/building_blocks/cut_autunite_slab_from_stone_types_autunite_stonecutting.json @@ -414,10 +413,10 @@ f38e19487233203d7135f35a7afe65d6b19a5aa7 data/createnuclear/advancements/recipes a021646becb7b6411eddd86644e5b17c8365582c data/createnuclear/loot_tables/blocks/autunite.json 62b7087350b0a9af9007b848c7f619a730e90693 data/createnuclear/loot_tables/blocks/autunite_pillar.json 771b416236bcc21f380e0f312c61803224987616 data/createnuclear/loot_tables/blocks/cut_autunite.json +3b81b5b58b7ef985348cf511e609064a7171d7dc data/createnuclear/loot_tables/blocks/cut_autunite_bricks.json feae7c8978bcce63f2eeb2ad6ed6a7ef53cbc13e data/createnuclear/loot_tables/blocks/cut_autunite_brick_slab.json 1fa4418198a079b6236b2f3e4b11a7f7d0fc6962 data/createnuclear/loot_tables/blocks/cut_autunite_brick_stairs.json db666ffaca36edc9e246e225f225c1e87604dd88 data/createnuclear/loot_tables/blocks/cut_autunite_brick_wall.json -3b81b5b58b7ef985348cf511e609064a7171d7dc data/createnuclear/loot_tables/blocks/cut_autunite_bricks.json 10aff7424eefd85e50269c66e60ae343043193cd data/createnuclear/loot_tables/blocks/cut_autunite_slab.json e6e624e978fdacfa3cdd123d23d021f504308149 data/createnuclear/loot_tables/blocks/cut_autunite_stairs.json f28efa9fb383b86c770b8c7344fc30f6ab9200d3 data/createnuclear/loot_tables/blocks/cut_autunite_wall.json @@ -444,10 +443,10 @@ af059cd55441441329347fbd569245b539b095db data/createnuclear/loot_tables/blocks/r e76c0b96c978e266f39eca8e46cd5ba2388e1749 data/createnuclear/loot_tables/blocks/reactor_controller.json 95a90d9d9a553448c878dfdf4b153ceada923030 data/createnuclear/loot_tables/blocks/reactor_cooler.json daa4fad27f07fd72cb25a524464edea9efe771b7 data/createnuclear/loot_tables/blocks/reactor_core.json +1f0c66a193aaddb26626967d16cd8112e18b7383 data/createnuclear/loot_tables/blocks/reactor_fluid_input.json 576b0bf970ddbdd11ec06963e1d65e08e63d69e1 data/createnuclear/loot_tables/blocks/reactor_frame.json -be48e04b069441c8593aab5e9bf78f4edc2dd249 data/createnuclear/loot_tables/blocks/reactor_input.json -1107576382a5ebd9b8d53e1a92306de08a211645 data/createnuclear/loot_tables/blocks/reactor_liquid_input.json 37af2b0b5eacf53995703344a45fb3f4d0efe1f9 data/createnuclear/loot_tables/blocks/reactor_output.json +4d10dc9daa7551a1c4879edbc22f63a8f1d84c73 data/createnuclear/loot_tables/blocks/reactor_rod_input.json 88c7cfbf28fdbe53241453e073722791c780de75 data/createnuclear/loot_tables/blocks/reinforced_glass.json feedbac4c2a466fb93f82756562edc63cb1b4b5b data/createnuclear/loot_tables/blocks/small_autunite_brick.json d51f9b307f2986ac086d32f48bd41e6dc4024348 data/createnuclear/loot_tables/blocks/small_autunite_brick_slab.json @@ -483,6 +482,7 @@ ae6d07dc30751bfa39edbcdb8758a2faababa5da data/createnuclear/recipes/crafting/ste 5fb04284d66de4bf54471a3db0d9a3bfa6b7a18c data/createnuclear/recipes/crafting/steel_nugget_from_decompacting.json 047c50559746a9ffb5835ff960ba500400e7e299 data/createnuclear/recipes/crafting/thorium_ingot_from_decompacting.json 428e74b7762c3b5b74e80850a5c75d27960c73c9 data/createnuclear/recipes/crafting/thorium_nugget_from_decompacting.json +ebfe438f4284101e07538accdf15789d06140c94 data/createnuclear/recipes/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json 4b86d48cdf03dcfaa383552881a7f52b7bebe9c5 data/createnuclear/recipes/cut_autunite_brick_slab.json b9d828959c4614caa4a0f3ac82f322dd538c6219 data/createnuclear/recipes/cut_autunite_brick_slab_from_stone_types_autunite_stonecutting.json bb8a46365f31a2e4b5440a47d1d22d122d0e973b data/createnuclear/recipes/cut_autunite_brick_slab_recycling.json @@ -490,7 +490,6 @@ bb8a46365f31a2e4b5440a47d1d22d122d0e973b data/createnuclear/recipes/cut_autunite 65ae0b709f14ec4c018ab5548d91c3a53657f612 data/createnuclear/recipes/cut_autunite_brick_stairs_from_stone_types_autunite_stonecutting.json f16b4fafe9693a2d4eaea0616aa1c01042430154 data/createnuclear/recipes/cut_autunite_brick_wall.json e40db55eb02cdbedc6f4dc52786069c74b267ada data/createnuclear/recipes/cut_autunite_brick_wall_from_stone_types_autunite_stonecutting.json -ebfe438f4284101e07538accdf15789d06140c94 data/createnuclear/recipes/cut_autunite_bricks_from_stone_types_autunite_stonecutting.json b68221950ba50e3c11cdd6b58de2aafea83b07b5 data/createnuclear/recipes/cut_autunite_from_stone_types_autunite_stonecutting.json 0bfedb8324af8797150b1faf2c2b50856d1b4ace data/createnuclear/recipes/cut_autunite_slab.json f04d6df381ea8dfbcae8d4387a5a58e25ed325e9 data/createnuclear/recipes/cut_autunite_slab_from_stone_types_autunite_stonecutting.json @@ -610,6 +609,7 @@ bce34f53cb2d00f7dee84683e8fdd429dabbcc1d data/createnuclear/tags/items/anti_radi 8e6598f14a72a61cbe1e5ed2aaea229fb2dd74e6 data/createnuclear/tags/items/cooler.json c5587bb72c54f59e9f9a4cd2c3e6bedb78ee198d data/createnuclear/tags/items/fuel.json 1a438d724641b4899f18b4abeef0b0708c76ea70 data/createnuclear/tags/items/stone_types/autunite.json +d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json 75f0600da4891d0f4a3329fb44cac6c4945a0b49 data/forge/tags/blocks/glass.json 1fd17be1d553e7ddf20494ee1e98084f02137cc8 data/forge/tags/blocks/ores.json 925cb97bc13b3122fe17e59ff3ec2fe4d1eaacd5 data/forge/tags/blocks/ores/lead.json @@ -670,10 +670,10 @@ e84d8e1fa924bec3e226b8917b4973b9629a5f52 data/minecraft/tags/blocks/campfires.js 75f0600da4891d0f4a3329fb44cac6c4945a0b49 data/minecraft/tags/blocks/impermeable.json 8875ba7215b30d75573e3dcfe46e0b690b1d7f2f data/minecraft/tags/blocks/lush_ground_replaceable.json e84d8e1fa924bec3e226b8917b4973b9629a5f52 data/minecraft/tags/blocks/mineable/axe.json -2844dedd4483b2d2ed5abcac2f0eca476c29efa4 data/minecraft/tags/blocks/mineable/pickaxe.json +299ef1307fe3379e6919e195533d45e342939765 data/minecraft/tags/blocks/mineable/pickaxe.json a7d4278d8a39649c8b658ad2f3f1d092cb012bdf data/minecraft/tags/blocks/mineable/shovel.json 8875ba7215b30d75573e3dcfe46e0b690b1d7f2f data/minecraft/tags/blocks/moss_replaceable.json -c47b0de40f93afb83463f8b3c7be32b613542b5d data/minecraft/tags/blocks/needs_diamond_tool.json +af6dc9f8e98b963b468d2ec348343783ec30be1d data/minecraft/tags/blocks/needs_diamond_tool.json 1fd17be1d553e7ddf20494ee1e98084f02137cc8 data/minecraft/tags/blocks/needs_iron_tool.json 9b9e13222cf9d971353888483c5f041cbb664dc3 data/minecraft/tags/blocks/slabs.json 7e5c701218bfbd3b186b102ff52dc79454a39e8f data/minecraft/tags/blocks/stairs.json diff --git a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 index 411d2de5..7abd9b80 100644 --- a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 +++ b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-22T19:57:09.3552703 Create Nuclear Advancements +// 1.20.1 2026-06-25T13:51:56.534886 Create Nuclear Advancements 605607e2254e01df3e30839921ddd33635250d04 data/createnuclear/advancements/absolute_zero.json b6aa52d55ebb681fa0784c5419667c88a4b0e6db data/createnuclear/advancements/anti_radiation_armor.json fe81bbd052ebe4a70c48912b47e12ed4e4523d1d data/createnuclear/advancements/automatic_uranium.json @@ -24,10 +24,10 @@ e9d8bd7f04cac0f3ea72a02a5cdc4cc98f728d98 data/createnuclear/advancements/reactor bf6947708102180f9cd08e31305253774187d763 data/createnuclear/advancements/reactor_controller.json 74363604b80b4a402fb582711f5967b9f68051e1 data/createnuclear/advancements/reactor_cooler.json f88401b0664256c3b2cb35c018f8f738b60bc3e9 data/createnuclear/advancements/reactor_core.json +40298539329e3744cf3850f8a0a6d255c64a7f2f data/createnuclear/advancements/reactor_fluid_input.json eb2975b0ff5956717aa1737794258d4ed7d7528f data/createnuclear/advancements/reactor_frame.json -4f963ff2f6c09a0272c25ebdb46423700e5256eb data/createnuclear/advancements/reactor_input.json -e8d320e7680173b5d7d320672fca004ffc45c6d3 data/createnuclear/advancements/reactor_liquid_input.json -e045547fcf9e7f98141755ebed8b1466c8122161 data/createnuclear/advancements/reactor_output.json +9fcf0d3e6707c1ad3c28590a33d0e2e8109c00a9 data/createnuclear/advancements/reactor_output.json +5a28e4b2e4d63b83e7596f18a1346ec6b55f7b00 data/createnuclear/advancements/reactor_rod_input.json 91aab6f0a18aee167c63a3aece5fa9778cf52b0b data/createnuclear/advancements/reinforced_glass.json 734a40badf33a911d1e0adb9a2b18688d5cb5401 data/createnuclear/advancements/root.json 79e11acd6d9c16e92bf10d417251a9d6859399c3 data/createnuclear/advancements/silence_the_core.json diff --git a/src/generated/resources/assets/createnuclear/blockstates/reactor_fluid_input.json b/src/generated/resources/assets/createnuclear/blockstates/reactor_fluid_input.json new file mode 100644 index 00000000..2ada65ac --- /dev/null +++ b/src/generated/resources/assets/createnuclear/blockstates/reactor_fluid_input.json @@ -0,0 +1,26 @@ +{ + "variants": { + "facing=down": { + "model": "createnuclear:block/reactor/fluid_input/fluid_input_vertical", + "x": 180 + }, + "facing=east": { + "model": "createnuclear:block/reactor/fluid_input/fluid_input", + "y": 270 + }, + "facing=north": { + "model": "createnuclear:block/reactor/fluid_input/fluid_input", + "y": 180 + }, + "facing=south": { + "model": "createnuclear:block/reactor/fluid_input/fluid_input" + }, + "facing=up": { + "model": "createnuclear:block/reactor/fluid_input/fluid_input_vertical" + }, + "facing=west": { + "model": "createnuclear:block/reactor/fluid_input/fluid_input", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/blockstates/reactor_input.json b/src/generated/resources/assets/createnuclear/blockstates/reactor_input.json deleted file mode 100644 index 593b3cbc..00000000 --- a/src/generated/resources/assets/createnuclear/blockstates/reactor_input.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "variants": { - "facing=down": { - "model": "createnuclear:block/reactor/input/input_vertical", - "x": 180 - }, - "facing=east": { - "model": "createnuclear:block/reactor/input/input", - "y": 270 - }, - "facing=north": { - "model": "createnuclear:block/reactor/input/input", - "y": 180 - }, - "facing=south": { - "model": "createnuclear:block/reactor/input/input" - }, - "facing=up": { - "model": "createnuclear:block/reactor/input/input_vertical" - }, - "facing=west": { - "model": "createnuclear:block/reactor/input/input", - "y": 90 - } - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/blockstates/reactor_liquid_input.json b/src/generated/resources/assets/createnuclear/blockstates/reactor_liquid_input.json deleted file mode 100644 index 15331d70..00000000 --- a/src/generated/resources/assets/createnuclear/blockstates/reactor_liquid_input.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "variants": { - "facing=down": { - "model": "createnuclear:block/reactor/liquid_input/liquid_input_vertical", - "x": 180 - }, - "facing=east": { - "model": "createnuclear:block/reactor/liquid_input/liquid_input", - "y": 270 - }, - "facing=north": { - "model": "createnuclear:block/reactor/liquid_input/liquid_input", - "y": 180 - }, - "facing=south": { - "model": "createnuclear:block/reactor/liquid_input/liquid_input" - }, - "facing=up": { - "model": "createnuclear:block/reactor/liquid_input/liquid_input_vertical" - }, - "facing=west": { - "model": "createnuclear:block/reactor/liquid_input/liquid_input", - "y": 90 - } - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/blockstates/reactor_rod_input.json b/src/generated/resources/assets/createnuclear/blockstates/reactor_rod_input.json new file mode 100644 index 00000000..37ee320b --- /dev/null +++ b/src/generated/resources/assets/createnuclear/blockstates/reactor_rod_input.json @@ -0,0 +1,26 @@ +{ + "variants": { + "facing=down": { + "model": "createnuclear:block/reactor/rod_input/rod_input_vertical", + "x": 180 + }, + "facing=east": { + "model": "createnuclear:block/reactor/rod_input/rod_input", + "y": 270 + }, + "facing=north": { + "model": "createnuclear:block/reactor/rod_input/rod_input", + "y": 180 + }, + "facing=south": { + "model": "createnuclear:block/reactor/rod_input/rod_input" + }, + "facing=up": { + "model": "createnuclear:block/reactor/rod_input/rod_input_vertical" + }, + "facing=west": { + "model": "createnuclear:block/reactor/rod_input/rod_input", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 4ae6378e..90abc88e 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -49,14 +49,14 @@ "advancement.createnuclear.reactor_cooler.desc": "ɹoʇɔɐǝɹ ɹnoʎ ןooɔ oʇ ɹǝןooɔ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reactor_core": "ɹǝʍoԀ ɟO ǝɹoƆ", "advancement.createnuclear.reactor_core.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu ɹnoʎ ɟo ʎbɹǝuǝ ןןnɟ ǝɥʇ ssǝuɹɐɥ oʇ ǝɹoɔ ɹoʇɔɐǝɹ ǝɥʇ ʇɟɐɹƆ", + "advancement.createnuclear.reactor_fluid_input": "ןǝnℲ pınןℲ", + "advancement.createnuclear.reactor_fluid_input.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı ʇuɐןooɔ pınןɟ pǝǝɟ oʇ ʇnduı pınןɟ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reactor_frame": "ǝɯɐɹℲ ɹoʇɔɐǝᴚ", "advancement.createnuclear.reactor_frame.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu ɹnoʎ pןınq oʇ ǝɯɐɹɟ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", - "advancement.createnuclear.reactor_input": "ɹoʇɔɐǝᴚ ǝɥ⟘ buıןǝnℲ", - "advancement.createnuclear.reactor_input.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı spoɹ ǝʇıɥdɐɹb puɐ ɯnıuɐɹn pǝǝɟ oʇ ʇnduı ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", - "advancement.createnuclear.reactor_liquid_input": "ןǝnℲ pınbıꞀ", - "advancement.createnuclear.reactor_liquid_input.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı ʇuɐןooɔ pınbıן pǝǝɟ oʇ ʇnduı pınbıן ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reactor_output": "ʇndʇnO ɹǝʍoԀ", "advancement.createnuclear.reactor_output.desc": "ɹoʇɔɐǝɹ ɹnoʎ ʎq pǝɔnpoɹd ʎbɹǝuǝ ǝɥʇ ɹǝɟsuɐɹʇ oʇ ʇndʇno ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", + "advancement.createnuclear.reactor_rod_input": "ɹoʇɔɐǝᴚ ǝɥ⟘ buıןǝnℲ", + "advancement.createnuclear.reactor_rod_input.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı spoɹ ǝʇıɥdɐɹb puɐ ɯnıuɐɹn pǝǝɟ oʇ ʇnduı poɹ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reinforced_glass": "ssɐן⅁ pǝɔɹoɟuıǝᴚ", "advancement.createnuclear.reinforced_glass.desc": "ǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ ssɐןb pǝɔɹoɟuıǝɹ ǝɯos ʇɟɐɹƆ", "advancement.createnuclear.root": "ʎǝuɹnoſ ɹɐǝןɔnN ǝɥ⟘ buıʇɹɐʇS", @@ -130,20 +130,20 @@ "block.createnuclear.reactor_cooler.tooltip.summary": "‾ɹoʇɔɐǝɹ‾ ǝɥʇ pןınq oʇ pǝsn ‾ʞɔoןᗺ‾", "block.createnuclear.reactor_core": "ǝɹoƆ ɹoʇɔɐǝᴚ", "block.createnuclear.reactor_core.tooltip.summary": "‾ɹoʇɔɐǝɹ‾ ǝɥʇ pןınq oʇ pǝsn ‾ʞɔoןᗺ‾", + "block.createnuclear.reactor_fluid_input": "ʇnduI pınןℲ ɹoʇɔɐǝᴚ", + "block.createnuclear.reactor_fluid_input.tooltip.behaviour1": "˙‾buıʇɐǝɥɹǝʌo‾ pıoʌɐ puɐ ‾ɹoʇɔɐǝᴚ ǝɥ⟘‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı ‾uǝboɹʇıN pınbıꞀ‾ ɹo ‾ɹǝʇɐM‾ ʇɹǝsuI", + "block.createnuclear.reactor_fluid_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", + "block.createnuclear.reactor_fluid_input.tooltip.summary": "˙ɹoʇɔɐǝᴚ ǝɥʇ oʇuı ‾uǝboɹʇıN pınbıꞀ‾ ɹo ‾ɹǝʇɐM‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI pınןℲ ɹoʇɔɐǝᴚ ǝɥ⟘‾", "block.createnuclear.reactor_frame": "ǝɯɐɹℲ ɹoʇɔɐǝᴚ", "block.createnuclear.reactor_frame.tooltip.summary": "‾ɹoʇɔɐǝɹ‾ ǝɥʇ pןınq oʇ pǝsn ‾ʞɔoןᗺ‾", - "block.createnuclear.reactor_input": "ʇnduI ɹoʇɔɐǝᴚ", - "block.createnuclear.reactor_input.tooltip.behaviour1": "˙‾ɹoʇɔɐǝᴚ ǝɥ⟘‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı spoɹ )‾ǝʇıɥdɐɹ⅁‾ ǝʞıן( ‾buıןooƆ‾ puɐ )‾ɯnıɹoɥ⟘‾ ɹo ‾ɯnıuɐɹ∩‾ ǝʞıן( ‾buıʇɐǝH‾ ʇɹǝsuI", - "block.createnuclear.reactor_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", - "block.createnuclear.reactor_input.tooltip.summary": "˙ɹoʇɔɐǝᴚ ǝɥʇ oʇuı spoɹ ‾buıןooƆ‾ ɹo ‾buıʇɐǝH‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI poᴚ ɹoʇɔɐǝᴚ ǝɥ⟘‾", - "block.createnuclear.reactor_liquid_input": "ʇnduI pınbıꞀ ɹoʇɔɐǝᴚ", - "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "˙‾buıʇɐǝɥɹǝʌo‾ pıoʌɐ puɐ ‾ɹoʇɔɐǝᴚ ǝɥ⟘‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı ‾uǝboɹʇıN pınbıꞀ‾ ɹo ‾ɹǝʇɐM‾ ʇɹǝsuI", - "block.createnuclear.reactor_liquid_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", - "block.createnuclear.reactor_liquid_input.tooltip.summary": "˙ɹoʇɔɐǝᴚ ǝɥʇ oʇuı ‾uǝboɹʇıN pınbıꞀ‾ ɹo ‾ɹǝʇɐM‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI pınןℲ ɹoʇɔɐǝᴚ ǝɥ⟘‾", "block.createnuclear.reactor_output": "ʇndʇnO ɹoʇɔɐǝᴚ", "block.createnuclear.reactor_output.tooltip.behaviour1": "‾ʇndʇno ɹoʇɔɐǝɹ‾ ǝɥʇ oʇ ‾ʇɟɐɥs‾ buıɥɔɐʇʇɐ ʎq ɹoʇɔɐǝɹ ǝɥʇ ʎq ǝɔnpoɹd ‾ʎbɹǝuǝ ǝɥʇ ʇɔɐɹʇxǝ‾ uɐɔ noʎ", "block.createnuclear.reactor_output.tooltip.condition1": "ʎbɹǝuǝ ǝɔnpoɹd ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", "block.createnuclear.reactor_output.tooltip.summary": "‾ɹoʇɔɐǝᴚ‾ ǝɥʇ ʎq pǝʇɐɹǝuǝb ʎbɹǝuǝ ןɐɔıuɐɥɔǝɯ ǝɥʇ ʇɔɐɹʇxǝ oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇndʇnO ɹoʇɔɐǝᴚ ǝɥ⟘‾", + "block.createnuclear.reactor_rod_input": "ʇnduI poᴚ ɹoʇɔɐǝᴚ", + "block.createnuclear.reactor_rod_input.tooltip.behaviour1": "˙‾ɹoʇɔɐǝᴚ ǝɥ⟘‾ ɹǝʍod oʇ sǝıʇıʇuɐnb ǝbɹɐן uı spoɹ )‾ǝʇıɥdɐɹ⅁‾ ǝʞıן( ‾buıןooƆ‾ puɐ )‾ɯnıɹoɥ⟘‾ ɹo ‾ɯnıuɐɹ∩‾ ǝʞıן( ‾buıʇɐǝH‾ ʇɹǝsuI", + "block.createnuclear.reactor_rod_input.tooltip.condition1": "pǝןqɯǝssɐ sı ɹoʇɔɐǝɹ ǝɥʇ uǝɥM", + "block.createnuclear.reactor_rod_input.tooltip.summary": "˙ɹoʇɔɐǝᴚ ǝɥʇ oʇuı spoɹ ‾buıןooƆ‾ ɹo ‾buıʇɐǝH‾ ʇɹǝsuı oʇ pǝsn ǝq uɐɔ ʇɐɥʇ ‾ʞɔoןq‾ ɐ sı ‾ʇnduI poᴚ ɹoʇɔɐǝᴚ ǝɥ⟘‾", "block.createnuclear.reinforced_glass": "ssɐן⅁ pǝɔɹoɟuıǝᴚ", "block.createnuclear.small_autunite_brick": "ʞɔıɹᗺ ǝʇıunʇnⱯ ןןɐɯS", "block.createnuclear.small_autunite_brick_slab": "qɐןS ʞɔıɹᗺ ǝʇıunʇnⱯ ןןɐɯS", @@ -342,7 +342,7 @@ "item.createnuclear.enriched_yellowcake": "ǝʞɐɔʍoןןǝʎ pǝɥɔıɹuƎ", "item.createnuclear.graphene": "ǝuǝɥdɐɹ⅁", "item.createnuclear.graphite_rod": "poᴚ ǝʇıɥdɐɹ⅁", - "item.createnuclear.graphite_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", + "item.createnuclear.graphite_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı poɹ ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.gray_cloth": "ɥʇoןƆ ʎɐɹ⅁", "item.createnuclear.green_cloth": "ɥʇoןƆ uǝǝɹ⅁", "item.createnuclear.lead_ingot": "ʇobuI pɐǝꞀ", @@ -378,11 +378,11 @@ "item.createnuclear.thorium_ingot": "ʇobuI ɯnıɹoɥ⟘", "item.createnuclear.thorium_nugget": "ʇǝbbnN ɯnıɹoɥ⟘", "item.createnuclear.thorium_rod": "poᴚ ɯnıɹoɥ⟘", - "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", + "item.createnuclear.thorium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı poɹ ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.uranium_bucket": "ʇǝʞɔnᗺ ɯnıuɐɹ∩", "item.createnuclear.uranium_powder": "ɹǝpʍoԀ ɯnıuɐɹ∩", "item.createnuclear.uranium_rod": "poᴚ ɯnıuɐɹ∩", - "item.createnuclear.uranium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", + "item.createnuclear.uranium_rod.tooltip.summary": "˙ʇı ǝʇɐɹǝdo oʇ ‾ʇnduı poɹ ɹoʇɔɐǝɹ‾ ǝɥʇ uı pǝsn ǝq oʇ ‾poᴚ‾", "item.createnuclear.white_cloth": "ɥʇoןƆ ǝʇıɥM", "item.createnuclear.wolf_irradiated_spawn_egg": "bbƎ uʍɐdS ɟןoM pǝʇɐıpɐɹɹI", "item.createnuclear.yellow_cloth": "ɥʇoןƆ ʍoןןǝʎ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 4dd629d1..dbfc7a51 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -49,14 +49,14 @@ "advancement.createnuclear.reactor_cooler.desc": "Craft a reactor cooler to cool your reactor", "advancement.createnuclear.reactor_core": "Core Of Power", "advancement.createnuclear.reactor_core.desc": "Craft the reactor core to harness the full energy of your nuclear reactor", + "advancement.createnuclear.reactor_fluid_input": "Fluid Fuel", + "advancement.createnuclear.reactor_fluid_input.desc": "Craft a reactor fluid input to feed fluid coolant into your reactor", "advancement.createnuclear.reactor_frame": "Reactor Frame", "advancement.createnuclear.reactor_frame.desc": "Craft a reactor frame to build your nuclear reactor", - "advancement.createnuclear.reactor_input": "Fueling The Reactor", - "advancement.createnuclear.reactor_input.desc": "Craft a reactor input to feed uranium and graphite rods into your reactor", - "advancement.createnuclear.reactor_liquid_input": "Liquid Fuel", - "advancement.createnuclear.reactor_liquid_input.desc": "Craft a reactor liquid input to feed liquid coolant into your reactor", "advancement.createnuclear.reactor_output": "Power Output", "advancement.createnuclear.reactor_output.desc": "Craft a reactor output to transfer the energy produced by your reactor", + "advancement.createnuclear.reactor_rod_input": "Fueling The Reactor", + "advancement.createnuclear.reactor_rod_input.desc": "Craft a reactor rod input to feed uranium and graphite rods into your reactor", "advancement.createnuclear.reinforced_glass": "Reinforced Glass", "advancement.createnuclear.reinforced_glass.desc": "Craft some reinforced glass for the first time", "advancement.createnuclear.root": "Starting The Nuclear Journey", @@ -130,20 +130,20 @@ "block.createnuclear.reactor_cooler.tooltip.summary": "_Block_ used to build the _reactor_", "block.createnuclear.reactor_core": "Reactor Core", "block.createnuclear.reactor_core.tooltip.summary": "_Block_ used to build the _reactor_", + "block.createnuclear.reactor_fluid_input": "Reactor Fluid Input", + "block.createnuclear.reactor_fluid_input.tooltip.behaviour1": "Insert _Water_ or _Liquid Nitrogen_ in large quantities to power _The Reactor_ and avoid _overheating_.", + "block.createnuclear.reactor_fluid_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_fluid_input.tooltip.summary": "_The Reactor Fluid Input_ is a _block_ that can be used to insert _Water_ or _Liquid Nitrogen_ into the Reactor.", "block.createnuclear.reactor_frame": "Reactor Frame", "block.createnuclear.reactor_frame.tooltip.summary": "_Block_ used to build the _reactor_", - "block.createnuclear.reactor_input": "Reactor Input", - "block.createnuclear.reactor_input.tooltip.behaviour1": "Insert _Heating_ (like _Uranium_ or _Thorium_) and _Cooling_ (like _Graphite_) rods in large quantities to power _The Reactor_.", - "block.createnuclear.reactor_input.tooltip.condition1": "When the reactor is assembled", - "block.createnuclear.reactor_input.tooltip.summary": "_The Reactor Rod Input_ is a _block_ that can be used to insert _Heating_ or _Cooling_ rods into the Reactor.", - "block.createnuclear.reactor_liquid_input": "Reactor Liquid Input", - "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "Insert _Water_ or _Liquid Nitrogen_ in large quantities to power _The Reactor_ and avoid _overheating_.", - "block.createnuclear.reactor_liquid_input.tooltip.condition1": "When the reactor is assembled", - "block.createnuclear.reactor_liquid_input.tooltip.summary": "_The Reactor Fluid Input_ is a _block_ that can be used to insert _Water_ or _Liquid Nitrogen_ into the Reactor.", "block.createnuclear.reactor_output": "Reactor Output", "block.createnuclear.reactor_output.tooltip.behaviour1": "You can _extract the energy_ produce by the reactor by attaching _shaft_ to the _reactor output_", "block.createnuclear.reactor_output.tooltip.condition1": "When the reactor produce energy", "block.createnuclear.reactor_output.tooltip.summary": "_The Reactor Output_ is a _block_ that can be used to extract the mechanical energy generated by the _Reactor_", + "block.createnuclear.reactor_rod_input": "Reactor Rod Input", + "block.createnuclear.reactor_rod_input.tooltip.behaviour1": "Insert _Heating_ (like _Uranium_ or _Thorium_) and _Cooling_ (like _Graphite_) rods in large quantities to power _The Reactor_.", + "block.createnuclear.reactor_rod_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_rod_input.tooltip.summary": "_The Reactor Rod Input_ is a _block_ that can be used to insert _Heating_ or _Cooling_ rods into the Reactor.", "block.createnuclear.reinforced_glass": "Reinforced Glass", "block.createnuclear.small_autunite_brick": "Small Autunite Brick", "block.createnuclear.small_autunite_brick_slab": "Small Autunite Brick Slab", @@ -342,7 +342,7 @@ "item.createnuclear.enriched_yellowcake": "Enriched Yellowcake", "item.createnuclear.graphene": "Graphene", "item.createnuclear.graphite_rod": "Graphite Rod", - "item.createnuclear.graphite_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.graphite_rod.tooltip.summary": "_Rod_ to be used in the _reactor rod input_ to operate it.", "item.createnuclear.gray_cloth": "Gray Cloth", "item.createnuclear.green_cloth": "Green Cloth", "item.createnuclear.lead_ingot": "Lead Ingot", @@ -378,11 +378,11 @@ "item.createnuclear.thorium_ingot": "Thorium Ingot", "item.createnuclear.thorium_nugget": "Thorium Nugget", "item.createnuclear.thorium_rod": "Thorium Rod", - "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor rod input_ to operate it.", "item.createnuclear.uranium_bucket": "Uranium Bucket", "item.createnuclear.uranium_powder": "Uranium Powder", "item.createnuclear.uranium_rod": "Uranium Rod", - "item.createnuclear.uranium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.uranium_rod.tooltip.summary": "_Rod_ to be used in the _reactor rod input_ to operate it.", "item.createnuclear.white_cloth": "White Cloth", "item.createnuclear.wolf_irradiated_spawn_egg": "Irradiated Wolf Spawn Egg", "item.createnuclear.yellow_cloth": "Yellow Cloth", diff --git a/src/generated/resources/assets/createnuclear/models/item/reactor_fluid_input.json b/src/generated/resources/assets/createnuclear/models/item/reactor_fluid_input.json new file mode 100644 index 00000000..9def8ea6 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/reactor_fluid_input.json @@ -0,0 +1,3 @@ +{ + "parent": "createnuclear:block/reactor/fluid_input/item" +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/reactor_input.json b/src/generated/resources/assets/createnuclear/models/item/reactor_input.json deleted file mode 100644 index b4175b22..00000000 --- a/src/generated/resources/assets/createnuclear/models/item/reactor_input.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "createnuclear:block/reactor/input/item" -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/reactor_liquid_input.json b/src/generated/resources/assets/createnuclear/models/item/reactor_liquid_input.json deleted file mode 100644 index 35072cc1..00000000 --- a/src/generated/resources/assets/createnuclear/models/item/reactor_liquid_input.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "createnuclear:block/reactor/liquid_input/item" -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/reactor_rod_input.json b/src/generated/resources/assets/createnuclear/models/item/reactor_rod_input.json new file mode 100644 index 00000000..5fe1a68b --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/reactor_rod_input.json @@ -0,0 +1,3 @@ +{ + "parent": "createnuclear:block/reactor/rod_input/item" +} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json b/src/generated/resources/data/createnuclear/advancements/reactor_fluid_input.json similarity index 63% rename from src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json rename to src/generated/resources/data/createnuclear/advancements/reactor_fluid_input.json index a2ae7ed4..729e09e1 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_liquid_input.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_fluid_input.json @@ -1,12 +1,12 @@ { - "parent": "createnuclear:reactor_input", + "parent": "createnuclear:reactor_rod_input", "criteria": { "0": { "conditions": { "items": [ { "items": [ - "createnuclear:reactor_liquid_input" + "createnuclear:reactor_fluid_input" ] } ] @@ -18,16 +18,16 @@ "announce_to_chat": false, "description": { "color": "#DBA213", - "translate": "advancement.createnuclear.reactor_liquid_input.desc" + "translate": "advancement.createnuclear.reactor_fluid_input.desc" }, "frame": "task", "hidden": false, "icon": { - "item": "createnuclear:reactor_liquid_input" + "item": "createnuclear:reactor_fluid_input" }, "show_toast": true, "title": { - "translate": "advancement.createnuclear.reactor_liquid_input" + "translate": "advancement.createnuclear.reactor_fluid_input" } }, "requirements": [ diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_output.json b/src/generated/resources/data/createnuclear/advancements/reactor_output.json index 651c4a18..47d25fd7 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_output.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_output.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_liquid_input", + "parent": "createnuclear:reactor_fluid_input", "criteria": { "0": { "conditions": { diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_input.json b/src/generated/resources/data/createnuclear/advancements/reactor_rod_input.json similarity index 70% rename from src/generated/resources/data/createnuclear/advancements/reactor_input.json rename to src/generated/resources/data/createnuclear/advancements/reactor_rod_input.json index d75676da..1f9bf2c0 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_input.json +++ b/src/generated/resources/data/createnuclear/advancements/reactor_rod_input.json @@ -6,7 +6,7 @@ "items": [ { "items": [ - "createnuclear:reactor_input" + "createnuclear:reactor_rod_input" ] } ] @@ -18,16 +18,16 @@ "announce_to_chat": false, "description": { "color": "#DBA213", - "translate": "advancement.createnuclear.reactor_input.desc" + "translate": "advancement.createnuclear.reactor_rod_input.desc" }, "frame": "task", "hidden": false, "icon": { - "item": "createnuclear:reactor_input" + "item": "createnuclear:reactor_rod_input" }, "show_toast": true, "title": { - "translate": "advancement.createnuclear.reactor_input" + "translate": "advancement.createnuclear.reactor_rod_input" } }, "requirements": [ diff --git a/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_liquid_input.json b/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_fluid_input.json similarity index 71% rename from src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_liquid_input.json rename to src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_fluid_input.json index 59a5a712..6fb4edd0 100644 --- a/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_liquid_input.json +++ b/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_fluid_input.json @@ -11,11 +11,11 @@ "entries": [ { "type": "minecraft:item", - "name": "createnuclear:reactor_liquid_input" + "name": "createnuclear:reactor_fluid_input" } ], "rolls": 1.0 } ], - "random_sequence": "createnuclear:blocks/reactor_liquid_input" + "random_sequence": "createnuclear:blocks/reactor_fluid_input" } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_input.json b/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_rod_input.json similarity index 72% rename from src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_input.json rename to src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_rod_input.json index 12d08521..bc711698 100644 --- a/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_input.json +++ b/src/generated/resources/data/createnuclear/loot_tables/blocks/reactor_rod_input.json @@ -11,11 +11,11 @@ "entries": [ { "type": "minecraft:item", - "name": "createnuclear:reactor_input" + "name": "createnuclear:reactor_rod_input" } ], "rolls": 1.0 } ], - "random_sequence": "createnuclear:blocks/reactor_input" + "random_sequence": "createnuclear:blocks/reactor_rod_input" } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_fluid_input_from_fluid_pipe_and_reactor_casing.json similarity index 79% rename from src/generated/resources/data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json rename to src/generated/resources/data/createnuclear/recipes/deploying/reactor_fluid_input_from_fluid_pipe_and_reactor_casing.json index a6843872..c7a3c964 100644 --- a/src/generated/resources/data/createnuclear/recipes/deploying/reactor_liquid_input_from_fluid_pipe_and_reactor_casing.json +++ b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_fluid_input_from_fluid_pipe_and_reactor_casing.json @@ -10,7 +10,7 @@ ], "results": [ { - "item": "createnuclear:reactor_liquid_input" + "item": "createnuclear:reactor_fluid_input" } ] } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_rod_input_from_hopper_and_reactor_casing.json similarity index 79% rename from src/generated/resources/data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json rename to src/generated/resources/data/createnuclear/recipes/deploying/reactor_rod_input_from_hopper_and_reactor_casing.json index 86e5dbc3..e0d05ca4 100644 --- a/src/generated/resources/data/createnuclear/recipes/deploying/reactor_input_from_hopper_and_reactor_casing.json +++ b/src/generated/resources/data/createnuclear/recipes/deploying/reactor_rod_input_from_hopper_and_reactor_casing.json @@ -10,7 +10,7 @@ ], "results": [ { - "item": "createnuclear:reactor_input" + "item": "createnuclear:reactor_rod_input" } ] } \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 750d45c4..ef0c1084 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -4,8 +4,8 @@ "createnuclear:reactor_core", "createnuclear:reactor_frame", "createnuclear:reactor_cooler", - "createnuclear:reactor_input", - "createnuclear:reactor_liquid_input", + "createnuclear:reactor_rod_input", + "createnuclear:reactor_fluid_input", "createnuclear:reactor_output", "createnuclear:reactor_controller", "createnuclear:enriching_campfire", diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json index 218be9ea..188e478f 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json @@ -4,8 +4,8 @@ "createnuclear:reactor_core", "createnuclear:reactor_frame", "createnuclear:reactor_cooler", - "createnuclear:reactor_input", - "createnuclear:reactor_liquid_input", + "createnuclear:reactor_rod_input", + "createnuclear:reactor_fluid_input", "createnuclear:reactor_output", "createnuclear:reactor_controller", "createnuclear:enriched_soul_soil", diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlockEntityTypes.java b/src/main/java/net/nuclearteam/createnuclear/CNBlockEntityTypes.java index 19ed5ae3..6489ae40 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlockEntityTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlockEntityTypes.java @@ -10,7 +10,7 @@ import net.nuclearteam.createnuclear.content.multiblock.core.ReactorCoreEntity; import net.nuclearteam.createnuclear.content.multiblock.frame.ReactorFrameEntity; import net.nuclearteam.createnuclear.content.multiblock.frame.ReactorFrameRenderer; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputEntity; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInputEntity; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputEntity; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputRenderer; @@ -37,14 +37,14 @@ public class CNBlockEntityTypes { .renderer(() -> ReactorFrameRenderer::new) .register(); - public static final BlockEntityEntry REACTOR_INPUT = - CreateNuclear.REGISTRATE.blockEntity("reactor_input", ReactorInputEntity::new) - .validBlocks(CNBlocks.REACTOR_INPUT) + public static final BlockEntityEntry REACTOR_ROD_INPUT = + CreateNuclear.REGISTRATE.blockEntity("reactor_rod_input", ReactorRodInputEntity::new) + .validBlocks(CNBlocks.REACTOR_ROD_INPUT) .register(); - public static final BlockEntityEntry REACTOR_LIQUID_INPUT = - CreateNuclear.REGISTRATE.blockEntity("reactor_liquid_input", ReactorFluidInputEntity::new) - .validBlocks(CNBlocks.REACTOR_LIQUID_INPUT) + public static final BlockEntityEntry REACTOR_FLUID_INPUT = + CreateNuclear.REGISTRATE.blockEntity("reactor_fluid_input", ReactorFluidInputEntity::new) + .validBlocks(CNBlocks.REACTOR_FLUID_INPUT) .register(); public static final BlockEntityEntry REACTOR_OUTPUT = diff --git a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java index d2e87f60..02159b2d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNBlocks.java @@ -20,7 +20,6 @@ import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; -import net.minecraft.sounds.SoundEvents; import net.minecraft.tags.ItemTags; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantments; @@ -41,22 +40,19 @@ import net.nuclearteam.createnuclear.content.enriching.fire.EnrichingFireBlock; import net.minecraftforge.common.Tags; -import net.minecraftforge.common.util.ForgeSoundType; -import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem; import net.nuclearteam.createnuclear.content.multiblock.alarm.ReactorAlarm; import net.nuclearteam.createnuclear.content.multiblock.casing.ReactorCasing; import net.nuclearteam.createnuclear.CNTags.CNBlockTags; -import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerGenerator; import net.nuclearteam.createnuclear.content.multiblock.cooler.ReactorCooler; import net.nuclearteam.createnuclear.content.multiblock.core.ReactorCore; import net.nuclearteam.createnuclear.content.multiblock.frame.ReactorFrame; import net.nuclearteam.createnuclear.content.multiblock.frame.ReactorframeItem; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInput; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputGenerator; -import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorLiquidInput; -import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorLiquidInputGenerator; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInput; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInputGenerator; +import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInput; +import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputGenerator; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutput; import net.nuclearteam.createnuclear.content.multiblock.output.ReactorOutputGenerator; import net.nuclearteam.createnuclear.content.multiblock.reinforced.ReinforcedGlassBlock; @@ -149,31 +145,31 @@ public class CNBlocks { .transform(pickaxeOnly()) .register(); - public static final BlockEntry REACTOR_INPUT = CreateNuclear.REGISTRATE - .block("reactor_input", ReactorInput::new) + public static final BlockEntry REACTOR_ROD_INPUT = CreateNuclear.REGISTRATE + .block("reactor_rod_input", ReactorRodInput::new) .initialProperties(SharedProperties::stone) .properties(p -> p.explosionResistance(6F)) .properties(p -> p.destroyTime(2F)) .addLayer(() -> RenderType::cutoutMipped) .transform(pickaxeOnly()) .tag(BlockTags.NEEDS_DIAMOND_TOOL) - .blockstate(new ReactorInputGenerator()::generate) + .blockstate(new ReactorRodInputGenerator()::generate) .item() - .transform(customItemModel("reactor", "input", "item")) + .transform(customItemModel("reactor", "rod_input", "item")) .register(); - public static final BlockEntry REACTOR_LIQUID_INPUT = - CreateNuclear.REGISTRATE.block("reactor_liquid_input", ReactorLiquidInput::new) + public static final BlockEntry REACTOR_FLUID_INPUT = + CreateNuclear.REGISTRATE.block("reactor_fluid_input", ReactorFluidInput::new) .initialProperties(SharedProperties::stone) .properties(p -> p.explosionResistance(6F)) .properties(p -> p.destroyTime(2F)) .addLayer(() -> RenderType::cutoutMipped) .transform(pickaxeOnly()) .tag(BlockTags.NEEDS_DIAMOND_TOOL) - .blockstate(new ReactorLiquidInputGenerator()::generate) + .blockstate(new ReactorFluidInputGenerator()::generate) .item() - .transform(customItemModel("reactor", "liquid_input", "item")) + .transform(customItemModel("reactor", "fluid_input", "item")) .register(); public static final BlockEntry REACTOR_OUTPUT = diff --git a/src/main/java/net/nuclearteam/createnuclear/CNMenus.java b/src/main/java/net/nuclearteam/createnuclear/CNMenus.java index 6a4b1fd7..ff585658 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNMenus.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNMenus.java @@ -9,12 +9,12 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintItemScreen; import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintMenu; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputMenu; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputScreen; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInputMenu; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInputScreen; public class CNMenus { public static final MenuEntry REACTOR_BLUEPRINT_MENU = menu("reactor_blueprint_menu", ReactorBluePrintMenu::new, () -> ReactorBluePrintItemScreen::new); - public static final MenuEntry SLOT_ITEM_STORAGE = menu("slot_item_menu", ReactorInputMenu::new, () -> ReactorInputScreen::new); + public static final MenuEntry SLOT_ITEM_STORAGE = menu("slot_item_menu", ReactorRodInputMenu::new, () -> ReactorRodInputScreen::new); private static > MenuEntry menu(String name, ForgeMenuFactory factory, NonNullSupplier> screenFactory) { return CreateNuclear.REGISTRATE diff --git a/src/main/java/net/nuclearteam/createnuclear/CNShapes.java b/src/main/java/net/nuclearteam/createnuclear/CNShapes.java index 99b60380..602dfc49 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNShapes.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNShapes.java @@ -16,8 +16,8 @@ public class CNShapes { // Independent Shapers public static final VoxelShaper REACTOR_OUTPUT = shape(0, 0, 0, 16, 14, 16).forDirectional(), - REACTOR_INPUT = shape(0,0,0,16,16,16).forDirectional(), - REACTOR_LIQUID_INPUT = shape(0,0,0,16,16,16).forDirectional() + REACTOR_ROD_INPUT = shape(0,0,0,16,16,16).forDirectional(), + REACTOR_FLUID_INPUT = shape(0,0,0,16,16,16).forDirectional() ; private static Builder shape(VoxelShape shape) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/CNMultiblock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/CNMultiblock.java index 4196d34c..aa5a5008 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/CNMultiblock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/CNMultiblock.java @@ -16,8 +16,8 @@ public class CNMultiblock { private static final Predicate blockInWorldAPredicate = state -> stateIs(CNBlocks.REACTOR_CASING.get()).test(state) || stateIs(CNBlocks.REACTOR_OUTPUT.get()).test(state) - || stateIs(CNBlocks.REACTOR_INPUT.get()).test(state) - || stateIs(CNBlocks.REACTOR_LIQUID_INPUT.get()).test(state) + || stateIs(CNBlocks.REACTOR_ROD_INPUT.get()).test(state) + || stateIs(CNBlocks.REACTOR_FLUID_INPUT.get()).test(state) || stateIs(CNBlocks.REACTOR_ALARM.get()).test(state) ; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 202f376d..5dec30b8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -74,8 +74,8 @@ public static void findAndRegisterSpecialBlocks(BoundingBox reactorPos, ReactorC int zMin = reactorPos.minZ(), zMax = reactorPos.maxZ(); final Block reactorOutputBlock = CNBlocks.REACTOR_OUTPUT.get(); - final Block reactorInputBlock = CNBlocks.REACTOR_INPUT.get(); - final Block reactorInputFluidBlock = CNBlocks.REACTOR_LIQUID_INPUT.get(); + final Block reactorRodInputBlock = CNBlocks.REACTOR_ROD_INPUT.get(); + final Block reactorInputFluidBlock = CNBlocks.REACTOR_FLUID_INPUT.get(); final Block reactorAlarmBlock = CNBlocks.REACTOR_ALARM.get(); final Block reactorFrameBlock = CNBlocks.REACTOR_FRAME.get(); @@ -102,7 +102,7 @@ public static void findAndRegisterSpecialBlocks(BoundingBox reactorPos, ReactorC if (blockState.is(reactorOutputBlock)) { entity.addOutput(mutablePos.immutable()); - } else if (blockState.is(reactorInputBlock)) { + } else if (blockState.is(reactorRodInputBlock)) { entity.addInput(mutablePos.immutable()); } else if (blockState.is(reactorInputFluidBlock)) { entity.addInputFluid(mutablePos.immutable()); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java index 2ea86266..67d3d11f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java @@ -20,7 +20,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.nuclearteam.createnuclear.CNBlockEntityTypes; import net.nuclearteam.createnuclear.CNBlocks; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInput; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInput; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; @@ -73,7 +73,7 @@ public InteractionResult onWrenched(BlockState state, UseOnContext context) { Player player = context.getPlayer(); if (player.getItemInHand(InteractionHand.OFF_HAND).is(Blocks.HOPPER.asItem())) { - level.setBlock(pos, CNBlocks.REACTOR_INPUT.getDefaultState().setValue(ReactorInput.FACING, context.getClickedFace()), 2); + level.setBlock(pos, CNBlocks.REACTOR_ROD_INPUT.getDefaultState().setValue(ReactorRodInput.FACING, context.getClickedFace()), 2); player.sendSystemMessage(Component.translatable("reactor.update.casing.input")); } return InteractionResult.SUCCESS; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java index 3b4e8229..70677bc0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java @@ -14,7 +14,7 @@ import net.minecraftforge.registries.ForgeRegistries; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import net.nuclearteam.createnuclear.content.multiblock.input.item.VirtualReactorInputsItem; -import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorInputEntity; +import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInputEntity; import java.util.ArrayList; import java.util.List; @@ -188,7 +188,7 @@ public List getBlocksPosition(Level level) { List positions = new ArrayList<>(); for (BlockPos p : this.getBlocksPosition()) { - if (level.getBlockEntity(p) instanceof ReactorInputEntity) positions.add(p); + if (level.getBlockEntity(p) instanceof ReactorRodInputEntity) positions.add(p); } return List.copyOf(positions); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorLiquidInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java similarity index 93% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorLiquidInput.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java index 65592e0a..7a3d05ec 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorLiquidInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java @@ -31,9 +31,9 @@ import javax.annotation.Nullable; -public class ReactorLiquidInput extends MultiDirectionalReactorBlock implements IWrenchable, IBE { +public class ReactorFluidInput extends MultiDirectionalReactorBlock implements IWrenchable, IBE { - public ReactorLiquidInput(Properties properties) { + public ReactorFluidInput(Properties properties) { super(properties); } @@ -73,7 +73,7 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { @Override public @NotNull VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return CNShapes.REACTOR_LIQUID_INPUT.get(state.getValue(FACING)); + return CNShapes.REACTOR_FLUID_INPUT.get(state.getValue(FACING)); } @Override @@ -109,7 +109,7 @@ public Class getBlockEntityClass() { @Override public BlockEntityType getBlockEntityType() { - return CNBlockEntityTypes.REACTOR_LIQUID_INPUT.get(); + return CNBlockEntityTypes.REACTOR_FLUID_INPUT.get(); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorLiquidInputGenerator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputGenerator.java similarity index 68% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorLiquidInputGenerator.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputGenerator.java index fa5e6e2e..ce60aa6a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorLiquidInputGenerator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputGenerator.java @@ -8,17 +8,17 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.generators.ModelFile; -public class ReactorLiquidInputGenerator extends SpecialBlockStateGen { +public class ReactorFluidInputGenerator extends SpecialBlockStateGen { @Override protected int getXRotation(BlockState state) { - return state.getValue(ReactorLiquidInput.FACING) == Direction.DOWN ? 180 : 0; + return state.getValue(ReactorFluidInput.FACING) == Direction.DOWN ? 180 : 0; } @Override protected int getYRotation(BlockState state) { - return state.getValue(ReactorLiquidInput.FACING).getAxis().isVertical() + return state.getValue(ReactorFluidInput.FACING).getAxis().isVertical() ? 0 - : horizontalAngle(state.getValue(ReactorLiquidInput.FACING)); + : horizontalAngle(state.getValue(ReactorFluidInput.FACING)); } @Override @@ -26,7 +26,7 @@ public ModelFile getModel(DataGenContext ctx, Regist return prov .models() .getExistingFile(prov - .modLoc("block/reactor/liquid_input/liquid_input" + (state.getValue(ReactorLiquidInput.FACING).getAxis().isVertical() + .modLoc("block/reactor/fluid_input/fluid_input" + (state.getValue(ReactorFluidInput.FACING).getAxis().isVertical() ? "_vertical" : "" ))); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java similarity index 89% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java index 74169e16..d44f550c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java @@ -38,9 +38,9 @@ @ParametersAreNonnullByDefault -public class ReactorInput extends MultiDirectionalReactorBlock implements IWrenchable, IBE { +public class ReactorRodInput extends MultiDirectionalReactorBlock implements IWrenchable, IBE { - public ReactorInput(Properties properties) { + public ReactorRodInput(Properties properties) { super(properties); } @@ -98,16 +98,16 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { } @Override public @NotNull VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { - return CNShapes.REACTOR_INPUT.get(state.getValue(FACING)); + return CNShapes.REACTOR_ROD_INPUT.get(state.getValue(FACING)); } @Override - public Class getBlockEntityClass() { - return ReactorInputEntity.class; + public Class getBlockEntityClass() { + return ReactorRodInputEntity.class; } @Override - public BlockEntityType getBlockEntityType() { - return CNBlockEntityTypes.REACTOR_INPUT.get(); + public BlockEntityType getBlockEntityType() { + return CNBlockEntityTypes.REACTOR_ROD_INPUT.get(); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java similarity index 89% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java index 0c845c89..b20632fa 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java @@ -22,17 +22,17 @@ import javax.annotation.Nullable; import java.util.List; -public class ReactorInputEntity extends SmartBlockEntity implements MenuProvider { +public class ReactorRodInputEntity extends SmartBlockEntity implements MenuProvider { //protected ReactorControllerBlockEntity controller; public ReactorControllerBlock controller = null; - public ReactorInputInventory inventory; + public ReactorRodInputInventory inventory; LazyOptional inventoryProvider; - public ReactorInputEntity(BlockEntityType type, BlockPos pos, BlockState state) { + public ReactorRodInputEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); - inventory = new ReactorInputInventory(this); + inventory = new ReactorRodInputInventory(this); inventoryProvider = LazyOptional.of(() -> inventory); } @@ -79,7 +79,7 @@ public Component getDisplayName() { @Nullable @Override public AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) { - return ReactorInputMenu.create(i, inventory, this); + return ReactorRodInputMenu.create(i, inventory, this); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputGenerator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputGenerator.java similarity index 69% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputGenerator.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputGenerator.java index 9ce0fafd..3789ac92 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputGenerator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputGenerator.java @@ -8,17 +8,17 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.generators.ModelFile; -public class ReactorInputGenerator extends SpecialBlockStateGen { +public class ReactorRodInputGenerator extends SpecialBlockStateGen { @Override protected int getXRotation(BlockState state) { - return state.getValue(ReactorInput.FACING) == Direction.DOWN ? 180 : 0; + return state.getValue(ReactorRodInput.FACING) == Direction.DOWN ? 180 : 0; } @Override protected int getYRotation(BlockState state) { - return state.getValue(ReactorInput.FACING).getAxis().isVertical() + return state.getValue(ReactorRodInput.FACING).getAxis().isVertical() ? 0 - : horizontalAngle(state.getValue(ReactorInput.FACING)); + : horizontalAngle(state.getValue(ReactorRodInput.FACING)); } @Override @@ -26,7 +26,7 @@ public ModelFile getModel(DataGenContext ctx, Regist return prov .models() .getExistingFile(prov - .modLoc("block/reactor/input/input" + (state.getValue(ReactorInput.FACING).getAxis().isVertical() + .modLoc("block/reactor/rod_input/rod_input" + (state.getValue(ReactorRodInput.FACING).getAxis().isVertical() ? "_vertical" : "" ))); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputInventory.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java similarity index 86% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputInventory.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java index 1f829fd2..2edb0cad 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputInventory.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java @@ -9,10 +9,10 @@ import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRod; import org.jetbrains.annotations.NotNull; -public class ReactorInputInventory extends ItemStackHandler { - private final ReactorInputEntity be; +public class ReactorRodInputInventory extends ItemStackHandler { + private final ReactorRodInputEntity be; - public ReactorInputInventory(ReactorInputEntity be) { + public ReactorRodInputInventory(ReactorRodInputEntity be) { super(1); this.be = be; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputMenu.java similarity index 80% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputMenu.java index 825cb548..981c507d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputMenu.java @@ -14,19 +14,19 @@ import net.minecraftforge.items.SlotItemHandler; import net.nuclearteam.createnuclear.CNMenus; -public class ReactorInputMenu extends MenuBase { +public class ReactorRodInputMenu extends MenuBase { - public ReactorInputMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { + public ReactorRodInputMenu(MenuType type, int id, Inventory inv, FriendlyByteBuf extraData) { super(type, id, inv, extraData); } - public ReactorInputMenu(MenuType type, int id, Inventory inv, ReactorInputEntity contentHolder) { + public ReactorRodInputMenu(MenuType type, int id, Inventory inv, ReactorRodInputEntity contentHolder) { super(type, id, inv, contentHolder); } - public static ReactorInputMenu create(int id, Inventory inv, ReactorInputEntity contentHolder) { - return new ReactorInputMenu(CNMenus.SLOT_ITEM_STORAGE.get(), id, inv, contentHolder); + public static ReactorRodInputMenu create(int id, Inventory inv, ReactorRodInputEntity contentHolder) { + return new ReactorRodInputMenu(CNMenus.SLOT_ITEM_STORAGE.get(), id, inv, contentHolder); } @Override @@ -70,18 +70,18 @@ public ItemStack quickMoveStack(Player playerIn, int index) { @Override - protected ReactorInputEntity createOnClient(FriendlyByteBuf extraData) { + protected ReactorRodInputEntity createOnClient(FriendlyByteBuf extraData) { ClientLevel world = Minecraft.getInstance().level; BlockEntity entity = world.getBlockEntity(extraData.readBlockPos()); - if (entity instanceof ReactorInputEntity reactorInputEntity) { - reactorInputEntity.readClient(extraData.readNbt()); - return reactorInputEntity; + if (entity instanceof ReactorRodInputEntity reactorRodInputEntity) { + reactorRodInputEntity.readClient(extraData.readNbt()); + return reactorRodInputEntity; } return null; } @Override - protected void initAndReadInventory(ReactorInputEntity contentHolder) { + protected void initAndReadInventory(ReactorRodInputEntity contentHolder) { } @@ -105,7 +105,7 @@ protected void addSlots() { } @Override - protected void saveData(ReactorInputEntity contentHolder) { + protected void saveData(ReactorRodInputEntity contentHolder) { } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputScreen.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputScreen.java similarity index 86% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputScreen.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputScreen.java index 37fdd038..5b6621d1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorInputScreen.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputScreen.java @@ -9,11 +9,11 @@ import static com.simibubi.create.foundation.gui.AllGuiTextures.PLAYER_INVENTORY; -public class ReactorInputScreen extends AbstractSimiContainerScreen { +public class ReactorRodInputScreen extends AbstractSimiContainerScreen { protected static final CNGuiTextures background = CNGuiTextures.REACTOR_SLOT_INVENTOR; - public ReactorInputScreen(ReactorInputMenu container, Inventory inv, Component title) { + public ReactorRodInputScreen(ReactorRodInputMenu container, Inventory inv, Component title) { super(container, inv, title); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java index cdd5f18a..c7768553 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java @@ -19,8 +19,8 @@ public class ReactorPattern { private static final Predicate blockInWorldAPredicate = state -> stateIs(CNBlocks.REACTOR_CASING.get()).test(state) || stateIs(CNBlocks.REACTOR_OUTPUT.get()).test(state) - || stateIs(CNBlocks.REACTOR_INPUT.get()).test(state) - || stateIs(CNBlocks.REACTOR_LIQUID_INPUT.get()).test(state) + || stateIs(CNBlocks.REACTOR_ROD_INPUT.get()).test(state) + || stateIs(CNBlocks.REACTOR_FLUID_INPUT.get()).test(state) || stateIs(CNBlocks.REACTOR_ALARM.get()).test(state) ; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java index bcaeb5e1..74c6fe64 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java @@ -317,24 +317,24 @@ public class CNAdvancement implements DataProvider { .whenIconCollected() ), - REACTOR_INPUT = create("reactor_input", b -> b.icon(CNBlocks.REACTOR_INPUT) + REACTOR_ROD_INPUT = create("reactor_rod_input", b -> b.icon(CNBlocks.REACTOR_ROD_INPUT) .title("Fueling The Reactor") - .description("Craft a reactor input to feed uranium and graphite rods into your reactor") + .description("Craft a reactor rod input to feed uranium and graphite rods into your reactor") .after(REACTOR_CASING) .whenIconCollected() ), - REACTOR_LIQUID_INPUT = create("reactor_liquid_input", b -> b.icon(CNBlocks.REACTOR_LIQUID_INPUT) - .title("Liquid Fuel") - .description("Craft a reactor liquid input to feed liquid coolant into your reactor") - .after(REACTOR_INPUT) + REACTOR_FLUID_INPUT = create("reactor_fluid_input", b -> b.icon(CNBlocks.REACTOR_FLUID_INPUT) + .title("Fluid Fuel") + .description("Craft a reactor fluid input to feed fluid coolant into your reactor") + .after(REACTOR_ROD_INPUT) .whenIconCollected() ), REACTOR_OUTPUT = create("reactor_output", b -> b.icon(CNBlocks.REACTOR_OUTPUT) .title("Power Output") .description("Craft a reactor output to transfer the energy produced by your reactor") - .after(REACTOR_LIQUID_INPUT) + .after(REACTOR_FLUID_INPUT) .whenIconCollected() ), diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java index 2aa512af..53d3e8f1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNDeployingRecipeGen.java @@ -12,16 +12,16 @@ public class CNDeployingRecipeGen extends DeployingRecipeGen { - GeneratedRecipe REACTOR_INPUT = deploying("reactor_input_from_hopper_and_reactor_casing", + GeneratedRecipe REACTOR_ROD_INPUT = deploying("reactor_rod_input_from_hopper_and_reactor_casing", Items.HOPPER, CNBlocks.REACTOR_CASING.get(), - CNBlocks.REACTOR_INPUT.get() + CNBlocks.REACTOR_ROD_INPUT.get() ); - GeneratedRecipe REACTOR_LIQUID_INPUT = deploying("reactor_liquid_input_from_fluid_pipe_and_reactor_casing", + GeneratedRecipe REACTOR_FLUID_INPUT = deploying("reactor_fluid_input_from_fluid_pipe_and_reactor_casing", AllBlocks.FLUID_PIPE.asItem(), CNBlocks.REACTOR_CASING.get(), - CNBlocks.REACTOR_LIQUID_INPUT.get() + CNBlocks.REACTOR_FLUID_INPUT.get() ); GeneratedRecipe REACTOR_OUTPUT = deploying("reactor_output_from_shaft_and_reactor_casing", diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 32037405..cd26b407 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -301,9 +301,9 @@ public static void ioPlacement(SceneBuilder scene, SceneBuildingUtil util) { scene.world().modifyBlock(pos.output, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), true); // Place I/O on roof - scene.world().modifyBlock(newIn1, s -> CNBlocks.REACTOR_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); - scene.world().modifyBlock(newIn2, s -> CNBlocks.REACTOR_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); - scene.world().modifyBlock(newLiq, s -> CNBlocks.REACTOR_LIQUID_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + scene.world().modifyBlock(newIn1, s -> CNBlocks.REACTOR_ROD_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + scene.world().modifyBlock(newIn2, s -> CNBlocks.REACTOR_ROD_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); + scene.world().modifyBlock(newLiq, s -> CNBlocks.REACTOR_FLUID_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); // Note: ReactorAlarm might not have FACING. Using default state. scene.world().modifyBlock(newAlm, s -> CNBlocks.REACTOR_ALARM.get().defaultBlockState(), true); scene.world().modifyBlock(newOut, s -> CNBlocks.REACTOR_OUTPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.UP), true); diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index e122efa7..6e027b70 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -4,13 +4,13 @@ "tag.item.createnuclear.fuel": "Fuel", - "block.createnuclear.reactor_input.tooltip.summary": "_The Reactor Rod Input_ is a _block_ that can be used to insert _Heating_ or _Cooling_ rods into the Reactor.", - "block.createnuclear.reactor_input.tooltip.condition1": "When the reactor is assembled", - "block.createnuclear.reactor_input.tooltip.behaviour1": "Insert _Heating_ (like _Uranium_ or _Thorium_) and _Cooling_ (like _Graphite_) rods in large quantities to power _The Reactor_.", + "block.createnuclear.reactor_rod_input.tooltip.summary": "_The Reactor Rod Input_ is a _block_ that can be used to insert _Heating_ or _Cooling_ rods into the Reactor.", + "block.createnuclear.reactor_rod_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_rod_input.tooltip.behaviour1": "Insert _Heating_ (like _Uranium_ or _Thorium_) and _Cooling_ (like _Graphite_) rods in large quantities to power _The Reactor_.", - "block.createnuclear.reactor_liquid_input.tooltip.summary": "_The Reactor Fluid Input_ is a _block_ that can be used to insert _Water_ or _Liquid Nitrogen_ into the Reactor.", - "block.createnuclear.reactor_liquid_input.tooltip.condition1": "When the reactor is assembled", - "block.createnuclear.reactor_liquid_input.tooltip.behaviour1": "Insert _Water_ or _Liquid Nitrogen_ in large quantities to power _The Reactor_ and avoid _overheating_.", + "block.createnuclear.reactor_fluid_input.tooltip.summary": "_The Reactor Fluid Input_ is a _block_ that can be used to insert _Water_ or _Liquid Nitrogen_ into the Reactor.", + "block.createnuclear.reactor_fluid_input.tooltip.condition1": "When the reactor is assembled", + "block.createnuclear.reactor_fluid_input.tooltip.behaviour1": "Insert _Water_ or _Liquid Nitrogen_ in large quantities to power _The Reactor_ and avoid _overheating_.", "block.createnuclear.reactor_controller.tooltip.summary": " The _Reactor Controller_ is the _most important_ block for operating the reactor", @@ -33,11 +33,11 @@ "block.createnuclear.reactor_frame.tooltip.summary": "_Block_ used to build the _reactor_", - "item.createnuclear.graphite_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.graphite_rod.tooltip.summary": "_Rod_ to be used in the _reactor rod input_ to operate it.", - "item.createnuclear.uranium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.uranium_rod.tooltip.summary": "_Rod_ to be used in the _reactor rod input_ to operate it.", - "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor input_ to operate it.", + "item.createnuclear.thorium_rod.tooltip.summary": "_Rod_ to be used in the _reactor rod input_ to operate it.", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", "item.createnuclear.reactor_blueprint_item.tooltip.condition1": "Filled with cooling and heating rods", diff --git a/src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/liquid_input.json b/src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/fluid_input.json similarity index 97% rename from src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/liquid_input.json rename to src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/fluid_input.json index 0abd0401..91e7ce7d 100644 --- a/src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/liquid_input.json +++ b/src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/fluid_input.json @@ -3,7 +3,7 @@ "parent": "block/block", "textures": { "0": "createnuclear:block/reactor/casing/reactor_casing", - "1": "createnuclear:block/reactor/liquid_input/input", + "1": "createnuclear:block/reactor/fluid_input/fluid_input", "2": "createnuclear:block/reactor/casing/reactor_casing", "particle": "createnuclear:block/reactor/casing/reactor_casing" }, diff --git a/src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/liquid_input_vertical.json b/src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/fluid_input_vertical.json similarity index 98% rename from src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/liquid_input_vertical.json rename to src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/fluid_input_vertical.json index 911c1104..bdb0efb7 100644 --- a/src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/liquid_input_vertical.json +++ b/src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/fluid_input_vertical.json @@ -2,10 +2,10 @@ "credit": "Made with Blockbench", "parent": "block/block", "textures": { - "0": "createnuclear:block/reactor/liquid_input/input", + "0": "createnuclear:block/reactor/fluid_input/fluid_input", "1": "createnuclear:block/reactor/casing/reactor_casing", "2": "createnuclear:block/reactor/casing/reactor_casing", - "particle": "createnuclear:block/reactor/input/input" + "particle": "createnuclear:block/reactor/rod_input/rod_input" }, "elements": [ { diff --git a/src/main/resources/assets/createnuclear/models/block/reactor/input/item.json b/src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/item.json similarity index 97% rename from src/main/resources/assets/createnuclear/models/block/reactor/input/item.json rename to src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/item.json index 59b71e8e..67a5e796 100644 --- a/src/main/resources/assets/createnuclear/models/block/reactor/input/item.json +++ b/src/main/resources/assets/createnuclear/models/block/reactor/fluid_input/item.json @@ -3,7 +3,7 @@ "parent": "block/block", "textures": { "0": "createnuclear:block/reactor/casing/reactor_casing", - "1": "createnuclear:block/reactor/input/input", + "1": "createnuclear:block/reactor/fluid_input/fluid_input", "2": "createnuclear:block/reactor/casing/reactor_casing", "particle": "createnuclear:block/reactor/casing/reactor_casing" }, diff --git a/src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/item.json b/src/main/resources/assets/createnuclear/models/block/reactor/rod_input/item.json similarity index 97% rename from src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/item.json rename to src/main/resources/assets/createnuclear/models/block/reactor/rod_input/item.json index 8e366191..44a5bfd3 100644 --- a/src/main/resources/assets/createnuclear/models/block/reactor/liquid_input/item.json +++ b/src/main/resources/assets/createnuclear/models/block/reactor/rod_input/item.json @@ -3,7 +3,7 @@ "parent": "block/block", "textures": { "0": "createnuclear:block/reactor/casing/reactor_casing", - "1": "createnuclear:block/reactor/liquid_input/input", + "1": "createnuclear:block/reactor/rod_input/rod_input", "2": "createnuclear:block/reactor/casing/reactor_casing", "particle": "createnuclear:block/reactor/casing/reactor_casing" }, diff --git a/src/main/resources/assets/createnuclear/models/block/reactor/input/input.json b/src/main/resources/assets/createnuclear/models/block/reactor/rod_input/rod_input.json similarity index 98% rename from src/main/resources/assets/createnuclear/models/block/reactor/input/input.json rename to src/main/resources/assets/createnuclear/models/block/reactor/rod_input/rod_input.json index f376046a..e51c4774 100644 --- a/src/main/resources/assets/createnuclear/models/block/reactor/input/input.json +++ b/src/main/resources/assets/createnuclear/models/block/reactor/rod_input/rod_input.json @@ -3,7 +3,7 @@ "parent": "block/block", "textures": { "0": "createnuclear:block/reactor/casing/reactor_casing", - "1": "createnuclear:block/reactor/input/input", + "1": "createnuclear:block/reactor/rod_input/rod_input", "2": "createnuclear:block/reactor/casing/reactor_casing", "particle": "createnuclear:block/reactor/casing/reactor_casing" }, diff --git a/src/main/resources/assets/createnuclear/models/block/reactor/input/input_vertical.json b/src/main/resources/assets/createnuclear/models/block/reactor/rod_input/rod_input_vertical.json similarity index 98% rename from src/main/resources/assets/createnuclear/models/block/reactor/input/input_vertical.json rename to src/main/resources/assets/createnuclear/models/block/reactor/rod_input/rod_input_vertical.json index 378d4c7c..754f8f59 100644 --- a/src/main/resources/assets/createnuclear/models/block/reactor/input/input_vertical.json +++ b/src/main/resources/assets/createnuclear/models/block/reactor/rod_input/rod_input_vertical.json @@ -2,10 +2,10 @@ "credit": "Made with Blockbench", "parent": "block/block", "textures": { - "0": "createnuclear:block/reactor/input/input", + "0": "createnuclear:block/reactor/rod_input/rod_input", "1": "createnuclear:block/reactor/casing/reactor_casing", "2": "createnuclear:block/reactor/casing/reactor_casing", - "particle": "createnuclear:block/reactor/input/input" + "particle": "createnuclear:block/reactor/rod_input/rod_input" }, "elements": [ { diff --git a/src/main/resources/assets/createnuclear/textures/block/reactor/liquid_input/input.png b/src/main/resources/assets/createnuclear/textures/block/reactor/fluid_input/fluid_input.png similarity index 100% rename from src/main/resources/assets/createnuclear/textures/block/reactor/liquid_input/input.png rename to src/main/resources/assets/createnuclear/textures/block/reactor/fluid_input/fluid_input.png diff --git a/src/main/resources/assets/createnuclear/textures/block/reactor/input/input.png b/src/main/resources/assets/createnuclear/textures/block/reactor/rod_input/rod_input.png similarity index 100% rename from src/main/resources/assets/createnuclear/textures/block/reactor/input/input.png rename to src/main/resources/assets/createnuclear/textures/block/reactor/rod_input/rod_input.png From 845406763533a9a3253a398ffa171990f38c1d31 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 14:23:09 +0200 Subject: [PATCH 099/171] Fix ponder scenes for renamed Reactor IO blocks and fill empty NBT holes with casing --- .../ponder/scenes/CNPonderReactorScenes.java | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index cd26b407..4ec88b55 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -116,11 +116,34 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil util, int S, int H, int plate, boolean bySections) { Positions pos = positionsFor(S, H); - scene.world().modifyBlock(pos.input1, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); - scene.world().modifyBlock(pos.input2, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); - scene.world().modifyBlock(pos.liquidInput, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); - scene.world().modifyBlock(pos.alarm, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); - scene.world().modifyBlock(pos.output, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + int minX = MARGIN; + int maxX = MARGIN + S - 1; + int minZ = MARGIN; + int maxZ = MARGIN + S - 1; + int minY = 1; + int maxY = H; + + // Remplacer toutes les faces (sauf les arêtes et le contrôleur) par du Casing + // Cela permet de boucher tous les trous causés par les anciens blocs I/O renommés dans le NBT. + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { + boolean onXFace = (x == minX || x == maxX); + boolean onYFace = (y == minY || y == maxY); + boolean onZFace = (z == minZ || z == maxZ); + + int faceCount = (onXFace ? 1 : 0) + (onYFace ? 1 : 0) + (onZFace ? 1 : 0); + + // faceCount == 1 signifie qu'on est sur une face plane (pas une arête) + if (faceCount == 1) { + BlockPos currentPos = new BlockPos(x, y, z); + if (!currentPos.equals(pos.controller)) { + scene.world().modifyBlock(currentPos, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); + } + } + } + } + } scene.idle(20); @@ -235,6 +258,13 @@ public static void ioPlacement(SceneBuilder scene, SceneBuildingUtil util) { scene.rotateCameraY(180); scene.scaleSceneView(0.55f); + // Populate the correct I/O blocks at the beginning because the schematic has old broken IDs + scene.world().modifyBlock(pos.input1, s -> CNBlocks.REACTOR_ROD_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.SOUTH), false); + scene.world().modifyBlock(pos.input2, s -> CNBlocks.REACTOR_ROD_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.SOUTH), false); + scene.world().modifyBlock(pos.liquidInput, s -> CNBlocks.REACTOR_FLUID_INPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.SOUTH), false); + scene.world().modifyBlock(pos.alarm, s -> CNBlocks.REACTOR_ALARM.get().defaultBlockState(), false); + scene.world().modifyBlock(pos.output, s -> CNBlocks.REACTOR_OUTPUT.get().defaultBlockState().setValue(BlockStateProperties.FACING, Direction.SOUTH), false); + // Show the entire T1 structure instantly scene.world().showSection(util.select().layersFrom(1), Direction.UP); scene.idle(20); From 0e484ad67ed80bec819db4906076d68375158e9e Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 14:26:52 +0200 Subject: [PATCH 100/171] Update Ponder NBT schematics to use the new Reactor IO block IDs --- .../ponder/reactor/reactor_t1_ponder.nbt | Bin 1545 -> 1491 bytes .../ponder/reactor/reactor_t2_ponder.nbt | Bin 2590 -> 2396 bytes .../ponder/reactor/reactor_t3_ponder.nbt | Bin 4194 -> 3755 bytes .../createnuclear/ponder/reactor/setup.nbt | Bin 1370 -> 1296 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t1_ponder.nbt b/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t1_ponder.nbt index 213467878a053e685207c4ffb7e08d8e6d729aab..912ad19d14dc6eaece23e2c6b9cb07c83c201352 100644 GIT binary patch literal 1491 zcmZ{d4LH*Y9LN6~J1_MNVG2vSl8{l$W=|8Tlt)=6OfoiOJo9>EM`$PIL4~U`TC~-T zteo1^&TC5N9xunRVczd>R-LzH-bPOD?s=~6x##&l-Gs5!=%^4%oNW||4%A&3h#EL)5HR z0LH*M11!e@aBYq&h;GS*Ld4un2orN5bSen$@0{^z1!KIOGqmM65ZsF63ZXw_LJh@S zFow>A!a1%Qaxv($isiWK$i-@yc_#Fe+GrpS)|T5r=mlVm2MAumgyNku_H#aBLE_Zp z-TB97nqLl5g04fFP$R21xR9pa^RV$SCIYmyjah*Y*u$>%oTGs1Z5mjR2{t z$-Ted@P?>(XT^YMjha~H*Oa+~$hv%0P&X^uu5ws^l62C{r0!<$Fl`}j<;&^GnR~}q zLwBw7p=vees+F@HimP1zhl#0XEjW>HShSIOn~w?UB;#mK+hoOn8C!aF#7LMhDyM2o z4?Z_EJr(={Jtp+G;rio`Ju69%u+WlvZ1}Om`rJF2xL=NcU>wrBU#PhOS7IzAZZPgj z8ZO1~whS(fzt53|r&9>sIITYEhMrACAi>Y5ovLprWf1o@(2D7pbg|cRD~@bC@rk=GF!d9GFmFpILce7 z^|};ThOLkkGd|Pn|B%gtMM?3d-UoWd>;5h5j8d|(|2NJz;X5v2m9@PeBOa@iC?)t_ z{N}xMnG9NYkA?){=bsl==IS3x z#QSFB7-l`R41@q!Lcsgu8=clk}?jl_Qp!KWL#f z$EFuh%?aB_7ReH6=vX{zwy#^+i7U$^1hP9jN)^L*Gf9c-XdH(mq9j{AitRxLr(Q@e zeEKxdDPKA6Gj1**dh2kbV&`qG@7%KTo0-n6TH2c}Gvh`n_%!Ky&azR~=>*GbM*!eY DF!SIS literal 1545 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 BOi%y- literal 2590 zcma)63p~?%8#nj8g*tnMu-MHJ9^Wm-nsH>3#cuexKj}`9Hts`99D0`905n-E~#D_s{ZU zbmvV@qo)2ZFgvH99JLOz*$cbQU0dewl>g%jh_T5w<{c~3ZRToRlFQaS2eHbc=%1)` zboic{FjcCydtWD1pIRBxR-2D$L46AW=6pgQ*HdXh!|7hEsnB!~Nykj}EXM-fj3D|}H) z@f_&J?G>18FS(6F^4eRq>JL=PeK?|uH%@(}{L0>}RBOG){{{kl1~*(-{r3NZS$`K; zqT_evf9<(DAQ;7B5FmmUfJ4)Vaz5b9Me~1Z3 ziS#$yghL$)H+mo@%=%LZThC-=}ZL zjzNIkM5;srphmt#{Y9d9QN~SWtms>}NF?)+~AzOJFN9L!+U9 z6G=wqfsV}oi|YP~gsc6`Q_|(6p>at#3i(_UI^09rH}}W_DBeCqi1yBy$~Uf`ZcWBq zL&n@h0T6#iTW7Ud`=YIFX+D{bKs}+ddIl;3Bwtlsi=(@M7(~toCg=<&R;!JOp7%2bnvISm^u23UFd1e$B*^x$+N3( z3|8&is}9m_T94uHRmAC$FU9j$9U}aNvN%}pP41s90j0dzO*=U2bN7!*0Qu9e!Y8=VaFzVrei!cTyZkY?i$toAFwETsc}W9NNb*a#XGTqF{UF!j9gT8FZp) z$Wu!A2`2n8*5Wa?5=FazF+N8PSL5+aWRKx96}UzNW2SiM$?ou5KM8Fe(p7W_(C5`t z{%Hk)2}0k1=JN5V(a?xNMoNi|8RPIIFR8Isf3zuwQN1bD5z+1QXjrThj6K<%@+74E zdN+>Qiea@n2PLgA4H3}DRRz*%)?z|a6*u*e$7^whxnPzT9|cEy&k2KV?9$Fn@)yhmfd!$;kmbY3Mcdsq65|u1q*-*LC(7fUM4t)Da9z23WAXlwB1dksa zmWR%d&N;)nC+E*Fc295~HtUK5pM)9M9B()_JKlohMObnipU+j83+Ja^G%U@GG_+l0 znF$?7Ji-JMDDt{0=fyHk2HI_QacCoGshQc1?~Ryl8`9-gWa;L`>^5!@ZJ$cDWBEv| zA4oqty6+U0k@3#-Oz zC|bClUMrdGzh=?;c2@-vhMv%b+4vmqDrDa3Pa0$8bw1TK!0_YGbB#f|_-yf2@I=tG z1BnR1B7jeF`H3Fdw1egQhARzT%Y~p|lm@B2$N^S_z3C1^K1#{y*#RuKAbMHRbXjz~ zxdt&^6;~5p&ry2K;xl8W)^r1x30KA27X-X-z>|4&e+0Z{BOMEk4SUhURPbi%m0+m= zR)NRS0*}HTT%Zp>P(c?Dow8irM-*QwUr~|sB2{HjtwI9euHs(xY;R0esX;$?`MHHe zB-)&1!c`|%7Xm7Z1cUjO!s>?knUutQTs=mO*xidntgzJKk{6|gR+Ryh-O*DjL@j@Tjwkf5^~8| z)TREk-YX@^3iv3Z#qRT`s}m-TmMO(g!j|XW_9rCMP_t;OZ8}@Su(Lorh$826;vDBn zMpb@gjW7MX7M63`dZx=9MDgq$nsHxPzf{7W)F8YHxx3QYwUM`FUxu07mXRowlG6g2 z( p@CiG@-iK?5mi7Nisb;v@Ns6j$Owm@TQ)KcJyTt}MY|g75-m=*F4c7D?I;p;=|opk5Ins9|V-ZqX>A^ z69eky&APM)WgjVU8U#Cacs3b0bqujThovVJt;f5BA`ODiF~rtEv^xA?4og!}N(R=! zf*h8ze7m6T+4kv{DAX*D9&tX9o>!56>0;fZ;(}ZUy0H>S~ ztQ?lNP-Hgv9=@Ez`a&o&7?f>O;J^es5Ip-jAUKA24_7QsEAH>ts7@yFPokI0U2&Mj^qY4Sb2=BP>WN zQeE556YFSc!B47b&}Zx$akk~&TEwVpEQnw~UjiCAz^8#8?02f$@xZn^ZeQE^gjx4u zTq}<{PW$|Z&{k-rE0(~zDOh5M-8#H z2R;3nVdVBcogTEh!$I-~t4q+6_39aa+PYW?e%%86I1p%nEe_F&8bTo^0|>J$&C4ZGd`@uMrJt|7HwXZG-RjKHho`o9oJF97x^U#*m3a(H^uQJZQixbFUQ zw5CG=nWaBossWtii*%xW)DZ`I{s)AeUF|gUn=spS(9-;a-Q1g`J6CT4jt(WW{(`jy zt&X|3&RGYRCE0JXOTcRL+q)@ZPrVeYA#}%8X4r!UIfRi}y5ptl0E{mJM|b>L*tTYz z^>hRUhm1BXofXQ`S+Ue2ZeR0A=o>teod*n2!Jr4tDR;jnG#wYB3} z6O-k{*cfcQt)P`8nXjM5KU^4y<^A*X?$Nyi?I&zH{T(je5u9U`+{2ZbW;ZfQZsE!@ z1W)&s=%WeA*4*PX$)}!}J4}wN=whDiV6$QunvieJJxi0Adtx$~9Cy)0hOD4jac&u# zdKS5ft~4uX*4%X^CY{M~6Lsdv!kQH@G$G5H>q(QCda7_MLl%i9_|g0+@0Ge}f(uP@ zn`x6LTVHz9BpFN_hRhR9SYKLrVkk_Ghp3YwlQ%2yXhNkm*N-N#@Ei+jBHri4mYHWa z=9N_7%5DpoM193n_QDYVoBYXWR3Xb|$nt)^w)EQ@*mvLRj#leP_|{M|oA~5!1@}Ww_Zsdn5+gPH9^HGhr0L zuI6?e#QWx3Lw^Gd;hc)zDx5bqT&bL`w4iAyT0eKix(nKXB4x+uJY*wY>S z1JW|SoVY#PXe3!4{V-VpDVyojbo}}j;H?q^zz(K=vKA&rJc13KXvm5E&nbec! zCrmT{p8oibTmPfHh#+U%!?{NHPQSskRSkEv`ybt0=4_*TisPT8^R@&zHyz5AQia%) zL$;=qM(Ko9H+X#>5a`u(h%Kdxv9u2*#L`x@yp&2`GvDWJ5s2Dfihb0Y%%K;Yqx2D?_?+kEO0(`lX=}GdS)a{tOKm%f-UYmDAMXuURu@S- z<>mf7&L1V)!*Di1N*ujAg<|5+Zh18Jr>x1?it-A(*S?|v0!as10PCx)TzC;5MdA{# zqp@@{9o{wJ7cuH61a}seO*Hg=osR6Nao?rUDDLcU z=ap%(jz_EHH^R=@bYf;v$(=RPHe>n9-fYXK+wHmB2l6@jVjf5CHl{dk+!6m|G3E&d zA>{`lC@|uk{~XB`!&bx=!#2{-XF~nVA6jJkP}~bV7*82q!_Mr;T=CDR-{SblyIZU5 z8g4}lIon3cwqh;f0t5`pCl$f~-$5%2+-{0piU+ig0qOHf3TM}pivxUztSlm_x9v{4 zLQV4^dR|G|?3$b60Ovugy*TRM*5KTlo5E%Mw)-YT&pAn3g;m`{R(s##x0~dN1H6W; z%p$27b|>ATrVL2BbCO$bO`h-_)`6PdTE^^}H{CeuPP>yTtm^hka$Ci3Heq@|-`7?s zb49C5e}=3!FBc)^kyN%~*2R@5K|IXn|MTb=R#~m$;2>Y&OLMIn{VcuIR|!mzJmOb z6&|tn)vQ~t=|>MH64&d@@_W+0dj622-&n&**9x_|i_wQ8mYZHza}<5YsGk28^`yLU z%Tvd@FAQ?|CpXQWV|FaByEM!$$9;c%qg~sfQLNOqI3ufXL^AqzT#ZgDvg<37mbefi z`$n?wzT!5Bx~o^)+ew8*jxWV3@6v{Ie^{;}%@R|}|1;nJboe8U%EM-XD^w^iDwk>^ zn=9ESf!EK`Pro^)#A>M=uJ3w;fQ^`_!tGTkCzM!Km9}PqXV2*%0yUJ-es3PAPzJg% zh(PC+$aX~o{h%{>A<9<-wyv8~W*?ncrp}~SIBcI=JERMbMTgHcjSRS-Q~GQ3$DaM+ z@v+Fi0Q&e(5JO`g&T&ZLv%&xH@zA{G@l^4j5QcmjDy%HE|2DM`=+<9Sjt5#_!XwC) zwqEtqivE$*$Hm^F^ab_k&Hj>76QxsOJRO5a{+VRF9?SjQ2Dd0AGx_x!FEx zUqO0aEl2=-yHwmqx|J#dzht!E2t_k=y+y;*{pkKChyIL}kmFWY2TDFa92?YU4zpwh zb%oTz57i37i5L9tZ(z;7An>rJM2MR=qnTibzTt%e*y(6jhxQ-L0?ZPQQv;Gz<&i$r z4q)OS%rb}}@tTS`6dV*Vv}S=}0n*J-{yBFM)0Sff+&U)KS%{xD+xxX9X^uWnxmrk0 z09@)PL1f*2EkKYz3_icxqB>%D0UM<8qyV6T_nXk41s)jIKGB@CuRyTa(5qMn$~^gc zUfR_cr?x|BhqjRu&QY}?GBZHU5hIJB=)w4rea&Y98m4Vzvfv2ek!dDys!KtPNW6{yp_<=s}MAM#7rr+KJ#ukm$B0-axVk$dqqE z#DITDO3Tm~k{9z7$m_NqlJ{oL_(yzF%rhBmu895Q;1 zY1+oD&!?nXd0aFCc$hIzLQKckfKq<`>K7SWLd8YQy&U_&3{#W7Ss+w4Xo#CoLmbNI zQ+KiC;1(7xr*<|Bh&A$Nln~NoAmlm~u+lU2v>_86BWoQk8ss&f1*r{s)>b?LBv=`z zG^tU2A8Gv>1FYcP^fi+WD81aXdllHwm&lFswe{{*g};SBO*5ILWvFCf4#CanmSB93 zykWWj;hU z$@|xm0-BH=i(DuzK0t+f z-|#@uI=2()UYM$)s4O)vjnT8#ROkC1tqYB=5-Vx@w?5z2H#hOeQdf3HaqQ>q#y_?F z*=Yvis`THHW^B&z@V@hTyY+#;<^~}a{f!-$`AI^b(0D64&O__f8z(oqv!x-aAqIUR zMm+SKdgIJSiLGuht$Y=hJIGjkk9o<+;89wX-c`TS*T3LNWcu*I+l3QoeP#N}2=&wwAnPcZs$m7zP5=h$n1(}>RhXBILFA_exJ1g2$jzE zx+Cmt8cs=gvdI?;ax!5LqG6r6%!(yj?^UApV;lj3D|yUpiGQWlTcSk^p^8C5Dz;^_ z0=FmnMCx{`BYh+D+!5aP8+8!w;*Fi|$T-X5>Yhea)38hm=MsZuO~Nc`fJE#QJXJwj zVJEGgq_f*yitXMNiA5@H?A%{9ZRM^N^q~sps zuJ$#PB$+g8Qb4F9nIprxVB^IWT{kgRqEwVkz@78V)WU)^XE)->%-FRz=TxLSk?}Ov z$dpSJ4Xk!38}a<^ENt1Ftm_<@>qI^aRY>1r2UM?E>NklV)`0v1T|ho{L7Mo+XvG8z zcnM)W6EajRHGkTa8SVM1>wvyR$t7d_k6W>9>FTKZ@;xRE>ymKSZ4CCXQ0!sSfiynxui_=Ez3xm(`Tmj%N=>9xUwiBEzP9PPf~YKXmeCBue{^$lM5oPFVZx zcWpcomTP~l{6hA_0bSPfZx3!#i1Qp@X}iOzbW*~$4+}=H>XsrzQNHcsa{izZZ#uAo zUUTYAw0JyQ0&5Q)$CWcmv#Q$Z24z{>QKG|!hzXG*4~`3xFkW1Taz!BZy6of3QJaKsm*y!;@40wqDIW-u zE}HTzc!6q{9OS|3Y)D)&A@R3L{l*$3A#|#$oduh~o%SEvWip^W3G-jhp;rgK3YG48 zoIR?YOu5jO%a>V|-Wo_J#ube1<3_KQ3Gxuhjq^L)JaTb&k7xOEfD(n963 zQX^(Jvsl6sv;fCp)dT3cj@$?9_Zc>9Ov1(36hu=)m!^WXix? z76;}_{RltY8g%#27EAY^ogDFIRzdU%`8@DwYyzdw;!q?bYa=*Y4@cGDO-N5F(6I5DV9v-brA z8lih1#WXDQDv_kdeiw1Zx_GhvLKZY4_LlMd3K|3EscS3VndN-HR}|TjsRsRr2dBCy zY-2Jwd>OF4biU(ft>4&feU2aB)eG()o^&4qocIJ(j19Pcc&h2PzA@ki`ZMH*XvNW= zvl{OKx6_{?KSbm1{hT!sy172&Ah~n~q9YC2L6^s!d_?537cMb6(n+AR%5ChV@0MJ4 zArVz8unft&?m--3IJL^1G~8PNgLPJ%EZ}PEnI7ogL@Mv(5hP(eE%F;lTUqW3-q_ew z;aVANnjm58%+l!Zf1CVuwdy58KbLDQ3~v0Uy7wSi7PV}0o5JlJ7-B{GFNC*wOerf@yN`##K`qW6HQ`$9zNt7(*JZ p^VrE-<=|{|?q!FA%<_AaZ77BmTguf=mv#1$YIO8=oaa({Dr^r7d25??)qza_qf-6?s@OOJ|1`N?OAXv z18hr8U~`fY%nNLwyx=%%fZ&uF?eAZGUj$$miBF-%qVCj+>3t6+f}U8&xpTU&_mOu; zZx!>q`4n>PrN})>;WE_8?Nn)9!ve0k*o!gp>P2S7a&Fr(bijjE8fqn0v)54H8EG!` zZ;rbV3c2;qCnnr!w9gW0CF}r+r{E00cJ4+7?g#s|i@GjI zzrTA22@BLg{J`UOfx#em2z#$2{P{RfaAI5XILHy(QoI?n2ngXr-4M5Hf)gN&^9Hj8 z5Q2t$0JlwoRv_6GaD=qP1DN;GAz87(Tm*!hl0Tm9Lq1?Pf}qtt*%jpI*%EJu5dp&O zLzMvLOTZB(Xa)c8xfqtcfU@S8{yuC$?4Ysfr!ji;(f%ZnUPOw+I+W=IP1asbSI6y~ zCK%BJWcGAf>bZmb>L}sn(t%1i#4=O#2fG{xQiQ3i;L!CiiPNu1ISEvUsZ*fAPcaDR z_Y~RSC6WZkMG}H7%)s<5ifoWBbKMeBf}_r+k4T%JWiA*xR@KaK+l}7R$N={7HNa+zDr`}`4-n1XT zNfj5wGQ&JPDhkUB=mkbyl4(liS3WS0(;h124lnkP6361ts`1k4n&VffqlL!h_MCRU zdz$mRG?fnrj+mBmN1pC9`TA3}#jzP;_CJNChSGUF@p`z#QW7{Fdec|{u0cZ?EQdam zbOQ^#eOw3GdyjP9DDQl6euzFqMwgMR$;udIUzsl>YA4D&OPo*8hdidsNYyVCF-dJ3 z=l`w=jHq?yCS;Dd@q=ru)6!9%)U<1dlCp<9n{}t}I&JTg$@LNJrui0`LR7&*ILDQU z0|w}0OB+JX|ZEJo6;u?YwzR zcu+pvnV`)*pE44qt<&RbS|8r94qL1AXUI)y8MAFCr>$JxobN>jRp(vvI`7X4`kva zXy6hY|E;=qCgCL~>1ti*E|-++JY|Pr(un;5tATV^1{imoaRMyqmDBViSwp>;sR5Dl{6~g)6Rc z+DNyin+6@8;cl>+Wu8vsakURSSmeAOJY<iC;YqhFiO(EvpBE;W$a7(%;{LAs zfKPtcM5$voO&4o4B+j;DrA)w<&*EoY{4>A+3pK%=fD6_UQjkZ;4{6h{=bpKF;?5M; zowqr8G$qs@YbJBHiSno(apwG3;Ph_hk<#Wu<(;=%e%%0~6?P_#iL5}G04JL{6ROKP zGuPSaEwsy10|whd7CFBTOW}1h_h=~UdtI0-bdKB0LjT#Lg)J2pir;-+t@!cb)xw#- z3Y=;!9`1S2@;OOQ&a0!{z4*Rlw0%qO$y0kPqqpq4A2+}2)bqEy|2YfJ`W8H~JoRto zl1ZyItmDq4EzIFNR1$wIWt<@vUlVUiDysmW3;;QAz!my8Lr9 zb-!~1?`JF=(R&eozHZIgM2w~m1_|VzsANQUsGP}bgbAPq&Y|nzy-S=iY+$`8U zXWh&5!a2UL)pz85zN6E}bNy~XmrzJxlh&yVKCQghD+^~CZOPlTtLgPrv0K`@Tf(C< z)*re0w(6Vn&4Rr_*T0nRH9A)ux&Fw{<^{;wv?1Cqb-kYYG3r&3SKkt! ze56uuwr0UUg%yifLZ>X~GBOEHJp9#b&N800vu!Moe?9eM<~NX^d*+|if9<|wSL|~K z4e52^uV(FA7k;c#@AXuRdI3-ndj+^k&RPi!6IH+9wrjaB6tXkc$2eC%m3n5Lc)0YQ z>6XurLN)}5>V&XzhaPkaEeH^m31MXqJ?IExa;#!<3{_ac#S+@M02Ieg|T_oa;V3J3d|Y_`1A(byolVuAjI!Kki#ytyZ&qnBH%Xs#9}s z{=I4DexJ|&)7yu~_wXM3RaI|WmK6AVqih*hhSvJeUT=RW)M$MFeQJ5H@hO9lrS;7$ zzjPc-cbi(_jh9ZpT+sRH?8cg{Jj1rf8U?Q_jK(T7yvKFsB8cL From 20c1df0be230ded3469c7f79130a2b56058dc1b0 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 14:30:07 +0200 Subject: [PATCH 101/171] Remove redundant modifyBlock loop, IO blocks are now natively Casings in NBT --- .../ponder/scenes/CNPonderReactorScenes.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 4ec88b55..0be3884e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -123,28 +123,6 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u int minY = 1; int maxY = H; - // Remplacer toutes les faces (sauf les arêtes et le contrôleur) par du Casing - // Cela permet de boucher tous les trous causés par les anciens blocs I/O renommés dans le NBT. - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { - boolean onXFace = (x == minX || x == maxX); - boolean onYFace = (y == minY || y == maxY); - boolean onZFace = (z == minZ || z == maxZ); - - int faceCount = (onXFace ? 1 : 0) + (onYFace ? 1 : 0) + (onZFace ? 1 : 0); - - // faceCount == 1 signifie qu'on est sur une face plane (pas une arête) - if (faceCount == 1) { - BlockPos currentPos = new BlockPos(x, y, z); - if (!currentPos.equals(pos.controller)) { - scene.world().modifyBlock(currentPos, s -> CNBlocks.REACTOR_CASING.get().defaultBlockState(), false); - } - } - } - } - } - scene.idle(20); for (int y = 1; y <= H; y++) { From a34caef8a0ec46641a93aaf4a2aed6cdc7e73f23 Mon Sep 17 00:00:00 2001 From: valentinlamine Date: Thu, 25 Jun 2026 14:34:01 +0200 Subject: [PATCH 102/171] fix: streamline block model generation to handle translucency directly in PaletteBlockPattern --- run/schematics/reactor.nbt | Bin 1376 -> 1305 bytes run/schematics/reactor9x9.nbt | Bin 3359 -> 3029 bytes run/schematics/reactor_t1_ponder.nbt | Bin 1545 -> 1442 bytes run/schematics/reactor_t2_ponder.nbt | Bin 2590 -> 2346 bytes run/schematics/reactor_t3_ponder.nbt | Bin 4194 -> 3700 bytes run/schematics/reactorhdsbquifu.nbt | Bin 1051 -> 1038 bytes run/schematics/setup.nbt | Bin 1370 -> 1296 bytes run/schematics/testalarm.nbt | Bin 1307 -> 1287 bytes .../ponder/reactor/reactor_t1_ponder.nbt | Bin 1491 -> 1442 bytes .../ponder/reactor/reactor_t2_ponder.nbt | Bin 2396 -> 2346 bytes .../ponder/reactor/reactor_t3_ponder.nbt | Bin 3755 -> 3700 bytes .../createnuclear/ponder/reactor/setup.nbt | Bin 1296 -> 1265 bytes 12 files changed, 0 insertions(+), 0 deletions(-) diff --git a/run/schematics/reactor.nbt b/run/schematics/reactor.nbt index a1da9d7740359a99639da60750137ffa1ee88549..9012281306d8df0eac3279015cb6a0ba32240188 100644 GIT binary patch literal 1305 zcmZwEeNfVO90%|p66L6=l_sWvv)xkId`J^K@uBAF&WA*SVdX>W$hIBuB>;{!bjp|CSTW{T|9ZKF}S_fojE=Bv_!g6c0YhfzF|o}MD|J& z7!s%PXCCkK9~oC1TYq9Y;b0;b|z`H1sw zzkrnwE`vt-#sH1ipX$jzACkK%(9PYQa z+3o<(YLh@rdIK(7xm`du2CzYPqynTJ01q)qLD)EK5}!{F0ydw7x0Opcx63*kgRt4( zk-CLc3h;JLZj^ff9;zc1k(~g1^jv#Os+QwsW7g8<5ALk<_0ju1?@ItN!YgqngVBB6 z+$Qr-+vBv(o>7#9510g3S6+mb_TP8+#-aXA?-;e@933|7=B^YIj2j=av3R9CWLkO0 z6ZK5YeT8;$d`BHowBk;|wO)QAXmY0DkcRY*oYW1W7j{SnDt=4}fEL*L{HB}1S;TsXevZh}Zf5>n(SroTADH`2crcBMHK!xt%ZI~ZLAAE|-u zB=}+{2lec{r?_9=rnz8JtTzX?Et<22B9_5B#O67LHfy3>XVKSZon6hSK4&KTthHn< z7RtgQr3alTHr!IzML-e!IJ!5C4yXSm!DHyCkk=kF)7s*jF_1QQ-v~AEPjERpcAjm# zSr8~_$Q%lj8qe(Us&X0_CpQstVSXNL#lE0)7?pR5tcH#_|JfCa&#r%(@-RyWJTDve=xL*C*EUXOCBC654x^ z$R{GCMg(5=16v+WFE5$&kF?561!N)j-R_2u&MDdkWW8__$s*PcpSRxr#@wjdV}I_{ zW2m9p;n?a4!N6w)zu}`ryr@7ZDWKt!D5HDMv8>njSA6x)O&r1cHYN+Ler_*Oc~J7G zHOsd`=VOXSg=L@OU}g7@)~YucbHyBSyeb|_hG;Sx%)o01<%aTbQ)C@S9H)9JNzSCn z{9wjj4dL30&Fgp5kG}h#iuhH$i1@+6wJS6nU!9lk){|f~*G|yA{8A$XFC6e>PBeEtpbo}TXYTeZQbv4o zPk){FhrjTr&P&ey-u7VON~}>dtWU$VdJT8!Mh}@+DI_he;lyhGH`>MT+o|fYZZ3qF zyVY+S>r{Xl81xqor1&HX-`shrT*_^Zadu?47D^vzdUZj3;=LO!`4yv5CUYj)GQWmM MDjK;*3I>4x038&EFaQ7m literal 1376 zcmb2|=3oGW|7)Xt`)`{GEOkBiBUx}kyIj|{cBY@qmd|I!6mfFt%*tM{b!X(lO(`BF z&Cle&#D{;X+QX;V`{IReLWQoa?YT46QeIQ`8m8sOMAv-2CUJTHwY%Au_pd*DDtsYF zYksfg+XwBN?)|%4RxN&4y?RBo<%>`0yjvCd|J583NGoiWe0)-Gi`?u3kA*5U8ry{{rg7S6x2j98NIat~akjnbVvPnis^a77 zL-^!huw_Yn=5YJGFu_Eg3mbI_YJewoj|EQe zZdxu|`D;hZuN|GBU=ymaP<-aIL+#U|mOUDdb!PCg*$=2vgH8d-gr|@$R=*3!{JSsk~i#qixsEJ!fw( z`ehVw(shdL`LxXeX6&iT8q&@;bV69ULk~KIZU_(sGTB29I))Ymh|XEWB)QAJV!yHa z8GrfR^|vp#?dRLgcQf|Xy}S9dcj?$aefqH^aCu+6{NaZZZpZdt%l&!yra*{!(<`@t zyB-(c9=~aj&hH$Wu!4&xv~i)9K?v*4#fQ#5|G4*DjoBR@nft5H&h{)Q-F;`a!_9)t zbJo3Fubfl**nP*k&oO8Fc&^_q=n@JEY|=V)!Kan?dS&4(qb+%xb~U}8Dt1d-cT0Fw z#`+^y-xhsyzFDw0==zs!agxt1*M~p);~3z|xk|%PG&N({p|;mkEqo=T%p)_8emzy8 zTWTl0F5C*F&-VsU)A=vk6SpmTmG{y-?eD^0$HVWo)vqo5esufgRUd9$Xn*ki{QdP( zRef^d$+oN6U+L{yYkhp`-0O3X%baX;lKu24WohjZ07Ttn?E!XHM?`C<@H9MwX51;k@SiI(E&W@d$b$sUQ|37|J zW+}fQXUFS`*vq%mx-8CD8nd30X9=CM02EklX<9iu;yN!+Sy(z*{rQeKN&Cz5&I1GC zqw&wmzZ~J)Ps?zm9{%bD)LNA~=lPzv&d=k}9)kPNNtp4@-`Q`T|y>I?LO?`iTxzdlir<=N$EWR`2?0nza55E7E@AK82 zn4Pd@ecAM6cd@PVv+I^O#P!EMzLq-uhNO*!*!%9g>%L?j<~90q^yR(0uJG%MQf=~| zbNA1@^-E%2*s*tA$8_%bOq{#_l)A=SvxJ-jtMU$A4oO>noIBWX{pW38f45(H-@|?O m<5Ho?-nZw9zrXif@&A+A+g4~N$Nf$J$6o(^S-puJ0|NjXEU$+E diff --git a/run/schematics/reactor9x9.nbt b/run/schematics/reactor9x9.nbt index 84b17de9e6d07df29ed6c53c8b9fa1b205b00626..5951f274f7b3339990d0fb5f613e805b874007ee 100644 GIT binary patch literal 3029 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 diff --git a/run/schematics/reactor_t1_ponder.nbt b/run/schematics/reactor_t1_ponder.nbt index 213467878a053e685207c4ffb7e08d8e6d729aab..44cd6ae659d2f5edfc57ae2b227f583f5d361240 100644 GIT binary patch literal 1442 zcmZ{a3sBMr9LN8FugI_rT^3=cIc50F_jIPFt&Aem%g2y>Pa{ecL!3yiqy(2~3d>jM zse!Ld(@HJOptF3`)SQvZm5DEu@||GQcH6D)cK5yC_w)Pwe)>!e4I6!z81N@jL`Yct z84^C;3V-$tF+74~P7I9)T7twxvDao?Y(j#m6ROBQ;IE!dx96r)pTtzDx`(DpH#7*ff-5EMjGxes;`w1J`4|NY+_8OJpOqHb6dmFxdGM!Ax#lZ*9R&51y{f{gyac? z_Q8cY(@BmRv04>#ZSr2HL2|PB+pM$?b9SIlg>`P}rJ$#dxdVh;({-{_uF}dV z;!~K&9Ac+?>xH3R0=wtxFX+rG$?oWLM!Dcx__ikSvID>*uvZE*WV||nvVqP9Y_CC@ zr|1~~Ez^I65`DBlRp1RYs|Y6Hx&wAI$0-4T#YRcQ`R#%0O-AK{Y4B}qa4iBWB}gY# zbfG7?z(3=>$f=YJm6QU(pU1SoD`{d1XhzW4keD%;{14C$kYZQuk>~=5oCE~J1e4xq zV=sOlC$BR9_o6b)kNp*W@yPU1&yQi-Cr7D)^%3O$U#G@yWK9#!xX(xOhOSL?9&6s9 zqslGb8U=)uqfyuPdA>40}A?EdTL3rX@JnHi-f1Nz zro9y$ltbntTC6DQj=xt<84HEc^E+(K=V4ecqrn_=-N zR4wObgsPo{@HHPb6+i#BegQC-RNRc3v~8C>w^>op%3nNFA%{bhnP3` zQGyynj`v8#FO&_zf~g<07duxu{TipcAQ>Vj-MBc5VRld(d$xFBw5fes%AGh-%aiiX zl8QPKddFLz$#VLI^=}Irq66k>q4iVgweORb_hl6m5)5U6bRlkrVFwE!#pV*lpR5ga zab&f8S^2^gI=a61pup!_kavL!nyihTFuKuua33$5zNSj2Un9F^(V^A77mIwpp&i04 znck7+yqY~EODtVzF8MNsU#|aN%NLs0Q@BXwr&9jTL}JbQ{=d~_T}U08`1j^(Brd@)V~DJDodN8J!ab3++lb%Lg1Lp6Rd9yWUV)vHyPe OD1O+*B1ZW=0Q?1jZqP;m literal 1545 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 E0T7%}Z~y=R literal 2590 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 R*)2001fE~%P7732{sVvDPLu!u literal 4194 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 K+>?8a7#IMPeE7@& literal 1051 zcmb2|=3oGW|7&L-%)9I$&~|*@#%OlYLN-1drsr`FFL}3y92DL8aoeVXHyL{wFLI~P zYYTrYxM8x7RLt$j(*GV|Lgk;{|M|Q&UDi5QAXO#zXTpq*U%D^1ZT@GuxHx$CrK!u7 z{+k$B6>WMt|Lvmc&+5u?=4UcPFMuohyadKwQ znIjwA?cPl6uc%mF>v!DnW5@R!i|sbL*FJKrtx$4HOS+*f|Lugk&EC!J<=;M>le>5G z@b8s1K*6B@>V4cFKj_KbJ9>C`MTPxT{^}>na`%3_KQc5I>i?x8_tlf_t7P9&LnGnC zazBA~7`>`>jJdz7xa)M&J-xLrzg?f5np#wSb8qCXV|B65awG5ehfHF7rxKwn73lrq z>E4ySZ@-C|XD4^b9(nS?YEk(0yQj-`KmNSy1=Hf2BC~p<^Y6HD9e?WC#A~?4hAFUn z!HbYwp1Yr~CasWaYg(14aU_6iRolV^SrRa+eK9vspul2cGf-B>&rBhUX(^I4P;SFo z$sUl_6;gS&vURcC(c%TA!KQb(I*M1t7cZZ=Z(cz5nwb}@zRhGyZ+o3*v4}_YRKOyp z(p6bI&UGhiUDzdPyZ43Qy0+I-4|l6P%-Rvxxq9}hhgGWQR>pmD`g&^N`3-TMv*p2> zcvQ6lmahV;v{=TpR{EuJNbZ_EP1SXUm0w@K*UNK!xhYdCx%_a+8c$@{(5tJEp(BW0{<-wo_An+w>boUhC#WzRioc;P>F}mBd)<+aa+=++L^t zId6Vk+7?sipDb=rSx_^F^}5jZAcK;n2hPsQSds^H-qfTlH~aLZ62Ew&H48pBFLaUg znzGP^^;O8#WzUb#F5J2)F8@x`rq#c8uiPzbFK-?Gr~dgYiH|$BJwN#K@ijFW%|*-2 zHy*lL@ciT9*>OPQ-t~ZdyUY08%6o@gN}mIL`>qGox7Pi~4Mj8V{yP4lt!#(Xx^TYy zhW6FK@L87!4vFQzirGTe%lzVbJ$1*=g8@jP8`lX6-HT=0l&Vv?-cHrb*|$<^-RET& z&UG(dkhLRz*8>fg04~8PPCQEmoHc>*ZU|x?2;f2xOiL94xWI&wm*VU7C&Q0fUjE3prp^D-AsJPJl}sx-5*^yV;l1U*G$c-davyN!I8bQtZV1X>z}@TZB3qb@C1w9 wl_rIs%1$oXaPszK)%$TwZ__Sx_wPKtU*h&OU*D3Cv;Q&b^zD-9G-6-?08*X~4FCWD diff --git a/run/schematics/setup.nbt b/run/schematics/setup.nbt index 227cf19b50d159e0e22c21860a07f781fb510c96..e753f36bf8aac6b6c0537a75a3d786e427d6bc43 100644 GIT binary patch literal 1296 zcmZwDe^AnQ9LMo5AmyaYE;n5%R$eP}k(3Nl0kefW%LM$DO+w?ua({Dr^r7d25??)qza_qf-6?s@OOJ|1`N?OAXv z18hr8U~`fY%nNLwyx=%%fZ&uF?eAZGUj$$miBF-%qVCj+>3t6+f}U8&xpTU&_mOu; zZx!>q`4n>PrN})>;WE_8?Nn)9!ve0k*o!gp>P2S7a&Fr(bijjE8fqn0v)54H8EG!` zZ;rbV3c2;qCnnr!w9gW0CF}r+r{E00cJ4+7?g#s|i@GjI zzrTA22@BLg{J`UOfx#em2z#$2{P{RfaAI5XILHy(QoI?n2ngXr-4M5Hf)gN&^9Hj8 z5Q2t$0JlwoRv_6GaD=qP1DN;GAz87(Tm*!hl0Tm9Lq1?Pf}qtt*%jpI*%EJu5dp&O zLzMvLOTZB(Xa)c8xfqtcfU@S8{yuC$?4Ysfr!ji;(f%ZnUPOw+I+W=IP1asbSI6y~ zCK%BJWcGAf>bZmb>L}sn(t%1i#4=O#2fG{xQiQ3i;L!CiiPNu1ISEvUsZ*fAPcaDR z_Y~RSC6WZkMG}H7%)s<5ifoWBbKMeBf}_r+k4T%JWiA*xR@KaK+l}7R$N={7HNa+zDr`}`4-n1XT zNfj5wGQ&JPDhkUB=mkbyl4(liS3WS0(;h124lnkP6361ts`1k4n&VffqlL!h_MCRU zdz$mRG?fnrj+mBmN1pC9`TA3}#jzP;_CJNChSGUF@p`z#QW7{Fdec|{u0cZ?EQdam zbOQ^#eOw3GdyjP9DDQl6euzFqMwgMR$;udIUzsl>YA4D&OPo*8hdidsNYyVCF-dJ3 z=l`w=jHq?yCS;Dd@q=ru)6!9%)U<1dlCp<9n{}t}I&JTg$@LNJrui0`LR7&*ILDQU z0|w}0OB+JX|ZEJo6;u?YwzR zcu+pvnV`)*pE44qt<&RbS|8r94qL1AXUI)y8MAFCr>$JxobN>jRp(vvI`7X4`kva zXy6hY|E;=qCgCL~>1ti*E|-++JY|Pr(un;5tATV^1{imoaRMyqmDBViSwp>;sR5Dl{6~g)6Rc z+DNyin+6@8;cl>+Wu8vsakURSSmeAOJY<iC;YqhFiO(EvpBE;W$a7(%;{LAs zfKPtcM5$voO&4o4B+j;DrA)w<&*EoY{4>A+3pK%=fD6_UQjkZ;4{6h{=bpKF;?5M; zowqr8G$qs@YbJBHiSno(apwG3;Ph_hk<#Wu<(;=%e%%0~6?P_#iL5}G04JL{6ROKP zGuPSaEwsy10|whd7CFBTOW}1h_h=~UdtI0-bdKB0LjT#Lg)J2pir;-+t@!cb)xw#- z3Y=;!9`1S2@;OOQ&a0!{z4*Rlw0%qO$y0kPqqpq4A2+}2)bqEy|2YfJ`W8H~JoRto zl1ZyItmDq4EzIFNR1$wIWt<@vUlVUiDysmW3;;QAz!my8Lr9 zb-!~1?`JF=(R&eozHZIgM2w~m1_|VzsANQUsGP}bgbAPq&Y|nzy-S=iY+$`8U zXWh&5!a2UL)pz85zN6E}bNy~XmrzJxlh&yVKCQghD+^~CZOPlTtLgPrv0K`@Tf(C< z)*re0w(6Vn&4Rr_*T0nRH9A)ux&Fw{<^{;wv?1Cqb-kYYG3r&3SKkt! ze56uuwr0UUg%yifLZ>X~GBOEHJp9#b&N800vu!Moe?9eM<~NX^d*+|if9<|wSL|~K z4e52^uV(FA7k;c#@AXuRdI3-ndj+^k&RPi!6IH+9wrjaB6tXkc$2eC%m3n5Lc)0YQ z>6XurLN)}5>V&XzhaPkaEeH^m31MXqJ?IExa;#!<3{_ac#S+@M02Ieg|T_oa;V3J3d|Y_`1A(byolVuAjI!Kki#ytyZ&qnBH%Xs#9}s z{=I4DexJ|&)7yu~_wXM3RaI|WmK6AVqih*hhSvJeUT=RW)M$MFeQJ5H@hO9lrS;7$ zzjPc-cbi(_jh9ZpT+sRH?8cg{Jj1rf8U?Q_jK(T7yvKFsB8cL diff --git a/run/schematics/testalarm.nbt b/run/schematics/testalarm.nbt index 0d8dc14b9ca3460f775c57ac40b469ccfe489399..292fa369eecdffb0e6b0da326b071114c4847bef 100644 GIT binary patch literal 1287 zcmb2|=HSSev&~}qUy@o}l9-cNl&hDQRKl<}%D4Zqi@@4{K64VqEIui2JkY8f^L@)| zSLL&*ksF&{pAi0@vZnOSg?Ag?#8`aJ{=qCG*!{!bV2iN&)vmbf zt4pr?bO>E4t$QpYXga;~`ihT=Hy=d0HHR>N9UT?XwXq9>Mtp1Ma zAt|pWuwCzaajN6&)ro@4Mw1j5e>-s^tnJ$mWyyah{wH|9-?&s_n@IAzu7~|;365*; z$4cH5PCt3T+vvlj9*I-3d!97(B)oWd()BQESIdvWQ&{C zI6dt_YFSE%{~TUs{lf=N8zg0veF$PUYFgNy{953;BwJit}$ ztKwB`O}yUnR`0)ye;Dvi-9KYlY23N02}|dCyjr}KbA=h_)nyBAnYheuSfsE(gF}Oh zsjCUdT&Urp!6nqy)B<8^XmD|LH8m|-umHrA>S}6Rv|yn|28hY@_07Tl>uL*biG)b6 zo5z)5d-whAcII1J@7esUc4c3enfjUO)KsQZ3Q#obGt;ckLP+TM<8P7sw<-NkoS80O zxig}T^W}tT`p2it5&igdbIH3GcPry|t@K}iXmNPqj_{QEXI7_5cG&%IV%ziL+)25E zqC%&zAg)uQa0E0yaR0VxDw95cat}WyzFzdD_|LPi&gdu>%iY33=tm1mE{Mq#0_g_YzUp}(p ze|IQ+ro!hfiuR7Oa!b}PT6a;2ccR?s-4i-~D|RYfymRxC==Yx5g8MfvEl=Gy=l$kV zC-vNldEsBX5+85*m&bGL_xq2(R`*`eSje7hu`jYsqCfPpZ-!9!R&V?Lof~WSOK%i? z|Go8Xf9?&PnE|a^D*oI)EcWtp*x|`aUq4q_SM5C%w)p>@zBvD14+UZJ=>OBaTEIj^457N*I2_h{Awy)ftcnXmo__g-$xW1mvG+|p7@ z(8T1aDGc$NJVikUU~Y+V)`HoA%x5d%i2H0M2<56qYcxkdP=@wRr|6Snx4gDp2;0=U zZIbSmsW}VRrhwFdq*nJJiLG5O7Ui$IWnL6m=JRb0m9v)751k6m8eaCibIa!Y)k8m@ z)t@=OM0_Rxl9-u+H4$6&*}nOO@B8`KE#t)cs}~i%N^SgXbDHb;=F6)W&J5k-C=<(G zpuF{c`rAJ3Z>y?jY`gm5WrOk2ZJ|d(zIg6eir;vpN7M85t+V>v(23*0+RQ_nR4kdyDL>QrBHtWVeIsnsuqGdi-+5zxRGxt@m1VIsQew1J|yT IwuTH004lC}cK`qY literal 1307 zcmV+$1?2i4iwFP!00000|E-$OZ{#!-$6st`I+@Z1j{G>R;KC8Edt$YyQZLJj6`eW~%KxARZCGg1Wf-Hf$izEP$7*GiKwYJS;>23s+~%#>YYgu<*shj_~EHbv|E*eji}tSTziV!|y7Hnt)QUY8VPu4MV}IVJKKN423plFbY-;H#@uU(eu@C z^C>QGkvF!FN7O1MM^-xeeK(#p=5g)hPzC}Tn^nVA5M19C(7X}-e;sGO8g9(HYcccH zaASTtZ=VgT75R_5JiE-x?M|;q=(K#jq~yFXH=m~)N$+p+Qm$2ct)ILxk1I}#r<-b5 zYNF4-7+Rrq+q9TbE8JDBd9?!9uQ-&QfW~IkaJ2&0=LIxxWUo*)T&>{HTEU^UVmfc1 z46AiTBDpAklBK!vmXmmy-?nRJ3B?y$Zt5=DVUPXzPiE8wK2jGFdhfgalNb9?Tb$9) zcXxOHn(JG0eP^z>o%`e}zj;&y&zj;FQLhftS4Qh( zn`%=Y%lni>4^v`HjJxxlEFL)f=%KTnO3Qq=neuf?r(JqpRCQZnO|$-K9GdGN=KQBQ+QgW zYEvJc-uJNf>Awz7?;HJijCQG2RTRxEW82szGhWhJcjr7^H+?#;tDSzeqBw7Iyw^Ru zpRCec*#tJ7L#H;H?ow<+|6EYrOc@9!|~yBL?1ji zAM5tU_uI@EMw1~_E#Hw4`VC5E)oxt1wQ9Io3Ri8#K;GunZg+QOz8Y?pa(77PtKnuT zT;3vYY{$(&?w--SU#8RT9GQ*NrreH*^_#hxH4tzJtQu~}wJg%J_%0NJ4vue08kL$Yvnz!ayK*#(7I_4LI+A^?e zxC*j>RuCKotA^W3#!-l%6e1`E2BpBD6d05OgHm8n3LHv-Ln&}51rDXap%es^f`C#G zPznM{K@3tznsv59YAu^(rc?83^Fmcysha;WUy|6SN)wl5M&?VqeKGRxbgh~{TBEVJ z+ND7nbh6mwSysp}KZ6QQtIP!w=stngYU*dL6UyScznFGV2-qtMRGL~zo|afrlGe4{ zTop1Sq1Em_4c_HLpEA#KMbVeOymqT*8uj!mlze#oagH&~1 Rl|*O1(tiNkwf;IW006oBhMNEY diff --git a/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t1_ponder.nbt b/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t1_ponder.nbt index 912ad19d14dc6eaece23e2c6b9cb07c83c201352..44cd6ae659d2f5edfc57ae2b227f583f5d361240 100644 GIT binary patch literal 1442 zcmZ{a3sBMr9LN8FugI_rT^3=cIc50F_jIPFt&Aem%g2y>Pa{ecL!3yiqy(2~3d>jM zse!Ld(@HJOptF3`)SQvZm5DEu@||GQcH6D)cK5yC_w)Pwe)>!e4I6!z81N@jL`Yct z84^C;3V-$tF+74~P7I9)T7twxvDao?Y(j#m6ROBQ;IE!dx96r)pTtzDx`(DpH#7*ff-5EMjGxes;`w1J`4|NY+_8OJpOqHb6dmFxdGM!Ax#lZ*9R&51y{f{gyac? z_Q8cY(@BmRv04>#ZSr2HL2|PB+pM$?b9SIlg>`P}rJ$#dxdVh;({-{_uF}dV z;!~K&9Ac+?>xH3R0=wtxFX+rG$?oWLM!Dcx__ikSvID>*uvZE*WV||nvVqP9Y_CC@ zr|1~~Ez^I65`DBlRp1RYs|Y6Hx&wAI$0-4T#YRcQ`R#%0O-AK{Y4B}qa4iBWB}gY# zbfG7?z(3=>$f=YJm6QU(pU1SoD`{d1XhzW4keD%;{14C$kYZQuk>~=5oCE~J1e4xq zV=sOlC$BR9_o6b)kNp*W@yPU1&yQi-Cr7D)^%3O$U#G@yWK9#!xX(xOhOSL?9&6s9 zqslGb8U=)uqfyuPdA>40}A?EdTL3rX@JnHi-f1Nz zro9y$ltbntTC6DQj=xt<84HEc^E+(K=V4ecqrn_=-N zR4wObgsPo{@HHPb6+i#BegQC-RNRc3v~8C>w^>op%3nNFA%{bhnP3` zQGyynj`v8#FO&_zf~g<07duxu{TipcAQ>Vj-MBc5VRld(d$xFBw5fes%AGh-%aiiX zl8QPKddFLz$#VLI^=}Irq66k>q4iVgweORb_hl6m5)5U6bRlkrVFwE!#pV*lpR5ga zab&f8S^2^gI=a61pup!_kavL!nyihTFuKuua33$5zNSj2Un9F^(V^A77mIwpp&i04 znck7+yqY~EODtVzF8MNsU#|aN%NLs0Q@BXwr&9jTL}JbQ{=d~_T}U08`1j^(Brd@)V~DJDodN8J!ab3++lb%Lg1Lp6Rd9yWUV)vHyPe OD1O+*B1ZW=0Q?1jZqP;m literal 1491 zcmZ{d4LH*Y9LN6~J1_MNVG2vSl8{l$W=|8Tlt)=6OfoiOJo9>EM`$PIL4~U`TC~-T zteo1^&TC5N9xunRVczd>R-LzH-bPOD?s=~6x##&l-Gs5!=%^4%oNW||4%A&3h#EL)5HR z0LH*M11!e@aBYq&h;GS*Ld4un2orN5bSen$@0{^z1!KIOGqmM65ZsF63ZXw_LJh@S zFow>A!a1%Qaxv($isiWK$i-@yc_#Fe+GrpS)|T5r=mlVm2MAumgyNku_H#aBLE_Zp z-TB97nqLl5g04fFP$R21xR9pa^RV$SCIYmyjah*Y*u$>%oTGs1Z5mjR2{t z$-Ted@P?>(XT^YMjha~H*Oa+~$hv%0P&X^uu5ws^l62C{r0!<$Fl`}j<;&^GnR~}q zLwBw7p=vees+F@HimP1zhl#0XEjW>HShSIOn~w?UB;#mK+hoOn8C!aF#7LMhDyM2o z4?Z_EJr(={Jtp+G;rio`Ju69%u+WlvZ1}Om`rJF2xL=NcU>wrBU#PhOS7IzAZZPgj z8ZO1~whS(fzt53|r&9>sIITYEhMrACAi>Y5ovLprWf1o@(2D7pbg|cRD~@bC@rk=GF!d9GFmFpILce7 z^|};ThOLkkGd|Pn|B%gtMM?3d-UoWd>;5h5j8d|(|2NJz;X5v2m9@PeBOa@iC?)t_ z{N}xMnG9NYkA?){=bsl==IS3x z#QSFB7-l`R41@q!Lcsgu8=clk}?jl_Qp!KWL#f z$EFuh%?aB_7ReH6=vX{zwy#^+i7U$^1hP9jN)^L*Gf9c-XdH(mq9j{AitRxLr(Q@e zeEKxdDPKA6Gj1**dh2kbV&`qG@7%KTo0-n6TH2c}Gvh`n_%!Ky&azR~=>*GbM*!eY DF!SIS diff --git a/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t2_ponder.nbt b/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t2_ponder.nbt index be135fa5114e527c1651f927b72691d00445dfa3..d3b8229d22864f49357486df1cd3f8b4739081dc 100644 GIT binary patch literal 2346 zcmb7DdpHw%AK%4gE=fmniBQjxl##Z~{mz@3M&*|1LR+4b`$jG^w-65Es1|LgV=gD1 z_Rh4Om?x)5IxfRuR;ZKAE!iw)IkLQZAI|f<@AG_~@8|P;zTeOH_x}xBX$FsM^-``E9}cr@NJTCD9zS#Q4~! zkKoioIJE$-s=OB*A(dHSrv)BGC|3d^K$$0wx7;c%R~W*Opj>3F`F+b@qIUW2VQEVDsXutSx34uKOhxqF*+9_S19h#H$KF=h z*~qhflS@=7RFKG&{8DDJolr8Rx^S#_AUQ#cLIs;!qR_JQrvSwYtVrzSvqHG(!>9Uv zR*3<_FfcJ6h-@Y32N9Z=%DsbwkTRnN4`kZ@@2&5hfqnknQb3qJ0I6)JBGoAcRNpRP z7_ejPx;}&~2g0NPh`I!Q2#YLXvK+?d#y5#|DGjp+B2jiK+dHKsl3>4PbtXVBrGSWJ zg1!M+P9Bp2QZ$q>k?=0+$a-QuY+|RP*eL~uH3N`er8?}ZwR)O5SxyF%0wkU#=&Q5H z5|*5{o>&jd!kU4|a61*PPAQ2b*socur-6yX1bqZqP6?9&RU{rOZ7*6VDb410i( zsF6>7yqi>IVVR!?#^Q9*vb;%FqdY6pygjn?Bkw|>C+%jX?GSG2!zbPdZs0KY#*?H_ z5mq=-KLGWLK^L8yAAK>{+hqzTqAK>mi5?Z^aKAFAcD7R625bw-fY2P%2K5}Kl*@3L zC`%`bb~#(gBP7Fs=2$eS=QgE$50~j_*+S7i&sI7ZlA%s>%o)^knNqI6WuCBXsnQ;0 zD@BB4AZU&ygL>{$`3{?b_d;CQ@7m7BxaGcMV}9HJ{92r|c`0YcrTiBr?rr192{-X` zpTn9Hw7Pmj-hPZ%M~=^-ioO?B@F+uYI`MRwp~qL;N$0(IOkH1PWqZ>`p~+U~@~?wd zeC#!0O%knUB$*U>eP)O4%uGw(-5Jq5KE7nyJieu8sa@5Aly#?|Y85MDRUh;^gbW;_ z)zt6YRhmS<#96@S7>)PzQ~B*-SB>c++0Tu)wkn_t_tokwmZiFSB8;N_zrT4a1okZ) z;F@Kcxu{$hip!pp6$Q)8E=U(94Fi+-%DFC?U;J&n-?LE0?rA&?2Z3T)+*OpdBjrxn z$v;rlXoKEEMLZ2RLC!e!L*-moadwi;fp@MG`Hj9}l;>}!mA2x0hUnvJ!t7J=95`vw zm?J{k`dmxIHsO5)7i>O89v7$%);Z~TROjXNT6EuTvbGV5@0aI=J~`i)|oT^dTAM>=BNjKGBL3sD%^ui@$H4H8M-WGR6{TtQw77y764I_DW&Sv9PTQ zO@4>Ddas{Nen#M+-ih=8rS$gWZCW^MtJ$fMf|!n}=>y}q2Gl~MJL6B)HwULVWAm4H za3d<2g}r7m=+{fU;N@5TBTwA;(f8sQpN;E`Z*zTj%HjMTntA&cdK#UnD!za6sCV_f z{k`3}A>%Hz=n6lEhY^=j9Lj!et1&A)?(*-86@F9?5~^KYP+Pyjlm*yS0QT>n;FSE+(H4v$F8RPHXmiS$FAtaYiZ|*Qf@g>I_ojoHf3*0!XWmdo!20dcQJ%3K^JBWQv&PVMniv zw}ds}8!up(e#@WEE%&GO%rcvjTCqCum$Qh0YAL5 zDSd_T@`Q0N$1g_=ye#B%pF~|%n{fx{k$O4;iH!@coXctxy`9m^?#sa9l%Mx<;sAiZ E0T7%}Z~y=R literal 2396 zcmaix4>;5N9>@2Gncexv{ja@6Y%1d%n6EP$+7vJqfgO zHt;9^sIaqyD04!17&##DtSQ+q3eZ?U2-E6UduaBqlY!iY3{65Ia7iED%N@|2`=NNZ zFb_fOx~CZ&aZ~mBA?kIRCmy9B#!jK--GvPd0K!+@fbS1MQz(9Py{^vC58@a zQQYQYuf_(|aR8>qv<#TA=o<(R&jy;B^A14j+5qYrLVd7T04-z9Oa*vBdEY5Uyi}0a zcM8yJ3orHC#fFy(_WE`?0IV|tsLKnB0A8DD8K7`CfGLdk+0+M^f`s2GBwB{1un1De z0h)db7Z_~nE$q{Qmi!0xJ$A3NEkQTje6xVT@qSs_3szNTz=iFY&e_cP$Bro27z`lZdaulSQNr*g0~G8X7lj{I&G~P$ z*cx3aaN>RlLJtfd-_dAn5G;GDB+EmnKz&{LSvO`UZ0v??^gtdk+RB#z84KaJ1#vr- z$6jJ&qX%W9D{p}+y#Tr831+a$@f<@aQxQZ=2IOy}8A5r?)y`BTqVf>?06105M!7CI zpbR1Ms~v}#yIZ`TSPvU96=B3=P(G7pxQ1}!HH$VL>9lcEmz+Fe9}wq?*|^Eqb+vcN zAsC0hNUS3;-0uYY4Ynvp%h+-6f}hxDUjIV>W90cCGf+)z%Y#hWE#9IC${m8^2s3cnNO<@?8Nq zBbwnR+WpyLkLUm#WYnk<@`!yz_P{7uuV)f{Gp8CPHD`80CfjLrvBvu&eS=By+MH^z zEz&heVc|F+x7{;$;;P5AG>7|e@A6cAa9XQJOn>{Gw@um~A_TV@V){EMRrR(kc=ZmC zr#{*y$5@J%`R*(Y%lu=k&Ca)vh_8Gl)$5dWSEM6HN55BDjg$thaYz}`a~7+XP}1Fz zj%7MUy~=K+G@}}a%ppCjSd~RdcSE*tbo_di_mI+TY8>c8dM;vBHYNQSvZYLCv{!lO zw^Y{o4E=tV_`4>qtedWx6;pJBv*YpGXNkxSp@JHNcS;O*ky&OStEx~cIB{TEIsdqY z!P9?pEF(!B^v9U%<0m-I_%(T4w~L&fY-a_M5GB}15~5J|2qD$1^Wfl6ir>>p{?eAdJ$rtD)B}~%^ZTUQ!lA2o+;JDeW5JZEG!3W zfM=<3yP4h9)ZBcby*`Aurx{ zpDZ7i2)Md)*=#D8z+85oS1Va;J9*QfaZ&mp^7)kU;tU18bHt3?q)%HLe-t#UNJ@%$Jrva!LrUPsv&-Rq>@;J3FWVR@jbqX;<} z6;ri1K0bMkU@v}NuKu6O4fft;g%vCOcX=IC+$=ey$zZv<=Wp&N-etKJ_`@FDl3jgI zvPf^SHBqcn^=>8tPA<8Zf!6rr^-=8YGptk9ZkJ=Rdq*|8l`}~SSo={8NqP_-y_>7M zrB5YOq=1!x*^5cXmU(4~LOeR0t83GzLVu&+GQVd3nkaPqY>O0J{&Ly~kN#gdqK#x) z^}pn=PC~i5a(ybvb_H7a7)4PO*|pJ_84x(vgh-nN%Omvu?T?m~ z!kQEB`4byXosW-M8BXbWQQjQ4Bx;pXYbyH7^?uU}C=i7;NJ_<&=8Lf>n|`iGy`os6 zQ88l``6_~`jI;y(()woVY69~aLwgoZsg8;;9qYM}l& z@lfkUA$Fl-(SKMeV&0+pna^Z$8ny0h{bF#B_48T*rOHQ1u)>%pIA%9K3!nl3{{=e8 BOi%y- diff --git a/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t3_ponder.nbt b/src/main/resources/assets/createnuclear/ponder/reactor/reactor_t3_ponder.nbt index b0a604660a00496687d31c2f0ea2b2e22330ada5..9676d99e7c61a319fc77b41f4109cef3c270af4d 100644 GIT binary patch literal 3700 zcmbuC3s6&69>#$n2ukQk1ylm7PHDjvQF)Y@D~h8b2W`q3+zGPA`p1dC)NV??bA8c{ShpfWLK10fE*nHGJNc74sz>&6_ znTm1d)jhpZ48Hr^6yo->^B)Dn9bf^^kV{ z*VpdQ4{o$;X8%Hays<7&Io2}V7f@a!`k*(s>a|5ZJ5aeZQ7#V-ovF*$Ju)4F6jI6} zf1@^-_!qOom?){eZ&!NB$G%O-05u9)708YSPaML1oJ-T=LRw;px{SOWualL=g8E!YjpA_#w?Rx)1$O7s zmcdW)#~cLuUc~LyNq(`@*SH~W zFRslEnN0Uioz-^p*s=-pA~uP?7t-uGr}wEA{4H$G@*MQ?eX7N^`-tkC$i zgEe6VKjkgpW0CKckm7Ti;r-rtT?GVczbFl55xwgCfYaVB-1tPtt?G%CPx}=sL%R^sEXMgOItTmssie> zAhigOgD;MC)>XiT3T{L9icuJPLv)O7;6a^1MqG4Rz=H|*dZP#Jwb|&`X$c2Hi^Jhh z*Bzxc2(XxH5A0Z!O@4o`&Cu)kGCumFiX!#PxIp|w@|fM7KBQrrYA@Qm<82QIYndOn zmlolnirdvqT!(oWOWQnBss^57LE8TdV&8Q-wME@nb7IoU)p%oe&lWeKtAbm*|BBgc zS(?VPwr8gg^`!jqQfCd9nt$KT49IcAShL&^ut6FTZ&YyGx`_zP#aNooNU17l^Jk&W zyXg|T^#S*r3CdvjtSE$YXQi=LfOz*x-hRBwD|z-(!@XT)*Ea7w#3}UuYdq_mNspbH zm{6A6s#YDiVt{gx7SSI|L(Z9M#MZxLuRmOx1|Nrh=`qBJl?rZk+p%ImG67!)6;Pua zHq&mR+Fvnmx20)jUSno!Epc?Ib8)Nr2 zJJ3zk#0*YZu6|O%hfCKVg(_&+(H2cJbQplWkI)TB#*Z z$xm)I-Ql%Y`aRi!C4HM;?g*WsN_O*P`b0{S72{}z0LHiT%blPzd6I`b*(oBW(2DUz zhQNFdw^1e5L<%o^jA!4rMZ~&1BEWKh0%Xa~jV&67E+QAgvcx2ms0`d;HV0 z9nt$=)EdXc*i8Le*h#Vt*PWW4^syZo6mL3Z%kN|xyZ;+Z)D{*j$VphRnx0dG z{ao$#(T(n&OmQ*)%=Gq7y_er=37=p69kh66z(Ab%PXBXA?7<`!|j9`K><K%F~y0pK@rI`}YJUo04;29Wi@O zke4fRCPZ?K^u$+vw@3z3rsqS8hVkK8(z76`8}kgOs0M$bfz(!*R8q^V26{_+dV7Zx z@SJjf5M#>whX514_|o%X$=R;tG!vkmWPjzy%<-tF6;IJ}Pl!N?(Z(0q^eU@n2Csz2 zFfPXtLvmvAKbOU2Dtkqp6h@sJ@j64<>%+UK3T*y z=*DaKY@vf)=)J5;*)_W~rez<`K;$X5v>+QApp%_Z^?Ar%*Tf)tT}3m&v)|Gp)G!V0 z;)pV(BK2Gowdi$Mn+Xp6mfOkcAD~^<{}<*G9K>_@)?&9qqSn2-t1yPUL*L=WMO^zW z%|g?^N4q$oO!JVbu8GI*)ls zU)PY(f|iE<3|VTPFZSO?zdAWNeJ|g2XNJ=^UztzOeC|faWAm<9-@X!4K$j_xNO&s~ zcOi&ZN!*1XUOjYSx?18c1o7&j3y0?Fq3ieup$kXxYKaR6v78}c^KBg~jLP|=^4=n! zf^d@0=zy*iQGEK*l_~j$6qkLz*TUs5fn$mmLOUz6&d>sHiY%9~;c>k)I5!anzrjQ8PY< zQaU&Ev8jgRFGT!sTo-c3^(>N2ZwtS1)Te+y&Q9D6Msc)$oAOVe@n>ew`g)S|3xyWs R*)2001fE~%P7732{sVvDPLu!u literal 3755 zcmbuC3ox7M8pn|prIntk>Q)KcJyTt}MY|g75-m=*F4c7D?I;p;=|opk5Ins9|V-ZqX>A^ z69eky&APM)WgjVU8U#Cacs3b0bqujThovVJt;f5BA`ODiF~rtEv^xA?4og!}N(R=! zf*h8ze7m6T+4kv{DAX*D9&tX9o>!56>0;fZ;(}ZUy0H>S~ ztQ?lNP-Hgv9=@Ez`a&o&7?f>O;J^es5Ip-jAUKA24_7QsEAH>ts7@yFPokI0U2&Mj^qY4Sb2=BP>WN zQeE556YFSc!B47b&}Zx$akk~&TEwVpEQnw~UjiCAz^8#8?02f$@xZn^ZeQE^gjx4u zTq}<{PW$|Z&{k-rE0(~zDOh5M-8#H z2R;3nVdVBcogTEh!$I-~t4q+6_39aa+PYW?e%%86I1p%nEe_F&8bTo^0|>J$&C4ZGd`@uMrJt|7HwXZG-RjKHho`o9oJF97x^U#*m3a(H^uQJZQixbFUQ zw5CG=nWaBossWtii*%xW)DZ`I{s)AeUF|gUn=spS(9-;a-Q1g`J6CT4jt(WW{(`jy zt&X|3&RGYRCE0JXOTcRL+q)@ZPrVeYA#}%8X4r!UIfRi}y5ptl0E{mJM|b>L*tTYz z^>hRUhm1BXofXQ`S+Ue2ZeR0A=o>teod*n2!Jr4tDR;jnG#wYB3} z6O-k{*cfcQt)P`8nXjM5KU^4y<^A*X?$Nyi?I&zH{T(je5u9U`+{2ZbW;ZfQZsE!@ z1W)&s=%WeA*4*PX$)}!}J4}wN=whDiV6$QunvieJJxi0Adtx$~9Cy)0hOD4jac&u# zdKS5ft~4uX*4%X^CY{M~6Lsdv!kQH@G$G5H>q(QCda7_MLl%i9_|g0+@0Ge}f(uP@ zn`x6LTVHz9BpFN_hRhR9SYKLrVkk_Ghp3YwlQ%2yXhNkm*N-N#@Ei+jBHri4mYHWa z=9N_7%5DpoM193n_QDYVoBYXWR3Xb|$nt)^w)EQ@*mvLRj#leP_|{M|oA~5!1@}Ww_Zsdn5+gPH9^HGhr0L zuI6?e#QWx3Lw^Gd;hc)zDx5bqT&bL`w4iAyT0eKix(nKXB4x+uJY*wY>S z1JW|SoVY#PXe3!4{V-VpDVyojbo}}j;H?q^zz(K=vKA&rJc13KXvm5E&nbec! zCrmT{p8oibTmPfHh#+U%!?{NHPQSskRSkEv`ybt0=4_*TisPT8^R@&zHyz5AQia%) zL$;=qM(Ko9H+X#>5a`u(h%Kdxv9u2*#L`x@yp&2`GvDWJ5s2Dfihb0Y%%K;Yqx2D?_?+kEO0(`lX=}GdS)a{tOKm%f-UYmDAMXuURu@S- z<>mf7&L1V)!*Di1N*ujAg<|5+Zh18Jr>x1?it-A(*S?|v0!as10PCx)TzC;5MdA{# zqp@@{9o{wJ7cuH61a}seO*Hg=osR6Nao?rUDDLcU z=ap%(jz_EHH^R=@bYf;v$(=RPHe>n9-fYXK+wHmB2l6@jVjf5CHl{dk+!6m|G3E&d zA>{`lC@|uk{~XB`!&bx=!#2{-XF~nVA6jJkP}~bV7*82q!_Mr;T=CDR-{SblyIZU5 z8g4}lIon3cwqh;f0t5`pCl$f~-$5%2+-{0piU+ig0qOHf3TM}pivxUztSlm_x9v{4 zLQV4^dR|G|?3$b60Ovugy*TRM*5KTlo5E%Mw)-YT&pAn3g;m`{R(s##x0~dN1H6W; z%p$27b|>ATrVL2BbCO$bO`h-_)`6PdTE^^}H{CeuPP>yTtm^hka$Ci3Heq@|-`7?s zb49C5e}=3!FBc)^kyN%~*2R@5K|IXn|MTb=R#~m$&YCV*TIw`KjkW0Nf}iYvudAkNhlxz8 zT05W7ahgTdox9&Z^7;l#Kfk8;3Zwqkn0;^59G%Uq(gAXw+c8ntT$^`^m_ znM!OHC^z^ql!#m~bWmrqI@;97Zt;boUGBjJW|^u6Xa0g0jC{5S7P4E2G&nP25{DTI zBpCRZ4|9`QN-#q_?@4uvXM!}1@O&@OA-\D`%lw<3|kx zIp$~Y{2yDb<`ga#PpD;yklz_0KX>KERw>qFiw{)r%-CHob$RPo&iVttTC^Vrf>AXG;(45&00?_}B@Az6K`LibTloUU9K=r}PFpwl)2X$6G<@b@G8h7C2yRWva5?hhw6>8iyD2 z6}MBV;|e{FtE~>D^@;(p93kR|nz&zmDVu-kUB$gu`>L(~+>*clBYD5HR(tTx*|&4A zU;DaylbwwJE3xnQ&o%LFnwlrXKPzQG56(C_A3=}i(rT^uuP~$(I z`wL&2pN(HBdGAMb%#O8o^6Ra}=kg2J-m142Jy*;|}lYamEIVt)6mihPO_b-3#7hPX*@7K%Zsh2CB7D=2`*jYIH{_e8*yFPmF zbN;#S&8Ep$-t4O>d$#CXt$Ch}=-IQcE0&g3secQ2TUL7LoAFA6b*DbKNWNIi_@+_$%#|3&O5y{Ym2<->J;*5XCw6=8d;Y^xYvJlk$G{e95&@Z86D RR@dLz-!S#U(U-Oi3;=z^3%&pV delta 1083 zcmey!If08!zMF$1Uv46sVm<4v`4@`Uy;YsQpy6T+b5zuE7u6tzaNb$<7wTh!w&jE> zu5ACsDj?&%di(CrcKa4;W<9-gsde42Nk=TrZKnNAHvJQ`OX=#)Q=zZsSno?Hzn%6s z{rdi0FX|`PUY>jJ%OC$aWjoKjd?}lpES8?Uti)!4a)Td3iO2;*2X!W^qdn)6;+M2_ zcN%g#9A~y-dcor0&M3=VqO>6R%!`T!Xa0g0jC{5S7P4D>VQ80oaDiE-s==AjLIexJ z!_dz7z<@!9t>G|3fdm5|^MOPL3!os^Bu3Ht42E{L0!%{ifdP|@Tfw|*U+ zc(h)&QshVFDuYrvy|+uso^Fx4XJQ?{e_>4BtdgH|R$pEH$v&Vuc)_=24sU%MZ%v-e zyuCh9eA;2t)48WCdE+nc)r_f#e>ds(x2Kbm!_DX0%k5wO+HZZ`_fM~$w`(nbcq(=O zq`0D|Vf(kAwcC1ldd=^Lzc-!r3))**_x_0M+uvmsA5Ai{;*V=@eLVTbx?4HhIA^Da zB(CuK-@NI9JG0)hjlYX*ZPvyXpWttu?0a?BQT^*j=Dl-$Xx%%@`v3e{8}e@b`LO20 zNdp9#0tWo13T_vi6HR@aJ; JfrfSr3;;E@7Uci{ From e3af2c3b736ad481e3836adb191369b259114d20 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Thu, 25 Jun 2026 18:40:12 +0200 Subject: [PATCH 103/171] chore: rename and reword reactor input/output advancements Rename the reactor_rod_input, reactor_fluid_input and reactor_output advancements to feeding_the_reactor, fueling_the_reactor and unlimited_power respectively, with updated titles/descriptions to match (e.g. "Fueling The Reactor" -> "Feeding The Reactor" for the rod input, "Power Output" -> "Unlimited Power" for the output). Tidy up several other titles/descriptions for consistent capitalization (cryogenic_baptism, t1/t2/t3 reactor tiers). Remove the now-unused reactor5x5.nbt/reactor7x7.nbt test schematics from run/schematics, and regenerate the corresponding advancement/lang datagen JSONs (old reactor_rod_input/reactor_fluid_input/reactor_output files deleted, new feeding_the_reactor/fueling_the_reactor/ unlimited_power files added). --- run/schematics/reactor5x5.nbt | Bin 956 -> 0 bytes run/schematics/reactor7x7.nbt | Bin 1850 -> 0 bytes .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 ++-- .../abc32a97b4e744838610c53dbbbaaf9f7d29a557 | 8 +++--- .../assets/createnuclear/lang/en_ud.json | 20 +++++++------- .../assets/createnuclear/lang/en_us.json | 20 +++++++------- ...od_input.json => feeding_the_reactor.json} | 4 +-- ...id_input.json => fueling_the_reactor.json} | 6 ++-- ...actor_output.json => unlimited_power.json} | 6 ++-- .../foundation/advancement/CNAdvancement.java | 26 +++++++++--------- 10 files changed, 48 insertions(+), 48 deletions(-) delete mode 100644 run/schematics/reactor5x5.nbt delete mode 100644 run/schematics/reactor7x7.nbt rename src/generated/resources/data/createnuclear/advancements/{reactor_rod_input.json => feeding_the_reactor.json} (82%) rename src/generated/resources/data/createnuclear/advancements/{reactor_fluid_input.json => fueling_the_reactor.json} (76%) rename src/generated/resources/data/createnuclear/advancements/{reactor_output.json => unlimited_power.json} (76%) diff --git a/run/schematics/reactor5x5.nbt b/run/schematics/reactor5x5.nbt deleted file mode 100644 index b58c68cfffd88870305b4e159740c8a19b912de4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 956 zcmb2|=3oGW|7&L*?3-;M(8k`M$Q&BK;O)Zm8?S%6#XqE^NuMm zf3xuAs`<5sdwxz9mfsbpC)J-~AsT#Z_obPiMXwun&Iva>>C@BI@le|Em5j6bpA{VT zS&n+O%Hr-%Ce4UWe$HWU)x0^CAt8T9)eJbiuUXiL@!!97lOAuf7-7an#L7P{!k2Br(8F^X9=wXQc7 z7fxEJ9MSS;1?x_y;#iIAPxtkAaDL?4DA9kV`{Qq0%i}E-Kdp)l7fLOY)4$)}^;zV_MX@@L7V>xxr9zka_`jx{y( zy6LfbllI)ZzIJ8K&f@Q>xx!xdCC9JzCRUZ3_-ed(7hsj1b9%}CYyRi8JuH{bpL28m zw*@a$KGfxDtlb=IJVR4s?eXrsXVPp>PPxyzCH_f!=Gs|{3#M3lRKB!n_^g(-Lz4gc zPN^vKMbow4y}nvtJa2#2zBpd<#}8jkW7(@a`{SS5mQsJq9fd|y8r!ObO=HeKhWavg zHrSWtaVWm54#eV1>3*JDpCz|EH+EX9+%1*Ic5;C+M_<#5hu_2tMT9h3fl=kCsiDEj zx^%$;5s@iO&YA{rB140fcjaPw!KvLd>F z>%6Hs;bD)LX5N>*+t2$n_5SR?&dJ-B%(eY@UM9v>dcodb5xYLk-dKBgtIPWO%l7Wm L%k~-SF)#oCsm|4K diff --git a/run/schematics/reactor7x7.nbt b/run/schematics/reactor7x7.nbt deleted file mode 100644 index eeef42b7ecead6ff69966bc4e10ad5eb271f65f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1850 zcma)5dsLEl7%uNljixOn3hgvI?dZ^n+C@>*a#YyGbygCjow4N| zf$5p!5ZkDO{!7a5ec3^;36|+)^r9GjeYdE_)7sWlTWwK|s%-+Zh<=nY| za@i7=~OrSm+;H^*){e!LfdP^T~4=U z7oHdt#`BUXs-M}y)3c&RlkdswyYMAp;lxW1$T6ysT6^)=rDTrui!hjXLdIEmVK%7g zx^|=Z!3C94a?>yMQAYcqvv)%dWq@*YyQ2P*x2IDiW}6G$D&u!$9jas(Q!3NiP1Jd$ zhvu=@R@>W)EL6k!yO^YjUZ3~KJ)JJc$Lw9r<@doc6yozPeDW}6F%lpaa$$Tt$K76( zyIbm*SKJoTJc1s11ux9VMqaYTNfFUjc_cHS`iFDB5QEo?TUv$qkNvyGige4_fxd*j2Q-~FwXQAw{meYw5afs&woaVWQmsP z0K*uu!t7X9>&QX!L>I{{Ks45X6y;*m3K4mvP`=6$oK<97p(N(h{gZIow7vLt2ux&A zY3%}p>WZAv-dg+GpnbsFvfhs-09kq#AoDc`YL!aKGnUALeo5od=~Lz&D0UF~tRyDb zf>X)MjU{v4Kfu^exZlb}-}{fhW(SQqvbk9`pWu>(TpYFs-ww`6&sa6Qd0TU#>ghW( z+4Rjj?#ax7UzKp6_a;j8j7RDw!3#MdQhdpQym_|NqtoU5K308Be^ZjdmwF}mq2TaT z7-M!CI>yino(xVF&88tU`%{@hXo?k=bYFt^+qa6Oi)?Tsp+DPKP+RZV5I(Y)OIdE_ ze+Wn@@o&%~aoMTnit_~#gCA&GO`F$ltju~_=2-DJ=RDBJ zjlcenneXoNnX?7!EfV>u0!Vje61)qbWHxO)C`BOKc_`Y8TYM^WsPWN6lXUNW(rH3P z%ONOzX)XpGE5-Hk);y0Y$9RbSiv77z{6*CFt(8UAd}7krERP46j^zjS)4tj`QOt2mof*S;3Ei46N*Un~f$*Z4773e+X?2AK%+Y#y%T?lhij6!U#L9IJ+ zu@)NIm@oO(t=M|w2AD|`369LwxnYO1tH~SHXeWJFIp(ySy}6GkCnzZ9MO5Uo^EP03 zX}@Kv?g|xIzJu4p10;sH;~3*5y{xS7H=n=^RZBdwJk@Mus4Y^8cka}wSIilvXjkdg zni6SeW*TuwIQXP{{M1D41Sy~1QhT&dtHb@|MbC0AyTz7FK{ClcQr z(Yi*@Iap3@eW8gwuzfHoXn%*65Qy`_M;|WJdaZ5bxcFCz{h*<6DEm7!=7wF2(J(6} z%BQUoK`swGw?$#aX}F^X>%`Xpy~oOiId=g@ZVK%Xh80OB1&_BQCilP<4Y?r zr|ZZSO_d5Oe@&pw{bQqJjdqe-E!|(4+^#4BT!C0GSEc)}ROe+?98aM_g!R+8-KyLD zKTOBDLMN-=G7ywT=h9!^M77b3aUj9j`#0TSSwko5fx)9ui}hU~3KZ#2b>wsUo4!3M zeWnC_YGyJz)}Y1?w}o$j`QLAJ5R93EnxaH$No_-0FwXjLSYeop@~iNVn7R4mfvDt_iUn~XzlI};dC0hZ#*pPi7W ztq=Z@k@&DdKrnRf==}3h$EmTjX$HkGp`!KNHk2U*(KAnut}D4R^P+JE_J_NZm_lB# F;4kUhp+5is diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 1137ce38..0c3ed876 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-25T14:01:50.1727214 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-25T18:37:37.4898863 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -0c556267e935b64bc549174c5ad935ce7d390480 assets/createnuclear/lang/en_ud.json -033947c30f5eed0a689b6deb821a68d6d30745fd assets/createnuclear/lang/en_us.json +959ed12b8547f580bc9635aad8e754c3d472f377 assets/createnuclear/lang/en_ud.json +b742d62f744385d54f53365b757ca3b8f89296b8 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 index 7abd9b80..f993613d 100644 --- a/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 +++ b/src/generated/resources/.cache/abc32a97b4e744838610c53dbbbaaf9f7d29a557 @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-25T13:51:56.534886 Create Nuclear Advancements +// 1.20.1 2026-06-25T18:37:37.4848866 Create Nuclear Advancements 605607e2254e01df3e30839921ddd33635250d04 data/createnuclear/advancements/absolute_zero.json b6aa52d55ebb681fa0784c5419667c88a4b0e6db data/createnuclear/advancements/anti_radiation_armor.json fe81bbd052ebe4a70c48912b47e12ed4e4523d1d data/createnuclear/advancements/automatic_uranium.json @@ -11,6 +11,8 @@ a0d591c0cfa26fbd3ea83da54cdd9f900d58926c data/createnuclear/advancements/craft_e f85ce01405f65f942bbc2960442677ef5a3863d9 data/createnuclear/advancements/cryogenic_baptism.json efcd55929d60b9925ac4833ad1171ddb81dd47a0 data/createnuclear/advancements/dye_anti_radiation_armor.json eda669191bc6149e3feee4a2b9b25b64e1d7da60 data/createnuclear/advancements/enriched_yellowcake.json +a4c2c7a01789564aa45097c6ce38c55b75264db7 data/createnuclear/advancements/feeding_the_reactor.json +6d6de5eb0a2736287ba0149dd54746319df6f271 data/createnuclear/advancements/fueling_the_reactor.json 68d2b2361f527a1d9fbe48da95f3f313654c6761 data/createnuclear/advancements/getting_concentrated.json bffbc5007ddb20829768a122cc514f84c2dee1e0 data/createnuclear/advancements/graphene.json 8e89393b2e396243d12cf5b29e283ab97c814519 data/createnuclear/advancements/graphite_rod.json @@ -24,10 +26,7 @@ e9d8bd7f04cac0f3ea72a02a5cdc4cc98f728d98 data/createnuclear/advancements/reactor bf6947708102180f9cd08e31305253774187d763 data/createnuclear/advancements/reactor_controller.json 74363604b80b4a402fb582711f5967b9f68051e1 data/createnuclear/advancements/reactor_cooler.json f88401b0664256c3b2cb35c018f8f738b60bc3e9 data/createnuclear/advancements/reactor_core.json -40298539329e3744cf3850f8a0a6d255c64a7f2f data/createnuclear/advancements/reactor_fluid_input.json eb2975b0ff5956717aa1737794258d4ed7d7528f data/createnuclear/advancements/reactor_frame.json -9fcf0d3e6707c1ad3c28590a33d0e2e8109c00a9 data/createnuclear/advancements/reactor_output.json -5a28e4b2e4d63b83e7596f18a1346ec6b55f7b00 data/createnuclear/advancements/reactor_rod_input.json 91aab6f0a18aee167c63a3aece5fa9778cf52b0b data/createnuclear/advancements/reinforced_glass.json 734a40badf33a911d1e0adb9a2b18688d5cb5401 data/createnuclear/advancements/root.json 79e11acd6d9c16e92bf10d417251a9d6859399c3 data/createnuclear/advancements/silence_the_core.json @@ -39,6 +38,7 @@ a44ae76ec00fae36f7df13e43f20ebe389b416d5 data/createnuclear/advancements/steel_i f7d455c664ca65948f6230eda0621365da68bbcd data/createnuclear/advancements/thorium_ingot.json 2f5be65619e05a1213ef6e71475b7b0c361a6be5 data/createnuclear/advancements/thorium_liquid.json c845dedfc3fe75d51227237a2fb1f5f14f28354b data/createnuclear/advancements/thorium_rod.json +d332d15cb59c5f942c728748121c4249e932df17 data/createnuclear/advancements/unlimited_power.json 5a41894d2428fb7297b98a6b78925a17af2a3095 data/createnuclear/advancements/uranium_liquid.json 01ac168072fa666f64148113ae806ec0b5ea5158 data/createnuclear/advancements/uranium_powder.json 06d1bfea924a4ea35ce78937adcab967cce02b67 data/createnuclear/advancements/uranium_rod.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 90abc88e..d8c16aa3 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -17,12 +17,16 @@ "advancement.createnuclear.craft_enriching_campfire.desc": "ǝɹıɟdɯɐƆ buıɥɔıɹuƎ uɐ ʇɟɐɹƆ", "advancement.createnuclear.crunchy_uranium": "ʇɔǝdxƎ noʎ pıᗡ ʇɐɥM", "advancement.createnuclear.crunchy_uranium.desc": ")ʇuǝɯǝɔuɐʌpⱯ uǝppıH(ㄥ§\n¿¿ ʇɐɥʍ pıp noʎ ˙˙˙˙˙oɹᗺ", - "advancement.createnuclear.cryogenic_baptism": "ǝɹoɯʎuɐ ʇǝǝɟ ʎɯ ןǝǝɟ ʇ,uɐɔ I", + "advancement.createnuclear.cryogenic_baptism": "ǝɹoɯʎuⱯ ʇǝǝℲ ʎW ןǝǝℲ ʇ,uɐɔ I", "advancement.createnuclear.cryogenic_baptism.desc": ")ʇuǝɯǝɔuɐʌpⱯ uǝppıH(ㄥ§\nǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ uǝboɹʇıu pınbıן ǝɥʇ uı ɯıʍS", "advancement.createnuclear.dye_anti_radiation_armor": "ɹoɯɹⱯ ʎW dɯıԀ", "advancement.createnuclear.dye_anti_radiation_armor.desc": "ɹoןoɔ ʎuɐ oʇ ɹoɯɹɐ uoıʇɐıpɐɹ ıʇuɐ ɹnoʎ ǝʎᗡ", "advancement.createnuclear.enriched_yellowcake": "ǝʞɐɔʍoןןǝʎ buıɔuɐɥuƎ", "advancement.createnuclear.enriched_yellowcake.desc": "ןnɟɹǝʍod ǝɹoɯ ʇı ǝʞɐɯ puɐ ǝʞɐɔʍoןןǝʎ ɥɔıɹuǝ oʇ uɐɟ ɐ ǝs∩", + "advancement.createnuclear.feeding_the_reactor": "ɹoʇɔɐǝᴚ ǝɥ⟘ buıpǝǝℲ", + "advancement.createnuclear.feeding_the_reactor.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı spoɹ buıןooɔ puɐ buıʇɐǝɥ pǝǝɟ oʇ ʇnduI poᴚ ɹoʇɔɐǝᴚ ɐ ʇɟɐɹƆ", + "advancement.createnuclear.fueling_the_reactor": "ɹoʇɔɐǝᴚ ǝɥ⟘ buıןǝnℲ", + "advancement.createnuclear.fueling_the_reactor.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı ʇuɐןooɔ pınbıן pǝǝɟ oʇ ʇnduI pınןℲ ɹoʇɔɐǝᴚ ɐ ʇɟɐɹƆ", "advancement.createnuclear.getting_concentrated": "pǝʇɐɹʇuǝɔuoƆ buıʇʇǝ⅁", "advancement.createnuclear.getting_concentrated.desc": "ǝʇɐɹʇuǝɔuoɔ uǝboɹʇıu uıɐʇqo oʇ ǝɔɐuɹnɟ ʇsɐןq ɐ uı ǝʇɐɹʇıu ʇןǝɯS", "advancement.createnuclear.graphene": "ǝuǝɥdɐɹ⅁", @@ -49,14 +53,8 @@ "advancement.createnuclear.reactor_cooler.desc": "ɹoʇɔɐǝɹ ɹnoʎ ןooɔ oʇ ɹǝןooɔ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reactor_core": "ɹǝʍoԀ ɟO ǝɹoƆ", "advancement.createnuclear.reactor_core.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu ɹnoʎ ɟo ʎbɹǝuǝ ןןnɟ ǝɥʇ ssǝuɹɐɥ oʇ ǝɹoɔ ɹoʇɔɐǝɹ ǝɥʇ ʇɟɐɹƆ", - "advancement.createnuclear.reactor_fluid_input": "ןǝnℲ pınןℲ", - "advancement.createnuclear.reactor_fluid_input.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı ʇuɐןooɔ pınןɟ pǝǝɟ oʇ ʇnduı pınןɟ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reactor_frame": "ǝɯɐɹℲ ɹoʇɔɐǝᴚ", "advancement.createnuclear.reactor_frame.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu ɹnoʎ pןınq oʇ ǝɯɐɹɟ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", - "advancement.createnuclear.reactor_output": "ʇndʇnO ɹǝʍoԀ", - "advancement.createnuclear.reactor_output.desc": "ɹoʇɔɐǝɹ ɹnoʎ ʎq pǝɔnpoɹd ʎbɹǝuǝ ǝɥʇ ɹǝɟsuɐɹʇ oʇ ʇndʇno ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", - "advancement.createnuclear.reactor_rod_input": "ɹoʇɔɐǝᴚ ǝɥ⟘ buıןǝnℲ", - "advancement.createnuclear.reactor_rod_input.desc": "ɹoʇɔɐǝɹ ɹnoʎ oʇuı spoɹ ǝʇıɥdɐɹb puɐ ɯnıuɐɹn pǝǝɟ oʇ ʇnduı poɹ ɹoʇɔɐǝɹ ɐ ʇɟɐɹƆ", "advancement.createnuclear.reinforced_glass": "ssɐן⅁ pǝɔɹoɟuıǝᴚ", "advancement.createnuclear.reinforced_glass.desc": "ǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ ssɐןb pǝɔɹoɟuıǝɹ ǝɯos ʇɟɐɹƆ", "advancement.createnuclear.root": "ʎǝuɹnoſ ɹɐǝןɔnN ǝɥ⟘ buıʇɹɐʇS", @@ -66,11 +64,11 @@ "advancement.createnuclear.steel_ingot": "ʇobuI ןǝǝʇS", "advancement.createnuclear.steel_ingot.desc": "sʇobuı ןǝǝʇs ǝʇɐǝɹɔ oʇ sʇobuı uoɹı puɐ ʇsnp ןɐoɔ ǝuıqɯoƆ", "advancement.createnuclear.t1": "Ɩ⟘ ɹǝןןoɹʇuoƆ ɹoʇɔɐǝᴚ", - "advancement.createnuclear.t1.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu Ɩ ɹǝıʇ ɐ ʇɹɐʇs puɐ pןınᗺ", + "advancement.createnuclear.t1.desc": "ɹoʇɔɐǝᴚ ɹɐǝןɔnN Ɩ ɹǝıʇ ɐ pןınᗺ", "advancement.createnuclear.t2": "ᄅ⟘ ɹǝןןoɹʇuoƆ ɹoʇɔɐǝᴚ", - "advancement.createnuclear.t2.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu ᄅ ɹǝıʇ ɐ ʇɹɐʇs puɐ pןınᗺ", + "advancement.createnuclear.t2.desc": "ɹoʇɔɐǝᴚ ɹɐǝןɔnN ᄅ ɹǝıʇ ɐ pןınᗺ", "advancement.createnuclear.t3": "Ɛ⟘ ɹǝןןoɹʇuoƆ ɹoʇɔɐǝᴚ", - "advancement.createnuclear.t3.desc": "ɹoʇɔɐǝɹ ɹɐǝןɔnu Ɛ ɹǝıʇ ɐ ʇɹɐʇs puɐ pןınᗺ", + "advancement.createnuclear.t3.desc": "ɹoʇɔɐǝᴚ ɹɐǝןɔnN Ɛ ɹǝıʇ ɐ pןınᗺ", "advancement.createnuclear.thorium_dust": "ɯnıɹoɥ⟘ pǝɹǝpʍoԀ", "advancement.createnuclear.thorium_dust.desc": "buıuıɟǝɹ ɹǝɥʇɹnɟ ɹoɟ ǝɹɐdǝɹd oʇ ʇsnp oʇuı ɯnıɹoɥʇ ʍɐɹ ɥsnɹƆ", "advancement.createnuclear.thorium_ingot": "ɯnıɹoɥ⟘ pǝʇɔɐdɯoƆ", @@ -79,6 +77,8 @@ "advancement.createnuclear.thorium_liquid.desc": "ʇsnp ɯnıɹoɥʇ buıxıɯ ʎq pınbıן ɯnıɹoɥʇ ǝɯos uıɐʇqO", "advancement.createnuclear.thorium_rod": "ʞɔıʇS ǝnןᗺ Ɐ ʇɐɥM", "advancement.createnuclear.thorium_rod.desc": "ǝɯıʇ ʇsɹıɟ ǝɥʇ ɹoɟ poɹ ɯnıɹoɥʇ ɐ ʇɟɐɹƆ", + "advancement.createnuclear.unlimited_power": "ɹǝʍoԀ pǝʇıɯıןu∩", + "advancement.createnuclear.unlimited_power.desc": "ɹoʇɔɐǝɹ ɹnoʎ ʎq pǝɔnpoɹd ʎbɹǝuǝ ǝɥʇ ʇɔɐɹʇxǝ oʇ ʇndʇnO ɹoʇɔɐǝᴚ ɐ ʇɟɐɹƆ", "advancement.createnuclear.uranium_liquid": "pınbıꞀ o⟘ pıןoS buıuɹn⟘", "advancement.createnuclear.uranium_liquid.desc": "ɹǝpʍod ɯnıuɐɹn buıxıɯ ʎq pınbıן ɯnıuɐɹn ǝɯos uıɐʇqO", "advancement.createnuclear.uranium_powder": "ɯnıuɐɹ∩ pǝɹǝpʍoԀ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index dbfc7a51..0a68dc6d 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -17,12 +17,16 @@ "advancement.createnuclear.craft_enriching_campfire.desc": "Craft an Enriching Campfire", "advancement.createnuclear.crunchy_uranium": "What Did You Expect", "advancement.createnuclear.crunchy_uranium.desc": "Bro..... you did what ??\n§7(Hidden Advancement)", - "advancement.createnuclear.cryogenic_baptism": "I can't feel my feet anymore", + "advancement.createnuclear.cryogenic_baptism": "I can't Feel My Feet Anymore", "advancement.createnuclear.cryogenic_baptism.desc": "Swim in the liquid nitrogen for the first time\n§7(Hidden Advancement)", "advancement.createnuclear.dye_anti_radiation_armor": "Pimp My Armor", "advancement.createnuclear.dye_anti_radiation_armor.desc": "Dye your anti radiation armor to any color", "advancement.createnuclear.enriched_yellowcake": "Enhancing Yellowcake", "advancement.createnuclear.enriched_yellowcake.desc": "Use a fan to enrich yellowcake and make it more powerful", + "advancement.createnuclear.feeding_the_reactor": "Feeding The Reactor", + "advancement.createnuclear.feeding_the_reactor.desc": "Craft a Reactor Rod Input to feed heating and cooling rods into your reactor", + "advancement.createnuclear.fueling_the_reactor": "Fueling The Reactor", + "advancement.createnuclear.fueling_the_reactor.desc": "Craft a Reactor Fluid Input to feed liquid coolant into your reactor", "advancement.createnuclear.getting_concentrated": "Getting Concentrated", "advancement.createnuclear.getting_concentrated.desc": "Smelt nitrate in a blast furnace to obtain nitrogen concentrate", "advancement.createnuclear.graphene": "Graphene", @@ -49,14 +53,8 @@ "advancement.createnuclear.reactor_cooler.desc": "Craft a reactor cooler to cool your reactor", "advancement.createnuclear.reactor_core": "Core Of Power", "advancement.createnuclear.reactor_core.desc": "Craft the reactor core to harness the full energy of your nuclear reactor", - "advancement.createnuclear.reactor_fluid_input": "Fluid Fuel", - "advancement.createnuclear.reactor_fluid_input.desc": "Craft a reactor fluid input to feed fluid coolant into your reactor", "advancement.createnuclear.reactor_frame": "Reactor Frame", "advancement.createnuclear.reactor_frame.desc": "Craft a reactor frame to build your nuclear reactor", - "advancement.createnuclear.reactor_output": "Power Output", - "advancement.createnuclear.reactor_output.desc": "Craft a reactor output to transfer the energy produced by your reactor", - "advancement.createnuclear.reactor_rod_input": "Fueling The Reactor", - "advancement.createnuclear.reactor_rod_input.desc": "Craft a reactor rod input to feed uranium and graphite rods into your reactor", "advancement.createnuclear.reinforced_glass": "Reinforced Glass", "advancement.createnuclear.reinforced_glass.desc": "Craft some reinforced glass for the first time", "advancement.createnuclear.root": "Starting The Nuclear Journey", @@ -66,11 +64,11 @@ "advancement.createnuclear.steel_ingot": "Steel Ingot", "advancement.createnuclear.steel_ingot.desc": "Combine coal dust and iron ingots to create steel ingots", "advancement.createnuclear.t1": "Reactor Controller T1", - "advancement.createnuclear.t1.desc": "Build and start a tier 1 nuclear reactor", + "advancement.createnuclear.t1.desc": "Build a tier 1 Nuclear Reactor", "advancement.createnuclear.t2": "Reactor Controller T2", - "advancement.createnuclear.t2.desc": "Build and start a tier 2 nuclear reactor", + "advancement.createnuclear.t2.desc": "Build a tier 2 Nuclear Reactor", "advancement.createnuclear.t3": "Reactor Controller T3", - "advancement.createnuclear.t3.desc": "Build and start a tier 3 nuclear reactor", + "advancement.createnuclear.t3.desc": "Build a tier 3 Nuclear Reactor", "advancement.createnuclear.thorium_dust": "Powdered Thorium", "advancement.createnuclear.thorium_dust.desc": "Crush raw thorium into dust to prepare for further refining", "advancement.createnuclear.thorium_ingot": "Compacted Thorium", @@ -79,6 +77,8 @@ "advancement.createnuclear.thorium_liquid.desc": "Obtain some thorium liquid by mixing thorium dust", "advancement.createnuclear.thorium_rod": "What A Blue Stick", "advancement.createnuclear.thorium_rod.desc": "Craft a thorium rod for the first time", + "advancement.createnuclear.unlimited_power": "Unlimited Power", + "advancement.createnuclear.unlimited_power.desc": "Craft a Reactor Output to extract the energy produced by your reactor", "advancement.createnuclear.uranium_liquid": "Turning Solid To Liquid", "advancement.createnuclear.uranium_liquid.desc": "Obtain some uranium liquid by mixing uranium powder", "advancement.createnuclear.uranium_powder": "Powdered Uranium", diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_rod_input.json b/src/generated/resources/data/createnuclear/advancements/feeding_the_reactor.json similarity index 82% rename from src/generated/resources/data/createnuclear/advancements/reactor_rod_input.json rename to src/generated/resources/data/createnuclear/advancements/feeding_the_reactor.json index 1f9bf2c0..524586ca 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_rod_input.json +++ b/src/generated/resources/data/createnuclear/advancements/feeding_the_reactor.json @@ -18,7 +18,7 @@ "announce_to_chat": false, "description": { "color": "#DBA213", - "translate": "advancement.createnuclear.reactor_rod_input.desc" + "translate": "advancement.createnuclear.feeding_the_reactor.desc" }, "frame": "task", "hidden": false, @@ -27,7 +27,7 @@ }, "show_toast": true, "title": { - "translate": "advancement.createnuclear.reactor_rod_input" + "translate": "advancement.createnuclear.feeding_the_reactor" } }, "requirements": [ diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_fluid_input.json b/src/generated/resources/data/createnuclear/advancements/fueling_the_reactor.json similarity index 76% rename from src/generated/resources/data/createnuclear/advancements/reactor_fluid_input.json rename to src/generated/resources/data/createnuclear/advancements/fueling_the_reactor.json index 729e09e1..c93fd2d3 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_fluid_input.json +++ b/src/generated/resources/data/createnuclear/advancements/fueling_the_reactor.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_rod_input", + "parent": "createnuclear:feeding_the_reactor", "criteria": { "0": { "conditions": { @@ -18,7 +18,7 @@ "announce_to_chat": false, "description": { "color": "#DBA213", - "translate": "advancement.createnuclear.reactor_fluid_input.desc" + "translate": "advancement.createnuclear.fueling_the_reactor.desc" }, "frame": "task", "hidden": false, @@ -27,7 +27,7 @@ }, "show_toast": true, "title": { - "translate": "advancement.createnuclear.reactor_fluid_input" + "translate": "advancement.createnuclear.fueling_the_reactor" } }, "requirements": [ diff --git a/src/generated/resources/data/createnuclear/advancements/reactor_output.json b/src/generated/resources/data/createnuclear/advancements/unlimited_power.json similarity index 76% rename from src/generated/resources/data/createnuclear/advancements/reactor_output.json rename to src/generated/resources/data/createnuclear/advancements/unlimited_power.json index 47d25fd7..afa6ecc5 100644 --- a/src/generated/resources/data/createnuclear/advancements/reactor_output.json +++ b/src/generated/resources/data/createnuclear/advancements/unlimited_power.json @@ -1,5 +1,5 @@ { - "parent": "createnuclear:reactor_fluid_input", + "parent": "createnuclear:fueling_the_reactor", "criteria": { "0": { "conditions": { @@ -18,7 +18,7 @@ "announce_to_chat": false, "description": { "color": "#DBA213", - "translate": "advancement.createnuclear.reactor_output.desc" + "translate": "advancement.createnuclear.unlimited_power.desc" }, "frame": "task", "hidden": false, @@ -27,7 +27,7 @@ }, "show_toast": true, "title": { - "translate": "advancement.createnuclear.reactor_output" + "translate": "advancement.createnuclear.unlimited_power" } }, "requirements": [ diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java index 74c6fe64..3c76031e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancement.java @@ -186,7 +186,7 @@ public class CNAdvancement implements DataProvider { ), CRYOGENIC_BAPTISM = create("cryogenic_baptism", b -> b.icon(CNFluids.LIQUID_NITROGEN.getBucket().get()) - .title("I can't feel my feet anymore") + .title("I can't Feel My Feet Anymore") .description("Swim in the liquid nitrogen for the first time") .after(ABSOLUTE_ZERO) .special(SECRET) @@ -291,21 +291,21 @@ public class CNAdvancement implements DataProvider { T1_REACTOR = create("t1", b -> b.icon(CNBlocks.REACTOR_CONTROLLER.asItem()) .title("Reactor Controller T1") - .description("Build and start a tier 1 nuclear reactor") + .description("Build a tier 1 Nuclear Reactor") .special(EXPERT) .after(REACTOR_CONTROLLER) ), T2_REACTOR = create("t2", b -> b.icon(CNBlocks.REACTOR_CONTROLLER.asItem()) .title("Reactor Controller T2") - .description("Build and start a tier 2 nuclear reactor") + .description("Build a tier 2 Nuclear Reactor") .special(EXPERT) .after(T1_REACTOR) ), T3_REACTOR = create("t3", b -> b.icon(CNBlocks.REACTOR_CONTROLLER.asItem()) .title("Reactor Controller T3") - .description("Build and start a tier 3 nuclear reactor") + .description("Build a tier 3 Nuclear Reactor") .special(EXPERT) .after(T2_REACTOR) ), @@ -317,23 +317,23 @@ public class CNAdvancement implements DataProvider { .whenIconCollected() ), - REACTOR_ROD_INPUT = create("reactor_rod_input", b -> b.icon(CNBlocks.REACTOR_ROD_INPUT) - .title("Fueling The Reactor") - .description("Craft a reactor rod input to feed uranium and graphite rods into your reactor") + REACTOR_ROD_INPUT = create("feeding_the_reactor", b -> b.icon(CNBlocks.REACTOR_ROD_INPUT) + .title("Feeding The Reactor") + .description("Craft a Reactor Rod Input to feed heating and cooling rods into your reactor") .after(REACTOR_CASING) .whenIconCollected() ), - REACTOR_FLUID_INPUT = create("reactor_fluid_input", b -> b.icon(CNBlocks.REACTOR_FLUID_INPUT) - .title("Fluid Fuel") - .description("Craft a reactor fluid input to feed fluid coolant into your reactor") + REACTOR_FLUID_INPUT = create("fueling_the_reactor", b -> b.icon(CNBlocks.REACTOR_FLUID_INPUT) + .title("Fueling The Reactor") + .description("Craft a Reactor Fluid Input to feed liquid coolant into your reactor") .after(REACTOR_ROD_INPUT) .whenIconCollected() ), - REACTOR_OUTPUT = create("reactor_output", b -> b.icon(CNBlocks.REACTOR_OUTPUT) - .title("Power Output") - .description("Craft a reactor output to transfer the energy produced by your reactor") + REACTOR_OUTPUT = create("unlimited_power", b -> b.icon(CNBlocks.REACTOR_OUTPUT) + .title("Unlimited Power") + .description("Craft a Reactor Output to extract the energy produced by your reactor") .after(REACTOR_FLUID_INPUT) .whenIconCollected() ), From 62905b15651441815a29fe951c5cac9a1aeeacfc Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:55:24 +0200 Subject: [PATCH 104/171] fix: update anti-radiation armor models to use flat 2D icons and correct texture references --- nitrogen.png | Bin 38099 -> 0 bytes .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 10 +++++----- .../item/default_anti_radiation_boots.json | 7 +++++-- .../item/default_anti_radiation_chestplate.json | 7 +++++-- .../item/default_anti_radiation_helmet.json | 7 +++++-- .../item/default_anti_radiation_leggings.json | 7 +++++-- .../net/nuclearteam/createnuclear/CNItems.java | 16 ++++++++++------ .../armor/AntiRadiationArmorModel.java | 1 - .../armors/default_anti_radiation_boots.png | Bin 0 -> 368 bytes .../default_anti_radiation_chestplate.png | Bin 0 -> 575 bytes .../armors/default_anti_radiation_helmet.png | Bin 0 -> 360 bytes .../armors/default_anti_radiation_leggings.png | Bin 0 -> 427 bytes .../item/default_anti_radiation_suit.png | Bin 2979 -> 0 bytes water.png | Bin 50213 -> 0 bytes 14 files changed, 35 insertions(+), 20 deletions(-) delete mode 100644 nitrogen.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_boots.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_chestplate.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_helmet.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_leggings.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/default_anti_radiation_suit.png delete mode 100644 water.png diff --git a/nitrogen.png b/nitrogen.png deleted file mode 100644 index 369ffd82069fe055935c89969c694c3cd08ac8b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38099 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 S;QM$00000 - * Replicates {@link AssetLookup#itemModelWithPartials()} (outer model parenting the - * Blockbench {@code item//item} model) and adds one model override per {@link DyeColor}, - * driven by the client-side {@code createnuclear:cloth_color} item property - * (see {@code CreateNuclearClient}). Each per-color child model reuses the same geometry but - * re-textures it with the matching {@code item/armors/_anti_radiation_suit} sheet. + * The undyed ("default") piece uses a flat 2D icon ({@code item/generated} with the + * {@code item/armors/default_anti_radiation_} sprite) instead of the 3D Blockbench + * model, since the dropped/inventory 3D rendering was problematic. The worn armor on the + * body is unaffected (handled by {@code AntiRadiationArmorModel}). + *

+ * One model override per {@link DyeColor} is added, driven by the client-side + * {@code createnuclear:cloth_color} item property (see {@code CreateNuclearClient}). Each + * per-color child model still re-textures the 3D Blockbench geometry ({@code item//item}) + * with the matching {@code item/armors/_anti_radiation_suit} sheet. *

* The texture keys differ per slot: the helmet geometry uses {@code layer0}/{@code particle}, * the other pieces use {@code 14} — hence {@code textureKeys} is passed explicitly. @@ -62,7 +66,7 @@ public class CNItems { private static NonNullBiConsumer, RegistrateItemModelProvider> coloredArmorModel(String slot, String... textureKeys) { return (c, p) -> { ResourceLocation baseParent = p.modLoc("item/" + c.getName() + "/item"); - ItemModelBuilder outer = p.withExistingParent(c.getName(), baseParent); + ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/armors/default_anti_radiation_" + slot)); // DyeColor.values() is ordered by id (0..15); overrides must be ascending by predicate // value so vanilla override resolution selects the exact color (returns last match <= value).cloth // The cloth_color property is clamped to [0,1] (see CreateNuclearClient), hence the diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java index 93e06f1f..cf32f88c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java @@ -41,7 +41,6 @@ public static LayerDefinition createBodyLayer() { partdefinition.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); - PartDefinition head = partdefinition.addOrReplaceChild("head", CubeListBuilder.create().texOffs(30, 0).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.2F)) .texOffs(30, 16).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, -8.0F, 1.0F)); diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_boots.png b/src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_boots.png new file mode 100644 index 0000000000000000000000000000000000000000..b1fa59cc09de834ac0483fb7beb6eef08e7fdbc0 GIT binary patch literal 368 zcmV-$0gwKPP)Px$DoI2^R5*>@lD|s=0TjnS#z`O-kr7B(K`kLTwFx&^(9z#;v$!<21TI0)-w-Vq zL^wEJL_syR1cGo_g9Slh9EOK^1ljOf^0@O%TI;)gzwdqDFCP4P#0G_n?F|7aTQ&#w za}2;VG?|-M0a)8Rjd*;Rh9J%=P)Px$`AI}UR5*>rl240LQ5eR5cee8@ z=sN`NTC^|Ph^q*}$Y2>fO|xj#0|yT0{k_k5c+Y|VEp4(1 znGxF)@S^G+lCC4t#j17^+*w<;cO51p#{gCDa8UZ70q6j?tUI=`dV}NkCv$iJ^zr00JiXwzT%Ct$kj%Eqs>nmIhy2)gFZ2L1jxE~{CMdxnH7v8e%&j66z zx<;kkC0(qJ|H01MvhBa*B{vKcY8Ix36HQ(sxA&C;!y(769c^{!H$l^b23?%^AwO?&<&l N002ovPDHLkV1jYZ1=;`r literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_helmet.png b/src/main/resources/assets/createnuclear/textures/item/armors/default_anti_radiation_helmet.png new file mode 100644 index 0000000000000000000000000000000000000000..3431a8491242dd77be945f0771a2688499ec71a1 GIT binary patch literal 360 zcmV-u0hj)XP)Px$B1uF+R5*>*lD|vCP!xr~MngadG?gM0BKRW~5jyD-u;QXni?eH?;Nb3VM|TG& z@jq};a4J@C(X|9^YrqFZwEBj|E(POcG0juwp6wpa{W#qBVC0ohnJdd{A;4bt6M&<8 z4S?Ibt5|+~*x1-Eg?chcPx!c-Ism8bJ`?r~>!uY}t7j32rds}%@B)Mv3})T52JL=r z0MHXY$0Z$SX$k;)@txfhAKkQK*$6~a*bB{8J@SmokF>Rr4psj7!>cks;`#zn{8*r@l&tLl0000Px$Wl2OqR5*>zl08d8Q5=UKrNF@#)HH;yBI;0)OH0($Pk$An zRZe*Ey+%cEah@xi&dg0O4%e29c)*Xc>?E=31K=fJ9~CoSdss52B__eR(^WbS=^g<6 zcK@s5XKTJT^8}M1+wq|E6VMj`$o6P-y1dA?AVUDru>s|u1=Epjfe=-zvbA8`RfsCZ zQr-p-kF6SB@51kbv;8p2vJ-&&%#ef9h^IDuZ0-foo+X;@002ovPDHLkV1mD}zbya& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/default_anti_radiation_suit.png b/src/main/resources/assets/createnuclear/textures/item/default_anti_radiation_suit.png deleted file mode 100644 index df8abdb3d82ab053a1e50c78f33239dfd6897e50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2979 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 OfWEe|R)dCP^#1^lyRLu$ diff --git a/water.png b/water.png deleted file mode 100644 index 577f3a5a7174a76a4ef51077095b2e0b63579ac1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50213 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 z 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 Date: Fri, 26 Jun 2026 10:23:53 +0200 Subject: [PATCH 105/171] fix: remove redundant logging in ReactorAssembler during assembly process --- .../createnuclear/content/multiblock/ReactorAssembler.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 5dec30b8..98890aed 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -37,9 +37,6 @@ public static void assemble(BlockPos pos, Level level) { BlockPattern result = CNMultiblock.REGISTRATE_MULTIBLOCK.findStructure(level, pos, entity); if (result == null) return; - CreateNuclear.LOGGER.warn("ReactorAssembler#assemble id: {}, size: {}, name: {}", - result.id(), result.data().getSize(), result.data().getName()); - sendMessageToPlayer(level, pos, CreateNuclearLang.translate("notification.reactor.assembled"), !entity.isAssembled()); switch (result.data()) { From 0bba0e6a4d468181d6679d996315bf123bf70757 Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:16:41 +0200 Subject: [PATCH 106/171] feat: implement AntiRadiationArmor model and update rendering logic for armor visibility --- gradle.properties | 2 +- .../createnuclear/ClientEvents.java | 24 ++++ .../AntiRadiationArmorClientExtensions.java | 35 +----- .../armor/AntiRadiationArmorModel.java | 119 ++++++++---------- .../armor/default_anti_radiation_suit.png | Bin 2979 -> 3608 bytes 5 files changed, 84 insertions(+), 96 deletions(-) diff --git a/gradle.properties b/gradle.properties index ebd1d0cc..d0a8924c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.12-beta +mod_version=2.0.13-beta # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java b/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java index 7d6e575e..226f2f3a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java @@ -4,10 +4,15 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderPlayerEvent; import net.minecraftforge.client.event.ViewportEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import net.minecraft.client.model.PlayerModel; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; import net.nuclearteam.createnuclear.foundation.mixin.CameraAccessor; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; @@ -79,4 +84,23 @@ public static void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) } } } + + @SubscribeEvent + public static void onRenderPlayerPre(RenderPlayerEvent.Pre event) { + Player player = event.getEntity(); + PlayerModel model = event.getRenderer().getModel(); + + if (player.getItemBySlot(EquipmentSlot.HEAD).getItem() instanceof AntiRadiationArmorItem) { + model.hat.visible = false; + } + if (player.getItemBySlot(EquipmentSlot.CHEST).getItem() instanceof AntiRadiationArmorItem) { + model.jacket.visible = false; + model.rightSleeve.visible = false; + model.leftSleeve.visible = false; + } + if (player.getItemBySlot(EquipmentSlot.LEGS).getItem() instanceof AntiRadiationArmorItem) { + model.rightPants.visible = false; + model.leftPants.visible = false; + } + } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java index 2b07943f..0e2ddf57 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java @@ -20,38 +20,11 @@ public final class AntiRadiationArmorClientExtensions implements IClientItemExte this.model = new AntiRadiationArmorModel(root); } + // Forge copies the body pose + standard part visibility from `original` onto the + // model after this returns, but it can't tell LEGS from FEET (both make the vanilla + // legs visible) and knows nothing about our custom boot parts. We pass the slot so + // renderToBuffer can show legs for leggings vs. only boots for the FEET slot. this.model.currentSlot = equipmentSlot; - this.model.setAllVisible(false); -// this.model.right_leg_armor.visible = false; -// this.model.right_boot.visible = false; -// this.model.left_leg_armor.visible = false; -// this.model.left_boot.visible = false; - - switch (equipmentSlot) { - case HEAD -> { - this.model.getHead().visible = true; - this.model.hat.visible = true; -// this.model.right_boot.visible = false; -// this.model.left_boot.visible = false; - } - case CHEST -> { - this.model.body.visible = true; - this.model.right_arm.visible = true; - this.model.left_arm.visible = true; - } - default -> { - this.model.getHead().visible = false; - this.model.hat.visible = false; - this.model.body.visible = false; - this.model.rightArm.visible = false; - this.model.leftArm.visible = false; - this.model.rightLeg.visible = false; - this.model.leftLeg.visible = false; - this.model.right_leg.visible = false; - this.model.left_leg.visible = false; - } - } - return this.model; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java index cf32f88c..dffd88f0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java @@ -1,5 +1,6 @@ package net.nuclearteam.createnuclear.content.equipment.armor; + import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.model.HumanoidModel; @@ -9,18 +10,19 @@ import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; - public class AntiRadiationArmorModel extends HumanoidModel { - // This layer location should be baked with EntityRendererProvider.Context in the entity renderer and passed into this model's constructor; - public final ModelPart head; - public final ModelPart body; - public final ModelPart right_arm; - public final ModelPart left_arm; - public final ModelPart right_leg; - public final ModelPart right_boot; - public final ModelPart left_leg; - public final ModelPart left_boot; - + private final ModelPart head; + private final ModelPart body; + private final ModelPart right_arm; + private final ModelPart left_arm; + private final ModelPart right_leg; + private final ModelPart left_leg; + private final ModelPart left_boot; + private final ModelPart right_boot; + + // Set per render pass by AntiRadiationArmorClientExtensions so renderToBuffer can show + // the legs for LEGS (leggings) but only the boots for FEET (boots) — Forge makes the + // vanilla leg parts visible for BOTH slots, so we disambiguate here. public EquipmentSlot currentSlot = EquipmentSlot.HEAD; public AntiRadiationArmorModel(ModelPart root) { @@ -30,82 +32,71 @@ public AntiRadiationArmorModel(ModelPart root) { this.right_arm = root.getChild("right_arm"); this.left_arm = root.getChild("left_arm"); this.right_leg = root.getChild("right_leg"); - this.right_boot = this.right_leg.getChild("right_boot"); this.left_leg = root.getChild("left_leg"); - this.left_boot = this.left_leg.getChild("left_boot"); + this.left_boot = root.getChild("left_boot"); + this.right_boot = root.getChild("right_boot"); } public static LayerDefinition createBodyLayer() { MeshDefinition meshdefinition = new MeshDefinition(); PartDefinition partdefinition = meshdefinition.getRoot(); + // HumanoidModel's constructor requires a "hat" child; keep it empty. partdefinition.addOrReplaceChild("hat", CubeListBuilder.create(), PartPose.ZERO); PartDefinition head = partdefinition.addOrReplaceChild("head", CubeListBuilder.create().texOffs(30, 0).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.2F)) - .texOffs(30, 16).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, -8.0F, 1.0F)); + .texOffs(30, 16).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, 0.0F, 0.0F)); - PartDefinition body = partdefinition.addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 19).addBox(-3.875F, 0.825F, -2.65F, 8.0F, 12.0F, 5.0F, new CubeDeformation(0.0F)) - .texOffs(0, 0).addBox(-4.575F, -0.175F, -2.95F, 9.0F, 13.0F, 6.0F, new CubeDeformation(0.0F)) - .texOffs(0, 36).addBox(-3.875F, 0.825F, -2.55F, 8.0F, 12.0F, 5.0F, new CubeDeformation(0.0F)) - .texOffs(64, 0).addBox(-4.675F, -0.175F, -2.85F, 9.0F, 13.0F, 6.0F, new CubeDeformation(0.0F)), PartPose.offset(0.175F, -0.825F, 0.85F)); + PartDefinition body = partdefinition.addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 19).addBox(-3.7F, 0.0F, -2.8F, 8.0F, 12.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(0, 0).addBox(-4.4F, -1.0F, -3.1F, 9.0F, 13.0F, 6.0F, new CubeDeformation(0.0F)) + .texOffs(0, 36).addBox(-4.0F, 0.0F, -2.7F, 8.0F, 12.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(64, 0).addBox(-4.5F, -1.0F, -3.0F, 9.0F, 13.0F, 6.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 0.0F)); - PartDefinition right_arm = partdefinition.addOrReplaceChild("right_arm", CubeListBuilder.create().texOffs(45, 32).mirror().addBox(-2.1F, -2.5F, -2.1F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.45F)).mirror(false) - .texOffs(29, 32).mirror().addBox(-2.1F, -2.5F, -2.1F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.55F)).mirror(false), PartPose.offset(-5.8F, 4.5F, 0.8F)); + PartDefinition right_arm = partdefinition.addOrReplaceChild("right_arm", CubeListBuilder.create().texOffs(45, 32).mirror().addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.45F)).mirror(false) + .texOffs(29, 32).mirror().addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.55F)).mirror(false), PartPose.offset(7.0F, 2.0F, 0.0F)); - PartDefinition left_arm = partdefinition.addOrReplaceChild("left_arm", CubeListBuilder.create().texOffs(45, 32).addBox(-1.9F, -2.5F, -2.1F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)) - .texOffs(29, 32).addBox(-1.9F, -2.5F, -2.1F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.5F)), PartPose.offset(6.2F, 4.5F, 0.8F)); + PartDefinition left_arm = partdefinition.addOrReplaceChild("left_arm", CubeListBuilder.create().texOffs(45, 32).addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)) + .texOffs(29, 32).addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.5F)), PartPose.offset(-7.0F, 2.0F, 0.0F)); - PartDefinition right_leg = partdefinition.addOrReplaceChild("right_leg", CubeListBuilder.create().texOffs(29, 48).mirror().addBox(-2.0733F, -0.3333F, -1.8667F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).mirror(false) - .texOffs(45, 48).mirror().addBox(-1.9633F, -0.3333F, -2.0667F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)).mirror(false), PartPose.offset(-1.6367F, 19.3333F, 0.7667F)); + PartDefinition right_leg = partdefinition.addOrReplaceChild("right_leg", CubeListBuilder.create().texOffs(29, 48).mirror().addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).mirror(false) + .texOffs(45, 48).mirror().addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)).mirror(false), PartPose.offset(1.9F, 12.0F, 0.0F)); - right_leg.addOrReplaceChild("right_boot", CubeListBuilder.create().texOffs(61, 39).mirror().addBox(-1.9633F, 7.6334F, -2.0667F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.25F)).mirror(false), PartPose.offset(-1.6367F, 19.3333F, 0.7667F)); + PartDefinition left_leg = partdefinition.addOrReplaceChild("left_leg", CubeListBuilder.create().texOffs(29, 48).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) + .texOffs(45, 48).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(-1.9F, 12.0F, 0.0F)); - PartDefinition left_leg = partdefinition.addOrReplaceChild("left_leg", CubeListBuilder.create().texOffs(29, 48).addBox(-1.9667F, -0.3333F, -1.8667F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) - .texOffs(45, 48).addBox(-2.0167F, -0.3333F, -2.0667F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(2.2167F, 19.3333F, 0.7667F)); + // Boots: separate parts, but expressed in the legs' pivot frame (±1.9, 12, 0) so that + // copyFrom(leg) in renderToBuffer makes them inherit the leg's walk animation while + // remaining independently toggleable. (Same world geometry as the raw Blockbench export.) + partdefinition.addOrReplaceChild("left_boot", CubeListBuilder.create().texOffs(61, 39).addBox(-2.0F, 8.3F, -2.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(-1.9F, 12.0F, 0.0F)); - left_leg.addOrReplaceChild("left_boot", CubeListBuilder.create().texOffs(61, 39).addBox(-2.0167F, 7.6334F, -2.0667F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(2.2167F, 19.3333F, 0.7667F)); + partdefinition.addOrReplaceChild("right_boot", CubeListBuilder.create().texOffs(61, 39).mirror().addBox(-2.0F, 8.3F, -2.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.25F)).mirror(false), PartPose.offset(1.9F, 12.0F, 0.0F)); return LayerDefinition.create(meshdefinition, 96, 96); } - @Override - public void setAllVisible(boolean pVisible) { - super.setAllVisible(pVisible); - this.head.visible = false; - this.hat.visible = false; - this.body.visible = false; - this.right_arm.visible = false; - this.left_arm.visible = false; - this.right_leg.visible = false; - this.right_boot.visible = false; - this.left_leg.visible = false; - this.left_boot.visible = false; - } - @Override public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - // Copier les animations des jambes vers les boots + // Make the boots follow the (already animated) legs. this.right_boot.copyFrom(this.right_leg); this.left_boot.copyFrom(this.left_leg); - - if (this.currentSlot == EquipmentSlot.LEGS) { - this.body.visible = false; - this.right_boot.visible = false; - this.left_boot.visible = false; - } else if (this.currentSlot == EquipmentSlot.FEET) { - this.right_leg.visible = false; - this.left_leg.visible = false; - this.right_boot.visible = true; - this.left_boot.visible = true; - } - - head.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - body.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - right_arm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - left_arm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - right_leg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - left_leg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - right_boot.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); - left_boot.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + + // Control part visibility based on the slot being rendered + this.head.visible = this.currentSlot == EquipmentSlot.HEAD; + this.body.visible = this.currentSlot == EquipmentSlot.CHEST; + this.right_arm.visible = this.currentSlot == EquipmentSlot.CHEST; + this.left_arm.visible = this.currentSlot == EquipmentSlot.CHEST; + this.right_leg.visible = this.currentSlot == EquipmentSlot.LEGS; + this.left_leg.visible = this.currentSlot == EquipmentSlot.LEGS; + this.right_boot.visible = this.currentSlot == EquipmentSlot.FEET; + this.left_boot.visible = this.currentSlot == EquipmentSlot.FEET; + + if (this.head.visible) head.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.body.visible) body.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.right_arm.visible) right_arm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.left_arm.visible) left_arm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.right_leg.visible) right_leg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.left_leg.visible) left_leg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.right_boot.visible) right_boot.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + if (this.left_boot.visible) left_boot.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/createnuclear/textures/models/armor/default_anti_radiation_suit.png b/src/main/resources/assets/createnuclear/textures/models/armor/default_anti_radiation_suit.png index df8abdb3d82ab053a1e50c78f33239dfd6897e50..b8a89e1934c724a3c56eed742c4b40ba2d699ed5 100644 GIT binary patch literal 3608 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 ZfB<6pkiQ=h;>uP4#)e3P(wi<({|A=aECT=l literal 2979 zcmchZ_dgVl1BZ`8#^H`+T~>ByX79bSLPoN3h>*zU>^(yw^UB`il6{iPD2{MvotZsK zWt{o#^G|$#c)y?5>-h_wBvWHuT52|G002O%ucu}9kBmc|xt2dY|EDO8s;E3lp3bnSy0x5|xbD9=zt|LrSSjd8vu;peW(mi^|mb=-k(G2hwlj>+v=9xQ1-clde{`<8Org zSwbB?u)DJa_4YhZF~e_6`J~Vf>uDXdoc?@2*_=2xlXq$n+!4;({rB5qrXU#C&|$Qw zY6f9iD!A_TJl9-;NhmO6uP2#goTsZ!;_RE;7)S1%A^-fi+lz%9?*N(!J077(K!40k zd6F}MG-amz&I4`+udS3c2M7jWLXkOO!poNq)LOZR1otVcc`l&6gSFa>P=jXSR1`t_ z#N?x0Nds3?@YqHf4u_r*>vZ}oTlsfgoF-Rlp%8X$a+BTQLgBvK7^*DoBj3(bF{v$% z2_g-~)-B-&z00B%Xvl+NtFOzh(kuGohs<6F*!;Ma@JKiFrwj~AoduWfLGY=12H4?^ zS}-F$^?%yDfn$9B6|Sy5^R3p_v7ThrvxdIL9TW6%cjlf;%76t|c3d{Cfm)9B(tH-z zDN;pdMocl{GJF4bJCU7!V0&=>1;tKZ7Atdt}J$?{l5}3Tx z(Yi0Qb#3HltF^UUi|e>if9%}#Gf}mDuTz=8?SE5ad8HtD+zAK<$eJ@ig3I04plTbQQLZ6({rKw6H8-)$dXg^T=;(o@pWkTs*A}J5g4R;6-#qnC=nI6>TDj&#{WdDOdz4 z3NX0uup~NoFn4qrWaPhd@pfkp)%@l>biJ84;V>)_l}7?_Ro@OcsV3sUnhGHu8^;o?bcxb*tntG<`j6axnP3yR%)o>MO&b$uU72y1; zj$bJ~I==eB#x`ROCRw4Qw*4i!%!jE7`2&RUR*%d%w{fd&96Z~1v7EP2;mP`I2dfCo z5zD!h)H0XAT9*8N%h(G2WLP*U!QgN05#<)itk<|Xw@Cpeqv^D@=nJ@+ZEEDI63>Ve zt;JjHG%&=*>7Pd40>@meY!_&jbY51l1s;S69$1RrA`_GAFOBaCW{0XazCeVlYnHMC zpz^(^uNXe#w+I5LL~O z`Q`iPQ^Ab@y`lyRniP_iFAwixhzEgt6jSV0^_lC;>2gWo_##_O2I5!bmRvZ$*EjUl zBp=nNv!tVz=que8-}VMwapQ%*M0kf}x?|xI5lU(M8KQ88zii>Ot!bJMew*eUd#rj? zww^2y&=ex-keg;I?H$GYAtNLB$+fzE*fbRnf0Z!h8JnomLRgk3kD!+r!-~cDqSQWw z5h!jB7G6$i>Oq!}9Zhs1*#oq|x({!w)4r(MNq8bolyj{KAz}1&0tl#}$6iLQIZd-9 zvyG2TmC%4YF|YdjxJsE1SAW{HN?9B^;}I&k4fpZ!J`<^!y||`jXlJ80nZculyvVkM z;|ud#&gWOjKD#AjDXnde&|{#WCAJ)555upFZ|g2Xb1vyi*wf5USxk=<^;Iz!LKdTL zfVjF*1OWI_!R70ND(*Khg^~DpNF;g0zFy;kJh18g@f3ScR1tR+NH^wm;pMjgsEwoF zoqKy}^hvT>juKucz-00$IADrSA0g^4{KF5FS|;;*+UQbaZLivDjkfkV?I+(qEpu|e zT><$O9eHK5RZPY~bIE0f2er=EfrYgp^F>S_-kDi*5KS?u18fi2E00J7;g3hg^4d?A z>c;Srz^OgyX9d`n#GnmSr?y^+VVnV>F-1Buu}(7Xgo)uMYu^pNSv49UkEjD7b09Pr z9qDgu0jsHgxt}oH(cFFxst; z>}w|fIH)~jwQN^fEF{MdLytDyHGMUk*No4;_oiQd)|=XW76LqcrJEeT^KiCKXovOYr+0Y5P(G@`*=)B47aZ3P;^*hu!I8{C_J5ZZ~d zLjGt3t91BfCJYbj#dvgoU#&a;%d9~@ky_r9=~*x471~cJWJ<=UmY=|San{%x$F}}> zHx5v3@o4M(%U~;;tVoP?9?2g@2D%Tw&$>lgyj(Q;x&6cM1`c&PT&F+VenyFTElB%- zV6~k0t%pnmq!uEN19VG;PemO8#0)vjPmj#Mi&7ez7rmjH`m(0c7grS9n6TM4nhH0@85@Lsxl@>9#}2vb*oP1g{DqzC&{l|lk zm0wtJOwgO$DxG5Fka~}n4fUCw3Th#0&;UnV7Yi5Vl$HrM{-XJm=NGlEi`}~Md8Ke= zHyRO;;Gw>>&~Rq_>a>YanmwrWWsuoJ^{87Er(VhMIq}0Ctkz8F7)XTv^>Z?r64Ys_ z`d5&6GxBD#PFBTTL*E8h7K*3wPLcmVgpmRO*Vkg)?eYIoo8rI51_EZ_PaV%jSQ-Br OfWEe|R)dCP^#1^lyRLu$ From d9ba39564a1d976d929620bc3a39a7e851e2867e Mon Sep 17 00:00:00 2001 From: MathisGredtYnov <113118860+MathisGredtYnov@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:38:22 +0200 Subject: [PATCH 107/171] fix: adjust arm dimensions and positions in AntiRadiationArmor model for better alignment --- .../equipment/armor/AntiRadiationArmorModel.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java index dffd88f0..7fa8caa8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorModel.java @@ -52,11 +52,11 @@ public static LayerDefinition createBodyLayer() { .texOffs(0, 36).addBox(-4.0F, 0.0F, -2.7F, 8.0F, 12.0F, 5.0F, new CubeDeformation(0.0F)) .texOffs(64, 0).addBox(-4.5F, -1.0F, -3.0F, 9.0F, 13.0F, 6.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 0.0F)); - PartDefinition right_arm = partdefinition.addOrReplaceChild("right_arm", CubeListBuilder.create().texOffs(45, 32).mirror().addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.45F)).mirror(false) - .texOffs(29, 32).mirror().addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.55F)).mirror(false), PartPose.offset(7.0F, 2.0F, 0.0F)); + PartDefinition right_arm = partdefinition.addOrReplaceChild("right_arm", CubeListBuilder.create().texOffs(45, 32).mirror().addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.45F)).mirror(false) + .texOffs(29, 32).mirror().addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.55F)).mirror(false), PartPose.offset(-5.0F, 2.0F, 0.0F)); - PartDefinition left_arm = partdefinition.addOrReplaceChild("left_arm", CubeListBuilder.create().texOffs(45, 32).addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)) - .texOffs(29, 32).addBox(-2.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.5F)), PartPose.offset(-7.0F, 2.0F, 0.0F)); + PartDefinition left_arm = partdefinition.addOrReplaceChild("left_arm", CubeListBuilder.create().texOffs(45, 32).addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.4F)) + .texOffs(29, 32).addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.5F)), PartPose.offset(5.0F, 2.0F, 0.0F)); PartDefinition right_leg = partdefinition.addOrReplaceChild("right_leg", CubeListBuilder.create().texOffs(29, 48).mirror().addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).mirror(false) .texOffs(45, 48).mirror().addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)).mirror(false), PartPose.offset(1.9F, 12.0F, 0.0F)); @@ -64,9 +64,6 @@ public static LayerDefinition createBodyLayer() { PartDefinition left_leg = partdefinition.addOrReplaceChild("left_leg", CubeListBuilder.create().texOffs(29, 48).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)) .texOffs(45, 48).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(-1.9F, 12.0F, 0.0F)); - // Boots: separate parts, but expressed in the legs' pivot frame (±1.9, 12, 0) so that - // copyFrom(leg) in renderToBuffer makes them inherit the leg's walk animation while - // remaining independently toggleable. (Same world geometry as the raw Blockbench export.) partdefinition.addOrReplaceChild("left_boot", CubeListBuilder.create().texOffs(61, 39).addBox(-2.0F, 8.3F, -2.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(-1.9F, 12.0F, 0.0F)); partdefinition.addOrReplaceChild("right_boot", CubeListBuilder.create().texOffs(61, 39).mirror().addBox(-2.0F, 8.3F, -2.0F, 4.0F, 4.0F, 4.0F, new CubeDeformation(0.25F)).mirror(false), PartPose.offset(1.9F, 12.0F, 0.0F)); From de768ac03cd5163f1e6fd8199d7578fe9e2ecd46 Mon Sep 17 00:00:00 2001 From: Dimitri Date: Fri, 26 Jun 2026 14:57:20 +0200 Subject: [PATCH 108/171] adding the iodine effect icon and removing all the protection --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +++--- .../assets/createnuclear/lang/en_ud.json | 18 +++++++++--------- .../assets/createnuclear/lang/en_us.json | 18 +++++++++--------- .../nuclearteam/createnuclear/CNEffects.java | 2 +- .../nuclearteam/createnuclear/CNPotions.java | 8 ++++---- .../createnuclear/lang/default/potion.json | 18 +++++++++--------- .../textures/mob_effect/iodine.png | Bin 0 -> 3444 bytes .../textures/mob_effect/iodine_protection.png | Bin 742 -> 0 bytes 8 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 src/main/resources/assets/createnuclear/textures/mob_effect/iodine.png delete mode 100644 src/main/resources/assets/createnuclear/textures/mob_effect/iodine_protection.png diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index aa5861ba..1fd96b9c 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-26T09:32:34.7876497 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-26T14:52:57.0934339 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -959ed12b8547f580bc9635aad8e754c3d472f377 assets/createnuclear/lang/en_ud.json -b742d62f744385d54f53365b757ca3b8f89296b8 assets/createnuclear/lang/en_us.json +279d589e70160128b89f54048159786a2283f68a assets/createnuclear/lang/en_ud.json +b8c4b52e70948811102c484fff9a90bf5790321f assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index d8c16aa3..bedb2760 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -313,7 +313,7 @@ "createnuclear.tooltip.typeRod": "%s :ǝdʎ⟘ poᴚ", "death.attack.createnuclear.fan_radiation": "ʇsɐןq uoıʇɐıpɐɹ ɯoɹɟ pǝıp %1$s", "death.attack.createnuclear.radiation": "uoıʇɐıpɐɹ ɯoɹɟ pǝıp %1$s", - "effect.createnuclear.iodine_protection": "ǝuıpoI uoıʇɔǝʇoɹԀ", + "effect.createnuclear.iodine": "ǝuıpoI", "effect.createnuclear.radiation": "uoıʇɐıpɐᴚ", "emi.category.createnuclear.fan_enriched": "buıɥɔıɹuƎ ʞןnᗺ", "emi.category.createnuclear.snow_powder": "uɐɟ ɔıuǝboʎɹƆ", @@ -387,23 +387,23 @@ "item.createnuclear.wolf_irradiated_spawn_egg": "bbƎ uʍɐdS ɟןoM pǝʇɐıpɐɹɹI", "item.createnuclear.yellow_cloth": "ɥʇoןƆ ʍoןןǝʎ", "item.createnuclear.yellowcake": "ǝʞɐɔʍoןןǝʎ", - "item.minecraft.lingering_potion.effect.potion_of_protection_iodine": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo uoıʇoԀ buıɹǝbuıꞀ", - "item.minecraft.lingering_potion.effect.potion_of_protection_iodine_augment": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo uoıʇoԀ buıɹǝbuıꞀ", + "item.minecraft.lingering_potion.effect.potion_of_iodine": "ǝuıpoI ɟo uoıʇoԀ buıɹǝbuıꞀ", + "item.minecraft.lingering_potion.effect.potion_of_iodine_augment": "ǝuıpoI ɟo uoıʇoԀ buıɹǝbuıꞀ", "item.minecraft.lingering_potion.effect.potion_of_radiation_1": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ buıɹǝbuıꞀ", "item.minecraft.lingering_potion.effect.potion_of_radiation_2": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ buıɹǝbuıꞀ", "item.minecraft.lingering_potion.effect.potion_of_radiation_augment_1": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ buıɹǝbuıꞀ", - "item.minecraft.potion.effect.potion_of_protection_iodine": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo uoıʇoԀ", - "item.minecraft.potion.effect.potion_of_protection_iodine_augment": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo uoıʇoԀ", + "item.minecraft.potion.effect.potion_of_iodine": "ǝuıpoI ɟo uoıʇoԀ", + "item.minecraft.potion.effect.potion_of_iodine_augment": "ǝuıpoI ɟo uoıʇoԀ", "item.minecraft.potion.effect.potion_of_radiation_1": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ", "item.minecraft.potion.effect.potion_of_radiation_2": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ", "item.minecraft.potion.effect.potion_of_radiation_augment_1": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ", - "item.minecraft.splash_potion.effect.potion_of_protection_iodine": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo uoıʇoԀ ɥsɐןdS", - "item.minecraft.splash_potion.effect.potion_of_protection_iodine_augment": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo uoıʇoԀ ɥsɐןdS", + "item.minecraft.splash_potion.effect.potion_of_iodine": "ǝuıpoI ɟo uoıʇoԀ ɥsɐןdS", + "item.minecraft.splash_potion.effect.potion_of_iodine_augment": "ǝuıpoI ɟo uoıʇoԀ ɥsɐןdS", "item.minecraft.splash_potion.effect.potion_of_radiation_1": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ ɥsɐןdS", "item.minecraft.splash_potion.effect.potion_of_radiation_2": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ ɥsɐןdS", "item.minecraft.splash_potion.effect.potion_of_radiation_augment_1": "uoıʇɐıpɐᴚ ɟo uoıʇoԀ ɥsɐןdS", - "item.minecraft.tipped_arrow.effect.potion_of_protection_iodine": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo ʍoɹɹⱯ", - "item.minecraft.tipped_arrow.effect.potion_of_protection_iodine_augment": "ǝuıpoI uoıʇɔǝʇoɹԀ ɟo ʍoɹɹⱯ", + "item.minecraft.tipped_arrow.effect.potion_of_iodine": "ǝuıpoI ɟo ʍoɹɹⱯ", + "item.minecraft.tipped_arrow.effect.potion_of_iodine_augment": "ǝuıpoI ɟo ʍoɹɹⱯ", "item.minecraft.tipped_arrow.effect.potion_of_radiation_1": "uoıʇɐıpɐᴚ ɟo ʍoɹɹⱯ", "item.minecraft.tipped_arrow.effect.potion_of_radiation_2": "uoıʇɐıpɐᴚ ɟo ʍoɹɹⱯ", "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "uoıʇɐıpɐᴚ ɟo ʍoɹɹⱯ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 0a68dc6d..1b01bd97 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -313,7 +313,7 @@ "createnuclear.tooltip.typeRod": "Rod Type: %s", "death.attack.createnuclear.fan_radiation": "%1$s died from radiation blast", "death.attack.createnuclear.radiation": "%1$s died from radiation", - "effect.createnuclear.iodine_protection": "Protection Iodine", + "effect.createnuclear.iodine": "Iodine", "effect.createnuclear.radiation": "Radiation", "emi.category.createnuclear.fan_enriched": "Bulk Enriching", "emi.category.createnuclear.snow_powder": "Cryogenic fan", @@ -387,23 +387,23 @@ "item.createnuclear.wolf_irradiated_spawn_egg": "Irradiated Wolf Spawn Egg", "item.createnuclear.yellow_cloth": "Yellow Cloth", "item.createnuclear.yellowcake": "Yellowcake", - "item.minecraft.lingering_potion.effect.potion_of_protection_iodine": "Lingering Potion of Protection Iodine", - "item.minecraft.lingering_potion.effect.potion_of_protection_iodine_augment": "Lingering Potion of Protection Iodine", + "item.minecraft.lingering_potion.effect.potion_of_iodine": "Lingering Potion of Iodine", + "item.minecraft.lingering_potion.effect.potion_of_iodine_augment": "Lingering Potion of Iodine", "item.minecraft.lingering_potion.effect.potion_of_radiation_1": "Lingering Potion of Radiation", "item.minecraft.lingering_potion.effect.potion_of_radiation_2": "Lingering Potion of Radiation", "item.minecraft.lingering_potion.effect.potion_of_radiation_augment_1": "Lingering Potion of Radiation", - "item.minecraft.potion.effect.potion_of_protection_iodine": "Potion of Protection Iodine", - "item.minecraft.potion.effect.potion_of_protection_iodine_augment": "Potion of Protection Iodine", + "item.minecraft.potion.effect.potion_of_iodine": "Potion of Iodine", + "item.minecraft.potion.effect.potion_of_iodine_augment": "Potion of Iodine", "item.minecraft.potion.effect.potion_of_radiation_1": "Potion of Radiation", "item.minecraft.potion.effect.potion_of_radiation_2": "Potion of Radiation", "item.minecraft.potion.effect.potion_of_radiation_augment_1": "Potion of Radiation", - "item.minecraft.splash_potion.effect.potion_of_protection_iodine": "Splash Potion of Protection Iodine", - "item.minecraft.splash_potion.effect.potion_of_protection_iodine_augment": "Splash Potion of Protection Iodine", + "item.minecraft.splash_potion.effect.potion_of_iodine": "Splash Potion of Iodine", + "item.minecraft.splash_potion.effect.potion_of_iodine_augment": "Splash Potion of Iodine", "item.minecraft.splash_potion.effect.potion_of_radiation_1": "Splash Potion of Radiation", "item.minecraft.splash_potion.effect.potion_of_radiation_2": "Splash Potion of Radiation", "item.minecraft.splash_potion.effect.potion_of_radiation_augment_1": "Splash Potion of Radiation", - "item.minecraft.tipped_arrow.effect.potion_of_protection_iodine": "Arrow of Protection Iodine", - "item.minecraft.tipped_arrow.effect.potion_of_protection_iodine_augment": "Arrow of Protection Iodine", + "item.minecraft.tipped_arrow.effect.potion_of_iodine": "Arrow of Iodine", + "item.minecraft.tipped_arrow.effect.potion_of_iodine_augment": "Arrow of Iodine", "item.minecraft.tipped_arrow.effect.potion_of_radiation_1": "Arrow of Radiation", "item.minecraft.tipped_arrow.effect.potion_of_radiation_2": "Arrow of Radiation", "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", diff --git a/src/main/java/net/nuclearteam/createnuclear/CNEffects.java b/src/main/java/net/nuclearteam/createnuclear/CNEffects.java index 1184ab2c..b2d72e95 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNEffects.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNEffects.java @@ -12,7 +12,7 @@ public class CNEffects { public static final DeferredRegister EFFECTS = DeferredRegister.create(ForgeRegistries.MOB_EFFECTS, CreateNuclear.MOD_ID); public static final RegistryObject RADIATION = EFFECTS.register("radiation", RadiationEffect::new); - public static final RegistryObject IODINE_PROTECTION = EFFECTS.register("iodine_protection", IodineEffect::new); + public static final RegistryObject IODINE = EFFECTS.register("iodine", IodineEffect::new); public static void register(IEventBus eventBus) { EFFECTS.register(eventBus); diff --git a/src/main/java/net/nuclearteam/createnuclear/CNPotions.java b/src/main/java/net/nuclearteam/createnuclear/CNPotions.java index 981ddd1f..5b5f7091 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNPotions.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNPotions.java @@ -22,11 +22,11 @@ public class CNPotions { public static final RegistryObject POTION_2 = CN_POTIONS.register("potion_of_radiation_2", () -> new Potion(new MobEffectInstance(CNEffects.RADIATION.get(), 410, 1))); - public static final RegistryObject POTION_1_IODINE = CN_POTIONS.register("potion_of_protection_iodine", - () -> new Potion(new MobEffectInstance(CNEffects.IODINE_PROTECTION.get(), 900)) + public static final RegistryObject POTION_1_IODINE = CN_POTIONS.register("potion_of_iodine", + () -> new Potion(new MobEffectInstance(CNEffects.IODINE.get(), 900)) ); - public static final RegistryObject POTION_AUGMENT_1_IODINE = CN_POTIONS.register("potion_of_protection_iodine_augment", - () -> new Potion(new MobEffectInstance(CNEffects.IODINE_PROTECTION.get(), 1800)) + public static final RegistryObject POTION_AUGMENT_1_IODINE = CN_POTIONS.register("potion_of_iodine_augment", + () -> new Potion(new MobEffectInstance(CNEffects.IODINE.get(), 1800)) ); public static void register(IEventBus eventBus) { diff --git a/src/main/resources/assets/createnuclear/lang/default/potion.json b/src/main/resources/assets/createnuclear/lang/default/potion.json index 40d1bb18..af7439ee 100644 --- a/src/main/resources/assets/createnuclear/lang/default/potion.json +++ b/src/main/resources/assets/createnuclear/lang/default/potion.json @@ -17,15 +17,15 @@ "item.minecraft.tipped_arrow.effect.potion_of_radiation_augment_1": "Arrow of Radiation", "item.minecraft.tipped_arrow.effect.potion_of_radiation_2": "Arrow of Radiation", - "effect.createnuclear.iodine_protection": "Protection Iodine", + "effect.createnuclear.iodine": "Iodine", - "item.minecraft.potion.effect.potion_of_protection_iodine": "Potion of Protection Iodine", - "item.minecraft.splash_potion.effect.potion_of_protection_iodine": "Splash Potion of Protection Iodine", - "item.minecraft.lingering_potion.effect.potion_of_protection_iodine": "Lingering Potion of Protection Iodine", - "item.minecraft.tipped_arrow.effect.potion_of_protection_iodine": "Arrow of Protection Iodine", + "item.minecraft.potion.effect.potion_of_iodine": "Potion of Iodine", + "item.minecraft.splash_potion.effect.potion_of_iodine": "Splash Potion of Iodine", + "item.minecraft.lingering_potion.effect.potion_of_iodine": "Lingering Potion of Iodine", + "item.minecraft.tipped_arrow.effect.potion_of_iodine": "Arrow of Iodine", - "item.minecraft.potion.effect.potion_of_protection_iodine_augment": "Potion of Protection Iodine", - "item.minecraft.splash_potion.effect.potion_of_protection_iodine_augment": "Splash Potion of Protection Iodine", - "item.minecraft.lingering_potion.effect.potion_of_protection_iodine_augment": "Lingering Potion of Protection Iodine", - "item.minecraft.tipped_arrow.effect.potion_of_protection_iodine_augment": "Arrow of Protection Iodine" + "item.minecraft.potion.effect.potion_of_iodine_augment": "Potion of Iodine", + "item.minecraft.splash_potion.effect.potion_of_iodine_augment": "Splash Potion of Iodine", + "item.minecraft.lingering_potion.effect.potion_of_iodine_augment": "Lingering Potion of Iodine", + "item.minecraft.tipped_arrow.effect.potion_of_iodine_augment": "Arrow of Iodine" } \ No newline at end of file diff --git a/src/main/resources/assets/createnuclear/textures/mob_effect/iodine.png b/src/main/resources/assets/createnuclear/textures/mob_effect/iodine.png new file mode 100644 index 0000000000000000000000000000000000000000..9bcf83221c1e5b47a3b209abf3c48e903641b3e0 GIT binary patch literal 3444 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%0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01FZT01FZU(%pXi0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600MwXL_t(Ijiu6ENKcTtW;Qi0F?_X7{lLl|RN%#i;9Mmt>`05bqXiQ{bI z)8qtFBOTU*7ek4E0)fjej^kh^1h!!IgwVKSrZp){np!R?ZQXYtlLY~>*G+Vtak5M~ z#$WUDc(_gxIO)yf&fY1^HlzT~q7S0&H zRa*+c`r!TEsY6@)F%)bD9cxD@tYP$9UXv3vI-Dz8RVl`50DOO%PUnmMVCH76W#B`T zylZ100)ZTS{wzKRa*(1r;yH>ELUf_rVyKYh)dY}+RaGwnuC|_L+ugU(*Pq7MksL%( zLo!E^q7*s+mA8SHWG4WL5R!SRs;me&ck(FPU>-zQcM@`%BBATZS5+b>1ff;f;gIBN z0>lBRuQD0>``HO&3@wM7m@x1JnYwjI&Zd#h%t4zDA*;8 z$}w*MbBrO+7-)qZj%cC=KoEfTdV#nA9Iv++Qz>fpF0;zIPNC@<%74Y=FL41_%=`d4 We0uQt=`I!k0000ls47YguJQ{>uF6ifOi{PD zbs{}UK3djZt>nqvW6s4qD1-ZCERRDRmN*N_31y=g{ z<>lpi<;HsXMd|v6mX?v90`zGE;%B09k2gXakl<5wp<;IRwdJb`TMuUx6%m z$bfql zS>oY8(T-KM{ee&cTe;p{mMKY>7kcDyNo!!D`F&PLG;RljAtlV2X)zj{Ux`>DEM<`193ZeHMJd|~|Z@KTLM z?e4xYT}@>R?qn}I8o~U|AX7Z}SF6xAiMI~y>EZKpY?1?c^M4C8b$s6!xlg|P|DB_C z!Nos>uFZdZT2xN+*csRN3OhxrA9rU()VWN5^ttq`oZro>%k!A0KN9|M+e+Nms5$%7 d&IRdz7)^Hu?cT|~xdfEhJYD@<);T3K0RV(~4EF#4 From 196171181e2b6a8c6c6b88e6602d45ce97efe62b Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 26 Jun 2026 20:54:49 +0200 Subject: [PATCH 109/171] fix: award placement advancements via the reactor controller, not the placed part Add MultiblockHelpers.handleAdvancedPlacedBy(pos, level, entity), which resolves the controller for a given multiblock part and forwards the "placed by" advancement trigger to CNAdvancementBehaviour.setPlacedBy using the controller's position. Update setPlacedBy(...) in ReactorAlarm, ReactorCasing, ReactorControllerBlock, ReactorCooler, ReactorFrame, ReactorFluidInput, ReactorRodInput, ReactorOutput and ReinforcedGlassBlock to call this new helper instead of calling CNAdvancementBehaviour.setPlacedBy directly on the placed part's own position, so the advancement state is tracked consistently on the controller's behaviour instance regardless of which part was placed. Also fix CNAdvancementBehaviour.award(...): it previously checked `advancements.contains(advancement)` (the per-instance award list, unrelated to whether the advancement was already granted) instead of checking the player's actual award state, which could award the same advancement repeatedly or skip awarding it depending on that list's contents. Now checks `!advancement.isAlreadyAwardedTo(player)`. Remove an unused `players` local variable from ReactorOutput.onRemove(...). --- .../content/multiblock/MultiblockHelpers.java | 15 +++++++++++++++ .../content/multiblock/alarm/ReactorAlarm.java | 2 +- .../content/multiblock/casing/ReactorCasing.java | 3 ++- .../controller/ReactorControllerBlock.java | 3 ++- .../content/multiblock/cooler/ReactorCooler.java | 3 ++- .../content/multiblock/frame/ReactorFrame.java | 3 ++- .../multiblock/input/fluid/ReactorFluidInput.java | 2 +- .../multiblock/input/item/ReactorRodInput.java | 2 +- .../content/multiblock/output/ReactorOutput.java | 3 +-- .../multiblock/pattern/ReactorPattern.java | 1 + .../reinforced/ReinforcedGlassBlock.java | 3 ++- .../advancement/CNAdvancementBehaviour.java | 2 +- 12 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java index 1bf4928b..85129254 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/MultiblockHelpers.java @@ -1,10 +1,15 @@ package net.nuclearteam.createnuclear.content.multiblock; +import net.minecraft.world.entity.LivingEntity; +import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; +import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiConsumer; @@ -49,4 +54,14 @@ public static ReactorControllerBlockEntity getControllerForPart(Level level, Blo return null; } + + public static void handleAdvancedPlacedBy(BlockPos pos, Level level, @Nullable LivingEntity entity) { + if (entity == null) return; + + ReactorControllerBlockEntity controller = getControllerForPart(level, pos); + + if (controller != null) { + CNAdvancementBehaviour.setPlacedBy(level, controller.getBlockPos(), entity); + } + } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java index 9f22b911..e3e4c803 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java @@ -48,7 +48,7 @@ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState s @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } // Unregisters this alarm from the multiblock controller on removal (piston, explosion, etc.) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java index 67d3d11f..84468301 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java @@ -20,6 +20,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.nuclearteam.createnuclear.CNBlockEntityTypes; import net.nuclearteam.createnuclear.CNBlocks; +import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.input.item.ReactorRodInput; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; @@ -51,7 +52,7 @@ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldS @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } @Override // called when the player destroys the block, with or without a tool diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java index d0f8299d..f34804e3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlock.java @@ -27,6 +27,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.nuclearteam.createnuclear.*; import net.nuclearteam.createnuclear.content.multiblock.IHeat; +import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.ReactorAssembler; import net.nuclearteam.createnuclear.content.multiblock.input.fluid.PersistentFluidLocks; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; @@ -161,7 +162,7 @@ public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState n @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); if (state.getValue(ASSEMBLED)) return; ReactorAssembler.assemble(pos, level); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java index 44c711c3..e98a90c4 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java @@ -9,6 +9,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; @@ -30,7 +31,7 @@ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldS @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } @Override // called when the player destroys the block, with or without a tool diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java index e4e9a675..4e6c7d69 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java @@ -21,6 +21,7 @@ import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.Property; import net.nuclearteam.createnuclear.CNBlockEntityTypes; +import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; @@ -115,7 +116,7 @@ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldS @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @javax.annotation.Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } @Override // called when the player destroys the block, with or without a tool diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java index 7a3d05ec..92b9e7f2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java @@ -46,7 +46,7 @@ public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldS @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java index d44f550c..9392a12a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInput.java @@ -74,7 +74,7 @@ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldS @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java index e2169e6f..95f5dbe8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java @@ -64,7 +64,7 @@ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldS @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @javax.annotation.Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } @Override @@ -76,7 +76,6 @@ public void playerDestroy(Level level, Player player, BlockPos pos, BlockState s @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); - List players = pLevel.players(); MultiblockHelpers.handleRemoval(pPos, pLevel, ReactorControllerBlockEntity::removeOutput); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java index c7768553..97628c18 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/pattern/ReactorPattern.java @@ -2,6 +2,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reinforced/ReinforcedGlassBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reinforced/ReinforcedGlassBlock.java index e7bdd914..ae7d0c48 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reinforced/ReinforcedGlassBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reinforced/ReinforcedGlassBlock.java @@ -14,6 +14,7 @@ import net.minecraft.world.level.material.FluidState; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import javax.annotation.Nullable; @@ -26,6 +27,6 @@ public ReinforcedGlassBlock(Properties properties) { @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); - CNAdvancementBehaviour.setPlacedBy(level, pos, pPlacer); + MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancementBehaviour.java b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancementBehaviour.java index e7b1a4f9..9abf48ef 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancementBehaviour.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/advancement/CNAdvancementBehaviour.java @@ -103,7 +103,7 @@ private Player getPlayer() { } private void award(CreateNuclearAdvancement advancement, Player player) { - if (advancements.contains(advancement)) advancement.awardTo(player); + if (!advancement.isAlreadyAwardedTo(player)) advancement.awardTo(player); removeAwarded(); } From 89b68af55458756b81249792a5799d9ed8749cfc Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 26 Jun 2026 23:54:50 +0200 Subject: [PATCH 110/171] chore: add a second client run config for local multiplayer testing Add a `client2` run config in build.gradle (parented to `client`, using a separate `run/client2` working directory and the `Dev2` username), so two game clients can be launched side by side for testing multiplayer-dependent behavior (e.g. reactor assembly synced across clients). Ignore the new `run/client2` working directory in .gitignore. --- .gitignore | 1 + build.gradle | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 1d1245d2..00f7ff92 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ run/.mixin.out run/gametest run/logs run/server +run/client2 # LLM .claude/* diff --git a/build.gradle b/build.gradle index 317252d5..5343aceb 100644 --- a/build.gradle +++ b/build.gradle @@ -117,6 +117,12 @@ minecraft { property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" } + client2 { + parent runs.client + workingDirectory project.file('run/client2') + args '--username', 'Dev2' + } + server { workingDirectory project.file('run/server') //property 'forge.enabledGameTestNamespaces', mod_id From 37b541be201cf98fbbcf4ff35b5d68903f551e68 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 27 Jun 2026 00:03:41 +0200 Subject: [PATCH 111/171] style: import BlockModelBuilder instead of using its fully qualified name Replace repeated fully qualified references to net.minecraftforge.client.model.generators.BlockModelBuilder in PaletteBlockPattern with a proper import. No behavioral change. --- .../content/decoration/palettes/PaletteBlockPattern.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java index 4ff53e5c..4359b8dc 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PaletteBlockPattern.java @@ -18,6 +18,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraft.core.Direction.Axis; +import net.minecraftforge.client.model.generators.BlockModelBuilder; import net.minecraftforge.client.model.generators.ConfiguredModel; import net.nuclearteam.createnuclear.CreateNuclear; @@ -141,7 +142,7 @@ private PaletteBlockPattern connectedTextures(Function { - net.minecraftforge.client.model.generators.BlockModelBuilder builder = prov.models() + BlockModelBuilder builder = prov.models() .cubeAll(createName(variant), all); if (isTranslucent) builder.renderType("translucent"); prov.simpleBlock(ctx.get(), builder); @@ -153,7 +154,7 @@ public IBlockStateProvider cubeBottomTop(String variant) { ResourceLocation bottom = toLocation(variant, textures[1]); ResourceLocation top = toLocation(variant, textures[2]); return (ctx, prov) -> { - net.minecraftforge.client.model.generators.BlockModelBuilder builder = prov.models() + BlockModelBuilder builder = prov.models() .cubeBottomTop(createName(variant), side, bottom, top); if (isTranslucent) builder.renderType("translucent"); prov.simpleBlock(ctx.get(), builder); @@ -167,7 +168,7 @@ public IBlockStateProvider pillar(String variant) { return (ctx, prov) -> prov.getVariantBuilder(ctx.getEntry()) .forAllStatesExcept(state -> { Axis axis = state.getValue(BlockStateProperties.AXIS); - net.minecraftforge.client.model.generators.BlockModelBuilder builder; + BlockModelBuilder builder; if (axis == Axis.Y) { builder = prov.models().cubeColumn(createName(variant), side, end); if (isTranslucent) builder.renderType("translucent"); @@ -192,7 +193,7 @@ public IBlockStateProvider cubeColumn(String variant) { ResourceLocation side = toLocation(variant, textures[0]); ResourceLocation end = toLocation(variant, textures[1]); return (ctx, prov) -> { - net.minecraftforge.client.model.generators.BlockModelBuilder builder = prov.models() + BlockModelBuilder builder = prov.models() .cubeColumn(createName(variant), side, end); if (isTranslucent) builder.renderType("translucent"); prov.simpleBlock(ctx.get(), builder); From 6219e3567a8d6b883ff0c42fbb4c1606c3cb7ccb Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 27 Jun 2026 11:54:13 +0200 Subject: [PATCH 112/171] chore: bump mod version to 2.0.14-beta --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d0a8924c..95fddd29 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.13-beta +mod_version=2.0.14-beta # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html From 7dcf7e9dc1c9c8f408ca565d90424e991d291725 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 27 Jun 2026 14:02:57 +0200 Subject: [PATCH 113/171] fix: update iodine mob effect icon texture (fix blur inventorie icon effet) --- .../textures/mob_effect/iodine.png | Bin 3444 -> 3409 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/createnuclear/textures/mob_effect/iodine.png b/src/main/resources/assets/createnuclear/textures/mob_effect/iodine.png index 9bcf83221c1e5b47a3b209abf3c48e903641b3e0..276fa23a52830171346b67769fb3304561929c1e 100644 GIT binary patch delta 3398 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 delta 3433 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 Date: Sat, 27 Jun 2026 23:03:56 +0200 Subject: [PATCH 114/171] feat: add Biome Restore Cell item to revert irradiated biome zones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add BiomeRestoreCellItem (content/biome), a chargeable item that, when used, calls the new BiomeIrradiationService.restoreArea(serverLevel, pos) to revert the biome of the chunk(s) the player is standing in back to their original noise-generated biome, consuming one charge per successful use. Optionally restores a circular area of chunks around the player instead of just the current one, both configurable via the new CBiomeRestore server config (maxCharge, alwaysShowBar, restoreInCircle, restoreRadiusChunks). To make this possible, track which chunks were irradiated: - PersistentIrradiatedZones (a SavedData) persists the set of irradiated chunk positions per level, written whenever BiomeIrradiationService applies an irradiated biome override and cleared as chunks get restored. - OriginalBiomeLookup.resolve(level, pos) returns the original (non-irradiated) biome for a position by re-sampling the noise biome source if that position is inside a tracked zone, or the regular biome otherwise — for callers that need the "real" biome regardless of the irradiation overlay. Register the item with four charge-tier item models (quarter/half/ three_quarters/full) driven by a new client-side createnuclear:biome_restore item property (CreateNuclearClient.biomeRestoreItemProperties), mirroring the existing pattern used for the anti-radiation armor's cloth_color property. Split CreateNuclearClient.registerItemProperties() into clothItemProperties()/biomeRestoreItemProperties() accordingly, and regenerate the lang/model datagen output for the new item. --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 11 ++- .../assets/createnuclear/lang/en_ud.json | 1 + .../assets/createnuclear/lang/en_us.json | 1 + .../models/item/biome_restore_cell.json | 32 ++++++++ .../models/item/biome_restore_cell/full.json | 6 ++ .../models/item/biome_restore_cell/half.json | 6 ++ .../item/biome_restore_cell/quarter.json | 6 ++ .../biome_restore_cell/three_quarters.json | 6 ++ .../nuclearteam/createnuclear/CNItems.java | 40 +++++++++- .../createnuclear/CreateNuclearClient.java | 28 ++++++- .../content/biome/BiomeRestoreCellItem.java | 75 ++++++++++++++++++ .../infrastructure/config/CBiomeRestore.java | 24 ++++++ .../infrastructure/config/CNCServer.java | 3 + .../biome/BiomeIrradiationService.java | 48 +++++++++++ .../worldgen/biome/OriginalBiomeLookup.java | 24 ++++++ .../biome/PersistentIrradiatedZones.java | 72 +++++++++++++++++ .../item/biome_restore_cell/empty.png | Bin 0 -> 835 bytes .../textures/item/biome_restore_cell/full.png | Bin 0 -> 807 bytes .../textures/item/biome_restore_cell/half.png | Bin 0 -> 815 bytes .../item/biome_restore_cell/quarter.png | Bin 0 -> 841 bytes .../biome_restore_cell/three_quarters.png | Bin 0 -> 819 bytes 21 files changed, 376 insertions(+), 7 deletions(-) create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/PersistentIrradiatedZones.java create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/empty.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/full.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/half.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/quarter.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/three_quarters.png diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 1fd96b9c..4beeb6b5 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-26T14:52:57.0934339 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-27T22:58:21.7694379 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -279d589e70160128b89f54048159786a2283f68a assets/createnuclear/lang/en_ud.json -b8c4b52e70948811102c484fff9a90bf5790321f assets/createnuclear/lang/en_us.json +dc54adf8c8c1b59d29350e21b25cff0944a33559 assets/createnuclear/lang/en_ud.json +599851e1479c4ce135a120f7ab850b3043897965 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json @@ -119,6 +119,11 @@ d234edb3b6bc81b7300ee65722973b66db0b82d9 assets/createnuclear/models/block/urani a4d5ee44c830e329034a46792280edea53343034 assets/createnuclear/models/block/uranium_ore.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/item/autunite.json 30b11d8da5d02a3e9cebb739b3b9efbee087573c assets/createnuclear/models/item/autunite_pillar.json +28aecd314b7f04b49ab32f2edd943b9281d49c65 assets/createnuclear/models/item/biome_restore_cell.json +a37e2ee1f055b543b19d919e7755de6f60147263 assets/createnuclear/models/item/biome_restore_cell/full.json +caa3620ba4350002f5ac7016be82ab19cd4ae957 assets/createnuclear/models/item/biome_restore_cell/half.json +2969af139b314746afbf862710e8cf2fe7694d7c assets/createnuclear/models/item/biome_restore_cell/quarter.json +a34a98be95112a5ba17cac7eaa78de8d5550ca79 assets/createnuclear/models/item/biome_restore_cell/three_quarters.json 3036f3b383b40ca2021856366cd0f01cb279285b assets/createnuclear/models/item/black_cloth.json 3a5955f81eeed80e907bf8e2ee4df14fe42843f0 assets/createnuclear/models/item/blue_cloth.json 8cdcca32a87171e2c709e762165330b2f0389f90 assets/createnuclear/models/item/brown_cloth.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index bedb2760..4b5bae1d 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -327,6 +327,7 @@ "fluid.createnuclear.uranium": "ɯnıuɐɹ∩ pınbıꞀ", "gui.createnuclear.reactor_controller.title": "ɹǝןןoɹʇuoƆ ɹoʇɔɐǝᴚ", "gui.createnuclear.reactor_input.title": "ǝbɐɹoʇS ʇnduI ɹoʇɔɐǝᴚ", + "item.createnuclear.biome_restore_cell": "ןןǝƆ ǝɹoʇsǝᴚ ǝɯoıᗺ", "item.createnuclear.black_cloth": "ɥʇoןƆ ʞɔɐןᗺ", "item.createnuclear.blue_cloth": "ɥʇoןƆ ǝnןᗺ", "item.createnuclear.brown_cloth": "ɥʇoןƆ uʍoɹᗺ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 1b01bd97..174c4cec 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -327,6 +327,7 @@ "fluid.createnuclear.uranium": "Liquid Uranium", "gui.createnuclear.reactor_controller.title": "Reactor Controller", "gui.createnuclear.reactor_input.title": "Reactor Input Storage", + "item.createnuclear.biome_restore_cell": "Biome Restore Cell", "item.createnuclear.black_cloth": "Black Cloth", "item.createnuclear.blue_cloth": "Blue Cloth", "item.createnuclear.brown_cloth": "Brown Cloth", diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json new file mode 100644 index 00000000..4e0bf8e0 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:item/generated", + "overrides": [ + { + "model": "createnuclear:item/biome_restore_cell/quarter", + "predicate": { + "createnuclear:biome_restore": 0.25 + } + }, + { + "model": "createnuclear:item/biome_restore_cell/half", + "predicate": { + "createnuclear:biome_restore": 0.5 + } + }, + { + "model": "createnuclear:item/biome_restore_cell/three_quarters", + "predicate": { + "createnuclear:biome_restore": 0.75 + } + }, + { + "model": "createnuclear:item/biome_restore_cell/full", + "predicate": { + "createnuclear:biome_restore": 1.0 + } + } + ], + "textures": { + "layer0": "createnuclear:item/biome_restore_cell/empty" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json new file mode 100644 index 00000000..057d5cf5 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_restore_cell/full" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json new file mode 100644 index 00000000..2364e432 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_restore_cell/half" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json new file mode 100644 index 00000000..a5d1a4d9 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_restore_cell/quarter" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json new file mode 100644 index 00000000..9f589b37 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_restore_cell/three_quarters" + } +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index eeb96926..b81652df 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -1,6 +1,5 @@ package net.nuclearteam.createnuclear; -import com.simibubi.create.foundation.data.AssetLookup; import com.tterrag.registrate.util.entry.ItemEntry; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; @@ -22,6 +21,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.ForgeSpawnEggItem; +import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import net.nuclearteam.createnuclear.api.data.recipe.SmithingClothRecipeBuilder; import net.nuclearteam.createnuclear.content.radiation.RadiationItem; @@ -85,6 +85,36 @@ private static NonNullBiConsumer, Regis }; } + /** + * Generates the per-tier model overrides for the biome restore cell, driven by the + * client-side {@code createnuclear:charge} item property (see {@code CreateNuclearClient}). + * Overrides must stay ascending by predicate value (vanilla resolves to the last match <= value), + * and the thresholds here must match the ratio returned by {@code biomeRestoreItemProperties}. + */ + private static NonNullBiConsumer, RegistrateItemModelProvider> biomeRestoreModel() { + return (c, p) -> { + ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/biome_restore_cell/empty")); + + record Tier(String name, float threshold) {} + List tiers = List.of( + new Tier("quarter", 0.25f), + new Tier("half", 0.5f), + new Tier("three_quarters", 0.75f), + new Tier("full", 1.0f) + ); + + for (Tier tier : tiers) { + ItemModelBuilder child = p.withExistingParent("item/biome_restore_cell/" + tier.name(), p.mcLoc("item/generated")) + .texture("layer0", CreateNuclear.asResource("item/biome_restore_cell/" + tier.name())); + + outer.override() + .predicate(CreateNuclear.asResource(BiomeRestoreCellItem.TAG), tier.threshold()) + .model(child) + .end(); + } + }; + } + public static final ItemEntry YELLOWCAKE = CreateNuclear.REGISTRATE .item("yellowcake", p -> new RadiationItem(p, 4)) @@ -448,6 +478,13 @@ private static NonNullBiConsumer, Regis .properties(p -> p.stacksTo(1)) .register(); + public static final ItemEntry BIOME_RESTORE_CELL = CreateNuclear.REGISTRATE + .item("biome_restore_cell", BiomeRestoreCellItem::new) + .lang("Biome Restore Cell") + .properties(p -> p.stacksTo(1).fireResistant().setNoRepair()) + .model(biomeRestoreModel()) + .register(); + private static ItemEntry registerSpawnEgg(String name, Supplier> entity, int backgroundColor, int highlightColor, String nameItems) { return CreateNuclear.REGISTRATE @@ -455,7 +492,6 @@ private static ItemEntry registerSpawnEgg(String name, Suppli .lang(nameItems) .model((c, p) -> p.withExistingParent(c.getName(), new ResourceLocation("item/template_spawn_egg"))) .register(); - } public static void register() {} diff --git a/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java b/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java index 92700bb0..417266ce 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java +++ b/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java @@ -3,13 +3,16 @@ import net.createmod.ponder.foundation.PonderIndex; import net.minecraft.client.renderer.item.ClampedItemPropertyFunction; import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.client.renderer.item.ItemPropertyFunction; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.Item; import net.minecraftforge.client.event.RegisterParticleProvidersEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.nuclearteam.createnuclear.content.particles.NuclearMushroomCloudParticle; import net.nuclearteam.createnuclear.content.particles.SmallNuclearExplosionParticle; +import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; import net.nuclearteam.createnuclear.foundation.ponder.CreateNuclearPonderPlugin; import net.nuclearteam.createnuclear.foundation.utility.ClothTagHelper; @@ -27,18 +30,24 @@ public static void clientInit(final FMLClientSetupEvent event) { event.enqueueWork(CreateNuclearClient::registerItemProperties); } + + private static void registerItemProperties() { + clothItemProperties(); + biomeRestoreItemProperties(); + } + /** * Registers the {@code createnuclear:cloth_color} item property used by the anti-radiation * armor item models to pick the right colored icon based on the {@code ClothColor} NBT tag. *

- * {@link ItemProperties#register} clamps the value to {@code [0,1]}, so the dyed color id is + * {@link ItemProperties#register(Item, ResourceLocation, ItemPropertyFunction)} clamps the value to {@code [0,1]}, so the dyed color id is * normalized to {@code (id+1)/16} (range {@code 0.0625..1.0}) and undyed maps to {@code 0} — * below the smallest override threshold, so no override fires and the default icon shows. * The model overrides in {@code CNItems.coloredArmorModel} use the matching {@code (id+1)/16} * predicate values. Mirrors the dyed worn-armor texture selected by * {@code AntiRadiationArmorItem.getArmorTexture}. */ - private static void registerItemProperties() { + private static void clothItemProperties() { ResourceLocation clothColor = CreateNuclear.asResource("cloth_color"); ClampedItemPropertyFunction fn = (stack, level, entity, seed) -> { DyeColor dye = DyeColor.byName(ClothTagHelper.getClothColor(stack, "default"), null); @@ -50,6 +59,21 @@ private static void registerItemProperties() { ItemProperties.register(CNItems.ANTI_RADIATION_BOOTS.get(), clothColor, fn); } + /** + * Registers the {@code createnuclear:charge} item property used by the biome restore cell's + * model to pick a texture variant based on its current charge ratio (0.0 = empty, 1.0 = full). + */ + private static void biomeRestoreItemProperties() { + ResourceLocation biomeRestore = CreateNuclear.asResource(BiomeRestoreCellItem.TAG); + ClampedItemPropertyFunction fn = ((stack, level, entity, seed) -> { + int max = BiomeRestoreCellItem.getMaxCharge(); + + return (float) BiomeRestoreCellItem.getChargeTag(stack, 0) / max; + }); + + ItemProperties.register(CNItems.BIOME_RESTORE_CELL.get(), biomeRestore, fn); + } + public static void setupParticles(RegisterParticleProvidersEvent registry) { CreateNuclear.LOGGER.debug("Registered particle factories"); registry.registerSpecial(CNParticleRegistry.NUCLEAR_MUSHROOM_CLOUD.get(), new NuclearMushroomCloudParticle.Factory()); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java b/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java new file mode 100644 index 00000000..518eaa03 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java @@ -0,0 +1,75 @@ +package net.nuclearteam.createnuclear.content.biome; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; +import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.BiomeIrradiationService; + +public class BiomeRestoreCellItem extends Item { + public static final String TAG = "biome_restore"; + private static final int CHARGE_PER_CLICK = 1; + + public BiomeRestoreCellItem(Properties pProperties) { + super(pProperties); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand interactionHand) { + ItemStack stack = player.getItemInHand(interactionHand); + + if (level.isClientSide || !(level instanceof ServerLevel serverLevel)) { + return InteractionResultHolder.success(stack); + } + + if (getCharge(stack) >= getMaxCharge()) return InteractionResultHolder.pass(stack); + + boolean restored = BiomeIrradiationService.restoreArea(serverLevel, player.blockPosition()); + if (!restored) return InteractionResultHolder.pass(stack); + + addCharge(stack, CHARGE_PER_CLICK); + + return InteractionResultHolder.success(stack); + } + + @Override + public boolean isBarVisible(ItemStack stack) { + return CNConfigs.server().biomeRestore.alwaysShowBar.get() || getCharge(stack) > 0; + } + + @Override + public int getBarWidth(ItemStack stack) { + return Math.round(13.0f * getCharge(stack) / getMaxCharge()); + } + + @Override + public int getBarColor(ItemStack stack) { + return 0x4A90D9; + } + + public static int getCharge(ItemStack stack) { + return getChargeTag(stack, 0); + } + + public static int getMaxCharge() { + return CNConfigs.server().biomeRestore.maxCharge.get(); + } + + public static void addCharge(ItemStack stack, int amount) { + int current = getCharge(stack); + int next = Mth.clamp(current + amount, 0, getMaxCharge()); + stack.getOrCreateTag().putInt(TAG, next); + } + + public static int getChargeTag(ItemStack stack, int defaultValue) { + if (stack == null) return defaultValue; + CompoundTag tag = stack.getTag(); + return (tag != null && tag.contains(TAG)) ? tag.getInt(TAG) : defaultValue; + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java new file mode 100644 index 00000000..eba118a1 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java @@ -0,0 +1,24 @@ +package net.nuclearteam.createnuclear.infrastructure.config; + +import net.createmod.catnip.config.ConfigBase; + +public class CBiomeRestore extends ConfigBase { + public final ConfigInt maxCharge = i(16, 1, 64, "maxCharge", Comments.maxCharge); + public final ConfigBool alwaysShowBar = b(false, "alwaysShowBar", Comments.alwaysShowBar); + public final ConfigBool restoreInCircle = b(false, "restoreInCircle", Comments.restoreInCircle); + public final ConfigInt restoreRadiusChunks = i(1, 1, 3, "restoreRadiusChunks", Comments.restoreRadiusChunks); + + @Override + public String getName() { + return "BiomeRestore"; + } + + private static class Comments { + static String maxCharge = "Maximum number of charges the Biome Restore Cell can hold."; + static String alwaysShowBar = "If true, the durability-style bar is always shown, even when the cell is empty. " + + "If false, the bar is hidden when the charge is 0."; + static String restoreInCircle = "If true, restoring a chunk also restores nearby chunks in a circle " + + "(see restoreRadiusChunks). If false, only the chunk the player stands in is restored."; + static String restoreRadiusChunks = "Radius in chunks used when restoreInCircle is true (1 to 3)."; + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java index e791b0ac..93e1d1bd 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CNCServer.java @@ -7,6 +7,8 @@ public class CNCServer extends ConfigBase { public final CNotify notify = nested(0, CNotify::new,Comments.ratio); public final CRadiation radiation = nested(0, CRadiation::new, Comments.radiation); public final CReactorHeat reactorHeat = nested(0, CReactorHeat::new, Comments.reactorHeat); + public final CBiomeRestore biomeRestore = nested(0, CBiomeRestore::new, Comments.biomeRestore); + @Override public String getName() { return "Server"; @@ -17,5 +19,6 @@ private static class Comments { static String radiation = "Enable or disable radiation effects emitted by mod items. "; static String ratio = "Ratio"; static String reactorHeat = "Heat thresholds for different reactor sizes"; + static String biomeRestore = ""; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java index 1043e989..4dde73a1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/BiomeIrradiationService.java @@ -7,10 +7,12 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeResolver; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import java.util.ArrayList; import java.util.List; @@ -45,9 +47,55 @@ public static void circularArea(ServerLevel serverLevel, BlockPos center, Resour } } + PersistentIrradiatedZones.get(serverLevel).addChunks(chunks.stream().map(ChunkAccess::getPos).toList()); serverLevel.getChunkSource().chunkMap.resendBiomesForChunks(chunks); } + public static boolean restoreArea(ServerLevel serverLevel, BlockPos pos) { + ChunkPos centerChunk = new ChunkPos(pos); + PersistentIrradiatedZones zones = PersistentIrradiatedZones.get(serverLevel); + + List restored = new ArrayList<>(); + for (ChunkPos target : resolveRestoreTargets(centerChunk)) { + if (!zones.containsChunk(target)) continue; + + ChunkAccess chunkAccess = serverLevel.getChunk(target.x, target.z, ChunkStatus.FULL, false); + if (chunkAccess == null) continue; + + BiomeResolver resolver = (x, y, z, sample) -> serverLevel.getChunkSource().getGenerator().getBiomeSource().getNoiseBiome(x, y, z, sample); + + chunkAccess.fillBiomesFromNoise(resolver, serverLevel.getChunkSource().randomState().sampler()); + chunkAccess.setUnsaved(true); + restored.add(chunkAccess); + + zones.removeChunk(target); + } + + if (restored.isEmpty()) return false; + + serverLevel.getChunkSource().chunkMap.resendBiomesForChunks(restored); + + return true; + } + + private static List resolveRestoreTargets(ChunkPos center) { + if (!CNConfigs.server().biomeRestore.restoreInCircle.get()) { + return List.of(center); + } + + int radius = CNConfigs.server().biomeRestore.restoreRadiusChunks.get(); + List targets = new ArrayList<>(); + for (int dz = -radius; dz <= radius; dz++) { + for (int dx = -radius; dx <= radius; dx++) { + if (dx * dx + dz * dz <= radius * radius) { + targets.add(new ChunkPos(center.x + dx, center.z + dz)); + } + } + } + + return targets; + } + private static BiomeResolver createCircularResolver(Registry biomeRegistry, BlockPos center, double radiusSq, ResourceKey defaultTarget, ServerLevel level) { return (x, y, z, noise) -> { int blockX = x << 2; diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java new file mode 100644 index 00000000..d3e43b39 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java @@ -0,0 +1,24 @@ +package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.QuartPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.biome.Biome; + +public class OriginalBiomeLookup { + private OriginalBiomeLookup() {} + + public static Holder resolve(ServerLevel level, BlockPos pos) { + if (!PersistentIrradiatedZones.get(level).isInsideAnyZone(pos)) { + return level.getBiome(pos); + } + + return level.getChunkSource().getGenerator().getBiomeSource().getNoiseBiome( + QuartPos.fromBlock(pos.getX()), + QuartPos.fromBlock(pos.getY()), + QuartPos.fromBlock(pos.getZ()), + level.getChunkSource().randomState().sampler() + ); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/PersistentIrradiatedZones.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/PersistentIrradiatedZones.java new file mode 100644 index 00000000..572ef107 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/PersistentIrradiatedZones.java @@ -0,0 +1,72 @@ +package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.saveddata.SavedData; +import net.nuclearteam.createnuclear.CreateNuclear; + +import java.util.HashSet; +import java.util.Set; + +public class PersistentIrradiatedZones extends SavedData { + private static final String DATA = String.join("_", CreateNuclear.MOD_ID, "irradiated", "zones"); + + private final Set chunks = new HashSet<>(); + + public static PersistentIrradiatedZones get(ServerLevel level) { + return level.getDataStorage().computeIfAbsent(nbt -> { + PersistentIrradiatedZones d = new PersistentIrradiatedZones(); + d.readFrom(nbt); + + return d; + }, PersistentIrradiatedZones::new, DATA); + } + + public void addChunks(Iterable newChunks) { + boolean changed = false; + for (ChunkPos pos : newChunks) { + changed |= chunks.add(pos); + } + + if (changed) setDirty(); + } + + public boolean isInsideAnyZone(BlockPos pos) { + return chunks.contains(new ChunkPos(pos)); + } + + public boolean containsChunk(ChunkPos pos) { + return chunks.contains(pos); + } + + public void removeChunk(ChunkPos pos) { + if (chunks.remove(pos)) setDirty(); + } + + public void readFrom(CompoundTag nbt) { + chunks.clear(); + ListTag list = nbt.getList("chunks", Tag.TAG_COMPOUND); + list.forEach(tag -> { + CompoundTag e = (CompoundTag) tag; + + chunks.add(new ChunkPos(e.getInt("x"), e.getInt("z"))); + }); + } + + @Override + public CompoundTag save(CompoundTag nbt) { + ListTag list = new ListTag(); + chunks.forEach(pos -> { + CompoundTag e = new CompoundTag(); + e.putInt("x", pos.x); + e.putInt("z", pos.z); + list.add(e); + }); + nbt.put("chunks", list); + return nbt; + } +} diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/empty.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..d4baa0efe6f998f30f033338b8964e8d36716afb GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv=}#LT=BJwMkF1yemk zJwqd5M)wk+q8+Ibo@t(*S_~XO4l9EcBP#Xw4R^)bF#(UvL3ZZ zZc*ZP7gntZaBXQ?G)1dZA&-T^A`yE?&Z0^g$y`}GTe!R8M-l4g# zw_}~ScUb@K-^-g`acjOja`X1eGczv!G|jhqdHpc+y5oNW_vd}{n;;`(9=&aG-umqO z;l1UZr+90^6$E5TjQ8(-aMs0ejfW4jL3i_N{^RS{@XK0m&D654(oe7R-nBDcOkzG4 z@3zDG?N1MEot1HPt%7jij5Av~8xxfN3w><%yyN@4EeP>u=mw()NE#*=ZqT#x;xv zAbD@)6o1h--dl^G>}9wXduMWz%MYXSZCjKrr`Re8l`_BhYP3&(N04bO^9G>iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV8~qdba4!^@W1Nk?-5)m^S`FPI=@&dI69!+ zq(z~NN3f?+Q{`G(JBy~)i@=TR*qqK~$OK#cYOJN=Z1>4%X^ETZTsKzwDIy@7n4Y>*XMVB z^Jnf|T>MY^u>Uio$kZ%n-KcKw)0yu$->s1D56%vG{CUm=Uhh}gyTx;lJfCgdcU#=` z;_rFsb-y1xj#{brKs<%vt89ta+`pd|+%5kb_C2lcY2?Bme^t-_{nR+=@}aiW`I(0L ztS+x_8!}wD#{Jmmi`!LJl}8cVE3bWZIGM?)y1e(6*{)UL=imASFRH%1WzD_2;ca$D z8{Zmfu}fSOEntG6fHamRgeBjw3=xMxnBymV33*4N*Bwyu7xGV{;1hwEA2@+QX# z9*|wm&fpt8sXjmVYVh)BQWtoCH{@N;mS1^vf+S~w?ZlZ8x-WQrlVASOmYz{w7Q_7e zJ1hJ0N%B#q&R;A`8K$$QO<|N_-SEgHhPk~dB`53H-5-B$1jTW`GxSN~-z=Pd-u%eD z-X%%)HZGSLg3j?-a<;3er!wd=%wlyrxG8gQg3CsC=DGRWo9kOu)L*MuR&EG-{)6)X W_loJ9Z4b;rQSIsK=d#Wzp$Pz}Fdhp4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/half.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/half.png new file mode 100644 index 0000000000000000000000000000000000000000..0ccf70331a851e945cd1352d1f9546d52620e057 GIT binary patch literal 815 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP_o1|q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&(KJi(Y*wyXh&*iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV94C|ba4!^@J~*VD0<+vF8#?>8~j5e7t|PdEUI%lN%Rkxw2~e z?MZo(mR|Pv@ALSa2`}HIShiJ%+VuTTj)=Ueci_r{l7nlf+q3?#i2NlfA;I$B_)q`c z&pGo}+eRt>7 zwXY7Rvh80Jy#D&3D@KblpCl(FtoZeRe&feWi~FO0T0~y^E!D-5Z}-2gv9a;s^qI52 zFP<*-TQS8}LoXpIZcvq*w|*IvEBbyJG;K_&xA);Hgt1G@^^7> zi?5n}@Z6!472iy!e6~5=bzH38_Q!;$bFZ7}8Vfwmj0nki&L`|#c<{ab|Eu-?(``qqM8)8{h#2F^Iy@o cq)>u^Vcyae@89l|KMIO+Pgg&ebxsLQ0C^lRssI20 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/quarter.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/quarter.png new file mode 100644 index 0000000000000000000000000000000000000000..27a791ed10314046f655c7dd37791a7f48863415 GIT binary patch literal 841 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP_o1|q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&(KJi(Y*wyXh&*iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV90#+ba4!^@J~*VD0<+vF8#?>8~j5e7t|PdEUI%lN%Rkxw2~e z?MZo(mR|Pv@ALSa2`}HIShiJ%+VuTTj)=Ueci_r{l7nlf+q3?#i2NlfA;I$B_)q`c z&pGo}+eRt>7 zwXY7Rvh80Jy#D&3D@KblpCl(FtoZeRe&feWi~FO0T0~y^E!D-5Z}-2gv9a;s^qI52 zFP<*-TQS8}LoXpIZcvq*w|*IvEBbyJG;K_&xA);Hgt2l@*6#W zID5U-`TOKYZZ8g<}T}94PpG(75e&xxDd~s?|nU)>~W0w#`qr-6SW%T=)Oy z`hUOeAD_IxzwT~oTH30Ae}D5ozF+@eLPApVbfsnFpDnIC&i*$xka54(oYc^@r{HCq z^YxxLHx8xE{8uzP=kya}O-H*_BW7mjrv8dhCT8YlNoMB5wLllMWpEn*`}yaufB4sr z=cHZRe^2}S^Yn==A1=FVdQ&MBb@ E0GCrd+yDRo literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/three_quarters.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/three_quarters.png new file mode 100644 index 0000000000000000000000000000000000000000..d417e4949918c61f7f82de1721a7e7657b09c1c3 GIT binary patch literal 819 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP_o1|q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&(KJi(Y*wyXh&*iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV94C}ba4!^@J~*VD0<+vF8#?>8~j5e7t|PdEUI%lN%Rkxw2~e z?MZo(mR|Pv@ALSa2`}HIShiJ%+VuTTj)=Ueci_r{l7nlf+q3?#i2NlfA;I$B_)q`c z&pGo}+eRt>7 zwXY7Rvh80Jy#D&3D@KblpCl(FtoZeRe&fXNl`W@Ir|skutGAs7^rFF>gnJviXU_h< zc)HYY#S~i&y@aHcE6Hg|CC}?$=@rdP%@go3W@ct?J{r%zeZIW?5)0EekDM+xpQ-%u zZ1uU%-|zby8gATZWMHrbXxI%$L!eS-=fAr)UrzmDc}@AXqv3<^^Z&ov|KE6CO8TD< z7ay%}=l7{Oc-Yc^n*Hqk(a|lp|JXAhE(F@kw&Dc$^gN4_voC(jhn2Chv8C)+D=6Mn zlai2N0CfD0ewDtghG_k_cQzS^rUukzx7+ZT9qT|H$Uf* gZ}OL1#M>DeEdDHyj@x(hIw;ybUHx3vIVCg!0Lca~_5c6? literal 0 HcmV?d00001 From 6213de1f659c9f1df6c9414291d86fcea2d65157 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 27 Jun 2026 23:17:43 +0200 Subject: [PATCH 115/171] refactor: extract item model/spawn-egg builders into CNBuilderTransformers Move coloredArmorModel(...), biomeRestoreModel(...) and registerSpawnEgg(...) out of CNItems and into a new CNBuilderTransformers helper class (foundation/data), as coloredArmorModel/biomeRestoreModel (static-imported) and a renamed, public spawnEgg(...). CNItems now only calls these helpers when registering items, dropping ~70 lines of datagen builder logic that had nothing to do with item registration itself. No behavioral change. --- .../nuclearteam/createnuclear/CNItems.java | 88 ++--------------- .../createnuclear/CreateNuclear.java | 1 - .../data/CNBuilderTransformers.java | 97 +++++++++++++++++++ 3 files changed, 104 insertions(+), 82 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index b81652df..4dbc83f8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -22,6 +22,7 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.ForgeSpawnEggItem; import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; +import net.nuclearteam.createnuclear.foundation.data.CNBuilderTransformers; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import net.nuclearteam.createnuclear.api.data.recipe.SmithingClothRecipeBuilder; import net.nuclearteam.createnuclear.content.radiation.RadiationItem; @@ -44,77 +45,12 @@ import java.util.Arrays; import java.util.List; +import static net.nuclearteam.createnuclear.foundation.data.CNBuilderTransformers.biomeRestoreModel; +import static net.nuclearteam.createnuclear.foundation.data.CNBuilderTransformers.coloredArmorModel; + @SuppressWarnings({"unused", "deprecation"}) public class CNItems { - /** - * Generates the item model for a dyeable anti-radiation armor piece. - *

- * The undyed ("default") piece uses a flat 2D icon ({@code item/generated} with the - * {@code item/armors/default_anti_radiation_} sprite) instead of the 3D Blockbench - * model, since the dropped/inventory 3D rendering was problematic. The worn armor on the - * body is unaffected (handled by {@code AntiRadiationArmorModel}). - *

- * One model override per {@link DyeColor} is added, driven by the client-side - * {@code createnuclear:cloth_color} item property (see {@code CreateNuclearClient}). Each - * per-color child model still re-textures the 3D Blockbench geometry ({@code item//item}) - * with the matching {@code item/armors/_anti_radiation_suit} sheet. - *

- * The texture keys differ per slot: the helmet geometry uses {@code layer0}/{@code particle}, - * the other pieces use {@code 14} — hence {@code textureKeys} is passed explicitly. - */ - private static NonNullBiConsumer, RegistrateItemModelProvider> coloredArmorModel(String slot, String... textureKeys) { - return (c, p) -> { - ResourceLocation baseParent = p.modLoc("item/" + c.getName() + "/item"); - ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/armors/default_anti_radiation_" + slot)); - // DyeColor.values() is ordered by id (0..15); overrides must be ascending by predicate - // value so vanilla override resolution selects the exact color (returns last match <= value).cloth - // The cloth_color property is clamped to [0,1] (see CreateNuclearClient), hence the - // (id+1)/16 normalization here must match the value returned there exactly. - for (DyeColor color : DyeColor.values()) { - String colorName = color.getSerializedName(); - ItemModelBuilder child = p.withExistingParent("item/colored/" + colorName + "_anti_radiation_" + slot, baseParent); - for (String key : textureKeys) { - child.texture(key, "item/armors/" + colorName + "_anti_radiation_suit"); - } - outer.override() - .predicate(CreateNuclear.asResource("cloth_color"), (color.getId() + 1) / 16f) - .model(child) - .end(); - } - }; - } - - /** - * Generates the per-tier model overrides for the biome restore cell, driven by the - * client-side {@code createnuclear:charge} item property (see {@code CreateNuclearClient}). - * Overrides must stay ascending by predicate value (vanilla resolves to the last match <= value), - * and the thresholds here must match the ratio returned by {@code biomeRestoreItemProperties}. - */ - private static NonNullBiConsumer, RegistrateItemModelProvider> biomeRestoreModel() { - return (c, p) -> { - ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/biome_restore_cell/empty")); - - record Tier(String name, float threshold) {} - List tiers = List.of( - new Tier("quarter", 0.25f), - new Tier("half", 0.5f), - new Tier("three_quarters", 0.75f), - new Tier("full", 1.0f) - ); - - for (Tier tier : tiers) { - ItemModelBuilder child = p.withExistingParent("item/biome_restore_cell/" + tier.name(), p.mcLoc("item/generated")) - .texture("layer0", CreateNuclear.asResource("item/biome_restore_cell/" + tier.name())); - - outer.override() - .predicate(CreateNuclear.asResource(BiomeRestoreCellItem.TAG), tier.threshold()) - .model(child) - .end(); - } - }; - } - public static final ItemEntry YELLOWCAKE = CreateNuclear.REGISTRATE .item("yellowcake", p -> new RadiationItem(p, 4)) @@ -450,10 +386,9 @@ record Tier(String name, float threshold) {} .register(); }); - - public static final ItemEntry SPAWN_WOLF = registerSpawnEgg("wolf_irradiated_spawn_egg", CNEntityType.IRRADIATED_WOLF, 0x42452B,0x4C422B, "Irradiated Wolf Spawn Egg"); - public static final ItemEntry SPAWN_CAT = registerSpawnEgg("cat_irradiated_spawn_egg", CNEntityType.IRRADIATED_CAT, 0x382C19, 0x742728, "Irradiated Cat Spawn Egg"); - public static final ItemEntry SPAWN_CHICKEN = registerSpawnEgg("chicken_irradiated_spawn_egg", CNEntityType.IRRADIATED_CHICKEN, 0x6B9455, 0x95393C, "Irradiated Chicken Spawn Egg"); + public static final ItemEntry SPAWN_WOLF = CNBuilderTransformers.spawnEgg("wolf_irradiated_spawn_egg", CNEntityType.IRRADIATED_WOLF, 0x42452B, 0x4C422B, "Irradiated Wolf Spawn Egg"); + public static final ItemEntry SPAWN_CAT = CNBuilderTransformers.spawnEgg("cat_irradiated_spawn_egg", CNEntityType.IRRADIATED_CAT, 0x382C19, 0x742728, "Irradiated Cat Spawn Egg"); + public static final ItemEntry SPAWN_CHICKEN = CNBuilderTransformers.spawnEgg("chicken_irradiated_spawn_egg", CNEntityType.IRRADIATED_CHICKEN, 0x6B9455, 0x95393C, "Irradiated Chicken Spawn Egg"); public static final ItemEntry REACTOR_BLUEPRINT = CreateNuclear.REGISTRATE .item("reactor_blueprint_item", ReactorBluePrintItem::new) @@ -485,14 +420,5 @@ record Tier(String name, float threshold) {} .model(biomeRestoreModel()) .register(); - - private static ItemEntry registerSpawnEgg(String name, Supplier> entity, int backgroundColor, int highlightColor, String nameItems) { - return CreateNuclear.REGISTRATE - .item(name, p -> new ForgeSpawnEggItem(entity, backgroundColor, highlightColor, p)) - .lang(nameItems) - .model((c, p) -> p.withExistingParent(c.getName(), new ResourceLocation("item/template_spawn_egg"))) - .register(); - } - public static void register() {} } diff --git a/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java b/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java index dd150866..db73cafd 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java +++ b/src/main/java/net/nuclearteam/createnuclear/CreateNuclear.java @@ -117,5 +117,4 @@ public static void onRegister(final RegisterEvent event) { public static ResourceLocation asResource(String path) { return new ResourceLocation(MOD_ID, path); } - } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java new file mode 100644 index 00000000..de448ca4 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java @@ -0,0 +1,97 @@ +package net.nuclearteam.createnuclear.foundation.data; + +import com.tterrag.registrate.providers.DataGenContext; +import com.tterrag.registrate.providers.RegistrateItemModelProvider; +import com.tterrag.registrate.util.entry.ItemEntry; +import com.tterrag.registrate.util.nullness.NonNullBiConsumer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.item.Item; +import net.minecraftforge.client.model.generators.ItemModelBuilder; +import net.minecraftforge.common.ForgeSpawnEggItem; +import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; + +import java.util.List; +import java.util.function.Supplier; + +public class CNBuilderTransformers { + + /** + * Generates the item model for a dyeable anti-radiation armor piece. + *

+ * The undyed ("default") piece uses a flat 2D icon ({@code item/generated} with the + * {@code item/armors/default_anti_radiation_} sprite) instead of the 3D Blockbench + * model, since the dropped/inventory 3D rendering was problematic. The worn armor on the + * body is unaffected (handled by {@code AntiRadiationArmorModel}). + *

+ * One model override per {@link DyeColor} is added, driven by the client-side + * {@code createnuclear:cloth_color} item property (see {@code CreateNuclearClient}). Each + * per-color child model still re-textures the 3D Blockbench geometry ({@code item//item}) + * with the matching {@code item/armors/_anti_radiation_suit} sheet. + *

+ * The texture keys differ per slot: the helmet geometry uses {@code layer0}/{@code particle}, + * the other pieces use {@code 14} — hence {@code textureKeys} is passed explicitly. + */ + public static NonNullBiConsumer, RegistrateItemModelProvider> coloredArmorModel(String slot, String... textureKeys) { + return (c, p) -> { + ResourceLocation baseParent = p.modLoc("item/" + c.getName() + "/item"); + ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/armors/default_anti_radiation_" + slot)); + // DyeColor.values() is ordered by id (0..15); overrides must be ascending by predicate + // value so vanilla override resolution selects the exact color (returns last match <= value).cloth + // The cloth_color property is clamped to [0,1] (see CreateNuclearClient), hence the + // (id+1)/16 normalization here must match the value returned there exactly. + for (DyeColor color : DyeColor.values()) { + String colorName = color.getSerializedName(); + ItemModelBuilder child = p.withExistingParent("item/colored/" + colorName + "_anti_radiation_" + slot, baseParent); + for (String key : textureKeys) { + child.texture(key, "item/armors/" + colorName + "_anti_radiation_suit"); + } + outer.override() + .predicate(CreateNuclear.asResource("cloth_color"), (color.getId() + 1) / 16f) + .model(child) + .end(); + } + }; + } + + /** + * Generates the per-tier model overrides for the biome restore cell, driven by the + * client-side {@code createnuclear:charge} item property (see {@code CreateNuclearClient}). + * Overrides must stay ascending by predicate value (vanilla resolves to the last match <= value), + * and the thresholds here must match the ratio returned by {@code biomeRestoreItemProperties}. + */ + public static NonNullBiConsumer, RegistrateItemModelProvider> biomeRestoreModel() { + return (c, p) -> { + ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/biome_restore_cell/empty")); + + record Tier(String name, float threshold) {} + List tiers = List.of( + new Tier("quarter", 0.25f), + new Tier("half", 0.5f), + new Tier("three_quarters", 0.75f), + new Tier("full", 1.0f) + ); + + for (Tier tier : tiers) { + ItemModelBuilder child = p.withExistingParent("item/biome_restore_cell/" + tier.name(), p.mcLoc("item/generated")) + .texture("layer0", CreateNuclear.asResource("item/biome_restore_cell/" + tier.name())); + + outer.override() + .predicate(CreateNuclear.asResource(BiomeRestoreCellItem.TAG), tier.threshold()) + .model(child) + .end(); + } + }; + } + + public static ItemEntry spawnEgg(String name, Supplier> entity, int backgroundColor, int highlightColor, String nameItems) { + return CreateNuclear.REGISTRATE + .item(name, p -> new ForgeSpawnEggItem(entity, backgroundColor, highlightColor, p)) + .lang(nameItems) + .model((c, p) -> p.withExistingParent(c.getName(), new ResourceLocation("item/template_spawn_egg"))) + .register(); + } +} From 9ded502cc578affc1036faeb61763f57293ba62a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 11:39:06 +0200 Subject: [PATCH 116/171] feat: extend radiation system to all living entities, not just players Generalize the radiation capability/source API from Player to LivingEntity: IRadiationSource.getRadiation, RadiationRegistry's overloads, and every IRadiationSource implementation (RadiationBucketItem, RadiationItem, UraniumOreItem) now take a LivingEntity instead of a Player. RadiationCapability now attaches its capability to any LivingEntity (not just Player) and ticks via a new onLivingEntityTick(LivingTickEvent) (replacing onPlayerTick(PlayerTickEvent)), wired up in CommentEvents.onLivingEntityTick. tickRadiation(entity) keeps the inventory-hash-based dirty check for players (who have a real inventory to hash) but always recomputes item radiation for non-player entities, since they have no equivalent inventory to diff against. computeItemRadiation/getStackRadiation are introduced to compute radiation from armor slots and held items for any LivingEntity. Register the IRRADIATED_RESISTANCE attribute for every living entity type in EntityAttributeModificationEvent instead of only EntityType.PLAYER, so non-player entities can actually hold the resistance attribute the radiation tick logic reads. Remove the dead, already-commented-out getArmorResistance(...) helper and its leftover commented call site, which duplicated armor-radiation logic that's now handled via computeItemRadiation/getStackRadiation. --- .../api/radiation/IRadiationSource.java | 3 +- .../api/radiation/RadiationRegistry.java | 5 +- .../radiation/RadiationBucketItem.java | 3 +- .../content/radiation/RadiationItem.java | 3 +- .../capability/RadiationCapability.java | 77 +++++++++++-------- .../content/uraniumOre/UraniumOreItem.java | 3 +- .../foundation/events/CommentEvents.java | 10 ++- 7 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/api/radiation/IRadiationSource.java b/src/main/java/net/nuclearteam/createnuclear/api/radiation/IRadiationSource.java index bdc23948..11e1d7fb 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/radiation/IRadiationSource.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/radiation/IRadiationSource.java @@ -1,8 +1,9 @@ package net.nuclearteam.createnuclear.api.radiation; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; public interface IRadiationSource { - double getRadiation(ItemStack stack, Player player); + double getRadiation(ItemStack stack, LivingEntity entity); } diff --git a/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java b/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java index 2fe1d091..9a878a94 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java @@ -2,6 +2,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -43,10 +44,10 @@ public static double get(ResourceKey stack) { return 0D; } - public static double getRadiation(ItemStack stack, Player player) { + public static double getRadiation(ItemStack stack, LivingEntity entity) { return get(stack) * stack.getCount(); } - public static double getRadiation(ResourceKey biome, Player player) { + public static double getRadiation(ResourceKey biome, LivingEntity entity) { return get(biome); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java index 93b2ae16..38b13da6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationBucketItem.java @@ -1,6 +1,7 @@ package net.nuclearteam.createnuclear.content.radiation; import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.ItemStack; @@ -32,7 +33,7 @@ public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundT } @Override - public double getRadiation(ItemStack stack, Player player) { + public double getRadiation(ItemStack stack, LivingEntity entity) { return this.radiation; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java index be57de09..5e02a0fb 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationItem.java @@ -1,5 +1,6 @@ package net.nuclearteam.createnuclear.content.radiation; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -15,7 +16,7 @@ public RadiationItem(Item.Properties settings, double radiation) { } @Override - public double getRadiation(ItemStack stack, Player player) { + public double getRadiation(ItemStack stack, LivingEntity entity) { return this.radiation * stack.getCount(); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java index d476469a..bd2f2795 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java @@ -17,6 +17,7 @@ import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent.PlayerTickEvent; +import net.minecraftforge.event.entity.living.LivingEvent.LivingTickEvent; import net.nuclearteam.createnuclear.CNAttributes; import net.nuclearteam.createnuclear.CNEffects; import net.nuclearteam.createnuclear.CNTags; @@ -71,39 +72,45 @@ public void setLastBiomeLocation(ResourceLocation location) { } public static void attach(AttachCapabilitiesEvent event) { - if (event.getObject() instanceof Player) { + if (event.getObject() instanceof LivingEntity) { event.addCapability(CreateNuclear.asResource("irradiated_resistance"), new RadiationProvider()); } } - public static void onPlayerTick(PlayerTickEvent event) { - if (event.phase != TickEvent.Phase.END) return; - - Player player = event.player; - Level level = player.level(); + public static void onLivingEntityTick(LivingTickEvent event) { + tickRadiation(event.getEntity()); + } + public static void tickRadiation(LivingEntity entity) { + Level level = entity.level(); if (level.isClientSide) return; - player.getCapability(RadiationProvider.CAP).ifPresent(cap -> { - long newHash = InventoryHashUtil.compute(player); - if (newHash != cap.getInventoryHash()) { - cap.setInventoryHash(newHash); - cap.setRadiation(Math.max(0, computeItemRadiation(player))); + + entity.getCapability(RadiationProvider.CAP).ifPresent(cap -> { + if (entity instanceof Player player) { + long newHash = InventoryHashUtil.compute(player); + if (newHash != cap.getInventoryHash()) { + cap.setInventoryHash(newHash); + cap.setRadiation(Math.max(0, computeItemRadiation(player))); + } + } else { + cap.setRadiation(Math.max(0, computeItemRadiation(entity))); } - ResourceKey biomeKey = level.getBiome(player.blockPosition()).unwrapKey().orElse(null); + + ResourceKey biomeKey = level.getBiome(entity.blockPosition()).unwrapKey().orElse(null); ResourceLocation biomeLoc = biomeKey != null ? biomeKey.location() : null; if (!Objects.equals(biomeLoc, cap.getLastBiomeLocation())) { cap.setLastBiomeLocation(biomeLoc); } - if (!canBeIrradiated(player)) return; + if (!canBeIrradiated(entity)) return; double totalRaw = cap.getRadiation() + getRawBiomeRadiation(biomeKey); - double resistance = getRadiationResistance(player); + double resistance = getRadiationResistance(entity); double totalRadiation = totalRaw * (1.0 - resistance); - applyEffects(player, totalRadiation); + applyEffects(entity, totalRadiation); }); } @@ -122,6 +129,24 @@ private static double computeItemRadiation(Player player) { return radiation; } + private static double getStackRadiation(ItemStack stack, LivingEntity entity) { + double radiation = 0; + if (stack.getItem() instanceof IRadiationSource source) radiation += source.getRadiation(stack, entity); + radiation += RadiationRegistry.getRadiation(stack, entity); + + return radiation; + } + + private static double computeItemRadiation(LivingEntity entity) { + double radiation = 0; + for (ItemStack stack : entity.getArmorSlots()) { + radiation += getStackRadiation(stack, entity); + } + radiation += getStackRadiation(entity.getMainHandItem(), entity); + radiation += getStackRadiation(entity.getOffhandItem(), entity); + return radiation; + } + private static double getRawBiomeRadiation(ResourceKey biomeKey) { if (biomeKey == null) return 0; return RadiationRegistry.get(biomeKey); @@ -164,24 +189,10 @@ public static double getRadiationResistance(LivingEntity entity) { if (attribute != null) resistance += attribute.getValue(); -// resistance += getArmorResistance(entity.getArmorSlots()); - return Mth.clamp(resistance, 0.0, 1.0); } - private static double getArmorResistance(Iterable stacks) { - double resistance = 0d; - - for (ItemStack stack : stacks) { - if (stack.getItem() instanceof AntiRadiationArmorItem) { - resistance += RADIATION_VALUE; - } - } - - return resistance; - } - - private static void applyEffects(Player player, double radiation) { + private static void applyEffects(LivingEntity entity, double radiation) { final double radiation_desactive = 0; MobEffect radiationEffect = CNEffects.RADIATION.get(); @@ -193,15 +204,15 @@ private static void applyEffects(Player player, double radiation) { else if (radiation < CNConfigs.server().radiation.radiationLevel3.get()) amp = CNConfigs.server().radiation.amplifierLevel2.get(); else amp = CNConfigs.server().radiation.amplifierLevel2.get(); - MobEffectInstance current = player.getEffect(radiationEffect); + MobEffectInstance current = entity.getEffect(radiationEffect); if (current != null && current.getAmplifier() != amp) { - player.removeEffect(radiationEffect); + entity.removeEffect(radiationEffect); current = null; } if (current == null || current.getDuration() <= 40) { - player.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 100, amp, true, true)); + entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 100, amp, true, true)); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/uraniumOre/UraniumOreItem.java b/src/main/java/net/nuclearteam/createnuclear/content/uraniumOre/UraniumOreItem.java index 6af2206d..20cd0258 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/uraniumOre/UraniumOreItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/uraniumOre/UraniumOreItem.java @@ -1,5 +1,6 @@ package net.nuclearteam.createnuclear.content.uraniumOre; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; @@ -15,7 +16,7 @@ public UraniumOreItem(Block block, Properties properties, double radiation) { } @Override - public double getRadiation(ItemStack stack, Player player) { + public double getRadiation(ItemStack stack, LivingEntity entity) { return this.radiation * stack.getCount(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java index 643b30ab..3bcbe1fb 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/CommentEvents.java @@ -2,10 +2,10 @@ import net.minecraft.world.entity.*; import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.event.TickEvent.PlayerTickEvent; import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.TickEvent.ServerTickEvent; import net.minecraftforge.event.entity.EntityAttributeModificationEvent; +import net.minecraftforge.event.entity.living.LivingEvent.LivingTickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.nuclearteam.createnuclear.*; @@ -24,15 +24,17 @@ public static void attachCapabilities(AttachCapabilitiesEvent event) { } @SubscribeEvent - public static void onPlayerTick(PlayerTickEvent event) { - RadiationCapability.onPlayerTick(event); + public static void onLivingEntityTick(LivingTickEvent event) { + RadiationCapability.onLivingEntityTick(event); } @Mod.EventBusSubscriber(modid = CreateNuclear.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public static class RadiationEvent { @SubscribeEvent public static void onEntityAttribute(EntityAttributeModificationEvent event) { - event.add(EntityType.PLAYER, CNAttributes.IRRADIATED_RESISTANCE.get()); + for (EntityType type : event.getTypes()) { + event.add(type, CNAttributes.IRRADIATED_RESISTANCE.get()); + } } } From 667125d1601c05dac21cdd6e85c48ca4599443b6 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 13:02:53 +0200 Subject: [PATCH 117/171] docs: refresh consolidated audit with a fresh independent re-verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-audit the codebase from scratch against the current state of src/main/java (291 files, ~25,070 lines), cross-checking every prior finding by direct file reads and `git show`/`git log` on the 2026-06-24..2026-06-28 commit range, rather than carrying forward unverified conclusions. Key updates: note the recent CNBuilderTransformers extraction, Biome Restore Cell feature, radiation-system generalization to all LivingEntity types, and centralized placement-advancement attribution as clean, non-regressing changes. Identify a new nuance on the multiblock controller scan: the shared scanControllerCandidates loop only short-circuits via findControllerPos (used by ReactorOutput/ReactorRodInput/ReactorFluidInput/ReactorAlarm) — but findController, called directly by ReactorCasing/ReactorCooler/ ReactorFrame, never short-circuits and always walks the full ~3971-cell search volume even after finding the relevant controller. Since ReactorCasing is the most frequently placed/broken block, this is now flagged as the hotter of the two paths and still unfixed. Also refine the double-scan-on-break writeup per block (ReactorRodInput is the only block already following the correct single-call pattern) and reclassify DefaultHeatCalculator's per-rod neighbor lookup as a minor item now that its O(n²) item rescan has already been eliminated. --- AUDIT_ACTUEL.md | 181 ++++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 91 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 01478db2..f2cf3518 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -1,34 +1,32 @@ # Audit consolidé — CreateNuclearForge (branche V2-CorrectifAudit) -**Dernière fusion : 2026-06-22.** Ce document fusionne `AUDIT_ACTUEL.md` (7 audits croisés sur `src/main/java`) et `AUDIT_INDEPENDANT.md` (relecture indépendante du 2026-06-20). Chaque point litigieux entre les deux a été **revérifié directement dans le code** (lecture de fichier + grep des appelants) avant classement. Les divergences entre les deux audits sont tranchées et annotées ci-dessous. - -> **Mise à jour 2026-06-23** : tous les problèmes radiation (ancienne §2) ont été corrigés et déplacés en §6 « pour mémoire ». Les sections et les points ont été renumérotés en conséquence. +**Dernière mise à jour : 2026-06-28.** Nouvel audit indépendant réalisé en repartant exclusivement du code actuel (`src/main/java`, **291 fichiers, ~25 070 lignes**, hors `src/generated` et `src/main/resources`). `AUDIT_V1.md` et l'historique de ce fichier (versions précédentes) n'ont servi qu'à comparer les résultats — chaque point a été **revérifié par lecture directe des fichiers cités** (et, pour les zones les plus actives, par `git show`/`git log` sur les commits du 2026-06-24 au 2026-06-28). > Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §6 pour mémoire, puis ne sont plus repris. -**Périmètre** : `src/main/java` (286 fichiers, ~24 600 lignes), hors `src/generated` et `src/main/resources`. Recoupé avec l'historique Git. - -**Limite de couverture honnête** : les bugs mineurs/robustesse `B7, B10, B17, B18` et la liste « mineurs » non numérotée d'`AUDIT_V1.md` n'ont pas été re-vérifiés ici faute de signal de changement — ni confirmés ni infirmés, à re-vérifier ponctuellement avant traitement. +**Limite de couverture honnête** : les bugs mineurs/robustesse listés au §1 de l'historique (`B7, B10, B17, B18` et la liste « mineurs » non numérotée d'`AUDIT_V1.md`) n'ont pas été re-vérifiés ici faute de signal de changement — ni confirmés ni infirmés, à re-vérifier ponctuellement avant traitement. --- ## 0. Constat global -Le **chantier architectural n°1 des audits précédents — la décomposition de `ReactorControllerBlockEntity` — est désormais réellement effectif** (commits `dd918582`, `6e717c44`, `8611ed76`, `56373bf7`, `39092ca3`). La classe fait **492 lignes** et délègue à `service/` (8 fichiers), `manager/` (5 fichiers), `consumable/` (6 fichiers), `display/` (2 fichiers). Ce qui reste est de la **coordination de multiblock** (positions I/O, état de pattern, délégation de verrou), plus un hub god-class. **Ce chantier est considéré comme clos** (voir §3). +Depuis le dernier audit (2026-06-24), le projet a continué d'évoluer activement (16 commits en 4 jours) : extraction de `CNBuilderTransformers` (SRP propre, 97 lignes, 3 builders isolés), ajout de l'item **Biome Restore Cell** (code neuf, propre, bien isolé dans `BiomeRestoreCellItem`/`BiomeIrradiationService`), refonte du système de radiation pour couvrir **toutes les `LivingEntity`** et non plus seulement les joueurs (`9ded502c`), centralisation de l'attribution des advancements de pose via le contrôleur plutôt que la pièce posée (`19617118`), et suppression du `LOGGER.warn` redondant dans `ReactorAssembler` (`b309f231`, **quick win déjà traité**). -En contrepartie, deux affirmations structurelles d'`AUDIT_V1.md`, reprises sans re-vérification, sont **fausses sur le code actuel** : l'« inversion de dépendance `api/` » et les « frameworks multiblock concurrents » (voir §3). À l'inverse, des bugs simples et jamais mis en doute (`B15`, tautologie `isNotDanger`) restent présents — signe que le nettoyage a suivi les zones très signalées (radiation, dead code, controller) plutôt qu'une revue ligne à ligne. +Aucun de ces changements ne casse les acquis des audits précédents : le point de vérité unique radiation (`canBeIrradiated`) tient toujours, l'extension aux mobs ne boucle pas sur le monde (elle s'appuie sur `LivingTickEvent`, déclenché nativement par tick et par entité), et la centralisation des advancements est un vrai gain (élimine un risque de double-attribution). Un commit au message trompeur (`20c1df0b`, *"IO blocks are now natively Casings"*) ne change **rien** à l'architecture : il ne fait que nettoyer 22 lignes d'une scène Ponder ; les blocs I/O (`ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`) restent des classes `Block` séparées de `ReactorCasing`. -La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vide) sur une logique métier non triviale (chaleur, pattern matching, verrouillage fluide) — précisément les zones où des bugs silencieux survivent à plusieurs passes d'audit. +**Nouveauté la plus significative de cet audit** : en creusant le scan multiblock fusionné (déjà crédité « corrigé » au tour précédent), la boucle partagée `scanControllerCandidates` (`ReactorPattern.java:40-56`) ne court-circuite en réalité que via `findControllerPos` (utilisé par `MultiblockHelpers`, donc par `ReactorOutput`/`ReactorRodInput`/`ReactorFluidInput`/`ReactorAlarm`). La méthode `findController` — appelée **directement** par `ReactorCasing`, `ReactorCooler` et `ReactorFrame` — a un visiteur qui retourne toujours `false` et **ne s'arrête jamais avant d'avoir parcouru les ~3971 positions** de la zone de recherche, même après avoir trouvé et traité le contrôleur pertinent. Comme `ReactorCasing` constitue le gros de la coque d'un réacteur (le bloc le plus posé/cassé), c'est en réalité le chemin le plus coûteux des deux — voir §2 point 1. + +La dette la plus structurelle reste **l'absence totale de tests** (`src/test` toujours vide, confirmé) — précisément là où des bugs silencieux (sur-extraction fluide, tautologie `IHeat`, scan non court-circuité) survivent à plusieurs passes d'audit. --- ## 1. 🐛 Bugs confirmés toujours présents (revérifiés) -| Réf. | Fichier:ligne | Gravité | Détail (vérifié) | +| Réf. | Fichier:ligne | Gravité | Détail (vérifié 2026-06-28) | |---|---|---|---| -| **isNotDanger tautologie** | `content/multiblock/IHeat.java:88-90` | 🟠 | `return of(heat,size) != DANGER \|\| of(heat,size) != NONE;` — toujours `true` (un `HeatLevel` ne peut être les deux). Appelant **confirmé `ReactorControllerBlockEntity.java:391`** (et non ~454 comme indiqué auparavant) : la garde « ne pas faire tourner les sorties en `DANGER` » est **inopérante**, les sorties tournent même en surchauffe. Correctif d'1 ligne (`!= DANGER` seul), à confirmer côté balance. | -| **ReactorInputFluidManager — sur-extraction** | `ReactorInputFluidManager.java:146-151` | 🟠 | `fluidNeeded` **n'est jamais décrémenté** entre handlers dans la boucle d'extraction → chaque handler tente d'extraire le besoin complet (sur-extraction si plusieurs inputs). De plus `if (toExtract > 1)` **ignore les extractions de 1 unité**. ⚠️ L'off-by-one `getFluidInTank(getTanks())` est en revanche **corrigé** → `getFluidInTank(0)` (l.126, l.144). *(Tranche le désaccord entre les deux audits : `AUDIT_ACTUEL` avait raison sur l'off-by-one corrigé ; `AUDIT_INDEPENDANT` se trompait en le disant encore présent.)* Toléré aujourd'hui car `SmartFluidTank` est mono-tank, mais reste une violation de contrat `IFluidHandler` qui deviendra active au premier tank multi-slot. | -| **InventoryHashUtil — resync durabilité** | `InventoryHashUtil` | 🟡 | Toujours `h = 31*h + stack.getDamageValue()` → resync radiation à chaque variation de durabilité d'un item. | +| **isNotDanger tautologie** | `content/multiblock/IHeat.java:88-90` | 🟠 | `return of(heat,size) != DANGER \|\| of(heat,size) != NONE;` — toujours `true`. Appelant unique confirmé `ReactorControllerBlockEntity.java:428` (la classe a grossi, la ligne a bougé). La garde « ne pas faire tourner les sorties en `DANGER` » reste **inopérante** : les sorties tournent même en surchauffe. Correctif d'1 ligne (`!= DANGER` seul), à confirmer côté balance. | +| **ReactorInputFluidManager — sur-extraction** | `controller/manager/ReactorInputFluidManager.java:137-155` | 🟠 | `fluidNeeded` (paramètre de `extractFluids`) n'est **toujours jamais décrémenté** entre handlers (l.146-151) → chaque handler de la boucle tente d'extraire le besoin complet, sur-extraction possible avec plusieurs inputs. `if (toExtract > 1)` (l.147) ignore toujours les extractions de 1 unité. Toléré aujourd'hui (tank mono-slot), reste une violation de contrat latente. | +| **InventoryHashUtil — resync durabilité** | `foundation/utility/InventoryHashUtil.java:90-91` | 🟡 | Toujours `h = 31*h + stack.getDamageValue()` pour tout item endommageable → resync à chaque variation de durabilité. | --- @@ -36,86 +34,82 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi ### 🔴 Critique — performance/correction du scan multiblock -1. **Scan géométrique du contrôleur : aucune garde client + double appel sur un même événement** *(partiellement corrigé, revérifié 2026-06-24)* - - ✅ **Corrigé** — `ReactorPattern.findController`/`findControllerPos` (`ReactorPattern.java`) partagent désormais une seule boucle de scan (`scanControllerCandidates`) avec court-circuit dès qu'un controller pertinent est trouvé. `findController` filtre maintenant via `isInReactorRange` : un controller voisin déjà assemblé dont la structure n'inclut pas `blockPos` n'est plus ré-assemblé/désassemblé inutilement (évitait un risque de double-enregistrement I/O via `ReactorAssembler.findAndRegisterSpecialBlocks`, qui n'est pas idempotent). - - ✅ **Corrigé** — `MultiblockHelpers.handleOnPlace`/`handleRemoval` faisaient **deux scans complets** par pose/casse (`findController` puis `findControllerPos`). Fusionné en un seul scan via une nouvelle surcharge `findControllerPos(pos, level, first)` qui fait le travail d'assemblage **et** retourne le controller pertinent ; la surcharge `handleOnPlace(pos, level, boolean)` (devenue inutilisée) a été supprimée. - - ❌ **Toujours non corrigé** — **aucune garde `level.isClientSide()`** nulle part dans la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler.assemble/disassemble`. Mutation d'état métier toujours potentiellement exécutée côté client en plus du serveur. - - ❌ **Toujours non corrigé** — **double appel à la casse** : `ReactorCasing.java` appelle toujours `pattern.findController` dans **`playerDestroy` (l.60) ET `onRemove` (l.66)** pour le même événement → deux scans complets. Idem `ReactorCooler.java` (l.39 + l.45). `ReactorFrame.java` reste le seul à garder `if (!state.is(newState.getBlock()))` côté `onRemove`. - - ❌ **Toujours non corrigé** — **spam de log** : `ReactorAssembler.assemble` logue toujours en `LOGGER.warn` (`ReactorAssembler.java:40-41`) à chaque réussite de pattern. - - *Reste à faire* : `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` ; supprimer l'appel redondant dans `ReactorCasing.playerDestroy`/`ReactorCooler.playerDestroy` (garder `onRemove`) ; `LOGGER.warn` → `LOGGER.debug`. Risque très faible, gain net en multijoueur — **reste la priorité n°1 du projet**, mais le scan lui-même (le plus coûteux des deux problèmes initiaux) est désormais optimisé et plus sûr sur les multiblocks voisins. +1. **Scan géométrique du contrôleur : court-circuit incomplet + aucune garde client + double appel pose/casse** *(nuancé — affiné 2026-06-28)* + - ✅ **Toujours acquis** — `ReactorPattern` n'a qu'**une seule** boucle de scan partagée (`scanControllerCandidates`, `ReactorPattern.java:40-56`) sur ~3971 positions (`y∈[-5,+5]`, `x,z∈[-9,+9]`), filtrée par `isInReactorRange` (l.111-113). + - ❌ **Nuance nouvelle, non vue par l'audit précédent** — le court-circuit (`return true` dans le visiteur dès qu'un contrôleur pertinent est trouvé) n'existe que dans **`findControllerPos`** (`ReactorPattern.java:73-94`, utilisé via `MultiblockHelpers.handleOnPlace/handleRemoval/getControllerForPart` → donc par `ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`). **`findController`** (`ReactorPattern.java:58-71`), appelé **directement** par `ReactorCasing.java:49,61,67`, `ReactorCooler.java:28,40,46` et `ReactorFrame.java:113,125,135`, a un visiteur qui **retourne toujours `false`** (l.69) : il continue de parcourir les ~3971 positions restantes même après avoir traité le contrôleur pertinent. `ReactorCasing` étant le bloc le plus posé/cassé (coque du réacteur), c'est le chemin le plus chaud des deux et il n'est **pas** optimisé. Fix trivial : faire retourner `inRange` au lieu de `false` dans le visiteur de `findController`, comme c'est déjà fait dans `findControllerPos`. + - ❌ **Toujours non corrigé** — **aucune garde `level.isClientSide()`** dans toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler.assemble/disassemble`. (Le seul `isClientSide` du fichier, `ReactorFrame.java:71`, est dans `neighborChanged`, sans rapport.) + - ❌ **Toujours non corrigé, état affiné par bloc** — double scan à la casse : + - `ReactorCasing`/`ReactorCooler` : **aucune garde**, `playerDestroy` et `onRemove` appellent chacun `pattern.findController(pos, level, false)` sans condition → double scan systématique à chaque casse joueur. + - `ReactorOutput.java:71-79` et `ReactorFluidInput.java:94-103` : même défaut via `MultiblockHelpers.handleRemoval`, **sans aucune garde** dans `onRemove`. + - `ReactorAlarm.java:43-60` et `ReactorFrame.java:123-137` : `onRemove` est **guardé** (`if (!state.is(newState.getBlock()))`) pour ne pas re-scanner sur un simple changement d'état (rotation, etc.), mais ce garde **ne protège pas** du double appel quand le joueur casse réellement le bloc — `playerDestroy` s'exécute toujours en plus. + - **`ReactorRodInput.java:82-92` est le seul bloc correctement conçu** : pas de `playerDestroy` du tout, un seul appel dans `onRemove`, guardé par le changement de type de bloc. **C'est le modèle de référence à généraliser** aux 5 autres blocs (retirer l'appel de `playerDestroy`, garder l'appel guardé dans `onRemove`). + - ✅ **Corrigé et confirmé stable** — `ReactorAssembler.assemble` ne logue plus rien en succès (`ReactorAssembler.java`, vérifié : aucun `LOGGER.warn`/`LOGGER.info` dans `assemble`/`disassemble`). *(Quick win traité par le commit `b309f231`.)* + - *Reste à faire* : (a) `findController` doit court-circuiter comme `findControllerPos` (1 ligne, gain net immédiat sur le chemin le plus chaud) ; (b) `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` ; (c) aligner `ReactorCasing`, `ReactorCooler`, `ReactorOutput`, `ReactorFluidInput`, `ReactorAlarm` sur le modèle `ReactorRodInput` (un seul appel, dans `onRemove`, guardé par le changement de bloc). Risque très faible, **reste la priorité n°1 du projet**. ### 🟠 Importants -2. **`DefaultHeatCalculator.computeHeat` — coût ~O(n²) avec désérialisation NBT répétée + asymétrie fuel/cooler** *(confirmé `DefaultHeatCalculator.java:35-75`)* - Pour chaque item du pattern, boucle sur la grille pour localiser sa position, puis pour chaque voisin **re-boucle sur la totalité des items** (l.59) pour retrouver le voisin par slot — chaque itération désérialise un `ItemStack.of(...)` depuis NBT sans cache (l.36, l.62). Coût pire cas ~57×81×4×57 ≈ 1 050 000 itérations/tick sur réacteur plein. Non couvert par les audits historiques (`reactorLogic/`). - - **Asymétrie** (l.61) : le calcul de proximité ne fire que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. De plus `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.67, **division**) côté fuel→voisin vs additions ailleurs. - - *Recommandation* : remplacer la boucle de recherche du voisin (l.59) par une `Map` construite une fois par appel → O(n) au lieu de O(n²), **sans changer le comportement**. **Ne pas toucher** à l'asymétrie/division sans confirmation balance (la logique de chaleur a des distinctions intentionnelles entre chemins — ne pas unifier sans vérification). - - **Dépendance avec le point 9 (tags `FUEL`/`COOLER`)** : `computeHeat` (et l'interface `IHeatCalculator.computeHeat`, `IHeatCalculator.java:9`) ne reçoivent **aucun `Level`**, alors que `HeatManager.calculateHeat` (`HeatManager.java:29`) en a un et ne le propage pas (`HeatManager.java:32`). Tant que ce `Level` n'est pas ajouté à la signature, ce fichier ne peut pas utiliser `TypeRodPredicate.isFuel/isCooled` (qui ont besoin de `RodType.resolveRodType(item, level)`) et reste donc sur le double-check `stack.is(TAG) || rod.type() == X` (l.61, l.64, l.85, l.87) — c'est le site le plus engageant des 4 listés au point 9, car il touche une interface publique et non un simple remplacement local. +2. **`DefaultHeatCalculator.computeHeat` — partiellement amélioré, reste O(n×81) + asymétrie fuel/cooler** *(réévalué 2026-06-28, moins grave qu'estimé précédemment)* + `DefaultHeatCalculator.java:35-97` a changé de forme depuis le dernier audit : les items du pattern sont désormais désérialisés **une seule fois** dans une `Map actualRods` (l.44-54), et la recherche du **voisin** se fait par lookup direct `actualRods.containsKey(neighborSlot)` (l.81) — **l'ancienne re-boucle O(n) sur tous les items à chaque voisin a disparu**, ce n'est donc plus un O(n²) sur les items. Reste cependant, pour chaque rod, une boucle complète sur la grille `formattedPattern` (9×9=81 cellules, l.70-73) pour retrouver sa propre position — non remplacée par une map slot→position précalculée (coût ~57×81 ≈ 4617 itérations/tick sur réacteur plein, contre le ~1 050 000 estimé par l'ancien audit, qui est donc à reclasser **🟡 mineur** plutôt que 🟠). + - **Asymétrie toujours présente** (l.82) : l'examen des voisins ne se fait que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.88, **division**) côté fuel→cooler-voisin vs addition (l.86) côté fuel→fuel-voisin. **Ne pas toucher sans confirmation balance** (toujours valable). + - `IHeatCalculator.computeHeat` (`IHeatCalculator.java:9`) ne reçoit toujours **aucun `Level`** ; `HeatManager.calculateHeat` (`HeatManager.java:30`) en reçoit un mais ne le propage pas (`HeatManager.java:34`) — bloque toujours la migration `isFuel`/`isCooled` (voir point 8) sur ce fichier précis. + - *Recommandation* : précalculer une `Map` (ou inverser `formattedPattern` en `Map` statique au chargement de la classe) pour éliminer la boucle 81 cellules — gain mineur, risque nul, mais moins urgent qu'estimé avant. -3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** - `getComponents()` retourne une liste de taille **1** (pas de contrôleur) ou **6** (normal) ; les appelants testent `components.size() < 6` et `components.get(2).get(1)` accède positionnellement à la ligne « fuel ». Tout ajout/réordonnancement de ligne casse silencieusement ces contrats implicites. +3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** *(inchangé)* + `getComponents()` retourne toujours une liste de taille 1 (pas de contrôleur) ou 6 (normal) ; les appelants gardent `if (components.size() < 6)` avant un accès positionnel `components.get(2).get(1)` (ligne « fuel »). Toujours fragile à tout réordonnancement de ligne. -4. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** - En mode « normal » (0), `HeatDisplaySource` affiche `"500 °C"` alors que `ReactorSummaryDisplaySource` affiche une **jauge** pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle pour un même mode utilisateur. +4. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** *(inchangé)* + `HeatDisplaySource` affiche `"500 °C"` en mode normal alors que `ReactorSummaryDisplaySource` force une jauge pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle toujours présente. ### 🟡 Mineurs -5. **`CreateNuclearJEI`** — champ statique mutable `Categories` (nom non conventionnel), vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). -6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13 ≈ 1859 itérations) avec 6 comparaisons positionnelles par cellule ; remplaçable par une `Map` précalculée. Coût ponctuel (ouverture ponder). +5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé)* +6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. 7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. -8. **`NuclearExplosionEntity.tick()` (`:96`)** — tri d'une pile de `BlockPos` par `distManhattan` en un tick. ⚠️ La taille réelle est `(2·chunksAffected+1)³` (≈125 pour `size=2`), **pas** 1331 comme indiqué auparavant — coût modeste, corrigé ici. -9. **`CNItemTags.FUEL`/`COOLER` — double source de catégorisation avec `RodType.type()`, déjà désynchronisée** *(assigné Gio, priorité basse)* — Tous les chemins métier (`RodType.TypeRodPredicate.IS_FUEL/IS_COOLED`, `ReactorInputInventory.isItemValid`, `DefaultHeatCalculator`, `ReactorBluePrintMenu`) testent `stack.is(TAG) || rodType.type() == X`, un OR redondant entre deux sources indépendantes. Le tag ne porte aucune stat (juste un `TagKey`) ; toutes les valeurs métier vivent déjà sur `RodType` (registre Java `ItemRodTypesValue` **et** registre dynamique data-driven `CreateNuclearRegistries.ROD_TYPE`, donc déjà extensible par datapack sans tag — confirme le constat positif d'`AUDIT_V1.md:154` sur ce design). Preuve de désync déjà réelle : `THORIUM_ROD` (`CNItems.java:250-258`) a `RodType.fuelRodType()` enregistré mais n'a **pas** le tag `CNItemTags.FUEL` (seulement le tag générique `"rods"`) — ne fonctionne aujourd'hui que grâce au fallback `RodType` dans le OR. - - **Plan concret retenu** : remplacer `TypeRodPredicate.IS_FUEL`/`IS_COOLED` (`RodType.java:301-320`, actuellement `Predicate` basés sur `ItemRodTypesValue.getRodType`, qui ignore le registre dynamique data-driven) par deux méthodes statiques `isFuel(ItemStack stack, Level level)`/`isCooled(ItemStack stack, Level level)` appelant `RodType.resolveRodType(stack.getItem(), level).type() == TypeRod.FUEL/COOLER` — `resolveRodType` interroge le registre dynamique avant de retomber sur le registre Java statique, donc un `RodType` défini uniquement par datapack sera enfin reconnu. Une variante `BiPredicate` a été envisagée mais écartée : aucun appelant actuel ne compose (`and`/`or`/`negate`) ni ne stocke ces prédicats comme valeur, donc le gain fonctionnel d'un type `(Bi)Predicate` est nul ici — une méthode statique nommée `isFuel`/`isCooled` est plus honnête qu'une constante `IS_FUEL` qui dépend en réalité d'un contexte (`Level`) à chaque appel. - - **Sites à migrer une fois `isFuel`/`isCooled` créées** (tous ont déjà un `Level` accessible sauf `DefaultHeatCalculator`, voir point 2) : `ReactorInputInventory.isItemValid` (`:30`, via `be.getLevel()`, ⚠️ nullable hors monde — prévoir fallback), `ReactorBluePrintMenu.saveData` (`:132-133` et `:165-166`, deux boucles dans la même méthode, via `playerInventory.player.level()`), `FuelDisplaySource`/`CoolerDisplaySource`/`ReactorSummaryDisplaySource` (déjà via `context.level()`), `ReactorInputManager.getInventory/extractItems` (déjà un paramètre `Level level`). - - **Déjà conformes au design cible** (aucun tag, déjà `RodType.resolveRodType(item, level)`) : `ReactorHeatUpdateCoordinator.canRun` (`:91`) et `RodsStats.getRodTypeStats` (`:60`) — pas de duplication ici, à ne pas toucher, sert de modèle de référence pour la migration des autres sites. - - *Recommandation* : restreindre les tags `FUEL`/`COOLER` à leur seul usage légitime restant (ingrédients de recettes JSON `Ingredient.of(tag)`, compat datapack/mods tiers côté craft) et ne plus s'y fier dans la logique interne — ne garder que `rodType.type() == X` via `isFuel`/`isCooled`. Risque faible, pas de stats dupliquées à corriger, juste un critère booléen redondant à retirer à 4 endroits (+1 nécessitant d'abord un changement de signature, voir point 2). - - **Pourquoi l'ajouter à l'audit malgré la priorité basse** : c'est une dette qui **s'auto-aggrave silencieusement** — chaque nouvel item fuel/cooler ajouté à `CNItems.java` est un nouveau risque d'oubli du tag (déjà arrivé une fois sur 3 avec `THORIUM_ROD`), et le `||` défensif partout dans le code masque le symptôme sans le corriger. Documenter le plan maintenant évite de redécouvrir le même diagnostic à un audit futur, et fixe le bon modèle de référence (`ReactorHeatUpdateCoordinator`/`RodsStats`) pendant qu'il est encore frais. +8. **`CNItemTags.FUEL`/`COOLER` — double source de catégorisation avec `RodType.type()`, toujours désynchronisée** *(assigné Gio, priorité basse — inchangé, plan non encore exécuté)* — `RodType.java:301-320` (`TypeRodPredicate.IS_FUEL`/`IS_COOLED`) est **toujours** un `Predicate` basé sur `ItemRodTypesValue.getRodType` (sans `Level`), **pas migré** vers `isFuel(ItemStack, Level)`/`isCooled(ItemStack, Level)` basé sur `RodType.resolveRodType`. Tous les sites listés au tour précédent (`ReactorRodInputInventory.isItemValid`, `ReactorBluePrintMenu.saveData` ×2, `*DisplaySource`, `ReactorInputManager`, `DefaultHeatCalculator`) testent toujours le double critère `stack.is(TAG) || rod.type() == X`. **`THORIUM_ROD`** (`CNItems.java:220-228`) a toujours `RodType.fuelRodType()` enregistré mais **pas** le tag `CNItemTags.FUEL` (seul `CNTags.forgeItemTag("rods")`, l.228) — preuve de désync inchangée. Plan déjà documenté au tour précédent, toujours valide, **non commencé**. +9. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`. --- -## 3. 🏗️ Architecture — état réévalué (sans objectif imposé) - -> Plusieurs « problèmes structurels » des audits V1/ACTUEL sont **réfutés par le code actuel**. On ne raisonne pas par règle automatique (« classe > N lignes → découper »). +## 3. 🏗️ Architecture — état réévalué -| Affirmation historique | Verdict actuel | +| Affirmation historique | Verdict actuel (revérifié 2026-06-28) | |---|---| -| **Inversion `api/`** (`MultiBlockManagerBeta`/`RodType`/`ReactorFluidType` importeraient `content.*`) | ❌ **Réfuté** — aucun des trois n'importe `content.*` ; ils utilisent leurs propres types `*Value` (api). Aucune action. | -| **Deux/trois frameworks multiblock concurrents** | ❌ **Réfuté** — `lib.multiblock.manager.*` et `IBetterPattern` **n'existent plus**. Le reste de `lib/multiblock` est **activement utilisé** par `CNMultiblock`. Ce n'est pas une couche concurrente mais un **pipeline séquentiel** : scan géométrique → `ReactorAssembler` → `CNMultiblock.findStructure` → données `RodType`/`ReactorFluidType`. Le vrai problème n'est pas la coexistence mais la **garde d'exécution de la 1ʳᵉ étape** (§2 point 1). Ne pas fusionner (gros risque, gain incertain). | -| **God class `ReactorControllerBlockEntity`, cible <300 lignes** | ✅ **Chantier clos** — 492 lignes, délégation réelle (service/manager/consumable/display). Ce qui reste est la coordination légitime d'un multiblock. **Continuer à viser <300 lignes serait une erreur** : il n'y a plus de logique métier à extraire, seulement de la coordination — découper ajouterait de l'indirection. | -| **Coordinateur de verrou fluide `ReactorFluidLockCoordinator`** | ✅ **Non justifié** (les deux audits convergent) — `tryLockFluid`/`canAcceptFluid`/`clearLock` sont de simples délégations 3-7 lignes vers `PersistentFluidLocks` (le double-système `FluidLockManager` a été supprimé, B14 résolu). `clearLockIfAllInputsEmpty` n'a plus de scan 3D (utilise `inputFluidManager.getFuildHandlers(level)`). Ne plus y revenir. | -| **`run/` à `.gitignore`** | ✅ Règles `run/*` présentes — mais résidu de fichiers déjà trackés (voir §4). | +| **Inversion `api/`** | ❌ **Toujours réfuté** — `MultiBlockManagerBeta`, `api/multiblock/rods/RodType`, `api/multiblock/fluid/ReactorFluidType` n'importent toujours aucun `content.*` (imports vérifiés ligne par ligne). Aucune action. | +| **Deux/trois frameworks multiblock concurrents** | ❌ **Toujours réfutté** — `lib/multiblock/manager/*` et `IBetterPattern` n'existent toujours pas (8 fichiers restants dans `lib/multiblock/`, tous utilisés). Le commit `20c1df0b` (*"IO blocks are now natively Casings"*) ne change rien à l'architecture : il nettoie 22 lignes d'une scène Ponder, les blocs I/O restent des `Block` séparés. | +| **God class `ReactorControllerBlockEntity`** | ✅ **Chantier toujours clos, classe en légère croissance maîtrisée** — **529 lignes** (492 au dernier audit), délégation à **34 fichiers** de support : `service/` (14, était 8), `manager/` (12, était 5), `consumable/` (6), `display/` (2). La croissance suit l'ajout de fonctionnalités (gestion de la frame, alarmes, etc.), pas une régression de la délégation — le constructeur injecte toujours les dépendances via interfaces (`IHeatService`, `IPersistenceService`, etc.). Pas d'action. | +| **Coordinateur de verrou fluide** | ✅ **Toujours non justifié** — `PersistentFluidLocks` reste le seul système ; pas de `FluidLockManager` concurrent retrouvé. `clearLockIfAllInputsEmpty` utilise toujours `inputFluidManager.getFuildHandlers(level)` (pas de scan 3D), avec une double itération mineure (boucle sur handlers puis sur `getTanks()`) sans gravité. | +| **`src/test`** | ❌ **Toujours vide** — confirmé, 0 fichier `.java` sous `src/test`. Le point structurel le plus important du projet reste entier. | +| **Radiation étendue à `LivingEntity` (nouveau, `9ded502c`)** | ✅ **Extension propre** — le point de vérité unique `canBeIrradiated(LivingEntity)` est toujours respecté (un seul appel, `RadiationCapability.java:107`), le hook passe par `LivingTickEvent` (pas de boucle manuelle sur les entités du monde). ⚠️ **Point à surveiller, pas un bug** : pour les non-joueurs, `tickRadiation` recalcule `computeItemRadiation` à **chaque tick sans dirty-check** (le hash d'inventaire existant ne couvre que le joueur, l.90-95 vs l.96-98) — assumé dans le commit (« no equivalent inventory to diff against »), mais à reconsidérer si la densité de mobs équipés en zone irradiée augmente. | +| **Advancements de pose centralisés sur le contrôleur (nouveau, `19617118`)** | ✅ **Amélioration confirmée** — `MultiblockHelpers.handleAdvancedPlacedBy` (l.58-66) redirige `setPlacedBy` vers le contrôleur via `getControllerForPart`, et `CNAdvancementBehaviour.java:106` vérifie maintenant `!advancement.isAlreadyAwardedTo(player)` (état Minecraft natif) au lieu d'une liste interne. Élimine un risque de double-attribution. Limite résiduelle (pas une régression) : si le contrôleur n'est pas encore résolu au moment de la pose, l'advancement de pose est silencieusement sauté pour cette pièce. | -**Vrai writ-large structurel : l'absence de tests.** Ni la taille des classes ni le nombre de packages radiation ne limitent autant la maintenabilité que l'absence totale de couverture sur la chaleur, le pattern matching et le verrouillage fluide — exactement là où les bugs silencieux (sur-extraction fluide, asymétrie `DefaultHeatCalculator`, tautologie `IHeat`) survivent à plusieurs audits. +**Vrai writ-large structurel : l'absence de tests**, inchangé — c'est toujours là (chaleur, pattern matching, verrouillage fluide, et maintenant le double-scan multiblock) que les bugs silencieux survivent aux audits successifs. --- ## 4. 🧹 Dead code & features inachevées — reste à faire -> **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (utilisé par `CNAdvancedModelBox` sur le chemin de rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé ~10× par `NuclearMushroomCloudModel`). +> **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé par `NuclearMushroomCloudModel`). **Pur dead code (retrait sûr)** -- **`SimpleMultiBlockPattern.test()`** (`lib/multiblock/SimpleMultiBlockPattern.java:72-74`) — aucun appelant (grep confirmé). Retrait trivial. -- **`IrradiatedBiomes.monsters()`** (l.17-18) — corps **vide**, appelé `(95, 5, 100)` (`:55`) silencieusement ignorés. À retirer ou implémenter. -- **Méthodes d'animation mortes** dans `CNAdvancedEntityModel`/`CNAdvancedModelBox` (`chainSwing`, `chainWave`, `chainFlap`, `faceTarget`, `walk`, `flap`, `swing`, `bob`, `moveBox`, `progressRotation*`, `progressPosition*`, `getMovementScale`/`setMovementScale`, `transitionTo`, `calculateChain*`, `displayList`/`compiled`) — zéro appelant, mais **retrait non trivial** (cascade interne : `calculateRotation`/`bob` appellent `getMovementScale()`). Nettoyage dédié + dédup `ModelBox`. **Pas un quick win.** +- **`lib/multiblock/SimpleMultiBlockPattern.java` méthode `test()`** (l.72-74) — toujours aucun appelant (grep confirmé). Retrait trivial. +- **`IrradiatedBiomes.monsters()`** — corps toujours vide, appelé avec des arguments (95, 5, 100) silencieusement ignorés. À retirer ou implémenter. **Code commencé puis abandonné (hygiène de fin de PR)** -- `PlayerInteracteReactorFluidInput.java:57-61` — bloc d'interaction fluide commenté/inachevé. -- `ReactorOutput.java:43,52,114` — propriété `SPEED` entièrement commentée. -- `CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` à trancher. +- `content/multiblock/input/fluid/PlayerInteracteReactorFluidInput.java:57-61` — bloc d'interaction fluide toujours commenté/inachevé (non touché par le récent nettoyage de `ReactorOutput`). +- `content/multiblock/output/ReactorOutput.java:43,52,93` — propriété `SPEED` toujours entièrement commentée (pas supprimée). +- `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. -**Reliquats Git (`run/`)** — 19 fichiers encore trackés malgré `.gitignore`. `git rm --cached` sur les **6 artefacts de debug/env** uniquement : +**Reliquats Git (`run/`)** — confirmé via `git ls-files run/` : il reste **6 fichiers de debug/env trackés** malgré `.gitignore` : `run/hs_err_pid21100.log`, `run/hs_err_pid27848.log`, `run/imgui.ini`, `run/servers.dat`, `run/servers.dat_old`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`. -⚠️ **Conserver** les `run/schematics/*.nbt` (assets de gameplay légitimes : `reactor*.nbt`, ponder, etc.). +⚠️ **Conserver** les 10 `run/schematics/*.nbt` (assets de gameplay légitimes). **Décisions produit (pas du pur dead code — choisir puis exécuter)** -- **Collier teignable chat/loup non câblé** *(confirmé)* : `IrradiatedWoldCollarLayer.render()` est un **corps vide** (l.21-22) ; `IrradiatedCatCollarLayer` n'est **jamais enregistré** via `addLayer(...)` (grep confirmé, renderers dans `CNEntityType.java:51,71` sans layer). Pourtant `IrradiatedCat` câble entièrement `DyeItem → setCollarColor/getCollarColor` (`IrradiatedCat.java:334-342`). ⚠️ `IrradiatedWolf` ne câble **même pas** l'interaction dye (`DATA_COLLAR_COLOR` commenté l.61, `mobInteract` sans logique dye). → Un joueur peut teindre le collier d'un chat irradié, l'action est acceptée, **rien ne s'affiche jamais**. *Décision* : enregistrer le layer + implémenter `render`, ou retirer toute la mécanique `DyeItem`/`setCollarColor`. +- **Collier teignable chat/loup non câblé** *(inchangé)* : `IrradiatedWoldCollarLayer.render()` reste un corps vide ; `IrradiatedCatCollarLayer` n'est toujours pas enregistré via `addLayer(...)` dans `CNEntityType.java`. `IrradiatedWolf` ne câble toujours pas l'interaction `DyeItem`/`setCollarColor` (`mobInteract` sans logique dye), alors qu'`IrradiatedCat` câble entièrement `DyeItem → setCollarColor/getCollarColor`. Un joueur peut toujours teindre le collier d'un chat irradié sans effet visible. *Décision* : enregistrer le layer + implémenter `render`, ou retirer toute la mécanique `DyeItem`/`setCollarColor`. -- ~~**Teinture de tissu sur l'armure anti-radiation — icône d'item non colorée**~~ — **✅ RÉSOLU (2026-06-22), vérifié en jeu**. Le diagnostic des deux audits était incomplet : l'**armure portée** prenait déjà la bonne couleur via `getArmorTexture` (chemin `HumanoidArmorLayer`, qui lit bien le NBT `ClothColor` en Forge 47.x), mais l'**icône d'item** (inventaire + slot résultat de la smithing table) restait sur la texture par défaut car le **modèle d'item est statique** et ne lit aucun NBT — deux chemins de rendu distincts. Correctif appliqué : enregistrement d'une `ItemProperty` client `createnuclear:cloth_color` (`CreateNuclearClient.registerItemProperties`, valeur normalisée `(id+1)/16` pour passer l'écrêtage `[0,1]`) + génération en datagen de 64 modèles enfants colorés et des `overrides` correspondants (`CNItems.coloredArmorModel`, clés texture `layer0`/`particle` pour le casque, `14` pour les autres pièces, pointant vers les sheets `item/armors/_anti_radiation_suit` déjà présentes). Le tooltip de pis-aller (`AntiRadiationArmorItem.makeSummary`/`appendHoverText`) et la clé de lang `tooltip.cloth.color` ont été retirés. `getArmorTexture` + `ClothTagHelper` sont donc **bien vivants et fonctionnels** — ni l'un ni l'autre n'est à supprimer. - -**Worldgen « irradié » — template non terminé** -- `IrradiatedBiomes.addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent du contenu vanilla sans rapport (`MiscOverworldPlacements.BLUE_ICE`, `Carvers.NETHER_CAVE`, `VOID_START_PLATFORM`) + `monsters()` no-op — pipeline copié/non re-thémé. -- `CNNoiseGeneratorSettings.IRRADIATED` définit `STEEL_BLOCK` comme bloc de remplissage par défaut (équivalent « stone ») — terrain massivement en acier si relié à une dimension. Point d'alerte indépendant des surface rules (corrigées). +**Worldgen « irradié » — template non terminé** *(inchangé)* +- `IrradiatedBiomes.addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent toujours du contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`). +- `CNNoiseGeneratorSettings.IRRADIATED` utilise toujours `STEEL_BLOCK` comme bloc de remplissage par défaut. --- @@ -123,56 +117,61 @@ La **dette la plus structurelle reste l'absence totale de tests** (`src/test` vi | Point | État | Réf. | |---|---|---| -| `ReactorPattern.findController/findControllerPos` : scan fusionné + court-circuit + filtre `isInReactorRange` (✅), double scan `MultiblockHelpers` éliminé (✅) ; **sans garde client** (❌), double appel `playerDestroy`+`onRemove` sur `ReactorCasing`/`ReactorCooler` (❌) | 🟡 partiellement corrigé — reste **priorité n°1** | §2.1 | -| `DefaultHeatCalculator.computeHeat` : ~O(n²) + désérialisation NBT par cellule, à chaque tick | ❌ non corrigé | §2.2 | -| `HelmetOverlay.renderHotbar` + 3× `getArmor(HEAD)`/frame | ❌ non corrigé | — | -| `clearLockIfAllInputsEmpty` : ancien scan cubique `O(n³)` | ✅ **corrigé** (utilise `inputFluidManager.getFuildHandlers`) | §3 | +| `ReactorPattern.findController` (Casing/Cooler/Frame) : **ne court-circuite jamais**, scanne ~3971 positions à chaque pose/casse même après avoir trouvé le contrôleur | ❌ **non corrigé, nouvellement précisé** — chemin le plus chaud | §2.1 | +| `ReactorPattern.findControllerPos` (Output/RodInput/FluidInput/Alarm via `MultiblockHelpers`) : court-circuite bien | ✅ déjà correct | §2.1 | +| Aucune garde `level.isClientSide()` sur toute la chaîne de scan | ❌ non corrigé | §2.1 | +| Double scan à la casse (`playerDestroy` + `onRemove`) sur Casing/Cooler/Output/FluidInput (sans garde) et Alarm/Frame (garde partielle) ; **`ReactorRodInput` seul correctement conçu** | ❌ non corrigé, modèle de référence identifié | §2.1 | +| `DefaultHeatCalculator.computeHeat` : neighbor lookup passé de O(n) à O(1) (map), reste une boucle O(81) de recherche de position par rod | 🟡 **partiellement corrigé, gravité réévaluée à la baisse** | §2.2 | +| `clearLockIfAllInputsEmpty` : pas de scan cubique O(n³), double itération mineure | ✅ acceptable | §3 | --- ## 6. ✅ Pour mémoire — déjà corrigé (ne plus reprendre) -Vérifiés résolus dans le code actuel : **B2** (`RadiationSyncPacket` supprimé, synchro via capability + `PlayerTickEvent`), **B3/B4/B5/B6/B8/B9/B11/B13/B16/B19** (cooldown `Map`, loot/tag thorium, `BiomeTagRule.apply` → `Condition`, packet blueprint, scan null-safe, paliers radiation 4 niveaux, logger après null-check, bras armure anti-radiation, garde `conditions` datagen, surface rules v1 disparues), **B12** (`AnimalUtil.isFood` teste `foodItems.test(stack)`), **B14** (`FluidLockManager` supprimé, `PersistentFluidLocks` seul), **off-by-one `getFluidInTank`** (→ `getFluidInTank(0)`). Le « double comptage `IRadiationSource` vs `RadiationRegistry` » est **architecturalement bloqué** (`RadiationRegistry` lève `IllegalStateException` à l'enregistrement si l'item implémente déjà `IRadiationSource`) — duplication de design maladroite mais pas de bug concret. +Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B3/B4/B5/B6/B8/B9/B11/B13/B16/B19, B12, B14**, off-by-one `getFluidInTank`, icône d'item de l'armure anti-radiation teinte, tous les problèmes radiation historiques (point de vérité unique `canBeIrradiated`). + +**Confirmé corrigé le 2026-06-26** : **spam de log `ReactorAssembler.assemble`** — plus aucun `LOGGER.warn`/`info` dans le chemin de succès (commit `b309f231`). *(Quick win n°3 de la feuille de route précédente, traité.)* -**Corrigé le 2026-06-22** : **icône d'item de l'armure anti-radiation teinte** — l'icône en inventaire / slot résultat de la smithing table suivait pas la couleur du tissu (l'armure *portée*, elle, fonctionnait déjà). Cause : modèle d'item statique, chemin de rendu distinct de `getArmorTexture`. Câblé via `ItemProperty` client `createnuclear:cloth_color` + 64 modèles d'overrides générés en datagen (`CNItems.coloredArmorModel`, `CreateNuclearClient.registerItemProperties`). Tooltip de pis-aller + clé de lang `tooltip.cloth.color` retirés. Détail en §4. +**Confirmé corrigé (NuclearExplosionEntity, ex-B15)** : l'ancien anti-pattern `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` a disparu. Le code actuel (`NuclearExplosionEntity.java:224-232`) fait une vérification explicite (`if (level().getBlockState(immutablePos).is(state.getBlock())) level().destroyBlock(...)`) au lieu d'avaler une exception. Plus d'anti-pattern de contrôle par exception. -**Corrigé le 2026-06-23** : **tous les problèmes radiation (ancienne §2)**. Cause racine commune des 3 chemins d'application : la logique d'éligibilité était dupliquée et divergente. -- **Point de vérité unique** : nouveau `RadiationCapability.canBeIrradiated(LivingEntity)` (spectateur → tag `IRRADIATED_IMMUNE` → config `enabledItemRadiation` → blacklist → résistance < 1.0), réutilisé par les trois chemins. -- **`RadiationEffectHandler.apply`** (fuite de tuyau, 3ᵉ chemin) : appliquait la radiation **sans aucune garde** → filtre désormais via `canBeIrradiated`. -- **`RadiationEffect`** : le filtre du `VicinityEffect` reconstruisait un `HashSet` + reparsait la blacklist **par entité/tick** → réduit à `canBeIrradiated(e) && !e.hasEffect(...)`. La blacklist est mise en **cache statique** dans `RadiationCapability`, reconstruite uniquement quand l'instance de liste de config change (auto-invalidée au reload, sans event ni couplage `config → content`). Élimine le point de perf §5. -- **`RadiationCapability.applyEffects`** : pas de garde spectateur → `onPlayerTick` gate désormais sur `canBeIrradiated(player)`. L'atténuation continue par résistance reste séparée (non touchée). -- **`RadiationCapability.lastBiomeLocation`** : lu mais non persisté → sérialisé/désérialisé en NBT (`RadiationProvider`). -- **Overlays concurrents** : `RadiationOverlay` (jamais rendu, fade binarisé par `Math.round`) + `EasingHudOverlay` + l'appel no-op `HelmetOverlay.setCoverage`/`COVERAGE_FACTORS` **supprimés** ; `IrradiatedOverlayRendererVision` (fade lisse, garde spectateur) reste seul. Compilation vérifiée (`gradlew compileJava`). +**Confirmé sain, nouveau code 2026-06-25/27** : `CNBuilderTransformers` (extraction propre des builders de modèles d'item/spawn-egg hors de `CNItems`, 97 lignes, SRP respectée) et l'item **Biome Restore Cell** (`BiomeRestoreCellItem`, 75 lignes, logique métier déléguée à `BiomeIrradiationService`, gardes serveur/client correctes) — aucun problème structurel à signaler, rien à ajouter au plan d'action. + +**Confirmé neutre** : le commit `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) ne fusionne rien dans le code de jeu — nettoyage cosmétique d'une scène Ponder uniquement. --- ## 7. 🗺️ Feuille de route — priorités **Quick wins (risque quasi nul, gain immédiat)** -1. Garde `level.isClientSide()` sur `findController`/`findControllerPos`/`ReactorAssembler` (§2.1). **← le plus rentable, toujours à faire.** -2. Retirer l'appel redondant à `findController` dans `ReactorCasing.playerDestroy` + `ReactorCooler.playerDestroy` (généraliser la garde de `ReactorFrame.onRemove`). *(Toujours à faire — distinct du double-scan `MultiblockHelpers`, déjà corrigé le 2026-06-24.)* -3. `ReactorAssembler` : `LOGGER.warn` → `LOGGER.debug` (l.37). +1. **`ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur** (l.69), pour court-circuiter comme `findControllerPos` le fait déjà. **← nouveau, le plus rentable : c'est le chemin appelé par le bloc le plus posé/cassé (Casing).** +2. Garde `level.isClientSide()` en tête de `findController`/`findControllerPos`/`ReactorAssembler.assemble/disassemble`. +3. Généraliser le modèle `ReactorRodInput` (un seul appel, dans `onRemove`, guardé par `!state.is(newState.getBlock())`, pas de `playerDestroy`) à `ReactorCasing`, `ReactorCooler`, `ReactorOutput`, `ReactorFluidInput` (aucune garde aujourd'hui) et `ReactorAlarm`/`ReactorFrame` (garde partielle, mais double appel résiduel à la casse joueur). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. -5. `NuclearExplosionEntity` (B15) : remplacer le try/catch de contrôle par une vérification explicite. -6. `git rm --cached` sur les 6 fichiers de debug `run/` (§4). -7. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. +5. `git rm --cached` sur les 6 fichiers de debug `run/` (§4). +6. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. **Corrections ciblées (risque faible à moyen)** -8. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). -9. `DefaultHeatCalculator` : map slot→ItemStack précalculée (O(n²) → O(n)) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance (§2.2). +7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). +8. `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle 81 cellules (gain mineur désormais, priorité baissée par rapport au tour précédent) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance. +9. Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques (§2.9). **Assigné Gio (priorité basse, à faire quand le temps le permet)** -13. Tags `CNItemTags.FUEL`/`COOLER` → créer `TypeRodPredicate.isFuel/isCooled(stack, level)` basés sur `RodType.resolveRodType`, migrer `ReactorInputInventory`, `ReactorBluePrintMenu`, les `*DisplaySource`, `ReactorInputManager` ; restreindre les tags au craft (§2.9). Le site `DefaultHeatCalculator` nécessite d'abord d'ajouter `Level` à `IHeatCalculator.computeHeat` (§2.2) — à faire en premier sur ce fichier précis, indépendamment du chantier perf O(n²) déjà prévu au point 9 ci-dessus. +10. Tags `CNItemTags.FUEL`/`COOLER` → créer `TypeRodPredicate.isFuel/isCooled(stack, level)` basés sur `RodType.resolveRodType`, migrer `ReactorRodInputInventory`, `ReactorBluePrintMenu`, les `*DisplaySource`, `ReactorInputManager` ; restreindre les tags au craft (§2.8). Le site `DefaultHeatCalculator` nécessite d'abord d'ajouter `Level` à `IHeatCalculator.computeHeat` — toujours en suspens, non commencé. **Décisions produit (choisir puis exécuter)** -10. Collier teignable chat/loup : finir le câblage (`addLayer` + `render`) ou retirer `DyeItem`/`setCollarColor` (§4). -11. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). +11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). +12. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). **Chantier de fond (le plus rentable à long terme)** -12. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs silencieux ont survécu à plusieurs audits. +13. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. + +**À surveiller sans action immédiate** +14. `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (recalcul à chaque tick) — compromis assumé par le commit `9ded502c`, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. **Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** -- Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos). +- Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos, croissance maîtrisée). - « Correction » de l'inversion de dépendance `api/` (n'existe pas). -- Fusion/suppression du pipeline multiblock (sain ; seule la garde d'exécution manque). -- Coordinateur dédié au verrouillage fluide `ReactorFluidLockCoordinator` (non justifié). +- Fusion/suppression du pipeline multiblock (sain). +- Coordinateur dédié au verrouillage fluide (non justifié). +- Spam de log `ReactorAssembler` (corrigé le 2026-06-26). +- Anti-pattern try/catch `NuclearExplosionEntity` / B15 (corrigé). From 34d5706f159279632b520f5d04b6bbdf78a3dd58 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 13:46:34 +0200 Subject: [PATCH 118/171] perf: add client-side guard and remove duplicate scan on block break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `if (level.isClientSide) return;` at the top of ReactorAssembler.assemble/disassemble — the single convergence point of the whole onPlace/onRemove/playerDestroy -> findController/ findControllerPos -> ReactorAssembler chain — so the multiblock scan and its mutations no longer run on the client in addition to the server. Remove the redundant `playerDestroy` override from ReactorCasing, ReactorCooler, ReactorFrame, ReactorAlarm, ReactorOutput and ReactorFluidInput, which each ran a second full controller scan on top of the one `onRemove` already runs for every block removal (including player breaks). Generalizes the pattern already used correctly by ReactorRodInput (removal handled solely in `onRemove`), cutting the scan count on breaking these blocks in half with no behavioral change. Document both fixes in AUDIT_ACTUEL.md, downgrade the multiblock scan finding from critical to important now that only the missing short-circuit in `findController` remains open, and flag a minor residual gap: ReactorOutput/ReactorFluidInput's `onRemove` still lacks the `!state.is(newState.getBlock())` guard that ReactorAlarm/ ReactorFrame have for their mutable block properties. --- AUDIT_ACTUEL.md | 31 +++++++++---------- .../content/multiblock/ReactorAssembler.java | 4 +++ .../multiblock/alarm/ReactorAlarm.java | 7 ----- .../multiblock/casing/ReactorCasing.java | 6 ---- .../multiblock/cooler/ReactorCooler.java | 6 ---- .../multiblock/frame/ReactorFrame.java | 6 ---- .../input/fluid/ReactorFluidInput.java | 6 ---- .../multiblock/output/ReactorOutput.java | 6 ---- 8 files changed, 19 insertions(+), 53 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f2cf3518..a16de078 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -32,19 +32,16 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to ## 2. 🆕 Autres problèmes (hors radiation) -### 🔴 Critique — performance/correction du scan multiblock +### 🟠 Important — performance résiduelle du scan multiblock (était 🔴, deux des trois sous-points corrigés le 2026-06-28) -1. **Scan géométrique du contrôleur : court-circuit incomplet + aucune garde client + double appel pose/casse** *(nuancé — affiné 2026-06-28)* +1. **Scan géométrique du contrôleur : court-circuit incomplet (findController)** *(garde client et double scan corrigés 2026-06-28, vérifié par lecture directe du code modifié)* - ✅ **Toujours acquis** — `ReactorPattern` n'a qu'**une seule** boucle de scan partagée (`scanControllerCandidates`, `ReactorPattern.java:40-56`) sur ~3971 positions (`y∈[-5,+5]`, `x,z∈[-9,+9]`), filtrée par `isInReactorRange` (l.111-113). - - ❌ **Nuance nouvelle, non vue par l'audit précédent** — le court-circuit (`return true` dans le visiteur dès qu'un contrôleur pertinent est trouvé) n'existe que dans **`findControllerPos`** (`ReactorPattern.java:73-94`, utilisé via `MultiblockHelpers.handleOnPlace/handleRemoval/getControllerForPart` → donc par `ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`). **`findController`** (`ReactorPattern.java:58-71`), appelé **directement** par `ReactorCasing.java:49,61,67`, `ReactorCooler.java:28,40,46` et `ReactorFrame.java:113,125,135`, a un visiteur qui **retourne toujours `false`** (l.69) : il continue de parcourir les ~3971 positions restantes même après avoir traité le contrôleur pertinent. `ReactorCasing` étant le bloc le plus posé/cassé (coque du réacteur), c'est le chemin le plus chaud des deux et il n'est **pas** optimisé. Fix trivial : faire retourner `inRange` au lieu de `false` dans le visiteur de `findController`, comme c'est déjà fait dans `findControllerPos`. - - ❌ **Toujours non corrigé** — **aucune garde `level.isClientSide()`** dans toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler.assemble/disassemble`. (Le seul `isClientSide` du fichier, `ReactorFrame.java:71`, est dans `neighborChanged`, sans rapport.) - - ❌ **Toujours non corrigé, état affiné par bloc** — double scan à la casse : - - `ReactorCasing`/`ReactorCooler` : **aucune garde**, `playerDestroy` et `onRemove` appellent chacun `pattern.findController(pos, level, false)` sans condition → double scan systématique à chaque casse joueur. - - `ReactorOutput.java:71-79` et `ReactorFluidInput.java:94-103` : même défaut via `MultiblockHelpers.handleRemoval`, **sans aucune garde** dans `onRemove`. - - `ReactorAlarm.java:43-60` et `ReactorFrame.java:123-137` : `onRemove` est **guardé** (`if (!state.is(newState.getBlock()))`) pour ne pas re-scanner sur un simple changement d'état (rotation, etc.), mais ce garde **ne protège pas** du double appel quand le joueur casse réellement le bloc — `playerDestroy` s'exécute toujours en plus. - - **`ReactorRodInput.java:82-92` est le seul bloc correctement conçu** : pas de `playerDestroy` du tout, un seul appel dans `onRemove`, guardé par le changement de type de bloc. **C'est le modèle de référence à généraliser** aux 5 autres blocs (retirer l'appel de `playerDestroy`, garder l'appel guardé dans `onRemove`). + - ❌ **Toujours non corrigé** — le court-circuit (`return true` dans le visiteur dès qu'un contrôleur pertinent est trouvé) n'existe que dans **`findControllerPos`** (`ReactorPattern.java:73-94`, utilisé via `MultiblockHelpers.handleOnPlace/handleRemoval/getControllerForPart` → donc par `ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`). **`findController`** (`ReactorPattern.java:58-71`), appelé **directement** par `ReactorCasing.java:49,61`, `ReactorCooler.java:28,40` et `ReactorFrame.java:113,129`, a un visiteur qui **retourne toujours `false`** (l.69) : il continue de parcourir les ~3971 positions restantes même après avoir traité le contrôleur pertinent. `ReactorCasing` étant le bloc le plus posé/cassé (coque du réacteur), c'est le chemin le plus chaud des deux et il n'est **toujours pas** optimisé. Fix trivial inchangé : faire retourner `inRange` au lieu de `false` dans le visiteur de `findController`, comme c'est déjà fait dans `findControllerPos`. + - ✅ **Corrigé le 2026-06-28** — garde `level.isClientSide` ajoutée en tête de `ReactorAssembler.assemble` (`ReactorAssembler.java:34`) et `ReactorAssembler.disassemble` (l.58), plutôt que dans `findController`/`findControllerPos` comme envisagé initialement : ces deux méthodes sont le point de convergence unique de toute la chaîne (`findController` direct sur Casing/Cooler/Frame, et `findControllerPos` via `MultiblockHelpers` sur Alarm/Output/FluidInput/RodInput), donc une garde centralisée ici couvre l'intégralité du chemin `onPlace/onRemove/playerDestroy → ... → assemble/disassemble` sans dupliquer le test dans 7 classes de blocs. + - ✅ **Corrigé le 2026-06-28** — double scan à la casse résolu en généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel dans `onRemove`, pas de `playerDestroy`) : `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` n'ont plus d'override `playerDestroy` (vérifié par lecture directe des 6 fichiers — l'override a été supprimé, pas seulement vidé). Comme `onRemove` se déclenche déjà systématiquement lors d'une casse joueur (avant l'appel `playerDestroy` du `PlayerInteractionManager`), retirer l'appel redondant dans `playerDestroy` élimine le double scan sans changer de comportement observable. `ReactorAlarm`/`ReactorFrame` conservent en plus leur garde `!state.is(newState.getBlock())` dans `onRemove` (utile pour leurs propriétés mutables `POWERED`/`PART`). + - **Point résiduel mineur, non corrigé** — `ReactorOutput` (propriété `DIR`) et `ReactorFluidInput` (propriété `FACING`) ont une propriété mutable mais leur `onRemove` (`ReactorOutput.java:71-74`, `ReactorFluidInput.java:93-97`) n'a **pas** la garde `!state.is(newState.getBlock())`. Pas un bug confirmé (aucun chemin connu ne change `DIR`/`FACING` via `setBlock` sans remplacer le bloc) mais à surveiller si une interaction clé/wrench s'avère un jour déclencher un retrait/réenregistrement non désiré. - ✅ **Corrigé et confirmé stable** — `ReactorAssembler.assemble` ne logue plus rien en succès (`ReactorAssembler.java`, vérifié : aucun `LOGGER.warn`/`LOGGER.info` dans `assemble`/`disassemble`). *(Quick win traité par le commit `b309f231`.)* - - *Reste à faire* : (a) `findController` doit court-circuiter comme `findControllerPos` (1 ligne, gain net immédiat sur le chemin le plus chaud) ; (b) `if (level.isClientSide()) return;` en tête de `findController`/`findControllerPos` ; (c) aligner `ReactorCasing`, `ReactorCooler`, `ReactorOutput`, `ReactorFluidInput`, `ReactorAlarm` sur le modèle `ReactorRodInput` (un seul appel, dans `onRemove`, guardé par le changement de bloc). Risque très faible, **reste la priorité n°1 du projet**. + - *Reste à faire* : `findController` doit court-circuiter comme `findControllerPos` (1 ligne, gain net immédiat sur le chemin le plus chaud — Casing). Risque très faible, **reste la priorité n°1 du projet** (perf uniquement désormais, plus une question de correction). ### 🟠 Importants @@ -117,10 +114,10 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to | Point | État | Réf. | |---|---|---| -| `ReactorPattern.findController` (Casing/Cooler/Frame) : **ne court-circuite jamais**, scanne ~3971 positions à chaque pose/casse même après avoir trouvé le contrôleur | ❌ **non corrigé, nouvellement précisé** — chemin le plus chaud | §2.1 | +| `ReactorPattern.findController` (Casing/Cooler/Frame) : **ne court-circuite jamais**, scanne ~3971 positions à chaque pose/casse même après avoir trouvé le contrôleur | ❌ **non corrigé** — chemin le plus chaud, dernier point ouvert | §2.1 | | `ReactorPattern.findControllerPos` (Output/RodInput/FluidInput/Alarm via `MultiblockHelpers`) : court-circuite bien | ✅ déjà correct | §2.1 | -| Aucune garde `level.isClientSide()` sur toute la chaîne de scan | ❌ non corrigé | §2.1 | -| Double scan à la casse (`playerDestroy` + `onRemove`) sur Casing/Cooler/Output/FluidInput (sans garde) et Alarm/Frame (garde partielle) ; **`ReactorRodInput` seul correctement conçu** | ❌ non corrigé, modèle de référence identifié | §2.1 | +| Aucune garde `level.isClientSide()` sur toute la chaîne de scan | ✅ **corrigé le 2026-06-28** — garde centralisée dans `ReactorAssembler.assemble`/`disassemble` | §2.1 | +| Double scan à la casse (`playerDestroy` + `onRemove`) sur Casing/Cooler/Output/FluidInput (sans garde) et Alarm/Frame (garde partielle) | ✅ **corrigé le 2026-06-28** — modèle `ReactorRodInput` généralisé aux 6 autres blocs (override `playerDestroy` supprimé) | §2.1 | | `DefaultHeatCalculator.computeHeat` : neighbor lookup passé de O(n) à O(1) (map), reste une boucle O(81) de recherche de position par rod | 🟡 **partiellement corrigé, gravité réévaluée à la baisse** | §2.2 | | `clearLockIfAllInputsEmpty` : pas de scan cubique O(n³), double itération mineure | ✅ acceptable | §3 | @@ -136,6 +133,8 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Confirmé sain, nouveau code 2026-06-25/27** : `CNBuilderTransformers` (extraction propre des builders de modèles d'item/spawn-egg hors de `CNItems`, 97 lignes, SRP respectée) et l'item **Biome Restore Cell** (`BiomeRestoreCellItem`, 75 lignes, logique métier déléguée à `BiomeIrradiationService`, gardes serveur/client correctes) — aucun problème structurel à signaler, rien à ajouter au plan d'action. +**Corrigé le 2026-06-28** : garde `level.isClientSide` manquante sur la chaîne multiblock et double scan `playerDestroy`/`onRemove` (§2.1). Fix appliqué de façon centralisée plutôt que classe par classe : (1) `if (level.isClientSide) return;` ajouté en tête de `ReactorAssembler.assemble`/`disassemble` — point de convergence unique de toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler` ; (2) l'override `playerDestroy` a été supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput` et `ReactorFluidInput`, généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel de retrait, dans `onRemove`, qui se déclenche systématiquement y compris lors d'une casse joueur). Vérifié par lecture directe des 7 fichiers modifiés. Seul le court-circuit manquant de `findController` (perf pure) reste ouvert — voir §2.1 et §7. + **Confirmé neutre** : le commit `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) ne fusionne rien dans le code de jeu — nettoyage cosmétique d'une scène Ponder uniquement. --- @@ -143,9 +142,9 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B ## 7. 🗺️ Feuille de route — priorités **Quick wins (risque quasi nul, gain immédiat)** -1. **`ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur** (l.69), pour court-circuiter comme `findControllerPos` le fait déjà. **← nouveau, le plus rentable : c'est le chemin appelé par le bloc le plus posé/cassé (Casing).** -2. Garde `level.isClientSide()` en tête de `findController`/`findControllerPos`/`ReactorAssembler.assemble/disassemble`. -3. Généraliser le modèle `ReactorRodInput` (un seul appel, dans `onRemove`, guardé par `!state.is(newState.getBlock())`, pas de `playerDestroy`) à `ReactorCasing`, `ReactorCooler`, `ReactorOutput`, `ReactorFluidInput` (aucune garde aujourd'hui) et `ReactorAlarm`/`ReactorFrame` (garde partielle, mais double appel résiduel à la casse joueur). +1. **`ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur** (l.69), pour court-circuiter comme `findControllerPos` le fait déjà. **← dernier point ouvert de ce chantier, le plus rentable : c'est le chemin appelé par le bloc le plus posé/cassé (Casing).** +2. ~~Garde `level.isClientSide()` en tête de `findController`/`findControllerPos`/`ReactorAssembler.assemble/disassemble`.~~ ✅ **fait le 2026-06-28** (garde centralisée dans `ReactorAssembler.assemble`/`disassemble`). +3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. 5. `git rm --cached` sur les 6 fichiers de debug `run/` (§4). 6. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java index 98890aed..924419ce 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/ReactorAssembler.java @@ -31,6 +31,8 @@ public final class ReactorAssembler { private ReactorAssembler() {} public static void assemble(BlockPos pos, Level level) { + if (level.isClientSide) return; + ReactorControllerBlockEntity entity = getBlockEntity(level, pos); if (entity == null) return; @@ -53,6 +55,8 @@ public static void assemble(BlockPos pos, Level level) { } public static void disassemble(BlockPos pos, Level level) { + if (level.isClientSide) return; + ReactorControllerBlockEntity entity = getBlockEntity(level, pos); if (entity == null || !entity.isAssembled()) return; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java index e3e4c803..a8d9eed8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarm.java @@ -38,13 +38,6 @@ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldS MultiblockHelpers.handleOnPlace(pos, level, ReactorControllerBlockEntity::addAlarm); } - // Unregisters this alarm from the multiblock controller when destroyed by a player - @Override - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - MultiblockHelpers.handleRemoval(pos, level, ReactorControllerBlockEntity::removeAlarm); - } - @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity pPlacer, ItemStack stack) { super.setPlacedBy(level, pos, state, pPlacer, stack); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java index 84468301..048aa90b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/casing/ReactorCasing.java @@ -55,12 +55,6 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } - @Override // called when the player destroys the block, with or without a tool - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - pattern.findController(pos, level, false); - } - @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { super.onRemove(state, level, pos, newState, movedByPiston); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java index e98a90c4..3cdb4cca 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/cooler/ReactorCooler.java @@ -34,12 +34,6 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } - @Override // called when the player destroys the block, with or without a tool - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - pattern.findController(pos, level, false); - } - @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { super.onRemove(state, level, pos, newState, movedByPiston); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java index 4e6c7d69..711f6846 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/frame/ReactorFrame.java @@ -119,12 +119,6 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @javax.anno MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } - @Override // called when the player destroys the block, with or without a tool - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - pattern.findController(pos, level, false); - } - @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { super.onRemove(state, level, pos, newState, movedByPiston); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java index 92b9e7f2..67f47120 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java @@ -90,12 +90,6 @@ public InteractionResult use(BlockState state, Level world, BlockPos pos, Player return PlayerInteracteReactorFluidInput.interact(world, pos, player, hand, heldItem, onClient, ray); } - @Override - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - MultiblockHelpers.handleRemoval(pos, level, ReactorControllerBlockEntity::removeInputFluid); - } - @Override public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { super.onRemove(state, world, pos, newState, isMoving); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java index 95f5dbe8..339c2bae 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java @@ -67,12 +67,6 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @javax.anno MultiblockHelpers.handleAdvancedPlacedBy(pos, level, pPlacer); } - @Override - public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { - super.playerDestroy(level, player, pos, state, blockEntity, tool); - MultiblockHelpers.handleRemoval(pos, level, ReactorControllerBlockEntity::removeOutput); - } - @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); From 9ddb5a2adca6ef7abf3b2d2e81ed502bcf5248df Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 16:08:19 +0200 Subject: [PATCH 119/171] chore: untrack stray run/ debug files and broaden .gitignore coverage Remove six previously-tracked files under run/ that are local dev-environment artifacts, not project sources: two JVM crash logs (hs_err_pid*.log), imgui.ini, the Jade mod jar (disabled), and the servers.dat/servers.dat_old multiplayer server list. Extend .gitignore so these stop reappearing as untracked/modified noise: add run/servers.*, run/mods/, run/hs_err_pid*.log, and run/imgui.init. --- .gitignore | 4 + run/hs_err_pid21100.log | 1152 ------- run/hs_err_pid27848.log | 2638 ----------------- run/imgui.ini | 25 - .../Jade-1.20.1-Forge-11.12.2.jar.disabled | Bin 547818 -> 0 bytes run/servers.dat | Bin 141 -> 0 bytes run/servers.dat_old | Bin 78 -> 0 bytes 7 files changed, 4 insertions(+), 3815 deletions(-) delete mode 100644 run/hs_err_pid21100.log delete mode 100644 run/hs_err_pid27848.log delete mode 100644 run/imgui.ini delete mode 100644 run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled delete mode 100644 run/servers.dat delete mode 100644 run/servers.dat_old diff --git a/.gitignore b/.gitignore index 00f7ff92..6fa41902 100644 --- a/.gitignore +++ b/.gitignore @@ -36,10 +36,14 @@ run/resources/ run/saves/ run/schematics/uploaded run/screenshots/ +run/servers.* +run/mods/ run/fabricloader.log run/options.txt run/usercache.json run/usernamecache.json +run/hs_err_pid*.log +run/imgui.init run/emi.json run/.mixin.out run/gametest diff --git a/run/hs_err_pid21100.log b/run/hs_err_pid21100.log deleted file mode 100644 index fc80693f..00000000 --- a/run/hs_err_pid21100.log +++ /dev/null @@ -1,1152 +0,0 @@ -# -# A fatal error has been detected by the Java Runtime Environment: -# -# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000000000008, pid=21100, tid=23416 -# -# JRE version: OpenJDK Runtime Environment Temurin-21.0.8+9 (21.0.8+9) (build 21.0.8+9-LTS) -# Java VM: OpenJDK 64-Bit Server VM Temurin-21.0.8+9 (21.0.8+9-LTS, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64) -# Problematic frame: -# C [jdwp.dll+0x161bf] -# -# No core dump will be written. Minidumps are not enabled by default on client versions of Windows -# -# If you would like to submit a bug report, please visit: -# https://github.com/adoptium/adoptium-support/issues -# The crash happened outside the Java Virtual Machine in native code. -# See problematic frame for where to report the bug. -# - ---------------- S U M M A R Y ------------ - -Command Line: -Ddebugger.agent.enable.coroutines=true -Dforge.enableGameTest=true -Dforge.logging.console.level=debug -Dforge.logging.markers=REGISTRIES -DignoreList=bootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -Djava.net.preferIPv6Addresses=system -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -DlegacyClassPath.file=C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\classpath\runClient_minecraftClasspath.txt -DmergeModules=jna-5.10.0.jar,jna-platform-5.10.0.jar -Dmixin.debug.export=true -Dmixin.debug.verbose=true -Dmixin.env.refMapRemappingFile=C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge/build/createSrgToMcp/output.srg -Dmixin.env.remapRefMap=true -Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp=C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\createSrgToMcp\output.srg --module-path=C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar --add-modules=ALL-MODULE-PATH --add-opens=java.base/java.util.jar=cpw.mods.securejarhandler --add-opens=java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports=java.base/sun.security.util=cpw.mods.securejarhandler --add-exports=jdk.naming.dns/com.sun.jndi.dns=java.naming -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump --module-path=C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar --add-modules=ALL-MODULE-PATH --add-opens=java.base/java.util.jar=cpw.mods.securejarhandler --add-opens=java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports=java.base/sun.security.util=cpw.mods.securejarhandler --add-exports=jdk.naming.dns/com.sun.jndi.dns=java.naming -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=127.0.0.1:58923 -javaagent:C:\Users\TcT_g\AppData\Local\JetBrains\IntelliJIdea2025.2\captureAgent\debugger-agent.jar=file:///C:/Users/TcT_g/AppData/Local/Temp/capture6757434691262209115.props -Dfile.encoding=UTF-8 -Duser.country=FR -Duser.language=fr -Duser.variant cpw.mods.bootstraplauncher.BootstrapLauncher --launchTarget forgeclientuserdev --version MOD_DEV --assetIndex 5 --assetsDir C:\Users\TcT_g\.gradle\caches\forge_gradle\assets --gameDir . --fml.forgeVersion 47.2.6 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createnuclear.forge.mixins.json - -Host: AMD Ryzen AI 7 350 w/ Radeon 860M , 16 cores, 31G, Windows 11 , 64 bit Build 26100 (10.0.26100.6725) -Time: Wed Nov 26 14:43:23 2025 Paris, Madrid elapsed time: 3.686376 seconds (0d 0h 0m 3s) - ---------------- T H R E A D --------------- - -Current thread (0x000002cd18843d50): JavaThread "main" [_thread_in_native, id=23416, stack(0x000000fc5da00000,0x000000fc5db00000) (1024K)] - -Stack: [0x000000fc5da00000,0x000000fc5db00000], sp=0x000000fc5dafe570, free space=1017k -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -C 0x0000000000000008 - -Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) -j org.lwjgl.glfw.GLFW.glfwInit()Z+0 org.lwjgl.glfw@3.3.1+7 -j net.minecraftforge.fml.earlydisplay.DisplayWindow.initWindow(Ljava/lang/String;)V+4 fmlearlydisplay@1.20.1-47.2.6 -j net.minecraftforge.fml.earlydisplay.DisplayWindow.start(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Runnable;+14 fmlearlydisplay@1.20.1-47.2.6 -j net.minecraftforge.fml.earlydisplay.DisplayWindow.initialize([Ljava/lang/String;)Ljava/lang/Runnable;+410 fmlearlydisplay@1.20.1-47.2.6 -j net.minecraftforge.fml.loading.ImmediateWindowHandler.load(Ljava/lang/String;[Ljava/lang/String;)V+180 fmlloader@1.20.1-47.2.6 -j net.minecraftforge.fml.loading.ModDirTransformerDiscoverer.earlyInitialization(Ljava/lang/String;[Ljava/lang/String;)V+2 fmlloader@1.20.1-47.2.6 -j cpw.mods.modlauncher.TransformationServicesHandler.lambda$discoverServices$18(Lcpw/mods/modlauncher/ArgumentHandler$DiscoveryData;Lcpw/mods/modlauncher/serviceapi/ITransformerDiscoveryService;)V+9 cpw.mods.modlauncher@10.0.9 -j cpw.mods.modlauncher.TransformationServicesHandler$$Lambda+0x000002cd41239450.accept(Ljava/lang/Object;)V+8 cpw.mods.modlauncher@10.0.9 -J 2638 c1 java.lang.Iterable.forEach(Ljava/util/function/Consumer;)V java.base@21.0.8 (39 bytes) @ 0x000002cd238d5a1c [0x000002cd238d5720+0x00000000000002fc] -j cpw.mods.modlauncher.TransformationServicesHandler.discoverServices(Lcpw/mods/modlauncher/ArgumentHandler$DiscoveryData;)V+145 cpw.mods.modlauncher@10.0.9 -j cpw.mods.modlauncher.Launcher.run([Ljava/lang/String;)V+14 cpw.mods.modlauncher@10.0.9 -j cpw.mods.modlauncher.Launcher.main([Ljava/lang/String;)V+78 cpw.mods.modlauncher@10.0.9 -j cpw.mods.modlauncher.BootstrapLaunchConsumer.accept([Ljava/lang/String;)V+1 cpw.mods.modlauncher@10.0.9 -j cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(Ljava/lang/Object;)V+5 cpw.mods.modlauncher@10.0.9 -j cpw.mods.bootstraplauncher.BootstrapLauncher.main([Ljava/lang/String;)V+515 cpw.mods.bootstraplauncher@1.1.2 -v ~StubRoutines::call_stub 0x000002cd2a8c10e7 - -siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), data execution prevention violation at address 0x0000000000000008 - - -Registers: -RAX=0x000002cd914aec80, RBX=0x000002cd3ca40620, RCX=0x000002cd18844108, RDX=0x000002cd3ca40620 -RSP=0x000000fc5dafe568, RBP=0x0000000000000002, RSI=0x000000fc5dafe610, RDI=0x000002cd18844108 -R8 =0x0000000000010002, R9 =0x0000000000000000, R10=0x00007ff9d57c0000, R11=0x000000fc5dafe538 -R12=0x0000000000000007, R13=0x000002cd3ca40620, R14=0x00007ff9d21a0300, R15=0x0000000000000000 -RIP=0x0000000000000008, EFLAGS=0x0000000000010206 - -XMM[0]=0x0000000000000000 0x0000000000000000 -XMM[1]=0x0000000000000000 0x0000000000000000 -XMM[2]=0x0000000000000000 0x0000000000000000 -XMM[3]=0x0000000000000000 0x0000000000000000 -XMM[4]=0x0000000000000000 0x0000000000000000 -XMM[5]=0x0000000000000000 0x0000000000000000 -XMM[6]=0x000e178101b4d89f 0x34e63b4167e12cdf -XMM[7]=0xa74594e14f971b4a 0xec33e0a163fa7256 -XMM[8]=0xc5f505e146f075b3 0x54e989ae64a07bb9 -XMM[9]=0x135ef2740d4ca252 0x7390eba50b1b77f3 -XMM[10]=0x043d11cdce7a6327 0x8e8662f20aa274b1 -XMM[11]=0x4c2a58254c2a5825 0x4c2a5825ac508dbe -XMM[12]=0x0000000000000000 0x0000000060263599 -XMM[13]=0x6c09519d6c09519d 0x6c09519d1859df5b -XMM[14]=0x0000000000000000 0x00000000ac508dbe -XMM[15]=0x0000000000000000 0x0000000000000011 - MXCSR=0x00001fa0 - - -Register to memory mapping: - -RAX=0x000002cd914aec80 points into unknown readable memory: 0x0000000000000000 | 00 00 00 00 00 00 00 00 -RBX=0x000002cd3ca40620 points into unknown readable memory: 0x000000060ea974c8 | c8 74 a9 0e 06 00 00 00 -RCX=0x000002cd18844108 points into unknown readable memory: 0x000002cd914aec80 | 80 ec 4a 91 cd 02 00 00 -RDX=0x000002cd3ca40620 points into unknown readable memory: 0x000000060ea974c8 | c8 74 a9 0e 06 00 00 00 -RSP=0x000000fc5dafe568 is pointing into the stack for thread: 0x000002cd18843d50 -RBP=0x0000000000000002 is an unknown value -RSI=0x000000fc5dafe610 is pointing into the stack for thread: 0x000002cd18843d50 -RDI=0x000002cd18844108 points into unknown readable memory: 0x000002cd914aec80 | 80 ec 4a 91 cd 02 00 00 -R8 =0x0000000000010002 is an unknown value -R9 =0x0 is null -R10=0x00007ff9d57c0000 VCRUNTIME140.dll -R11=0x000000fc5dafe538 is pointing into the stack for thread: 0x000002cd18843d50 -R12=0x0000000000000007 is an unknown value -R13=0x000002cd3ca40620 points into unknown readable memory: 0x000000060ea974c8 | c8 74 a9 0e 06 00 00 00 -R14=0x00007ff9d21a0300 jdwp.dll -R15=0x0 is null - -Top of Stack: (sp=0x000000fc5dafe568) -0x000000fc5dafe568: 00007ff9d21861bf 000002cd3ca40620 -0x000000fc5dafe578: 000000fc5dafe610 0000000000000000 -0x000000fc5dafe588: 0000000000000000 000002cd3c95ba30 -0x000000fc5dafe598: 000002cd23470490 000002cd1884cc60 -0x000000fc5dafe5a8: 00007ff9d21a03a0 000002cd18844320 -0x000000fc5dafe5b8: 00007ff9d218283f 000002cd3ca40620 -0x000000fc5dafe5c8: 0000000000000002 000002cd18844108 -0x000000fc5dafe5d8: 000002cd3ca40628 000002cd3f92bde0 -0x000000fc5dafe5e8: 00007ff874af8ec5 00000000000002cd -0x000000fc5dafe5f8: 000000fc5dafe780 0000000000000000 -0x000000fc5dafe608: 0000000bffffffff 0000000000000007 -0x000000fc5dafe618: 000002cd3ca40620 0000000000000000 -0x000000fc5dafe628: 000002cd3ca40628 0000000000000000 -0x000000fc5dafe638: 0000000000000000 0000000000000000 -0x000000fc5dafe648: 0000000000000000 0000000000000000 -0x000000fc5dafe658: 0000000000000000 0000000000000000 -0x000000fc5dafe668: 000002cd18844320 000002cd4128cf60 -0x000000fc5dafe678: 00007ff874dec3f7 000002cd3ca40628 -0x000000fc5dafe688: 000002cd3fb1b300 000002cd18843d50 -0x000000fc5dafe698: 00000000000003d8 0000000000000000 -0x000000fc5dafe6a8: 000002cd1ad8e450 000000fc5dafe820 -0x000000fc5dafe6b8: 0000000000000005 000002cd4128cf60 -0x000000fc5dafe6c8: 000002cd822f2dc0 0000338c96f7c239 -0x000000fc5dafe6d8: 000002cd40611e50 000002cd18823960 -0x000000fc5dafe6e8: 000002cd188443b0 000002cd188443c0 -0x000000fc5dafe6f8: 000002cd18844798 00000000000003d8 -0x000000fc5dafe708: 000002cd18843d50 000002cd18843d50 -0x000000fc5dafe718: 000002cd18823aa0 000002cd18831c30 -0x000000fc5dafe728: 000002cd18831c48 000002cd18831d18 -0x000000fc5dafe738: 00000000000000d8 000000fc5dafe750 -0x000000fc5dafe748: 00007ff874f00133 000002cd18843d50 -0x000000fc5dafe758: 000002cd18823aa0 000002cd18831c30 - -Instructions: (pc=0x00007ff9d21861bf) -0x00007ff9d21860bf: 2c 41 b8 61 02 00 00 48 8d 0d 83 6e 01 00 48 8b -0x00007ff9d21860cf: d3 e8 37 50 00 00 41 8b cc e8 37 a0 ff ff 48 8b -0x00007ff9d21860df: d0 48 8d 0d f9 a3 01 00 e8 c8 50 00 00 4c 8b 4e -0x00007ff9d21860ef: 28 48 8d 0d 01 a4 01 00 4c 8b 46 20 48 8b 56 08 -0x00007ff9d21860ff: e8 d4 0c 01 00 48 8b 05 f5 0f 02 00 f6 80 10 02 -0x00007ff9d218610f: 00 00 02 74 28 41 b8 6a 02 00 00 48 8d 0d cf 62 -0x00007ff9d218611f: 01 00 48 8b d3 e8 e3 4f 00 00 48 8d 15 b8 63 01 -0x00007ff9d218612f: 00 48 8d 0d d1 62 01 00 e8 78 50 00 00 48 8b 07 -0x00007ff9d218613f: 48 8b cf ff 50 78 48 8b 0d b4 0f 02 00 4c 8b f8 -0x00007ff9d218614f: f6 81 10 02 00 00 02 74 28 41 b8 6b 02 00 00 48 -0x00007ff9d218615f: 8d 0d 8b 62 01 00 48 8b d3 e8 9f 4f 00 00 48 8d -0x00007ff9d218616f: 15 ac 63 01 00 48 8d 0d 8d 62 01 00 e8 34 50 00 -0x00007ff9d218617f: 00 48 8b 07 48 8b cf ff 90 88 00 00 00 83 3d 29 -0x00007ff9d218618f: 0b 02 00 00 76 0c e8 d6 5b ff ff 83 25 1b 0b 02 -0x00007ff9d218619f: 00 00 48 8b 5e 08 48 85 db 74 4b 48 8b 05 4f 0f -0x00007ff9d21861af: 02 00 80 78 13 00 74 0b 48 8b cb e8 7d 06 01 00 -0x00007ff9d21861bf: 88 46 10 4d 8b c7 48 8b d6 41 8a ce e8 a0 a0 00 -0x00007ff9d21861cf: 00 48 8b e8 48 85 c0 75 25 48 8b cb e8 7c 44 00 -0x00007ff9d21861df: 00 84 c0 0f 84 ea 00 00 00 48 8b d3 41 8a ce e8 -0x00007ff9d21861ef: 8d 13 00 00 eb e3 e8 ee 0d 00 00 48 8b e8 4c 8b -0x00007ff9d21861ff: cd 44 88 74 24 20 45 8b c4 48 8b d6 48 8b cf e8 -0x00007ff9d218620f: e1 00 00 00 83 3e 14 75 0b 48 8b 05 e1 0e 02 00 -0x00007ff9d218621f: c6 40 10 01 48 85 db 75 08 48 8b cd e8 14 53 ff -0x00007ff9d218622f: ff 48 8b 05 c9 0e 02 00 4d 85 ff 74 43 f6 80 10 -0x00007ff9d218623f: 02 00 00 02 74 2c 41 b8 b3 02 00 00 48 8d 15 4e -0x00007ff9d218624f: a1 01 00 48 8d 0d 97 61 01 00 e8 ae 4e 00 00 48 -0x00007ff9d218625f: 8d 15 9b 7c 01 00 48 8d 0d 9c 61 01 00 e8 43 4f -0x00007ff9d218626f: 00 00 48 8b 07 49 8b d7 48 8b cf ff 50 68 eb 41 -0x00007ff9d218627f: f6 80 10 02 00 00 02 74 2c 41 b8 b5 02 00 00 48 -0x00007ff9d218628f: 8d 15 0b a1 01 00 48 8d 0d 54 61 01 00 e8 6b 4e -0x00007ff9d218629f: 00 00 48 8d 15 78 62 01 00 48 8d 0d 59 61 01 00 -0x00007ff9d21862af: e8 00 4f 00 00 48 8b 07 48 8b cf ff 90 88 00 00 - - -Stack slot to memory mapping: - -stack at sp + 0 slots: 0x000002cd3ca40620 points into unknown readable memory: 0x000000060ea974c8 | c8 74 a9 0e 06 00 00 00 -stack at sp + 1 slots: 0x000000fc5dafe610 is pointing into the stack for thread: 0x000002cd18843d50 -stack at sp + 2 slots: 0x0 is null -stack at sp + 3 slots: 0x0 is null -stack at sp + 4 slots: 0x000002cd3c95ba30 points into unknown readable memory: 0x000002cd1884cbf0 | f0 cb 84 18 cd 02 00 00 -stack at sp + 5 slots: 0x000002cd23470490 is at entry_point+-400 in (nmethod*)0x000002cd23470490 -Compiled method (c1) 3714 1 3 java.lang.Object:: (1 bytes) - total in heap [0x000002cd23470490,0x000002cd23470780] = 752 - relocation [0x000002cd234705f0,0x000002cd23470620] = 48 - main code [0x000002cd23470620,0x000002cd234706f0] = 208 - stub code [0x000002cd234706f0,0x000002cd23470728] = 56 - metadata [0x000002cd23470728,0x000002cd23470738] = 16 - scopes data [0x000002cd23470738,0x000002cd23470748] = 16 - scopes pcs [0x000002cd23470748,0x000002cd23470778] = 48 - dependencies [0x000002cd23470778,0x000002cd23470780] = 8 -stack at sp + 6 slots: 0x000002cd1884cc60 points into unknown readable memory: 0x8000001500000001 | 01 00 00 00 15 00 00 80 -stack at sp + 7 slots: 0x00007ff9d21a03a0 jdwp.dll - - -Compiled method (c1) 3717 2638 3 java.lang.Iterable::forEach (39 bytes) - total in heap [0x000002cd238d5510,0x000002cd238d5f38] = 2600 - relocation [0x000002cd238d5670,0x000002cd238d5720] = 176 - main code [0x000002cd238d5720,0x000002cd238d5cd8] = 1464 - stub code [0x000002cd238d5cd8,0x000002cd238d5d60] = 136 - metadata [0x000002cd238d5d60,0x000002cd238d5d70] = 16 - scopes data [0x000002cd238d5d70,0x000002cd238d5e18] = 168 - scopes pcs [0x000002cd238d5e18,0x000002cd238d5f18] = 256 - dependencies [0x000002cd238d5f18,0x000002cd238d5f20] = 8 - nul chk table [0x000002cd238d5f20,0x000002cd238d5f38] = 24 - -[Constant Pool (empty)] - -[MachCode] -[Entry Point] - # {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable' - # this: rdx:rdx = 'java/lang/Iterable' - # parm0: r8:r8 = 'java/util/function/Consumer' - # [sp+0x70] (sp of caller) - 0x000002cd238d5720: 448b 5208 | 49bb 0000 | 0040 cd02 | 0000 4d03 | d34c 3bd0 - - 0x000002cd238d5734: ; {runtime_call ic_miss_stub} - 0x000002cd238d5734: 0f85 4692 | 0307 660f | 1f44 0000 -[Verified Entry Point] - 0x000002cd238d5740: 8984 2400 | 80ff ff55 | 4883 ec60 | 4181 7f20 | 0100 0000 - - 0x000002cd238d5754: ; {runtime_call StubRoutines (final stubs)} - 0x000002cd238d5754: 7405 e865 | 9504 0748 | 8954 2438 | 4c89 4424 - - 0x000002cd238d5764: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5764: 3048 be18 | 956a 81cd | 0200 008b | becc 0000 | 0083 c702 | 89be cc00 | 0000 81e7 | fe07 0000 - 0x000002cd238d5784: 85ff 0f84 | 7504 0000 - - 0x000002cd238d578c: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d578c: 48be 1895 | 6a81 cd02 | 0000 4883 | 8610 0100 - - 0x000002cd238d579c: ; {metadata(method data for {method} {0x000002cd40057168} 'requireNonNull' '(Ljava/lang/Object;)Ljava/lang/Object;' in 'java/util/Objects')} - 0x000002cd238d579c: 0001 48be | b814 0181 | cd02 0000 | 8bbe cc00 | 0000 83c7 | 0289 becc | 0000 0081 | e7fe ff1f - 0x000002cd238d57bc: 0085 ff0f | 845d 0400 | 004d 85c0 - - 0x000002cd238d57c8: ; {metadata(method data for {method} {0x000002cd40057168} 'requireNonNull' '(Ljava/lang/Object;)Ljava/lang/Object;' in 'java/util/Objects')} - 0x000002cd238d57c8: 48be b814 | 0181 cd02 | 0000 48c7 | c720 0100 | 0074 0748 | c7c7 1001 | 0000 488b | 1c3e 488d - 0x000002cd238d57e8: 5b01 4889 | 1c3e 0f84 | 6903 0000 - - 0x000002cd238d57f4: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d57f4: 488b f248 | bf18 956a | 81cd 0200 | 008b 7608 | 49ba 0000 | 0040 cd02 | 0000 4903 | f248 3bb7 - 0x000002cd238d5814: 3001 0000 | 750d 4883 | 8738 0100 | 0001 e960 | 0000 0048 | 3bb7 4001 | 0000 750d | 4883 8748 - 0x000002cd238d5834: 0100 0001 | e94a 0000 | 0048 83bf | 3001 0000 | 0075 1748 | 89b7 3001 | 0000 48c7 | 8738 0100 - 0x000002cd238d5854: 0001 0000 | 00e9 2900 | 0000 4883 | bf40 0100 | 0000 7517 | 4889 b740 | 0100 0048 | c787 4801 - 0x000002cd238d5874: 0000 0100 | 0000 e908 | 0000 0048 | 8387 2001 | 0000 0148 | 8bf2 488b | d648 b8a0 | 39bf 8bcd - 0x000002cd238d5894: ; {virtual_call} - 0x000002cd238d5894: 0200 00e8 - - 0x000002cd238d5898: ; ImmutableOopMap {[48]=Oop [56]=Oop } - ;*invokeinterface iterator {reexecute=0 rethrow=0 return_oop=0} - ; - java.lang.Iterable::forEach@6 (line 74) - 0x000002cd238d5898: f4b3 1b07 - - 0x000002cd238d589c: ; {other} - 0x000002cd238d589c: 0f1f 8400 | 8c03 0000 | 4889 4424 | 40e9 bc01 | 0000 6690 | 488b 4424 - - 0x000002cd238d58b4: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d58b4: 4048 ba18 | 956a 81cd | 0200 008b | 4008 49ba | 0000 0040 | cd02 0000 | 4903 c248 | 3b82 c001 - 0x000002cd238d58d4: 0000 750d | 4883 82c8 | 0100 0001 | e960 0000 | 0048 3b82 | d001 0000 | 750d 4883 | 82d8 0100 - 0x000002cd238d58f4: 0001 e94a | 0000 0048 | 83ba c001 | 0000 0075 | 1748 8982 | c001 0000 | 48c7 82c8 | 0100 0001 - 0x000002cd238d5914: 0000 00e9 | 2900 0000 | 4883 bad0 | 0100 0000 | 7517 4889 | 82d0 0100 | 0048 c782 | d801 0000 - 0x000002cd238d5934: 0100 0000 | e908 0000 | 0048 8382 | b001 0000 | 0148 8b54 | 2440 6666 | 9048 b800 | 34bf 8bcd - 0x000002cd238d5954: ; {virtual_call} - 0x000002cd238d5954: 0200 00e8 - - 0x000002cd238d5958: ; ImmutableOopMap {[48]=Oop [56]=Oop [64]=Oop } - ;*invokeinterface next {reexecute=0 rethrow=0 return_oop=0} - ; - java.lang.Iterable::forEach@22 (line 74) - 0x000002cd238d5958: b4b5 1b07 - - 0x000002cd238d595c: ; {other} - 0x000002cd238d595c: 0f1f 8400 | 4c04 0001 | 4c8b 4424 | 3049 3b00 - - 0x000002cd238d596c: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d596c: 498b d048 | be18 956a | 81cd 0200 | 008b 5208 | 49ba 0000 | 0040 cd02 | 0000 4903 | d248 3b96 - 0x000002cd238d598c: f801 0000 | 750d 4883 | 8600 0200 | 0001 e960 | 0000 0048 | 3b96 0802 | 0000 750d | 4883 8610 - 0x000002cd238d59ac: 0200 0001 | e94a 0000 | 0048 83be | f801 0000 | 0075 1748 | 8996 f801 | 0000 48c7 | 8600 0200 - 0x000002cd238d59cc: 0001 0000 | 00e9 2900 | 0000 4883 | be08 0200 | 0000 7517 | 4889 9608 | 0200 0048 | c786 1002 - 0x000002cd238d59ec: 0000 0100 | 0000 e908 | 0000 0048 | 8386 e801 | 0000 0149 | 8bf0 4c8b | c048 8bd6 | 4889 4424 - 0x000002cd238d5a0c: 4848 b850 | dda3 8acd - - 0x000002cd238d5a14: ; {virtual_call} - 0x000002cd238d5a14: 0200 00e8 - - 0x000002cd238d5a18: ; ImmutableOopMap {[48]=Oop [56]=Oop [64]=Oop [72]=Oop } - ;*invokeinterface accept {reexecute=0 rethrow=0 return_oop=0} - ; - java.lang.Iterable::forEach@30 (line 75) - 0x000002cd238d5a18: 74b2 1b07 - - 0x000002cd238d5a1c: ; {other} - 0x000002cd238d5a1c: 0f1f 8400 | 0c05 0002 - - 0x000002cd238d5a24: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5a24: 48ba 1895 | 6a81 cd02 | 0000 8bb2 | d000 0000 | 83c6 0289 | b2d0 0000 | 0081 e6fe | 3f00 0085 - 0x000002cd238d5a44: f60f 84fd | 0100 004d | 8b97 5004 - - 0x000002cd238d5a50: ; ImmutableOopMap {[48]=Oop [56]=Oop [64]=Oop [72]=Oop } - ;*goto {reexecute=1 rethrow=0 return_oop=0} - ; - (reexecute) java.lang.Iterable::forEach@35 (line 76) - ; {poll} - 0x000002cd238d5a50: 0000 4185 - - 0x000002cd238d5a54: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5a54: 0248 ba18 | 956a 81cd | 0200 00ff | 8220 0200 | 0048 8b44 | 2440 483b | 0048 8bd0 - - 0x000002cd238d5a70: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5a70: 48be 1895 | 6a81 cd02 | 0000 8b52 | 0849 ba00 | 0000 40cd | 0200 0049 | 03d2 483b | 9668 0100 - 0x000002cd238d5a90: 0075 0d48 | 8386 7001 | 0000 01e9 | 6000 0000 | 483b 9678 | 0100 0075 | 0d48 8386 | 8001 0000 - 0x000002cd238d5ab0: 01e9 4a00 | 0000 4883 | be68 0100 | 0000 7517 | 4889 9668 | 0100 0048 | c786 7001 | 0000 0100 - 0x000002cd238d5ad0: 0000 e929 | 0000 0048 | 83be 7801 | 0000 0075 | 1748 8996 | 7801 0000 | 48c7 8680 | 0100 0001 - 0x000002cd238d5af0: 0000 00e9 | 0800 0000 | 4883 8658 | 0100 0001 | 488b d066 | 9048 b850 | 3ebf 8bcd - - 0x000002cd238d5b0c: ; {virtual_call} - 0x000002cd238d5b0c: 0200 00e8 - - 0x000002cd238d5b10: ; ImmutableOopMap {[48]=Oop [56]=Oop [64]=Oop } - ;*invokeinterface hasNext {reexecute=0 rethrow=0 return_oop=0} - ; - java.lang.Iterable::forEach@13 (line 74) - 0x000002cd238d5b10: 8cb2 1b07 - - 0x000002cd238d5b14: ; {other} - 0x000002cd238d5b14: 0f1f 8400 | 0406 0004 - - 0x000002cd238d5b1c: ; {metadata(method data for {method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5b1c: 85c0 48ba | 1895 6a81 | cd02 0000 | 48c7 c6a0 | 0100 0075 | 0748 c7c6 | 9001 0000 | 488b 3c32 - 0x000002cd238d5b3c: 488d 7f01 | 4889 3c32 | 0f85 66fd | ffff 4883 - - 0x000002cd238d5b4c: ; {poll_return} - 0x000002cd238d5b4c: c460 5d49 | 3ba7 4804 | 0000 0f87 | 1201 0000 | c366 6690 - - 0x000002cd238d5b60: ; {no_reloc} - 0x000002cd238d5b60: e92e 0100 | 0000 0000 | 0000 498b | 87b8 0100 | 0048 8d78 | 3049 3bbf | c801 0000 | 0f87 1b01 - 0x000002cd238d5b80: 0000 4989 | bfb8 0100 | 0048 c700 | 0100 0000 | 488b ca49 | ba00 0000 | 40cd 0200 | 0049 2bca - 0x000002cd238d5ba0: 8948 0848 | 33c9 8948 | 0c48 33c9 | 4889 4810 | 4889 4818 | 4889 4820 | 4889 4828 - - 0x000002cd238d5bbc: ; {metadata(method data for {method} {0x000002cd40057168} 'requireNonNull' '(Ljava/lang/Object;)Ljava/lang/Object;' in 'java/util/Objects')} - 0x000002cd238d5bbc: 488b d048 | beb8 1401 | 81cd 0200 | 0048 8386 | 3001 0000 | 0148 8bd0 | 4889 4424 | 5066 0f1f - 0x000002cd238d5bdc: ; {optimized virtual_call} - 0x000002cd238d5bdc: 4400 00e8 - - 0x000002cd238d5be0: ; ImmutableOopMap {[48]=Oop [56]=Oop [80]=Oop } - ;*invokespecial {reexecute=0 rethrow=0 return_oop=0} - ; - java.util.Objects::requireNonNull@8 (line 233) - ; - java.lang.Iterable::forEach@1 (line 73) - 0x000002cd238d5be0: 9c92 0307 - - 0x000002cd238d5be4: ; {other} - 0x000002cd238d5be4: 0f1f 8400 | d406 0005 | 488b 4424 - - 0x000002cd238d5bf0: ; ImmutableOopMap {rax=Oop [48]=Oop [56]=Oop } - ;*athrow {reexecute=1 rethrow=0 return_oop=0} - ; - (reexecute) java.util.Objects::requireNonNull@11 (line 233) - ; - java.lang.Iterable::forEach@1 (line 73) - ; {section_word} - 0x000002cd238d5bf0: 5048 baf1 | 5b8d 23cd - - 0x000002cd238d5bf8: ; {runtime_call handle_exception_nofpu Runtime1 stub} - 0x000002cd238d5bf8: 0200 00e8 | 801c 1207 - - 0x000002cd238d5c00: ; {metadata({method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5c00: 9049 bae0 | 9905 40cd | 0200 004c | 8954 2408 | 48c7 0424 | ffff ffff - - 0x000002cd238d5c18: ; {runtime_call counter_overflow Runtime1 stub} - 0x000002cd238d5c18: e8e3 6512 - - 0x000002cd238d5c1c: ; ImmutableOopMap {rdx=Oop r8=Oop [48]=Oop [56]=Oop } - ;*synchronization entry - ; - java.lang.Iterable::forEach@-1 (line 73) - 0x000002cd238d5c1c: 07e9 6afb - - 0x000002cd238d5c20: ; {metadata({method} {0x000002cd40057168} 'requireNonNull' '(Ljava/lang/Object;)Ljava/lang/Object;' in 'java/util/Objects')} - 0x000002cd238d5c20: ffff 49ba | 6071 0540 | cd02 0000 | 4c89 5424 | 0848 c704 | 24ff ffff - - 0x000002cd238d5c38: ; {runtime_call counter_overflow Runtime1 stub} - 0x000002cd238d5c38: ffe8 c265 - - 0x000002cd238d5c3c: ; ImmutableOopMap {rdx=Oop r8=Oop [48]=Oop [56]=Oop } - ;*synchronization entry - ; - java.util.Objects::requireNonNull@-1 (line 232) - ; - java.lang.Iterable::forEach@1 (line 73) - 0x000002cd238d5c3c: 1207 e982 - - 0x000002cd238d5c40: ; {runtime_call throw_null_pointer_exception Runtime1 stub} - 0x000002cd238d5c40: fbff ffe8 - - 0x000002cd238d5c44: ; ImmutableOopMap {rax=Oop r8=Oop [48]=Oop [56]=Oop [64]=Oop } - ;*invokeinterface accept {reexecute=0 rethrow=0 return_oop=0} - ; - java.lang.Iterable::forEach@30 (line 75) - 0x000002cd238d5c44: 58eb 1107 - - 0x000002cd238d5c48: ; {metadata({method} {0x000002cd400599e8} 'forEach' '(Ljava/util/function/Consumer;)V' in 'java/lang/Iterable')} - 0x000002cd238d5c48: 49ba e099 | 0540 cd02 | 0000 4c89 | 5424 0848 | c704 2423 - - 0x000002cd238d5c5c: ; {runtime_call counter_overflow Runtime1 stub} - 0x000002cd238d5c5c: 0000 00e8 - - 0x000002cd238d5c60: ; ImmutableOopMap {[48]=Oop [56]=Oop [64]=Oop [72]=Oop } - ;*goto {reexecute=1 rethrow=0 return_oop=0} - ; - (reexecute) java.lang.Iterable::forEach@35 (line 76) - 0x000002cd238d5c60: 9c65 1207 | e9e2 fdff - - 0x000002cd238d5c68: ; {runtime_call throw_null_pointer_exception Runtime1 stub} - 0x000002cd238d5c68: ffe8 32eb - - 0x000002cd238d5c6c: ; ImmutableOopMap {rax=Oop [48]=Oop [56]=Oop [64]=Oop } - ;*invokeinterface hasNext {reexecute=0 rethrow=0 return_oop=0} - ; - java.lang.Iterable::forEach@13 (line 74) - ; {internal_word} - 0x000002cd238d5c6c: 1107 49ba | 4f5b 8d23 | cd02 0000 | 4d89 9760 - - 0x000002cd238d5c7c: ; {runtime_call SafepointBlob} - 0x000002cd238d5c7c: 0400 00e9 | fc0e 0407 - - 0x000002cd238d5c84: ; {metadata(nullptr)} - 0x000002cd238d5c84: 48ba 0000 | 0000 0000 | 0000 b800 - - 0x000002cd238d5c90: ; {runtime_call load_klass_patching Runtime1 stub} - 0x000002cd238d5c90: 0f05 0ae8 - - 0x000002cd238d5c94: ; ImmutableOopMap {[48]=Oop [56]=Oop } - ;*new {reexecute=1 rethrow=0 return_oop=0} - ; - (reexecute) java.util.Objects::requireNonNull@4 (line 233) - ; - java.lang.Iterable::forEach@1 (line 73) - 0x000002cd238d5c94: e848 1207 | e9c3 feff | ff48 8bd2 - - 0x000002cd238d5ca0: ; {runtime_call fast_new_instance Runtime1 stub} - 0x000002cd238d5ca0: e8db 0112 - - 0x000002cd238d5ca4: ; ImmutableOopMap {[48]=Oop [56]=Oop } - ;*new {reexecute=0 rethrow=0 return_oop=0} - ; - java.util.Objects::requireNonNull@4 (line 233) - ; - java.lang.Iterable::forEach@1 (line 73) - 0x000002cd238d5ca4: 07e9 12ff | ffff 498b | 87f8 0400 | 0049 c787 | f804 0000 | 0000 0000 | 49c7 8700 | 0500 0000 - 0x000002cd238d5cc4: 0000 0048 | 83c4 605d - - 0x000002cd238d5ccc: ; {runtime_call unwind_exception Runtime1 stub} - 0x000002cd238d5ccc: e9af c911 | 07f4 f4f4 | f4f4 f4f4 -[Stub Code] - 0x000002cd238d5cd8: ; {no_reloc} - 0x000002cd238d5cd8: 0f1f 4400 - - 0x000002cd238d5cdc: ; {static_stub} - 0x000002cd238d5cdc: 0048 bb00 | 0000 0000 - - 0x000002cd238d5ce4: ; {runtime_call nmethod} - 0x000002cd238d5ce4: 0000 00e9 | fbff ffff - - 0x000002cd238d5cec: ; {static_stub} - 0x000002cd238d5cec: 9048 bb00 | 0000 0000 - - 0x000002cd238d5cf4: ; {runtime_call nmethod} - 0x000002cd238d5cf4: 0000 00e9 | fbff ffff - - 0x000002cd238d5cfc: ; {static_stub} - 0x000002cd238d5cfc: 9048 bb00 | 0000 0000 - - 0x000002cd238d5d04: ; {runtime_call nmethod} - 0x000002cd238d5d04: 0000 00e9 | fbff ffff - - 0x000002cd238d5d0c: ; {static_stub} - 0x000002cd238d5d0c: 9048 bb00 | 0000 0000 - - 0x000002cd238d5d14: ; {runtime_call nmethod} - 0x000002cd238d5d14: 0000 00e9 | fbff ffff - - 0x000002cd238d5d1c: ; {static_stub} - 0x000002cd238d5d1c: 48bb 0000 | 0000 0000 - - 0x000002cd238d5d24: ; {runtime_call nmethod} - 0x000002cd238d5d24: 0000 e9fb - - 0x000002cd238d5d28: ; {runtime_call handle_exception_from_callee Runtime1 stub} - 0x000002cd238d5d28: ffff ffe8 | 5022 1207 - - 0x000002cd238d5d30: ; {external_word} - 0x000002cd238d5d30: 48b9 90e2 | 2575 f87f | 0000 4883 - - 0x000002cd238d5d3c: ; {runtime_call} - 0x000002cd238d5d3c: e4f0 48b8 | 1079 e874 | f87f 0000 - - 0x000002cd238d5d48: ; {section_word} - 0x000002cd238d5d48: ffd0 f449 | ba4b 5d8d | 23cd 0200 - - 0x000002cd238d5d54: ; {runtime_call DeoptimizationBlob} - 0x000002cd238d5d54: 0041 52e9 | c422 0407 | f4f4 f4f4 -[/MachCode] - - ---------------- P R O C E S S --------------- - -Threads class SMR info: -_java_thread_list=0x000002cd8f5c2b60, length=25, elements={ -0x000002cd18843d50, 0x000002cd3ca5a6c0, 0x000002cd3ca5b110, 0x000002cd3ca601b0, -0x000002cd3ca611f0, 0x000002cd3ca61fa0, 0x000002cd3ca629f0, 0x000002cd3ca6f8d0, -0x000002cd3ca73ac0, 0x000002cd3ca9c770, 0x000002cd3f9f0980, 0x000002cd3fa845e0, -0x000002cd3fc04350, 0x000002cd3fba3b50, 0x000002cd3fc065d0, 0x000002cd3fc75fe0, -0x000002cd3fbd3540, 0x000002cd8525f610, 0x000002cd85372210, 0x000002cd8588fde0, -0x000002cd85dbd8c0, 0x000002cd85ea5070, 0x000002cd85e9bf00, 0x000002cd85ca75f0, -0x000002cd85b0a740 -} - -Java Threads: ( => current thread ) -=>0x000002cd18843d50 JavaThread "main" [_thread_in_native, id=23416, stack(0x000000fc5da00000,0x000000fc5db00000) (1024K)] - 0x000002cd3ca5a6c0 JavaThread "Reference Handler" daemon [_thread_blocked, id=25248, stack(0x000000fc5e200000,0x000000fc5e300000) (1024K)] - 0x000002cd3ca5b110 JavaThread "Finalizer" daemon [_thread_blocked, id=5336, stack(0x000000fc5e300000,0x000000fc5e400000) (1024K)] - 0x000002cd3ca601b0 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=11384, stack(0x000000fc5e400000,0x000000fc5e500000) (1024K)] - 0x000002cd3ca611f0 JavaThread "Attach Listener" daemon [_thread_blocked, id=27632, stack(0x000000fc5e500000,0x000000fc5e600000) (1024K)] - 0x000002cd3ca61fa0 JavaThread "Service Thread" daemon [_thread_blocked, id=13388, stack(0x000000fc5e600000,0x000000fc5e700000) (1024K)] - 0x000002cd3ca629f0 JavaThread "Monitor Deflation Thread" daemon [_thread_blocked, id=26172, stack(0x000000fc5e700000,0x000000fc5e800000) (1024K)] - 0x000002cd3ca6f8d0 JavaThread "C2 CompilerThread0" daemon [_thread_in_native, id=20612, stack(0x000000fc5e800000,0x000000fc5e900000) (1024K)] - 0x000002cd3ca73ac0 JavaThread "C1 CompilerThread0" daemon [_thread_blocked, id=19120, stack(0x000000fc5e900000,0x000000fc5ea00000) (1024K)] - 0x000002cd3ca9c770 JavaThread "C1 CompilerThread1" daemon [_thread_blocked, id=12212, stack(0x000000fc5ea00000,0x000000fc5eb00000) (1024K)] - 0x000002cd3f9f0980 JavaThread "Common-Cleaner" daemon [_thread_blocked, id=24772, stack(0x000000fc5eb00000,0x000000fc5ec00000) (1024K)] - 0x000002cd3fa845e0 JavaThread "C1 CompilerThread2" daemon [_thread_blocked, id=19904, stack(0x000000fc5ec00000,0x000000fc5ed00000) (1024K)] - 0x000002cd3fc04350 JavaThread "JDWP Transport Listener: dt_socket" daemon [_thread_blocked, id=6184, stack(0x000000fc5ef00000,0x000000fc5f000000) (1024K)] - 0x000002cd3fba3b50 JavaThread "JDWP Event Helper Thread" daemon [_thread_blocked, id=22384, stack(0x000000fc5f000000,0x000000fc5f100000) (1024K)] - 0x000002cd3fc065d0 JavaThread "JDWP Command Reader" daemon [_thread_in_native, id=23336, stack(0x000000fc5f100000,0x000000fc5f200000) (1024K)] - 0x000002cd3fc75fe0 JavaThread "IntelliJ Suspend Helper" daemon [_thread_blocked, id=23388, stack(0x000000fc5ed00000,0x000000fc5ee00000) (1024K)] - 0x000002cd3fbd3540 JavaThread "Notification Thread" daemon [_thread_blocked, id=12280, stack(0x000000fc5ee00000,0x000000fc5ef00000) (1024K)] - 0x000002cd8525f610 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=25304, stack(0x000000fc5f200000,0x000000fc5f300000) (1024K)] - 0x000002cd85372210 JavaThread "C2 CompilerThread2" daemon [_thread_blocked, id=18208, stack(0x000000fc5f300000,0x000000fc5f400000) (1024K)] - 0x000002cd8588fde0 JavaThread "C1 CompilerThread3" daemon [_thread_blocked, id=15436, stack(0x000000fc5ff00000,0x000000fc60000000) (1024K)] - 0x000002cd85dbd8c0 JavaThread "C2 CompilerThread3" daemon [_thread_blocked, id=1076, stack(0x000000fc60000000,0x000000fc60100000) (1024K)] - 0x000002cd85ea5070 JavaThread "C2 CompilerThread4" daemon [_thread_blocked, id=25664, stack(0x000000fc60100000,0x000000fc60200000) (1024K)] - 0x000002cd85e9bf00 JavaThread "C2 CompilerThread5" daemon [_thread_in_native, id=24456, stack(0x000000fc60200000,0x000000fc60300000) (1024K)] - 0x000002cd85ca75f0 JavaThread "C2 CompilerThread6" daemon [_thread_blocked, id=23260, stack(0x000000fc60300000,0x000000fc60400000) (1024K)] - 0x000002cd85b0a740 JavaThread "C2 CompilerThread7" daemon [_thread_blocked, id=26800, stack(0x000000fc60400000,0x000000fc60500000) (1024K)] -Total: 25 - -Other Threads: - 0x000002cd3ca3d5b0 VMThread "VM Thread" [id=26936, stack(0x000000fc5e100000,0x000000fc5e200000) (1024K)] - 0x000002cd3f9117b0 WatcherThread "VM Periodic Task Thread" [id=8988, stack(0x000000fc5e000000,0x000000fc5e100000) (1024K)] - 0x000002cd3c8df4b0 WorkerThread "GC Thread#0" [id=23352, stack(0x000000fc5db00000,0x000000fc5dc00000) (1024K)] - 0x000002cd858a49b0 WorkerThread "GC Thread#1" [id=24496, stack(0x000000fc5f400000,0x000000fc5f500000) (1024K)] - 0x000002cd858cc5f0 WorkerThread "GC Thread#2" [id=23976, stack(0x000000fc5f500000,0x000000fc5f600000) (1024K)] - 0x000002cd858cc990 WorkerThread "GC Thread#3" [id=24628, stack(0x000000fc5f600000,0x000000fc5f700000) (1024K)] - 0x000002cd858ccd30 WorkerThread "GC Thread#4" [id=25432, stack(0x000000fc5f700000,0x000000fc5f800000) (1024K)] - 0x000002cd858cbeb0 WorkerThread "GC Thread#5" [id=19584, stack(0x000000fc5f800000,0x000000fc5f900000) (1024K)] - 0x000002cd858cbb10 WorkerThread "GC Thread#6" [id=9052, stack(0x000000fc5f900000,0x000000fc5fa00000) (1024K)] - 0x000002cd858cb3d0 WorkerThread "GC Thread#7" [id=20212, stack(0x000000fc5fa00000,0x000000fc5fb00000) (1024K)] - 0x000002cd858cc250 WorkerThread "GC Thread#8" [id=9424, stack(0x000000fc5fb00000,0x000000fc5fc00000) (1024K)] - 0x000002cd858cb770 WorkerThread "GC Thread#9" [id=25420, stack(0x000000fc5fc00000,0x000000fc5fd00000) (1024K)] - 0x000002cd858fc280 WorkerThread "GC Thread#10" [id=27420, stack(0x000000fc5fd00000,0x000000fc5fe00000) (1024K)] - 0x000002cd858fc9c0 WorkerThread "GC Thread#11" [id=24424, stack(0x000000fc5fe00000,0x000000fc5ff00000) (1024K)] - 0x000002cd858fd100 WorkerThread "GC Thread#12" [id=4876, stack(0x000000fc60500000,0x000000fc60600000) (1024K)] - 0x000002cd1ae10110 ConcurrentGCThread "G1 Main Marker" [id=24552, stack(0x000000fc5dc00000,0x000000fc5dd00000) (1024K)] - 0x000002cd1ae11740 WorkerThread "G1 Conc#0" [id=20756, stack(0x000000fc5dd00000,0x000000fc5de00000) (1024K)] - 0x000002cd3c9788a0 ConcurrentGCThread "G1 Refine#0" [id=22628, stack(0x000000fc5de00000,0x000000fc5df00000) (1024K)] - 0x000002cd3c979320 ConcurrentGCThread "G1 Service" [id=23180, stack(0x000000fc5df00000,0x000000fc5e000000) (1024K)] -Total: 19 - -Threads with active compile tasks: -C2 CompilerThread0 3727 4134 4 java.lang.invoke.MethodType::methodType (69 bytes) -C2 CompilerThread5 3727 4097 4 java.lang.invoke.MethodType::makeImpl (109 bytes) -Total: 2 - -VM state: not at safepoint (normal execution) - -VM Mutex/Monitor currently owned by a thread: None - -Heap address: 0x000000060e000000, size: 7968 MB, Compressed Oops mode: Zero based, Oop shift amount: 3 - -CDS archive(s) mapped at: [0x000002cd40000000-0x000002cd40c80000-0x000002cd40c80000), size 13107200, SharedBaseAddress: 0x000002cd40000000, ArchiveRelocationMode: 1. -Compressed class space mapped at: 0x000002cd41000000-0x000002cd81000000, reserved size: 1073741824 -Narrow klass base: 0x000002cd40000000, Narrow klass shift: 0, Narrow klass range: 0x100000000 - -GC Precious Log: - CardTable entry size: 512 - Card Set container configuration: InlinePtr #cards 4 size 8 Array Of Cards #cards 32 size 80 Howl #buckets 8 coarsen threshold 7372 Howl Bitmap #cards 1024 size 144 coarsen threshold 921 Card regions per heap region 1 cards per card region 8192 - CPUs: 16 total, 16 available - Memory: 31865M - Large Page Support: Disabled - NUMA Support: Disabled - Compressed Oops: Enabled (Zero based) - Heap Region Size: 4M - Heap Min Capacity: 8M - Heap Initial Capacity: 500M - Heap Max Capacity: 7968M - Pre-touch: Disabled - Parallel Workers: 13 - Concurrent Workers: 3 - Concurrent Refinement Workers: 13 - Periodic GC: Disabled - -Heap: - garbage-first heap total 512000K, used 256284K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 61 young (249856K), 4 survivors (16384K) - Metaspace used 21158K, committed 21504K, reserved 1114112K - class space used 2274K, committed 2432K, reserved 1048576K - -Heap Regions: E=young(eden), S=young(survivor), O=old, HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, TAMS=top-at-mark-start, PB=parsable bottom -| 0|0x000000060e000000, 0x000000060e38ee78, 0x000000060e400000| 88%| O| |TAMS 0x000000060e000000| PB 0x000000060e000000| Untracked -| 1|0x000000060e400000, 0x000000060e800000, 0x000000060e800000|100%| O| |TAMS 0x000000060e400000| PB 0x000000060e400000| Untracked -| 2|0x000000060e800000, 0x000000060ec00000, 0x000000060ec00000|100%| O| |TAMS 0x000000060e800000| PB 0x000000060e800000| Untracked -| 3|0x000000060ec00000, 0x000000060ec00000, 0x000000060f000000| 0%| F| |TAMS 0x000000060ec00000| PB 0x000000060ec00000| Untracked -| 4|0x000000060f000000, 0x000000060f000000, 0x000000060f400000| 0%| F| |TAMS 0x000000060f000000| PB 0x000000060f000000| Untracked -| 5|0x000000060f400000, 0x000000060f400000, 0x000000060f800000| 0%| F| |TAMS 0x000000060f400000| PB 0x000000060f400000| Untracked -| 6|0x000000060f800000, 0x000000060f800000, 0x000000060fc00000| 0%| F| |TAMS 0x000000060f800000| PB 0x000000060f800000| Untracked -| 7|0x000000060fc00000, 0x000000060fc00000, 0x0000000610000000| 0%| F| |TAMS 0x000000060fc00000| PB 0x000000060fc00000| Untracked -| 8|0x0000000610000000, 0x0000000610000000, 0x0000000610400000| 0%| F| |TAMS 0x0000000610000000| PB 0x0000000610000000| Untracked -| 9|0x0000000610400000, 0x0000000610400000, 0x0000000610800000| 0%| F| |TAMS 0x0000000610400000| PB 0x0000000610400000| Untracked -| 10|0x0000000610800000, 0x0000000610800000, 0x0000000610c00000| 0%| F| |TAMS 0x0000000610800000| PB 0x0000000610800000| Untracked -| 11|0x0000000610c00000, 0x0000000610c00000, 0x0000000611000000| 0%| F| |TAMS 0x0000000610c00000| PB 0x0000000610c00000| Untracked -| 12|0x0000000611000000, 0x0000000611000000, 0x0000000611400000| 0%| F| |TAMS 0x0000000611000000| PB 0x0000000611000000| Untracked -| 13|0x0000000611400000, 0x0000000611400000, 0x0000000611800000| 0%| F| |TAMS 0x0000000611400000| PB 0x0000000611400000| Untracked -| 14|0x0000000611800000, 0x0000000611800000, 0x0000000611c00000| 0%| F| |TAMS 0x0000000611800000| PB 0x0000000611800000| Untracked -| 15|0x0000000611c00000, 0x0000000611c00000, 0x0000000612000000| 0%| F| |TAMS 0x0000000611c00000| PB 0x0000000611c00000| Untracked -| 16|0x0000000612000000, 0x0000000612000000, 0x0000000612400000| 0%| F| |TAMS 0x0000000612000000| PB 0x0000000612000000| Untracked -| 17|0x0000000612400000, 0x0000000612400000, 0x0000000612800000| 0%| F| |TAMS 0x0000000612400000| PB 0x0000000612400000| Untracked -| 18|0x0000000612800000, 0x0000000612800000, 0x0000000612c00000| 0%| F| |TAMS 0x0000000612800000| PB 0x0000000612800000| Untracked -| 19|0x0000000612c00000, 0x0000000612c00000, 0x0000000613000000| 0%| F| |TAMS 0x0000000612c00000| PB 0x0000000612c00000| Untracked -| 20|0x0000000613000000, 0x0000000613000000, 0x0000000613400000| 0%| F| |TAMS 0x0000000613000000| PB 0x0000000613000000| Untracked -| 21|0x0000000613400000, 0x0000000613400000, 0x0000000613800000| 0%| F| |TAMS 0x0000000613400000| PB 0x0000000613400000| Untracked -| 22|0x0000000613800000, 0x0000000613800000, 0x0000000613c00000| 0%| F| |TAMS 0x0000000613800000| PB 0x0000000613800000| Untracked -| 23|0x0000000613c00000, 0x0000000613c00000, 0x0000000614000000| 0%| F| |TAMS 0x0000000613c00000| PB 0x0000000613c00000| Untracked -| 24|0x0000000614000000, 0x0000000614000000, 0x0000000614400000| 0%| F| |TAMS 0x0000000614000000| PB 0x0000000614000000| Untracked -| 25|0x0000000614400000, 0x0000000614400000, 0x0000000614800000| 0%| F| |TAMS 0x0000000614400000| PB 0x0000000614400000| Untracked -| 26|0x0000000614800000, 0x0000000614800000, 0x0000000614c00000| 0%| F| |TAMS 0x0000000614800000| PB 0x0000000614800000| Untracked -| 27|0x0000000614c00000, 0x0000000614c00000, 0x0000000615000000| 0%| F| |TAMS 0x0000000614c00000| PB 0x0000000614c00000| Untracked -| 28|0x0000000615000000, 0x0000000615000000, 0x0000000615400000| 0%| F| |TAMS 0x0000000615000000| PB 0x0000000615000000| Untracked -| 29|0x0000000615400000, 0x0000000615400000, 0x0000000615800000| 0%| F| |TAMS 0x0000000615400000| PB 0x0000000615400000| Untracked -| 30|0x0000000615800000, 0x0000000615800000, 0x0000000615c00000| 0%| F| |TAMS 0x0000000615800000| PB 0x0000000615800000| Untracked -| 31|0x0000000615c00000, 0x0000000615c00000, 0x0000000616000000| 0%| F| |TAMS 0x0000000615c00000| PB 0x0000000615c00000| Untracked -| 32|0x0000000616000000, 0x0000000616000000, 0x0000000616400000| 0%| F| |TAMS 0x0000000616000000| PB 0x0000000616000000| Untracked -| 33|0x0000000616400000, 0x0000000616400000, 0x0000000616800000| 0%| F| |TAMS 0x0000000616400000| PB 0x0000000616400000| Untracked -| 34|0x0000000616800000, 0x0000000616800000, 0x0000000616c00000| 0%| F| |TAMS 0x0000000616800000| PB 0x0000000616800000| Untracked -| 35|0x0000000616c00000, 0x0000000616c00000, 0x0000000617000000| 0%| F| |TAMS 0x0000000616c00000| PB 0x0000000616c00000| Untracked -| 36|0x0000000617000000, 0x0000000617000000, 0x0000000617400000| 0%| F| |TAMS 0x0000000617000000| PB 0x0000000617000000| Untracked -| 37|0x0000000617400000, 0x0000000617400000, 0x0000000617800000| 0%| F| |TAMS 0x0000000617400000| PB 0x0000000617400000| Untracked -| 38|0x0000000617800000, 0x0000000617800000, 0x0000000617c00000| 0%| F| |TAMS 0x0000000617800000| PB 0x0000000617800000| Untracked -| 39|0x0000000617c00000, 0x0000000617c00000, 0x0000000618000000| 0%| F| |TAMS 0x0000000617c00000| PB 0x0000000617c00000| Untracked -| 40|0x0000000618000000, 0x0000000618000000, 0x0000000618400000| 0%| F| |TAMS 0x0000000618000000| PB 0x0000000618000000| Untracked -| 41|0x0000000618400000, 0x0000000618400000, 0x0000000618800000| 0%| F| |TAMS 0x0000000618400000| PB 0x0000000618400000| Untracked -| 42|0x0000000618800000, 0x0000000618800000, 0x0000000618c00000| 0%| F| |TAMS 0x0000000618800000| PB 0x0000000618800000| Untracked -| 43|0x0000000618c00000, 0x0000000618c00000, 0x0000000619000000| 0%| F| |TAMS 0x0000000618c00000| PB 0x0000000618c00000| Untracked -| 44|0x0000000619000000, 0x0000000619000000, 0x0000000619400000| 0%| F| |TAMS 0x0000000619000000| PB 0x0000000619000000| Untracked -| 45|0x0000000619400000, 0x0000000619400000, 0x0000000619800000| 0%| F| |TAMS 0x0000000619400000| PB 0x0000000619400000| Untracked -| 46|0x0000000619800000, 0x0000000619800000, 0x0000000619c00000| 0%| F| |TAMS 0x0000000619800000| PB 0x0000000619800000| Untracked -| 47|0x0000000619c00000, 0x0000000619c00000, 0x000000061a000000| 0%| F| |TAMS 0x0000000619c00000| PB 0x0000000619c00000| Untracked -| 48|0x000000061a000000, 0x000000061a000000, 0x000000061a400000| 0%| F| |TAMS 0x000000061a000000| PB 0x000000061a000000| Untracked -| 49|0x000000061a400000, 0x000000061a400000, 0x000000061a800000| 0%| F| |TAMS 0x000000061a400000| PB 0x000000061a400000| Untracked -| 50|0x000000061a800000, 0x000000061a800000, 0x000000061ac00000| 0%| F| |TAMS 0x000000061a800000| PB 0x000000061a800000| Untracked -| 51|0x000000061ac00000, 0x000000061ac00000, 0x000000061b000000| 0%| F| |TAMS 0x000000061ac00000| PB 0x000000061ac00000| Untracked -| 52|0x000000061b000000, 0x000000061b000000, 0x000000061b400000| 0%| F| |TAMS 0x000000061b000000| PB 0x000000061b000000| Untracked -| 53|0x000000061b400000, 0x000000061b400000, 0x000000061b800000| 0%| F| |TAMS 0x000000061b400000| PB 0x000000061b400000| Untracked -| 54|0x000000061b800000, 0x000000061b800000, 0x000000061bc00000| 0%| F| |TAMS 0x000000061b800000| PB 0x000000061b800000| Untracked -| 55|0x000000061bc00000, 0x000000061bc00000, 0x000000061c000000| 0%| F| |TAMS 0x000000061bc00000| PB 0x000000061bc00000| Untracked -| 56|0x000000061c000000, 0x000000061c000000, 0x000000061c400000| 0%| F| |TAMS 0x000000061c000000| PB 0x000000061c000000| Untracked -| 57|0x000000061c400000, 0x000000061c400000, 0x000000061c800000| 0%| F| |TAMS 0x000000061c400000| PB 0x000000061c400000| Untracked -| 58|0x000000061c800000, 0x000000061c800000, 0x000000061cc00000| 0%| F| |TAMS 0x000000061c800000| PB 0x000000061c800000| Untracked -| 59|0x000000061cc00000, 0x000000061cc00000, 0x000000061d000000| 0%| F| |TAMS 0x000000061cc00000| PB 0x000000061cc00000| Untracked -| 60|0x000000061d000000, 0x000000061d000000, 0x000000061d400000| 0%| F| |TAMS 0x000000061d000000| PB 0x000000061d000000| Untracked -| 61|0x000000061d400000, 0x000000061d400000, 0x000000061d800000| 0%| F| |TAMS 0x000000061d400000| PB 0x000000061d400000| Untracked -| 62|0x000000061d800000, 0x000000061d800000, 0x000000061dc00000| 0%| F| |TAMS 0x000000061d800000| PB 0x000000061d800000| Untracked -| 63|0x000000061dc00000, 0x000000061dc00000, 0x000000061e000000| 0%| F| |TAMS 0x000000061dc00000| PB 0x000000061dc00000| Untracked -| 64|0x000000061e000000, 0x000000061e2b2820, 0x000000061e400000| 67%| E| |TAMS 0x000000061e000000| PB 0x000000061e000000| Complete -| 65|0x000000061e400000, 0x000000061e800000, 0x000000061e800000|100%| E|CS|TAMS 0x000000061e400000| PB 0x000000061e400000| Complete -| 66|0x000000061e800000, 0x000000061ec00000, 0x000000061ec00000|100%| E|CS|TAMS 0x000000061e800000| PB 0x000000061e800000| Complete -| 67|0x000000061ec00000, 0x000000061f000000, 0x000000061f000000|100%| E|CS|TAMS 0x000000061ec00000| PB 0x000000061ec00000| Complete -| 68|0x000000061f000000, 0x000000061f400000, 0x000000061f400000|100%| E|CS|TAMS 0x000000061f000000| PB 0x000000061f000000| Complete -| 69|0x000000061f400000, 0x000000061f800000, 0x000000061f800000|100%| E|CS|TAMS 0x000000061f400000| PB 0x000000061f400000| Complete -| 70|0x000000061f800000, 0x000000061fc00000, 0x000000061fc00000|100%| E|CS|TAMS 0x000000061f800000| PB 0x000000061f800000| Complete -| 71|0x000000061fc00000, 0x0000000620000000, 0x0000000620000000|100%| E|CS|TAMS 0x000000061fc00000| PB 0x000000061fc00000| Complete -| 72|0x0000000620000000, 0x0000000620400000, 0x0000000620400000|100%| E|CS|TAMS 0x0000000620000000| PB 0x0000000620000000| Complete -| 73|0x0000000620400000, 0x0000000620800000, 0x0000000620800000|100%| E|CS|TAMS 0x0000000620400000| PB 0x0000000620400000| Complete -| 74|0x0000000620800000, 0x0000000620c00000, 0x0000000620c00000|100%| E|CS|TAMS 0x0000000620800000| PB 0x0000000620800000| Complete -| 75|0x0000000620c00000, 0x0000000621000000, 0x0000000621000000|100%| E|CS|TAMS 0x0000000620c00000| PB 0x0000000620c00000| Complete -| 76|0x0000000621000000, 0x0000000621400000, 0x0000000621400000|100%| E|CS|TAMS 0x0000000621000000| PB 0x0000000621000000| Complete -| 77|0x0000000621400000, 0x0000000621800000, 0x0000000621800000|100%| E|CS|TAMS 0x0000000621400000| PB 0x0000000621400000| Complete -| 78|0x0000000621800000, 0x0000000621ab8280, 0x0000000621c00000| 67%| S|CS|TAMS 0x0000000621800000| PB 0x0000000621800000| Complete -| 79|0x0000000621c00000, 0x0000000622000000, 0x0000000622000000|100%| S|CS|TAMS 0x0000000621c00000| PB 0x0000000621c00000| Complete -| 80|0x0000000622000000, 0x0000000622400000, 0x0000000622400000|100%| S|CS|TAMS 0x0000000622000000| PB 0x0000000622000000| Complete -| 81|0x0000000622400000, 0x0000000622800000, 0x0000000622800000|100%| S|CS|TAMS 0x0000000622400000| PB 0x0000000622400000| Complete -| 82|0x0000000622800000, 0x0000000622c00000, 0x0000000622c00000|100%| E|CS|TAMS 0x0000000622800000| PB 0x0000000622800000| Complete -| 83|0x0000000622c00000, 0x0000000623000000, 0x0000000623000000|100%| E|CS|TAMS 0x0000000622c00000| PB 0x0000000622c00000| Complete -| 84|0x0000000623000000, 0x0000000623400000, 0x0000000623400000|100%| E|CS|TAMS 0x0000000623000000| PB 0x0000000623000000| Complete -| 85|0x0000000623400000, 0x0000000623800000, 0x0000000623800000|100%| E|CS|TAMS 0x0000000623400000| PB 0x0000000623400000| Complete -| 86|0x0000000623800000, 0x0000000623c00000, 0x0000000623c00000|100%| E|CS|TAMS 0x0000000623800000| PB 0x0000000623800000| Complete -| 87|0x0000000623c00000, 0x0000000624000000, 0x0000000624000000|100%| E|CS|TAMS 0x0000000623c00000| PB 0x0000000623c00000| Complete -| 88|0x0000000624000000, 0x0000000624400000, 0x0000000624400000|100%| E|CS|TAMS 0x0000000624000000| PB 0x0000000624000000| Complete -| 89|0x0000000624400000, 0x0000000624800000, 0x0000000624800000|100%| E|CS|TAMS 0x0000000624400000| PB 0x0000000624400000| Complete -| 90|0x0000000624800000, 0x0000000624c00000, 0x0000000624c00000|100%| E|CS|TAMS 0x0000000624800000| PB 0x0000000624800000| Complete -| 91|0x0000000624c00000, 0x0000000625000000, 0x0000000625000000|100%| E|CS|TAMS 0x0000000624c00000| PB 0x0000000624c00000| Complete -| 92|0x0000000625000000, 0x0000000625400000, 0x0000000625400000|100%| E|CS|TAMS 0x0000000625000000| PB 0x0000000625000000| Complete -| 93|0x0000000625400000, 0x0000000625800000, 0x0000000625800000|100%| E|CS|TAMS 0x0000000625400000| PB 0x0000000625400000| Complete -| 94|0x0000000625800000, 0x0000000625c00000, 0x0000000625c00000|100%| E|CS|TAMS 0x0000000625800000| PB 0x0000000625800000| Complete -| 95|0x0000000625c00000, 0x0000000626000000, 0x0000000626000000|100%| E|CS|TAMS 0x0000000625c00000| PB 0x0000000625c00000| Complete -| 96|0x0000000626000000, 0x0000000626400000, 0x0000000626400000|100%| E|CS|TAMS 0x0000000626000000| PB 0x0000000626000000| Complete -| 97|0x0000000626400000, 0x0000000626800000, 0x0000000626800000|100%| E|CS|TAMS 0x0000000626400000| PB 0x0000000626400000| Complete -| 98|0x0000000626800000, 0x0000000626c00000, 0x0000000626c00000|100%| E|CS|TAMS 0x0000000626800000| PB 0x0000000626800000| Complete -| 99|0x0000000626c00000, 0x0000000627000000, 0x0000000627000000|100%| E|CS|TAMS 0x0000000626c00000| PB 0x0000000626c00000| Complete -| 100|0x0000000627000000, 0x0000000627400000, 0x0000000627400000|100%| E|CS|TAMS 0x0000000627000000| PB 0x0000000627000000| Complete -| 101|0x0000000627400000, 0x0000000627800000, 0x0000000627800000|100%| E|CS|TAMS 0x0000000627400000| PB 0x0000000627400000| Complete -| 102|0x0000000627800000, 0x0000000627c00000, 0x0000000627c00000|100%| E|CS|TAMS 0x0000000627800000| PB 0x0000000627800000| Complete -| 103|0x0000000627c00000, 0x0000000628000000, 0x0000000628000000|100%| E|CS|TAMS 0x0000000627c00000| PB 0x0000000627c00000| Complete -| 104|0x0000000628000000, 0x0000000628400000, 0x0000000628400000|100%| E|CS|TAMS 0x0000000628000000| PB 0x0000000628000000| Complete -| 105|0x0000000628400000, 0x0000000628800000, 0x0000000628800000|100%| E|CS|TAMS 0x0000000628400000| PB 0x0000000628400000| Complete -| 106|0x0000000628800000, 0x0000000628c00000, 0x0000000628c00000|100%| E|CS|TAMS 0x0000000628800000| PB 0x0000000628800000| Complete -| 107|0x0000000628c00000, 0x0000000629000000, 0x0000000629000000|100%| E|CS|TAMS 0x0000000628c00000| PB 0x0000000628c00000| Complete -| 108|0x0000000629000000, 0x0000000629400000, 0x0000000629400000|100%| E|CS|TAMS 0x0000000629000000| PB 0x0000000629000000| Complete -| 109|0x0000000629400000, 0x0000000629800000, 0x0000000629800000|100%| E|CS|TAMS 0x0000000629400000| PB 0x0000000629400000| Complete -| 110|0x0000000629800000, 0x0000000629c00000, 0x0000000629c00000|100%| E|CS|TAMS 0x0000000629800000| PB 0x0000000629800000| Complete -| 111|0x0000000629c00000, 0x000000062a000000, 0x000000062a000000|100%| E|CS|TAMS 0x0000000629c00000| PB 0x0000000629c00000| Complete -| 112|0x000000062a000000, 0x000000062a400000, 0x000000062a400000|100%| E|CS|TAMS 0x000000062a000000| PB 0x000000062a000000| Complete -| 113|0x000000062a400000, 0x000000062a800000, 0x000000062a800000|100%| E|CS|TAMS 0x000000062a400000| PB 0x000000062a400000| Complete -| 114|0x000000062a800000, 0x000000062ac00000, 0x000000062ac00000|100%| E|CS|TAMS 0x000000062a800000| PB 0x000000062a800000| Complete -| 115|0x000000062ac00000, 0x000000062b000000, 0x000000062b000000|100%| E|CS|TAMS 0x000000062ac00000| PB 0x000000062ac00000| Complete -| 116|0x000000062b000000, 0x000000062b400000, 0x000000062b400000|100%| E|CS|TAMS 0x000000062b000000| PB 0x000000062b000000| Complete -| 117|0x000000062b400000, 0x000000062b800000, 0x000000062b800000|100%| E|CS|TAMS 0x000000062b400000| PB 0x000000062b400000| Complete -| 118|0x000000062b800000, 0x000000062bc00000, 0x000000062bc00000|100%| E|CS|TAMS 0x000000062b800000| PB 0x000000062b800000| Complete -| 119|0x000000062bc00000, 0x000000062c000000, 0x000000062c000000|100%| E|CS|TAMS 0x000000062bc00000| PB 0x000000062bc00000| Complete -| 120|0x000000062c000000, 0x000000062c400000, 0x000000062c400000|100%| E|CS|TAMS 0x000000062c000000| PB 0x000000062c000000| Complete -| 121|0x000000062c400000, 0x000000062c800000, 0x000000062c800000|100%| E|CS|TAMS 0x000000062c400000| PB 0x000000062c400000| Complete -| 122|0x000000062c800000, 0x000000062cc00000, 0x000000062cc00000|100%| E|CS|TAMS 0x000000062c800000| PB 0x000000062c800000| Complete -| 123|0x000000062cc00000, 0x000000062d000000, 0x000000062d000000|100%| E|CS|TAMS 0x000000062cc00000| PB 0x000000062cc00000| Complete -| 124|0x000000062d000000, 0x000000062d400000, 0x000000062d400000|100%| E|CS|TAMS 0x000000062d000000| PB 0x000000062d000000| Complete - -Card table byte_map: [0x000002cd33c90000,0x000002cd34c20000] _byte_map_base: 0x000002cd30c20000 - -Marking Bits: (CMBitMap*) 0x000002cd1ae00170 - Bits: [0x000002cd34c20000, 0x000002cd3c8a0000) - -Polling page: 0x000002cd18ac0000 - -Metaspace: - -Usage: - Non-class: 18.44 MB used. - Class: 2.22 MB used. - Both: 20.66 MB used. - -Virtual space: - Non-class space: 64.00 MB reserved, 18.62 MB ( 29%) committed, 1 nodes. - Class space: 1.00 GB reserved, 2.38 MB ( <1%) committed, 1 nodes. - Both: 1.06 GB reserved, 21.00 MB ( 2%) committed. - -Chunk freelists: - Non-Class: 13.03 MB - Class: 13.45 MB - Both: 26.48 MB - -MaxMetaspaceSize: unlimited -CompressedClassSpaceSize: 1.00 GB -Initial GC threshold: 21.00 MB -Current GC threshold: 21.00 MB -CDS: on - - commit_granule_bytes: 65536. - - commit_granule_words: 8192. - - virtual_space_node_default_size: 8388608. - - enlarge_chunks_in_place: 1. - - use_allocation_guard: 0. - - -Internal statistics: - -num_allocs_failed_limit: 0. -num_arena_births: 402. -num_arena_deaths: 0. -num_vsnodes_births: 2. -num_vsnodes_deaths: 0. -num_space_committed: 336. -num_space_uncommitted: 0. -num_chunks_returned_to_freelist: 0. -num_chunks_taken_from_freelist: 821. -num_chunk_merges: 0. -num_chunk_splits: 522. -num_chunks_enlarged: 339. -num_inconsistent_stats: 0. - -CodeHeap 'non-profiled nmethods': size=119168Kb used=3683Kb max_used=3683Kb free=115484Kb - bounds [0x000002cd2b010000, 0x000002cd2b3b0000, 0x000002cd32470000] -CodeHeap 'profiled nmethods': size=119104Kb used=8250Kb max_used=8250Kb free=110853Kb - bounds [0x000002cd23470000, 0x000002cd23c80000, 0x000002cd2a8c0000] -CodeHeap 'non-nmethods': size=7488Kb used=3438Kb max_used=3462Kb free=4049Kb - bounds [0x000002cd2a8c0000, 0x000002cd2ac30000, 0x000002cd2b010000] -CodeCache: size=245760Kb, used=15371Kb, max_used=15395Kb, free=230386Kb - total_blobs=4859, nmethods=4271, adapters=489, full_count=0 -Compilation: enabled, stopped_count=0, restarted_count=0 - -Compilation events (20 events): -Event: 3.647 Thread 0x000002cd3ca73ac0 4264 3 sun.nio.fs.WindowsPath::getPathForWin32Calls (6 bytes) -Event: 3.647 Thread 0x000002cd3ca73ac0 nmethod 4264 0x000002cd23c7c210 code [0x000002cd23c7c3c0, 0x000002cd23c7c510] -Event: 3.652 Thread 0x000002cd85372210 4265 4 java.util.regex.Pattern$BmpCharProperty::match (55 bytes) -Event: 3.653 Thread 0x000002cd85372210 nmethod 4265 0x000002cd2b3a5490 code [0x000002cd2b3a5660, 0x000002cd2b3a5958] -Event: 3.655 Thread 0x000002cd85ca75f0 4266 4 cpw.mods.niofs.union.UnionFileSystem::lambda$checkAccess$8 (19 bytes) -Event: 3.663 Thread 0x000002cd85ca75f0 nmethod 4266 0x000002cd2b3a5c90 code [0x000002cd2b3a5ec0, 0x000002cd2b3a6920] -Event: 3.668 Thread 0x000002cd3ca9c770 4267 3 java.lang.Class::protectionDomain (48 bytes) -Event: 3.669 Thread 0x000002cd3ca9c770 nmethod 4267 0x000002cd23c7c590 code [0x000002cd23c7c7e0, 0x000002cd23c7ce88] -Event: 3.671 Thread 0x000002cd3fa845e0 4269 3 jdk.internal.reflect.ReflectionFactory::copyField (11 bytes) -Event: 3.671 Thread 0x000002cd3ca9c770 4270 3 java.lang.reflect.ReflectAccess::copyField (5 bytes) -Event: 3.671 Thread 0x000002cd8588fde0 4271 3 java.lang.reflect.Field::copy (80 bytes) -Event: 3.671 Thread 0x000002cd3ca73ac0 4272 3 java.lang.reflect.Field:: (50 bytes) -Event: 3.671 Thread 0x000002cd3ca9c770 nmethod 4270 0x000002cd23c7d090 code [0x000002cd23c7d240, 0x000002cd23c7d388] -Event: 3.671 Thread 0x000002cd3fa845e0 nmethod 4269 0x000002cd23c7d490 code [0x000002cd23c7d640, 0x000002cd23c7d850] -Event: 3.671 Thread 0x000002cd8588fde0 nmethod 4271 0x000002cd23c7d990 code [0x000002cd23c7db60, 0x000002cd23c7dfb0] -Event: 3.671 Thread 0x000002cd3ca73ac0 nmethod 4272 0x000002cd23c7e110 code [0x000002cd23c7e2e0, 0x000002cd23c7e6c0] -Event: 3.672 Thread 0x000002cd85b0a740 4275 ! 4 java.lang.invoke.MemberName::getMethodType (211 bytes) -Event: 3.675 Thread 0x000002cd3ca73ac0 4277 3 java.lang.ThreadLocal$ThreadLocalMap::nextIndex (15 bytes) -Event: 3.675 Thread 0x000002cd3ca73ac0 nmethod 4277 0x000002cd23c7e810 code [0x000002cd23c7e9a0, 0x000002cd23c7ead8] -Event: 3.675 Thread 0x000002cd85b0a740 nmethod 4275 0x000002cd2b3a7e90 code [0x000002cd2b3a8080, 0x000002cd2b3a8678] - -GC Heap History (8 events): -Event: 0.565 GC heap before -{Heap before GC invocations=0 (full 0): - garbage-first heap total 512000K, used 24576K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 6 young (24576K), 0 survivors (0K) - Metaspace used 4126K, committed 4288K, reserved 1114112K - class space used 380K, committed 448K, reserved 1048576K -} -Event: 0.574 GC heap after -{Heap after GC invocations=1 (full 0): - garbage-first heap total 512000K, used 10805K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 1 young (4096K), 1 survivors (4096K) - Metaspace used 4126K, committed 4288K, reserved 1114112K - class space used 380K, committed 448K, reserved 1048576K -} -Event: 0.725 GC heap before -{Heap before GC invocations=1 (full 0): - garbage-first heap total 512000K, used 31285K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 6 young (24576K), 1 survivors (4096K) - Metaspace used 4867K, committed 5120K, reserved 1114112K - class space used 438K, committed 576K, reserved 1048576K -} -Event: 0.726 GC heap after -{Heap after GC invocations=2 (full 0): - garbage-first heap total 512000K, used 12398K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 1 young (4096K), 1 survivors (4096K) - Metaspace used 4867K, committed 5120K, reserved 1114112K - class space used 438K, committed 576K, reserved 1048576K -} -Event: 1.059 GC heap before -{Heap before GC invocations=2 (full 0): - garbage-first heap total 512000K, used 65646K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 15 young (61440K), 1 survivors (4096K) - Metaspace used 7113K, committed 7360K, reserved 1114112K - class space used 648K, committed 768K, reserved 1048576K -} -Event: 1.064 GC heap after -{Heap after GC invocations=3 (full 0): - garbage-first heap total 512000K, used 20027K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 2 young (8192K), 2 survivors (8192K) - Metaspace used 7113K, committed 7360K, reserved 1114112K - class space used 648K, committed 768K, reserved 1048576K -} -Event: 1.650 GC heap before -{Heap before GC invocations=3 (full 0): - garbage-first heap total 512000K, used 187963K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 43 young (176128K), 2 survivors (8192K) - Metaspace used 7307K, committed 7488K, reserved 1114112K - class space used 660K, committed 768K, reserved 1048576K -} -Event: 1.656 GC heap after -{Heap after GC invocations=4 (full 0): - garbage-first heap total 512000K, used 26908K [0x000000060e000000, 0x0000000800000000) - region size 4096K, 4 young (16384K), 4 survivors (16384K) - Metaspace used 7307K, committed 7488K, reserved 1114112K - class space used 660K, committed 768K, reserved 1048576K -} - -Dll operation events (12 events): -Event: 0.029 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\java.dll -Event: 0.030 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\zip.dll -Event: 0.055 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jsvml.dll -Event: 0.115 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\net.dll -Event: 0.117 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\nio.dll -Event: 0.121 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\zip.dll -Event: 0.368 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\instrument.dll -Event: 0.434 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jimage.dll -Event: 0.693 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\verify.dll -Event: 2.642 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\management.dll -Event: 2.647 Loaded shared library C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\management_ext.dll -Event: 3.653 Loaded shared library C:\Users\TcT_g\AppData\Local\Temp\lwjglTcT_g\3.3.1-build-7\lwjgl.dll - -Deoptimization events (20 events): -Event: 3.680 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23add704 sp=0x000000fc5dafdab0 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcf68 mode 1 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd2b2d2070 sp=0x000000fc5dafd960 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcde0 mode 1 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23ac7dac sp=0x000000fc5dafd980 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafce08 mode 1 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23add704 sp=0x000000fc5dafdab0 -Event: 3.680 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcf68 mode 1 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd2b2d2070 sp=0x000000fc5dafd960 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcde0 mode 1 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23ac7dac sp=0x000000fc5dafd980 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafce08 mode 1 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23add704 sp=0x000000fc5dafdab0 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcf68 mode 1 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd2b2d2070 sp=0x000000fc5dafd960 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcde0 mode 1 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23ac7dac sp=0x000000fc5dafd980 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafce08 mode 1 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT PACKING pc=0x000002cd23add704 sp=0x000000fc5dafdab0 -Event: 3.681 Thread 0x000002cd18843d50 DEOPT UNPACKING pc=0x000002cd2a9188e2 sp=0x000000fc5dafcf68 mode 1 - -Classes loaded (20 events): -Event: 3.667 Loading class java/nio/BufferOverflowException -Event: 3.667 Loading class java/nio/BufferOverflowException done -Event: 3.668 Loading class java/nio/DirectShortBufferU -Event: 3.668 Loading class java/nio/DirectShortBufferU done -Event: 3.669 Loading class java/nio/DirectCharBufferU -Event: 3.669 Loading class java/nio/DirectCharBufferU done -Event: 3.669 Loading class java/nio/DirectFloatBufferU -Event: 3.669 Loading class java/nio/DirectFloatBufferU done -Event: 3.669 Loading class java/nio/DirectDoubleBufferU -Event: 3.669 Loading class java/nio/DirectDoubleBufferU done -Event: 3.670 Loading class java/util/function/LongPredicate -Event: 3.670 Loading class java/util/function/LongPredicate done -Event: 3.673 Loading class java/nio/InvalidMarkException -Event: 3.673 Loading class java/nio/InvalidMarkException done -Event: 3.673 Loading class java/nio/BufferUnderflowException -Event: 3.673 Loading class java/nio/BufferUnderflowException done -Event: 3.674 Loading class org/lwjgl/system/MemoryStack -Event: 3.674 Loading class org/lwjgl/system/MemoryStack done -Event: 3.674 Loading class org/lwjgl/system/MemoryStack -Event: 3.674 Loading class org/lwjgl/system/MemoryStack done - -Classes unloaded (0 events): -No events - -Classes redefined (1 events): -Event: 0.393 Thread 0x000002cd3ca3d5b0 redefined class name=java.lang.Throwable, count=1 - -Internal exceptions (20 events): -Event: 3.567 Thread 0x000002cd18843d50 Exception (0x000000061e83afd0) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.569 Thread 0x000002cd18843d50 Exception (0x000000061e84b028) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.569 Thread 0x000002cd18843d50 Exception (0x000000061e856290) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.570 Thread 0x000002cd18843d50 Exception (0x000000061e85b3f0) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 840] -Event: 3.572 Thread 0x000002cd18843d50 Exception (0x000000061e893518) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 840] -Event: 3.599 Thread 0x000002cd18843d50 Exception (0x000000061ea74898) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.629 Thread 0x000002cd18843d50 Exception (0x000000061ebc97d8) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.629 Thread 0x000002cd18843d50 Exception (0x000000061ebcd748) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.638 Thread 0x000002cd18843d50 Exception (0x000000061e4ff880) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.639 Thread 0x000002cd18843d50 Exception (0x000000061e511e60) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.651 Thread 0x000002cd18843d50 Exception (0x000000061e70a1c0) -thrown [s\src\hotspot\share\prims\jni.cpp, line 520] -Event: 3.651 Thread 0x000002cd18843d50 Exception (0x000000061e70a510) -thrown [s\src\hotspot\share\prims\jni.cpp, line 520] -Event: 3.664 Thread 0x000002cd18843d50 Exception (0x000000061e7cde78) -thrown [s\src\hotspot\share\prims\jni.cpp, line 520] -Event: 3.665 Thread 0x000002cd18843d50 Exception (0x000000061e7ce1d8) -thrown [s\src\hotspot\share\prims\jni.cpp, line 520] -Event: 3.670 Thread 0x000002cd18843d50 Exception (0x000000061e10e830) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.671 Thread 0x000002cd18843d50 Exception (0x000000061e113b58) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.672 Thread 0x000002cd18843d50 Exception (0x000000061e128180) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.672 Thread 0x000002cd18843d50 Exception (0x000000061e12d870) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.672 Thread 0x000002cd18843d50 Exception (0x000000061e1310b8) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] -Event: 3.672 Thread 0x000002cd18843d50 Exception (0x000000061e1382d0) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 773] - -ZGC Phase Switch (0 events): -No events - -VM Operations (20 events): -Event: 3.206 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.206 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.209 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.209 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.260 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.260 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.260 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.260 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.306 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.306 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.318 Executing VM operation: ICBufferFull -Event: 3.319 Executing VM operation: ICBufferFull done -Event: 3.403 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.403 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.421 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.421 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.509 Executing VM operation: HandshakeAllThreads (Deoptimize) -Event: 3.509 Executing VM operation: HandshakeAllThreads (Deoptimize) done -Event: 3.668 Executing VM operation: ICBufferFull -Event: 3.669 Executing VM operation: ICBufferFull done - -Memory protections (0 events): -No events - -Nmethod flushes (0 events): -No events - -Events (20 events): -Event: 0.163 Thread 0x000002cd3ca73ac0 Thread added: 0x000002cd3fad77e0 -Event: 0.179 Thread 0x000002cd18843d50 Thread added: 0x000002cd3fc04350 -Event: 0.179 Thread 0x000002cd18843d50 Thread added: 0x000002cd3fba3b50 -Event: 0.180 Thread 0x000002cd3fc04350 Thread added: 0x000002cd3fc065d0 -Event: 0.359 Thread 0x000002cd3fad77e0 Thread exited: 0x000002cd3fad77e0 -Event: 0.359 Thread 0x000002cd3fa854a0 Thread exited: 0x000002cd3fa854a0 -Event: 0.403 Thread 0x000002cd18843d50 Thread added: 0x000002cd3fc75fe0 -Event: 0.404 Thread 0x000002cd18843d50 Thread added: 0x000002cd3fbd3540 -Event: 0.453 Thread 0x000002cd3ca6f8d0 Thread added: 0x000002cd8525f610 -Event: 0.453 Thread 0x000002cd3ca6f8d0 Thread added: 0x000002cd85372210 -Event: 0.611 Thread 0x000002cd3fa845e0 Thread added: 0x000002cd8588fde0 -Event: 0.630 Thread 0x000002cd3fa845e0 Thread added: 0x000002cd85dbd8c0 -Event: 0.631 Thread 0x000002cd3fa845e0 Thread added: 0x000002cd85ea5070 -Event: 0.635 Thread 0x000002cd3ca9c770 Thread added: 0x000002cd85e9bf00 -Event: 0.639 Thread 0x000002cd3ca73ac0 Thread added: 0x000002cd85ca75f0 -Event: 0.644 Thread 0x000002cd3ca73ac0 Thread added: 0x000002cd85b0a740 -Event: 3.282 Thread 0x000002cd18843d50 Thread added: 0x000002cd8a61c1a0 -Event: 3.290 Thread 0x000002cd8a61c1a0 Thread exited: 0x000002cd8a61c1a0 -Event: 3.295 Thread 0x000002cd18843d50 Thread added: 0x000002cd8a61c1a0 -Event: 3.304 Thread 0x000002cd8a61c1a0 Thread exited: 0x000002cd8a61c1a0 - - -Dynamic libraries: -0x00007ff60f510000 - 0x00007ff60f51e000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\java.exe -0x00007ff9ed660000 - 0x00007ff9ed8c8000 C:\Windows\SYSTEM32\ntdll.dll -0x00007ff9eb560000 - 0x00007ff9eb629000 C:\Windows\System32\KERNEL32.DLL -0x00007ff9eae40000 - 0x00007ff9eb232000 C:\Windows\System32\KERNELBASE.dll -0x00007ff9eacf0000 - 0x00007ff9eae3b000 C:\Windows\System32\ucrtbase.dll -0x00007ff9d56a0000 - 0x00007ff9d56b8000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jli.dll -0x00007ff9d57c0000 - 0x00007ff9d57de000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\VCRUNTIME140.dll -0x00007ff9ecc50000 - 0x00007ff9ece15000 C:\Windows\System32\USER32.dll -0x00007ff9d0f20000 - 0x00007ff9d11b3000 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.6899_none_3e0efeeae32e88c1\COMCTL32.dll -0x00007ff9ea7f0000 - 0x00007ff9ea817000 C:\Windows\System32\win32u.dll -0x00007ff9eb6a0000 - 0x00007ff9eb749000 C:\Windows\System32\msvcrt.dll -0x00007ff9eb430000 - 0x00007ff9eb45b000 C:\Windows\System32\GDI32.dll -0x00007ff9eaa40000 - 0x00007ff9eab6d000 C:\Windows\System32\gdi32full.dll -0x00007ff9ea820000 - 0x00007ff9ea8c3000 C:\Windows\System32\msvcp_win.dll -0x00007ff9ebca0000 - 0x00007ff9ebccf000 C:\Windows\System32\IMM32.DLL -0x00007ff9e2030000 - 0x00007ff9e203c000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\vcruntime140_1.dll -0x00007ff9c7c00000 - 0x00007ff9c7c8d000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\msvcp140.dll -0x00007ff874860000 - 0x00007ff8755f7000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\server\jvm.dll -0x00007ff9ed1c0000 - 0x00007ff9ed274000 C:\Windows\System32\ADVAPI32.dll -0x00007ff9ecea0000 - 0x00007ff9ecf46000 C:\Windows\System32\sechost.dll -0x00007ff9ecfb0000 - 0x00007ff9ed0c8000 C:\Windows\System32\RPCRT4.dll -0x00007ff9ece20000 - 0x00007ff9ece94000 C:\Windows\System32\WS2_32.dll -0x00007ff9e9420000 - 0x00007ff9e947e000 C:\Windows\SYSTEM32\POWRPROF.dll -0x00007ff9db040000 - 0x00007ff9db04b000 C:\Windows\SYSTEM32\VERSION.dll -0x00007ff9db460000 - 0x00007ff9db495000 C:\Windows\SYSTEM32\WINMM.dll -0x00007ff9e9400000 - 0x00007ff9e9414000 C:\Windows\SYSTEM32\UMPDC.dll -0x00007ff9e96e0000 - 0x00007ff9e96fb000 C:\Windows\SYSTEM32\kernel.appcore.dll -0x00007ff9e1f30000 - 0x00007ff9e1f3a000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jimage.dll -0x00007ff9e7e60000 - 0x00007ff9e80a2000 C:\Windows\SYSTEM32\DBGHELP.DLL -0x00007ff9ed280000 - 0x00007ff9ed5fb000 C:\Windows\System32\combase.dll -0x00007ff9ebce0000 - 0x00007ff9ebdb7000 C:\Windows\System32\OLEAUT32.dll -0x00007ff9cb010000 - 0x00007ff9cb04c000 C:\Windows\SYSTEM32\dbgcore.DLL -0x00007ff9eb240000 - 0x00007ff9eb2d8000 C:\Windows\System32\bcryptPrimitives.dll -0x00007ff9d2170000 - 0x00007ff9d21ac000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jdwp.dll -0x00007ff9dc090000 - 0x00007ff9dc09f000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\instrument.dll -0x00007ff9d4c30000 - 0x00007ff9d4c4f000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\java.dll -0x00007ff9d28e0000 - 0x00007ff9d28f8000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\zip.dll -0x00007ff9ebff0000 - 0x00007ff9ec73d000 C:\Windows\System32\SHELL32.dll -0x00007ff9ea8d0000 - 0x00007ff9eaa3b000 C:\Windows\System32\wintypes.dll -0x00007ff9e8440000 - 0x00007ff9e8c9d000 C:\Windows\SYSTEM32\windows.storage.dll -0x00007ff9ebba0000 - 0x00007ff9ebc92000 C:\Windows\System32\SHCORE.dll -0x00007ff9eb630000 - 0x00007ff9eb692000 C:\Windows\System32\shlwapi.dll -0x00007ff9ea710000 - 0x00007ff9ea739000 C:\Windows\SYSTEM32\profapi.dll -0x00007ff9b0b30000 - 0x00007ff9b0c07000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jsvml.dll -0x00007ff9d4d90000 - 0x00007ff9d4da0000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\net.dll -0x00007ff9e3db0000 - 0x00007ff9e3ecf000 C:\Windows\SYSTEM32\WINHTTP.dll -0x00007ff9e9c50000 - 0x00007ff9e9cbb000 C:\Windows\system32\mswsock.dll -0x00007ff9d28c0000 - 0x00007ff9d28d6000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\nio.dll -0x00007ff9d5530000 - 0x00007ff9d553b000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\dt_socket.dll -0x00007ff9e90a0000 - 0x00007ff9e90d4000 C:\Windows\SYSTEM32\IPHLPAPI.DLL -0x00007ff9d4840000 - 0x00007ff9d4850000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\verify.dll -0x00007ff9d3150000 - 0x00007ff9d315a000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\management.dll -0x00007ff9d2f80000 - 0x00007ff9d2f8b000 C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\management_ext.dll -0x00007ff9ecc40000 - 0x00007ff9ecc48000 C:\Windows\System32\PSAPI.DLL -0x00007ff9a93b0000 - 0x00007ff9a93c8000 C:\Windows\system32\napinsp.dll -0x00007ff9e9140000 - 0x00007ff9e9266000 C:\Windows\SYSTEM32\DNSAPI.dll -0x00007ff9eb7d0000 - 0x00007ff9eb7da000 C:\Windows\System32\NSI.dll -0x00007ff9a4270000 - 0x00007ff9a4282000 C:\Windows\System32\winrnr.dll -0x00007ff9a3e50000 - 0x00007ff9a3e78000 C:\Windows\system32\nlansp_c.dll -0x00007ff9e26a0000 - 0x00007ff9e26b6000 C:\Windows\system32\wshbth.dll -0x00007ff9e3080000 - 0x00007ff9e308b000 C:\Windows\System32\rasadhlp.dll -0x00007ff9e41e0000 - 0x00007ff9e4266000 C:\Windows\System32\fwpuclnt.dll -0x00007ff9cd6a0000 - 0x00007ff9cd715000 C:\Users\TcT_g\AppData\Local\Temp\lwjglTcT_g\3.3.1-build-7\lwjgl.dll -0x00007ff9cb110000 - 0x00007ff9cb171000 C:\Users\TcT_g\AppData\Local\Temp\lwjglTcT_g\3.3.1-build-7\glfw.dll - -JVMTI agents: -jdwp path:C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\jdwp.dll, loaded, initialized, options:transport=dt_socket,server=n,suspend=y,address=127.0.0.1:58923 -C:\Users\TcT_g\AppData\Local\JetBrains\IntelliJIdea2025.2\captureAgent\debugger-agent.jar path:C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\instrument.dll, loaded, initialized, instrumentlib options:file:///C:/Users/TcT_g/AppData/Local/Temp/capture6757434691262209115.props - -dbghelp: loaded successfully - version: 4.0.5 - missing functions: none -symbol engine: initialized successfully - sym options: 0x614 - pdb path: .;C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin;C:\Windows\SYSTEM32;C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.6899_none_3e0efeeae32e88c1;C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\jdk\bin\server;C:\Users\TcT_g\AppData\Local\Temp\lwjglTcT_g\3.3.1-build-7 - -VM Arguments: -jvm_args: -Ddebugger.agent.enable.coroutines=true -Dforge.enableGameTest=true -Dforge.logging.console.level=debug -Dforge.logging.markers=REGISTRIES -DignoreList=bootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -Djava.net.preferIPv6Addresses=system -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -DlegacyClassPath.file=C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\classpath\runClient_minecraftClasspath.txt -DmergeModules=jna-5.10.0.jar,jna-platform-5.10.0.jar -Dmixin.debug.export=true -Dmixin.debug.verbose=true -Dmixin.env.refMapRemappingFile=C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge/build/createSrgToMcp/output.srg -Dmixin.env.remapRefMap=true -Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp=C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\createSrgToMcp\output.srg --module-path=C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar --add-modules=ALL-MODULE-PATH --add-opens=java.base/java.util.jar=cpw.mods.securejarhandler --add-opens=java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports=java.base/sun.security.util=cpw.mods.securejarhandler --add-exports=jdk.naming.dns/com.sun.jndi.dns=java.naming -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump --module-path=C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar --add-modules=ALL-MODULE-PATH --add-opens=java.base/java.util.jar=cpw.mods.securejarhandler --add-opens=java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports=java.base/sun.security.util=cpw.mods.securejarhandler --add-exports=jdk.naming.dns/com.sun.jndi.dns=java.naming -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=127.0.0.1:58923 -javaagent:C:\Users\TcT_g\AppData\Local\JetBrains\IntelliJIdea2025.2\captureAgent\debugger-agent.jar=file:///C:/Users/TcT_g/AppData/Local/Temp/capture6757434691262209115.props -Dfile.encoding=UTF-8 -Duser.country=FR -Duser.language=fr -Duser.variant -java_command: cpw.mods.bootstraplauncher.BootstrapLauncher --launchTarget forgeclientuserdev --version MOD_DEV --assetIndex 5 --assetsDir C:\Users\TcT_g\.gradle\caches\forge_gradle\assets --gameDir . --fml.forgeVersion 47.2.6 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createnuclear.forge.mixins.json -java_class_path (initial): C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\classes\java\main;C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\resources\main;C:\Users\TcT_g\.gradle\caches\forge_gradle\deobf_dependencies\curse\maven\jade-324717\6106101_mapped_parchment_2023.09.03-1.20.1\jade-324717-6106101_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\TcT_g\.gradle\caches\forge_gradle\deobf_dependencies\com\simibubi\create\create-1.20.1\6.0.8-289_mapped_parchment_2023.09.03-1.20.1\create-1.20.1-6.0.8-289_mapped_parchment_2023.09.03-1.20.1-slim.jar;C:\Users\TcT_g\.gradle\caches\forge_gradle\deobf_dependencies\net\createmod\ponder\Ponder-Forge-1.20.1\1.0.91_mapped_parchment_2023.09.03-1.20.1\Ponder-Forge-1.20.1-1.0.91_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\TcT_g\.gradle\caches\forge_gradle\deobf_dependencies\com\tterrag\registrate\Registrate\MC1.20-1.3.3_mapped_parchment_2023.09.03-1.20.1\Registrate-MC1.20-1.3.3_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.github.llamalad7\mixinextras-forge\0.4.1\5c35573a7b76103724799ca1174a69699b8a9aec\mixinextras-forge-0.4.1.jar;C:\Users\TcT_g\Desktop\ynov\M1\CreateNuclear\CreateNuclearForge\build\fg_cache\net\minecraftforge\forge\1.20.1-47.2.6_mapped_parchment_2023.09.03-1.20.1\forge-1.20.1-47.2.6_mapped_parchment_2023.09.03-1.20.1-recomp.jar;C:\Users\TcT_g\.gradle\caches\forge_gradle\deobf_dependencies\dev\engine-room\flywheel\flywheel-forge-1.20.1\1.0.5_mapped_parchment_2023.09.03-1.20.1\flywheel-forge-1.20.1-1.0.5_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\TcT_g\.gradle\caches\forge_gradle\deobf_dependencies\mezz\jei\jei-1.20.1-forge\15.20.0.105_mapped_parchment_2023.09.03-1.20.1\jei-1.20.1-forge-15.20.0.105_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\TcT_g\.gradle\caches\forge_gradle\minecraft_repo\versions\1.20.1\client-extra.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\fmlearlydisplay\1.20.1-47.2.6\855538dcc7ae05a1de27881ebd5725cd7177201\fmlearlydisplay-1.20.1-47.2.6.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\javafmllanguage\1.20.1-47.2.6\56551ed4a181a00930b0365996e1d9f3ca851459\javafmllanguage-1.20.1-47.2.6.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\lowcodelanguage\1.20.1-47.2.6\f27bd133cd78227e8d6def633b83c881a30cc243\lowcodelanguage-1.20.1-47.2.6.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\mclanguage\1.20.1-47.2.6\6e1641ac5a046737d7c3209901ca0a829d636873\mclanguage-1.20.1-47.2.6.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\fmlcore\1.20.1-47.2.6\2d5f5aff839b7d2825c6968049399633d1c4d0b8\fmlcore-1.20.1-47.2.6.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\fmlloader\1.20.1-47.2.6\7e862c69c8fd10696819690249f2afa0d1da3c3b\fmlloader-1.20.1-47.2.6.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarSelector\0.3.19\376cc9c8ea60720cf027c01fc033de915699801c\JarJarSelector-0.3.19.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarMetadata\0.3.19\83feaa9b770e6ac0e96ee4fc23fa89325c5fe2\JarJarMetadata-0.3.19.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\31.1-jre\60458f877d055d0c9114d9e1a2efb737b4bc282c\guava-31.1-jre.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\ca.weblite\java-objc-bridge\1.1\1227f9e0666314f9de41477e3ec277e542ed7f7b\java-objc-bridge-1.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\coremods\5.0.1\386b00279628b105b2d507539c46e134e96f6237\coremods-5.0.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\forgespi\7.0.1\3b4972a0cdb135853dba219be61a79b22cff1309\forgespi-7.0.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\mergetool\1.1.5\f3da18e12c696d35a47c82cbb2cc8b5aa15e1154\mergetool-1.1.5-api.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.jetbrains\annotations\24.0.1\13c5c75c4206580aa4d683bffee658caae6c9f43\annotations-24.0.1.jar;C:\Users\TcT_g\.gradle\caches\parchmentgradle\org\parchmentmc\data\parchment-1.20.1\2023.09.03\parchment-1.20.1-2023.09.03.zip;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\accesstransformers\8.0.4\272d240aa73f42195b2a68e2ebd8b701ecf41f63\accesstransformers-8.0.4.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\eventbus\6.0.5\699143dd438431d06b57416944f7cedbe52e1475\eventbus-6.0.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\modlauncher\10.0.9\6d9443f56f50bb85cea383686ff9c867391458b\modlauncher-10.0.9.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.openjdk.nashorn\nashorn-core\15.3\43977e804697048fc8d81d333a36c17d07a5b3dd\nashorn-core-15.3.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4\4.9.1\e92af8ab33e428461927b484e90bb155a4f3a052\antlr4-4.9.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4-runtime\4.9.1\428664f05d2b7f7b7610204b5aa7c1763f62011a\antlr4-runtime-4.9.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\unsafe\0.2.0\54d7a0a5e8fdb71b973025caa46f341ae5904f39\unsafe-0.2.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.electronwill.night-config\toml\3.6.4\51d6cefb2b55ee55ee26b16391212fb2c7dfb4f4\toml-3.6.4.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.electronwill.night-config\core\3.6.4\510f174abbf1c947494db50ef2445683bd52c230\core-3.6.4.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.maven\maven-artifact\3.8.5\4433f50c07debefaed0553bd0068f4f48d449313\maven-artifact-3.8.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.jodah\typetools\0.6.3\a01aaa6ddaea9ec07ec4f209487b7a46a526283a\typetools-0.6.3.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecrell\terminalconsoleappender\1.2.0\96d02cd3b384ff015a8fef4223bcb4ccf1717c95\terminalconsoleappender-1.2.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.jline\jline-reader\3.12.1\4382ab1382c7b6f379377ed5f665dc2f6e1218bc\jline-reader-3.12.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.jline\jline-terminal\3.12.1\c777448314e050d980a6b697c140f3bfe9eb7416\jline-terminal-3.12.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.spongepowered\mixin\0.8.5\9d1c0c3a304ae6697ecd477218fa61b850bf57fc\mixin-0.8.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.github.oshi\oshi-core\6.2.2\54f5efc19bca95d709d9a37d19ffcbba3d21c1a6\oshi-core-6.2.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.10\dd9b193aef96e973d5a11ab13cd17430c2e4306b\gson-2.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.guava\failureaccess\1.0.1\1dcf1de382a0bf95a3d8b0849546c88bac1292c9\failureaccess-1.0.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.ibm.icu\icu4j\71.1\9e7d3304c23f9ba5cb71915f7cce23231a57a445\icu4j-71.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\authlib\4.0.43\2ff9d747a77570a07a60d32ac77eb6162ad2a2d9\authlib-4.0.43.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\blocklist\1.0.10\5c685c5ffa94c4cd39496c7184c1d122e515ecef\blocklist-1.0.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\brigadier\1.1.8\5244ce82c3337bba4a196a3ce858bfaecc74404a\brigadier-1.1.8.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\datafixerupper\6.0.8\3ba4a30557a9b057760af4011f909ba619fc5125\datafixerupper-6.0.8.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\logging\1.1.1\832b8e6674a9b325a5175a3a6267dfaf34c85139\logging-1.1.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\patchy\2.2.10\da05971b07cbb379d002cf7eaec6a2048211fefc\patchy-2.2.10.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.mojang\text2speech\1.17.9\3cad216e3a7f0c19b4b394388bc9ffc446f13b14\text2speech-1.17.9.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpclient\4.5.13\e5f6cae5ca7ecaac1ec2827a9e2d65ae2869cada\httpclient-4.5.13.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\commons-codec\commons-codec\1.15\49d94806b6e3dc933dacbd8acb0fdbab8ebd1e5d\commons-codec-1.15.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\commons-io\commons-io\2.11.0\a2503f302b11ebde7ebc3df41daebe0e4eea3689\commons-io-2.11.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\commons-logging\commons-logging\1.2\4bfc12adfe4842bf07b657f0369c4cb522955686\commons-logging-1.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-handler\4.1.82.Final\644041d1fa96a5d3130a29e8978630d716d76e38\netty-handler-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-codec\4.1.82.Final\b77200379acb345a9ffdece1c605e591ac3e4e0a\netty-codec-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-classes-epoll\4.1.82.Final\e7c7dd18deac93105797f30057c912651ea76521\netty-transport-classes-epoll-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport-native-unix-common\4.1.82.Final\3e895b35ca1b8a0eca56cacff4c2dde5d2c6abce\netty-transport-native-unix-common-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-transport\4.1.82.Final\e431a218d91acb6476ccad5f5aafde50aa3945ca\netty-transport-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-buffer\4.1.82.Final\a544270cf1ae8b8077082f5036436a9a9971ea71\netty-buffer-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-resolver\4.1.82.Final\38f665ae8dcd29032eea31245ba7806bed2e0fa8\netty-resolver-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\io.netty\netty-common\4.1.82.Final\22d148e85c3f5ebdacc0ce1f5aabb1d420f73f3\netty-common-4.1.82.Final.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\it.unimi.dsi\fastutil\8.5.9\bb7ea75ecdb216654237830b3a96d87ad91f8cc5\fastutil-8.5.9.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.java.dev.jna\jna-platform\5.12.1\97406a297c852f4a41e688a176ec675f72e8329\jna-platform-5.12.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.java.dev.jna\jna\5.12.1\b1e93a735caea94f503e95e6fe79bf9cdc1e985d\jna-5.12.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.sf.jopt-simple\jopt-simple\5.0.4\4fdac2fbe92dfad86aa6e9301736f6b4342a3f5c\jopt-simple-5.0.4.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-compress\1.21\4ec95b60d4e86b5c95a0e919cb172a0af98011ef\commons-compress-1.21.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-lang3\3.12.0\c6842c86792ff03b9f1d1fe2aab8dc23aa6c6f0e\commons-lang3-3.12.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.httpcomponents\httpcore\4.4.15\7f2e0c573eaa7a74bac2e89b359e1f73d92a0a1d\httpcore-4.4.15.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-core\2.19.0\3b6eeb4de4c49c0fe38a4ee27188ff5fee44d0bb\log4j-core-2.19.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-slf4j2-impl\2.19.0\5c04bfdd63ce9dceb2e284b81e96b6a70010ee10\log4j-slf4j2-impl-2.19.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.19.0\ea1b37f38c327596b216542bc636cfdc0b8036fa\log4j-api-2.19.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.joml\joml\1.10.5\22566d58af70ad3d72308bab63b8339906deb649\joml-1.10.5.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-glfw\3.3.1\cbac1b8d30cb4795149c1ef540f912671a8616d0\lwjgl-glfw-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-glfw\3.3.1\ed892f945cf7e79c8756796f32d00fa4ceaf573b\lwjgl-glfw-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-glfw\3.3.1\beda65ee503443e60aa196d58ed31f8d001dc22a\lwjgl-glfw-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-glfw\3.3.1\b997e3391d6ce8f05487e7335d95c606043884a1\lwjgl-glfw-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-jemalloc\3.3.1\a817bcf213db49f710603677457567c37d53e103\lwjgl-jemalloc-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-jemalloc\3.3.1\948a89b76a16aa324b046ae9308891216ffce5f9\lwjgl-jemalloc-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-jemalloc\3.3.1\cae85c4edb219c88b6a0c26a87955ad98dc9519d\lwjgl-jemalloc-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-jemalloc\3.3.1\fb476c8ec110e1c137ad3ce8a7f7bfe6b11c6324\lwjgl-jemalloc-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-openal\3.3.1\2623a6b8ae1dfcd880738656a9f0243d2e6840bd\lwjgl-openal-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-openal\3.3.1\30a474d0e57193d7bc128849a3ab66bc9316fdb1\lwjgl-openal-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-openal\3.3.1\40d65f1a7368a2aa47336f9cb69f5a190cf9975a\lwjgl-openal-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-openal\3.3.1\888349f7b1be6fbae58bf8edfb9ef12def04c4e3\lwjgl-openal-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-opengl\3.3.1\831a5533a21a5f4f81bbc51bb13e9899319b5411\lwjgl-opengl-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-opengl\3.3.1\c1807e9bd571402787d7e37e3029776ae2513bb8\lwjgl-opengl-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-opengl\3.3.1\527d78f1e9056aff3ed02ce93019c73c5e8f1721\lwjgl-opengl-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-opengl\3.3.1\deef3eb9b178ff2ff3ce893cc72ae741c3a17974\lwjgl-opengl-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-stb\3.3.1\b119297cf8ed01f247abe8685857f8e7fcf5980f\lwjgl-stb-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-stb\3.3.1\86315914ac119efdb02dc9e8e978ade84f1702af\lwjgl-stb-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-stb\3.3.1\fde63cdd2605c00636721a6c8b961e41d1f6b247\lwjgl-stb-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-stb\3.3.1\a8d41f419eecb430b7c91ea2ce2c5c451cae2091\lwjgl-stb-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-tinyfd\3.3.1\ff1914111ef2e3e0110ef2dabc8d8cdaad82347\lwjgl-tinyfd-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-tinyfd\3.3.1\a5d830475ec0958d9fdba1559efa99aef211e6ff\lwjgl-tinyfd-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-tinyfd\3.3.1\83a5e780df610829ff3a737822b4f931cffecd91\lwjgl-tinyfd-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl-tinyfd\3.3.1\842eedd876fae354abc308c98a263f6bbc9e8a4d\lwjgl-tinyfd-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl\3.3.1\ae58664f88e18a9bb2c77b063833ca7aaec484cb\lwjgl-3.3.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl\3.3.1\36c37f16ab611b3aa11f3bcf80b1d509b4ce6b\lwjgl-3.3.1-natives-windows.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl\3.3.1\f46cadcf95675908fd3a550d63d9d709cb68998\lwjgl-3.3.1-natives-windows-arm64.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.lwjgl\lwjgl\3.3.1\3b14f4beae9dd39791ec9e12190a9380cd8a3ce6\lwjgl-3.3.1-natives-windows-x86.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.machinezoo.noexception\noexception\1.7.1\b65330c98e38a1f915fa54a6e5eca496505e3f0a\noexception-1.7.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-simple\1.7.30\e606eac955f55ecf1d8edcccba04eb8ac98088dd\slf4j-simple-1.7.30.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\2.0.1\f48d81adce2abf5ad3cfe463df517952749e03bc\slf4j-api-2.0.1.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\net.minecraftforge\srgutils\0.4.11\fbad1341ffdb47d276bbdc40ecb06da49e053e74\srgutils-0.4.11.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.codehaus.plexus\plexus-utils\3.3.0\cf43b5391de623b36fe066a21127baef82c64022\plexus-utils-3.3.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\b421526c5f297295adef1c886e5246c39d4ac629\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\3.12.0\d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5\checker-qual-3.12.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.11.0\c5a0ace696d3f8b1c1d8cc036d8c03cc0cbe6b69\error_prone_annotations-2.11.0.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\1.3\ba035118bc8bac37d7eff77700720999acd9986d\j2objc-annotations-1.3.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.antlr\ST4\4.3\92f2c1ad8d84abcbeead6cf7f2c53a04166293c2\ST4-4.3.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.antlr\antlr-runtime\3.5.2\cd9cd41361c155f3af0f653009dcecb08d8b4afd\antlr-runtime-3.5.2.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.abego.treelayout\org.abego.treelayout.core\1.0.3\457216e8e6578099ae63667bb1e4439235892028\org.abego.treelayout.core-1.0.3.jar;C:\Users\TcT_g\.gradle\caches\modules-2\files-2.1\org.glassfish\javax.json\1.0.4\3178f73569fd7a1e5ffc464e680f7a8cc784b85a\javax.json-1.0.4.jar -Launcher Type: SUN_STANDARD - -[Global flags] - intx CICompilerCount = 12 {product} {ergonomic} - uint ConcGCThreads = 3 {product} {ergonomic} - uint G1ConcRefinementThreads = 13 {product} {ergonomic} - size_t G1HeapRegionSize = 4194304 {product} {ergonomic} - uintx GCDrainStackTargetSize = 64 {product} {ergonomic} - ccstr HeapDumpPath = MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump {manageable} {command line} - size_t InitialHeapSize = 524288000 {product} {ergonomic} - size_t MarkStackSize = 4194304 {product} {ergonomic} - size_t MaxHeapSize = 8355053568 {product} {ergonomic} - size_t MaxNewSize = 5012193280 {product} {ergonomic} - size_t MinHeapDeltaBytes = 4194304 {product} {ergonomic} - size_t MinHeapSize = 8388608 {product} {ergonomic} - uintx NonNMethodCodeHeapSize = 7602480 {pd product} {ergonomic} - uintx NonProfiledCodeHeapSize = 122027880 {pd product} {ergonomic} - uintx ProfiledCodeHeapSize = 122027880 {pd product} {ergonomic} - uintx ReservedCodeCacheSize = 251658240 {pd product} {ergonomic} - bool SegmentedCodeCache = true {product} {ergonomic} - size_t SoftMaxHeapSize = 8355053568 {manageable} {ergonomic} - bool UseCompressedOops = true {product lp64_product} {ergonomic} - bool UseG1GC = true {product} {ergonomic} - bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} - -Logging: -Log output configuration: - #0: stdout all=warning uptime,level,tags foldmultilines=false - #1: stderr all=off uptime,level,tags foldmultilines=false - -Environment Variables: -PATH=C:\Python314\Scripts\;C:\Python314\;C:\Program Files (x86)\Common Files\Oracle\Java\java8path;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA App\NvDLISR;C:\Program Files\dotnet\;C:\Windows\AtlasModules;C:\Windows\AtlasModules\Tools;C:\Windows\AtlasModules\Scripts;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\ProgramData\chocolatey\bin;C:\Program Files\cursor\resources\app\bin;C:\Program Files\PowerToys\;C:\Program Files\Docker\Docker\resources\bin;C:\Users\TcT_g\AppData\Local\Microsoft\WindowsApps;C:\Users\TcT_g\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files\JetBrains\IntelliJ IDEA 2025.2.3\bin;C:\Users\TcT_g\AppData\Roaming\npm;C:\Users\TcT_g\AppData\Local\Programs\Antigravity\bin -USERNAME=TcT_g -OS=Windows_NT -PROCESSOR_IDENTIFIER=AMD64 Family 26 Model 96 Stepping 0, AuthenticAMD -TMP=C:\Users\TcT_g\AppData\Local\Temp -TEMP=C:\Users\TcT_g\AppData\Local\Temp - - - - -Periodic native trim disabled - ---------------- S Y S T E M --------------- - -OS: - Windows 11 , 64 bit Build 26100 (10.0.26100.6725) -OS uptime: 0 days 6:19 hours -Hyper-V role detected - -CPU: total 16 (initial active 16) (16 cores per cpu, 2 threads per core) family 26 model 96 stepping 0 microcode 0xb60000e, cx8, cmov, fxsr, ht, mmx, 3dnowpref, sse, sse2, sse3, ssse3, sse4a, sse4.1, sse4.2, popcnt, lzcnt, tsc, tscinvbit, avx, avx2, aes, erms, clmul, bmi1, bmi2, adx, avx512f, avx512dq, avx512cd, avx512bw, avx512vl, sha, fma, vzeroupper, avx512_vpopcntdq, avx512_vpclmulqdq, avx512_vaes, avx512_vnni, clflush, clflushopt, avx512_vbmi2, avx512_vbmi, hv, rdtscp, rdpid, fsrm, gfni, avx512_bitalg, f16c, cet_ss, avx512_ifma -Processor Information for the first 16 processors : - Max Mhz: 2000, Current Mhz: 2000, Mhz Limit: 2000 - -Memory: 4k page, system-wide physical 31865M (12873M free) -TotalPageFile size 42617M (AvailPageFile size 8050M) -current process WorkingSet (physical memory assigned to process): 522M, peak: 522M -current process commit charge ("private bytes"): 827M, peak: 827M - -vm_info: OpenJDK 64-Bit Server VM (21.0.8+9-LTS) for windows-amd64 JRE (21.0.8+9-LTS), built on 2025-07-15T00:00:00Z by "admin" with MS VC++ 17.7 (VS2022) - -END. diff --git a/run/hs_err_pid27848.log b/run/hs_err_pid27848.log deleted file mode 100644 index 336db066..00000000 --- a/run/hs_err_pid27848.log +++ /dev/null @@ -1,2638 +0,0 @@ -# -# There is insufficient memory for the Java Runtime Environment to continue. -# Native memory allocation (mmap) failed to map 211812352 bytes. Error detail: G1 virtual space -# Possible reasons: -# The system is out of physical RAM or swap space -# This process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap -# Possible solutions: -# Reduce memory load on the system -# Increase physical memory or swap space -# Check if swap backing store is full -# Decrease Java heap size (-Xmx/-Xms) -# Decrease number of Java threads -# Decrease Java thread stack sizes (-Xss) -# Set larger code cache with -XX:ReservedCodeCacheSize= -# JVM is running with Zero Based Compressed Oops mode in which the Java heap is -# placed in the first 32GB address space. The Java Heap base address is the -# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress -# to set the Java Heap base and to place the Java Heap above 32GB virtual address. -# This output file may be truncated or incomplete. -# -# Out of Memory Error (os_windows.cpp:3618), pid=27848, tid=27956 -# -# JRE version: OpenJDK Runtime Environment Temurin-17.0.17+10 (17.0.17+10) (build 17.0.17+10) -# Java VM: OpenJDK 64-Bit Server VM Temurin-17.0.17+10 (17.0.17+10, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64) -# No core dump will be written. Minidumps are not enabled by default on client versions of Windows -# - ---------------- S U M M A R Y ------------ - -Command Line: -Dforge.enableGameTest=true -Dforge.logging.console.level=debug -Dforge.logging.markers=REGISTRIES -DignoreList=bootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -Djava.net.preferIPv6Addresses=system -DlegacyClassPath.file=C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\classpath\runClient_minecraftClasspath.txt -DmergeModules=jna-5.10.0.jar,jna-platform-5.10.0.jar -Dmixin.debug.export=true -Dmixin.debug.verbose=true -Dmixin.env.refMapRemappingFile=C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge/build/createSrgToMcp/output.srg -Dmixin.env.remapRefMap=true -Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp=C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\createSrgToMcp\output.srg --module-path=C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar --add-modules=ALL-MODULE-PATH --add-opens=java.base/java.util.jar=cpw.mods.securejarhandler --add-opens=java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports=java.base/sun.security.util=cpw.mods.securejarhandler --add-exports=jdk.naming.dns/com.sun.jndi.dns=java.naming -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -Dfile.encoding=UTF-8 -Duser.country=FR -Duser.language=fr -Duser.variant cpw.mods.bootstraplauncher.BootstrapLauncher --launchTarget forgeclientuserdev --version MOD_DEV --assetIndex 5 --assetsDir C:\Users\Utilisateur\.gradle\caches\forge_gradle\assets --gameDir . --fml.forgeVersion 47.2.6 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createnuclear.forge.mixins.json - -Host: 12th Gen Intel(R) Core(TM) i7-12700F, 20 cores, 15G, Windows 11 , 64 bit Build 26100 (10.0.26100.8328) -Time: Tue May 19 14:54:23 2026 Paris, Madrid (heure duild 26100 (10.0.26100.8328) elapsed time: 41.604246 seconds (0d 0h 0m 41s) - ---------------- T H R E A D --------------- - -Current thread (0x000001fbff57a010): VMThread "VM Thread" [stack: 0x000000c54f500000,0x000000c54f600000] [id=27956] - -Stack: [0x000000c54f500000,0x000000c54f600000] -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -V [jvm.dll+0x683fb9] -V [jvm.dll+0x83a1b5] -V [jvm.dll+0x83bc2e] -V [jvm.dll+0x83c2b3] -V [jvm.dll+0x248eff] -V [jvm.dll+0x680d79] -V [jvm.dll+0x675b7a] -V [jvm.dll+0x3091a7] -V [jvm.dll+0x310776] -V [jvm.dll+0x360bbe] -V [jvm.dll+0x360dfd] -V [jvm.dll+0x2e022c] -V [jvm.dll+0x2de602] -V [jvm.dll+0x2ddd9c] -V [jvm.dll+0x320a3b] -V [jvm.dll+0x840acd] -V [jvm.dll+0x841803] -V [jvm.dll+0x841d2f] -V [jvm.dll+0x842115] -V [jvm.dll+0x8421de] -V [jvm.dll+0x7ea44c] -V [jvm.dll+0x682e87] -C [ucrtbase.dll+0x37b0] -C [KERNEL32.DLL+0x2e957] -C [ntdll.dll+0x427c] - -VM_Operation (0x000000c553efefa0): G1CollectForAllocation, mode: safepoint, requested by thread 0x000001fbe8a6fbb0 - - ---------------- P R O C E S S --------------- - -Threads class SMR info: -_java_thread_list=0x000001fbea81b420, length=64, elements={ -0x000001fbef365e40, 0x000001fbff581410, 0x000001fbff583b00, 0x000001fbff597de0, -0x000001fbff5982c0, 0x000001fbff5987a0, 0x000001fbff59cc90, 0x000001fbff59f8c0, -0x000001fbff5a5e00, 0x000001fb93429fc0, 0x000001fb934c7bb0, 0x000001fb93561300, -0x000001fb93650850, 0x000001fbe78809b0, 0x000001fbdff9a200, 0x000001fbdff97980, -0x000001fbdff983a0, 0x000001fbdff99cf0, 0x000001fbdff9a710, 0x000001fbe787f060, -0x000001fbe787dc20, 0x000001fbe787e130, 0x000001fbe8a6a5a0, 0x000001fbe8a6a090, -0x000001fbe8a6afc0, 0x000001fbe8a6bef0, 0x000001fbe8a68c50, 0x000001fbe8a68740, -0x000001fbe8a6c400, 0x000001fbe8a6dd50, 0x000001fbe8a6e770, 0x000001fbe8a6ec80, -0x000001fbe8a6f6a0, 0x000001fbe8a6f190, 0x000001fbe8a6fbb0, 0x000001fbdff992d0, -0x000001fbe787fa80, 0x000001fbe8a30c40, 0x000001fbe8a32fb0, 0x000001fbe8a31660, -0x000001fbe8a2f800, 0x000001fbe8a2fd10, 0x000001fbe8a31b70, 0x000001fbe8a32080, -0x000001fbe8a31150, 0x000001fbe8a30730, 0x000001fbe8a32590, 0x000001fbe8a32aa0, -0x000001fbe8a334c0, 0x000001fbe8a339d0, 0x000001fbe8a35830, 0x000001fbe8a6d330, -0x000001fbdff51620, 0x000001fbdff52f70, 0x000001fbdff53480, 0x000001fbde3f9930, -0x000001fbdff501e0, 0x000001fbdff53ea0, 0x000001fbdff57650, 0x000001fbdff552e0, -0x000001fbdff543b0, 0x000001fbdff56720, 0x000001fbdff548c0, 0x000001fbdff50c00 -} - -Java Threads: ( => current thread ) - 0x000001fbef365e40 JavaThread "Render thread" [_thread_blocked, id=27932, stack(0x000000c54ef00000,0x000000c54f000000)] - 0x000001fbff581410 JavaThread "Reference Handler" daemon [_thread_blocked, id=27960, stack(0x000000c54f600000,0x000000c54f700000)] - 0x000001fbff583b00 JavaThread "Finalizer" daemon [_thread_blocked, id=27964, stack(0x000000c54f700000,0x000000c54f800000)] - 0x000001fbff597de0 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=27968, stack(0x000000c54f800000,0x000000c54f900000)] - 0x000001fbff5982c0 JavaThread "Attach Listener" daemon [_thread_blocked, id=27972, stack(0x000000c54f900000,0x000000c54fa00000)] - 0x000001fbff5987a0 JavaThread "Service Thread" daemon [_thread_blocked, id=27976, stack(0x000000c54fa00000,0x000000c54fb00000)] - 0x000001fbff59cc90 JavaThread "Monitor Deflation Thread" daemon [_thread_blocked, id=27980, stack(0x000000c54fb00000,0x000000c54fc00000)] - 0x000001fbff59f8c0 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=27984, stack(0x000000c54fc00000,0x000000c54fd00000)] - 0x000001fbff5a5e00 JavaThread "C1 CompilerThread0" daemon [_thread_blocked, id=27988, stack(0x000000c54fd00000,0x000000c54fe00000)] - 0x000001fb93429fc0 JavaThread "Sweeper thread" daemon [_thread_blocked, id=27992, stack(0x000000c54fe00000,0x000000c54ff00000)] - 0x000001fb934c7bb0 JavaThread "C1 CompilerThread1" daemon [_thread_blocked, id=27996, stack(0x000000c54ff00000,0x000000c550000000)] - 0x000001fb93561300 JavaThread "Common-Cleaner" daemon [_thread_blocked, id=28000, stack(0x000000c550000000,0x000000c550100000)] - 0x000001fb93650850 JavaThread "Notification Thread" daemon [_thread_blocked, id=28016, stack(0x000000c550300000,0x000000c550400000)] - 0x000001fbe78809b0 JavaThread "JNA Cleaner" daemon [_thread_blocked, id=28280, stack(0x000000c552400000,0x000000c552500000)] - 0x000001fbdff9a200 JavaThread "Timer hack thread" daemon [_thread_blocked, id=24660, stack(0x000000c551f00000,0x000000c552000000)] - 0x000001fbdff97980 JavaThread "Yggdrasil Key Fetcher" daemon [_thread_blocked, id=23804, stack(0x000000c552600000,0x000000c552700000)] - 0x000001fbdff983a0 JavaThread "Cleaner-0" daemon [_thread_blocked, id=19428, stack(0x000000c552b00000,0x000000c552c00000)] - 0x000001fbdff99cf0 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=18624, stack(0x000000c552d00000,0x000000c552e00000)] - 0x000001fbdff9a710 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=26600, stack(0x000000c552e00000,0x000000c552f00000)] - 0x000001fbe787f060 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=27640, stack(0x000000c552f00000,0x000000c553000000)] - 0x000001fbe787dc20 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=25292, stack(0x000000c553000000,0x000000c553100000)] - 0x000001fbe787e130 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=18128, stack(0x000000c553100000,0x000000c553200000)] - 0x000001fbe8a6a5a0 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=544, stack(0x000000c553200000,0x000000c553300000)] - 0x000001fbe8a6a090 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=26844, stack(0x000000c553300000,0x000000c553400000)] - 0x000001fbe8a6afc0 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=27520, stack(0x000000c553400000,0x000000c553500000)] - 0x000001fbe8a6bef0 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=27468, stack(0x000000c553500000,0x000000c553600000)] - 0x000001fbe8a68c50 JavaThread "modloading-worker-0" daemon [_thread_blocked, id=26204, stack(0x000000c553600000,0x000000c553700000)] - 0x000001fbe8a68740 JavaThread "FileSystemWatchService" daemon [_thread_in_native, id=24156, stack(0x000000c553800000,0x000000c553900000)] - 0x000001fbe8a6c400 JavaThread "JEI Config File Watcher" daemon [_thread_blocked, id=25816, stack(0x000000c553900000,0x000000c553a00000)] - 0x000001fbe8a6dd50 JavaThread "Worker-Main-1" daemon [_thread_blocked, id=10556, stack(0x000000c552300000,0x000000c552400000)] - 0x000001fbe8a6e770 JavaThread "Thread-3" daemon [_thread_blocked, id=24648, stack(0x000000c553a00000,0x000000c553b00000)] - 0x000001fbe8a6ec80 JavaThread "FileSystemWatchService" daemon [_thread_in_native, id=19160, stack(0x000000c553b00000,0x000000c553c00000)] - 0x000001fbe8a6f6a0 JavaThread "Worker-Main-2" daemon [_thread_blocked, id=5812, stack(0x000000c553c00000,0x000000c553d00000)] - 0x000001fbe8a6f190 JavaThread "Worker-Main-3" daemon [_thread_blocked, id=27348, stack(0x000000c553d00000,0x000000c553e00000)] - 0x000001fbe8a6fbb0 JavaThread "Worker-Main-4" daemon [_thread_blocked, id=26584, stack(0x000000c553e00000,0x000000c553f00000)] - 0x000001fbdff992d0 JavaThread "Worker-Main-5" daemon [_thread_blocked, id=27100, stack(0x000000c553f00000,0x000000c554000000)] - 0x000001fbe787fa80 JavaThread "Worker-Main-6" daemon [_thread_blocked, id=26144, stack(0x000000c554000000,0x000000c554100000)] - 0x000001fbe8a30c40 JavaThread "Worker-Main-7" daemon [_thread_blocked, id=14828, stack(0x000000c554100000,0x000000c554200000)] - 0x000001fbe8a32fb0 JavaThread "Worker-Main-8" daemon [_thread_blocked, id=14940, stack(0x000000c554200000,0x000000c554300000)] - 0x000001fbe8a31660 JavaThread "Worker-Main-9" daemon [_thread_blocked, id=12632, stack(0x000000c554300000,0x000000c554400000)] - 0x000001fbe8a2f800 JavaThread "Worker-Main-10" daemon [_thread_blocked, id=27600, stack(0x000000c554400000,0x000000c554500000)] - 0x000001fbe8a2fd10 JavaThread "Worker-Main-11" daemon [_thread_blocked, id=23584, stack(0x000000c554500000,0x000000c554600000)] - 0x000001fbe8a31b70 JavaThread "Worker-Main-13" daemon [_thread_blocked, id=26860, stack(0x000000c554600000,0x000000c554700000)] - 0x000001fbe8a32080 JavaThread "Worker-Main-12" daemon [_thread_blocked, id=25924, stack(0x000000c554700000,0x000000c554800000)] - 0x000001fbe8a31150 JavaThread "Worker-Main-14" daemon [_thread_blocked, id=18176, stack(0x000000c554900000,0x000000c554a00000)] - 0x000001fbe8a30730 JavaThread "Worker-Main-15" daemon [_thread_blocked, id=25156, stack(0x000000c554b00000,0x000000c554c00000)] - 0x000001fbe8a32590 JavaThread "Worker-Main-16" daemon [_thread_blocked, id=26168, stack(0x000000c554c00000,0x000000c554d00000)] - 0x000001fbe8a32aa0 JavaThread "Worker-Main-17" daemon [_thread_blocked, id=3980, stack(0x000000c554d00000,0x000000c554e00000)] - 0x000001fbe8a334c0 JavaThread "Worker-Main-18" daemon [_thread_blocked, id=16172, stack(0x000000c554e00000,0x000000c554f00000)] - 0x000001fbe8a339d0 JavaThread "Worker-Main-19" daemon [_thread_blocked, id=26028, stack(0x000000c554f00000,0x000000c555000000)] - 0x000001fbe8a35830 JavaThread "IO-Worker-20" [_thread_blocked, id=27012, stack(0x000000c555100000,0x000000c555200000)] - 0x000001fbe8a6d330 JavaThread "Cleaner-1" daemon [_thread_blocked, id=23984, stack(0x000000c556000000,0x000000c556100000)] - 0x000001fbdff51620 JavaThread "Server thread" [_thread_blocked, id=27908, stack(0x000000c551300000,0x000000c551400000)] - 0x000001fbdff52f70 JavaThread "FileSystemWatchService" daemon [_thread_in_native, id=27900, stack(0x000000c551600000,0x000000c551700000)] - 0x000001fbdff53480 JavaThread "IO-Worker-21" [_thread_blocked, id=24340, stack(0x000000c553700000,0x000000c553800000)] - 0x000001fbde3f9930 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=27420, stack(0x000000c550200000,0x000000c550300000)] - 0x000001fbdff501e0 JavaThread "IO-Worker-22" [_thread_blocked, id=28096, stack(0x000000c555e00000,0x000000c555f00000)] - 0x000001fbdff53ea0 JavaThread "IO-Worker-23" [_thread_blocked, id=26300, stack(0x000000c555f00000,0x000000c556000000)] - 0x000001fbdff57650 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=24460, stack(0x000000c555200000,0x000000c555300000)] - 0x000001fbdff552e0 JavaThread "Netty Server IO #0" daemon [_thread_in_native, id=27604, stack(0x000000c550500000,0x000000c550600000)] - 0x000001fbdff543b0 JavaThread "Netty Local Client IO #0" daemon [_thread_blocked, id=27412, stack(0x000000c550600000,0x000000c550700000)] - 0x000001fbdff56720 JavaThread "Netty Server IO #1" daemon [_thread_in_native, id=25360, stack(0x000000c551100000,0x000000c551200000)] - 0x000001fbdff548c0 JavaThread "IO-Worker-24" [_thread_blocked, id=21412, stack(0x000000c555300000,0x000000c555400000)] - 0x000001fbdff50c00 JavaThread "Sound engine" daemon [_thread_blocked, id=6428, stack(0x000000c555400000,0x000000c555500000)] - -Other Threads: -=>0x000001fbff57a010 VMThread "VM Thread" [stack: 0x000000c54f500000,0x000000c54f600000] [id=27956] - 0x000001fbef3679e0 WatcherThread [stack: 0x000000c550400000,0x000000c550500000] [id=28020] - 0x000001fbef3d2450 GCTaskThread "GC Thread#0" [stack: 0x000000c54f000000,0x000000c54f100000] [id=27936] - 0x000001fbd954b2e0 GCTaskThread "GC Thread#1" [stack: 0x000000c550800000,0x000000c550900000] [id=28036] - 0x000001fbd954a6b0 GCTaskThread "GC Thread#2" [stack: 0x000000c550900000,0x000000c550a00000] [id=28040] - 0x000001fbd90a8180 GCTaskThread "GC Thread#3" [stack: 0x000000c550a00000,0x000000c550b00000] [id=28044] - 0x000001fbd90a8440 GCTaskThread "GC Thread#4" [stack: 0x000000c550b00000,0x000000c550c00000] [id=28048] - 0x000001fbd90a8700 GCTaskThread "GC Thread#5" [stack: 0x000000c550c00000,0x000000c550d00000] [id=28052] - 0x000001fbdf747a30 GCTaskThread "GC Thread#6" [stack: 0x000000c550d00000,0x000000c550e00000] [id=28076] - 0x000001fbdd6529c0 GCTaskThread "GC Thread#7" [stack: 0x000000c551700000,0x000000c551800000] [id=28168] - 0x000001fbdb709300 GCTaskThread "GC Thread#8" [stack: 0x000000c551800000,0x000000c551900000] [id=28172] - 0x000001fbdf620160 GCTaskThread "GC Thread#9" [stack: 0x000000c551900000,0x000000c551a00000] [id=28176] - 0x000001fbdca83cb0 GCTaskThread "GC Thread#10" [stack: 0x000000c551a00000,0x000000c551b00000] [id=28180] - 0x000001fbdc7a4ea0 GCTaskThread "GC Thread#11" [stack: 0x000000c551b00000,0x000000c551c00000] [id=28184] - 0x000001fbd90d1fd0 GCTaskThread "GC Thread#12" [stack: 0x000000c551c00000,0x000000c551d00000] [id=28188] - 0x000001fbdd05fb70 GCTaskThread "GC Thread#13" [stack: 0x000000c551d00000,0x000000c551e00000] [id=28192] - 0x000001fbdcaa5840 GCTaskThread "GC Thread#14" [stack: 0x000000c551e00000,0x000000c551f00000] [id=28196] - 0x000001fbef3e3190 ConcurrentGCThread "G1 Main Marker" [stack: 0x000000c54f100000,0x000000c54f200000] [id=27940] - 0x000001fbef3e54e0 ConcurrentGCThread "G1 Conc#0" [stack: 0x000000c54f200000,0x000000c54f300000] [id=27944] - 0x000001fbdcaa6e40 ConcurrentGCThread "G1 Conc#1" [stack: 0x000000c552000000,0x000000c552100000] [id=28204] - 0x000001fbdcaa6600 ConcurrentGCThread "G1 Conc#2" [stack: 0x000000c552100000,0x000000c552200000] [id=28208] - 0x000001fbdcaa6b80 ConcurrentGCThread "G1 Conc#3" [stack: 0x000000c552200000,0x000000c552300000] [id=28212] - 0x000001fbff4b14a0 ConcurrentGCThread "G1 Refine#0" [stack: 0x000000c54f300000,0x000000c54f400000] [id=27948] - 0x000001fbdc2e2c30 ConcurrentGCThread "G1 Refine#1" [stack: 0x000000c552700000,0x000000c552800000] [id=28360] - 0x000001fbdc2e3500 ConcurrentGCThread "G1 Refine#2" [stack: 0x000000c552800000,0x000000c552900000] [id=28364] - 0x000001fbdef8f5c0 ConcurrentGCThread "G1 Refine#3" [stack: 0x000000c552900000,0x000000c552a00000] [id=28368] - 0x000001fbdef8d860 ConcurrentGCThread "G1 Refine#4" [stack: 0x000000c552a00000,0x000000c552b00000] [id=28372] - 0x000001fbdad67280 ConcurrentGCThread "G1 Refine#5" [stack: 0x000000c555000000,0x000000c555100000] [id=25524] - 0x000001fbdad65230 ConcurrentGCThread "G1 Refine#6" [stack: 0x000000c555500000,0x000000c555600000] [id=12304] - 0x000001fbdad67570 ConcurrentGCThread "G1 Refine#7" [stack: 0x000000c555600000,0x000000c555700000] [id=27188] - 0x000001fbdad68130 ConcurrentGCThread "G1 Refine#8" [stack: 0x000000c555700000,0x000000c555800000] [id=5156] - 0x000001fbdad68a00 ConcurrentGCThread "G1 Refine#9" [stack: 0x000000c555800000,0x000000c555900000] [id=26768] - 0x000001fbdad65b00 ConcurrentGCThread "G1 Refine#10" [stack: 0x000000c555900000,0x000000c555a00000] [id=25548] - 0x000001fbdad666c0 ConcurrentGCThread "G1 Refine#11" [stack: 0x000000c555a00000,0x000000c555b00000] [id=26400] - 0x000001fbdad65520 ConcurrentGCThread "G1 Refine#12" [stack: 0x000000c555b00000,0x000000c555c00000] [id=13180] - 0x000001fbdad68420 ConcurrentGCThread "G1 Refine#13" [stack: 0x000000c555c00000,0x000000c555d00000] [id=24672] - 0x000001fbdad66ca0 ConcurrentGCThread "G1 Refine#14" [stack: 0x000000c554a00000,0x000000c554b00000] [id=27068] - 0x000001fbff4b1890 ConcurrentGCThread "G1 Service" [stack: 0x000000c54f400000,0x000000c54f500000] [id=27952] - -Threads with active compile tasks: -C2 CompilerThread0 41732 24886 4 net.minecraftforge.registries.NamespacedWrapper::getOptional (12 bytes) -C2 CompilerThread1 41732 25205 % 4 net.minecraft.world.level.chunk.storage.ChunkSerializer::read @ 170 (1424 bytes) - -VM state: at safepoint (normal execution) - -VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event]) -[0x000001fbef35ff30] Threads_lock - owner thread: 0x000001fbff57a010 -[0x000001fbef360440] Heap_lock - owner thread: 0x000001fbe8a6fbb0 - -Heap address: 0x0000000702800000, size: 4056 MB, Compressed Oops mode: Zero based, Oop shift amount: 3 - -CDS archive(s) mapped at: [0x000001fb94000000-0x000001fb94bb0000-0x000001fb94bb0000), size 12255232, SharedBaseAddress: 0x000001fb94000000, ArchiveRelocationMode: 1. -Compressed class space mapped at: 0x000001fb95000000-0x000001fbd5000000, reserved size: 1073741824 -Narrow klass base: 0x000001fb94000000, Narrow klass shift: 0, Narrow klass range: 0x100000000 - -GC Precious Log: - CPUs: 20 total, 20 available - Memory: 16222M - Large Page Support: Disabled - NUMA Support: Disabled - Compressed Oops: Enabled (Zero based) - Heap Region Size: 2M - Heap Min Capacity: 8M - Heap Initial Capacity: 254M - Heap Max Capacity: 4056M - Pre-touch: Disabled - Parallel Workers: 15 - Concurrent Workers: 4 - Concurrent Refinement Workers: 15 - Periodic GC: Disabled - -Heap: - garbage-first heap total 3639296K, used 2162688K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 38 young (77824K), 38 survivors (77824K) - Metaspace used 147655K, committed 149440K, reserved 1179648K - class space used 22729K, committed 23552K, reserved 1048576K - -Heap Regions: E=young(eden), S=young(survivor), O=old, HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, OA=open archive, CA=closed archive, TAMS=top-at-mark-start (previous, next) -| 0|0x0000000702800000, 0x0000000702a00000, 0x0000000702a00000|100%|HS| |TAMS 0x0000000702a00000, 0x0000000702800000| Complete -| 1|0x0000000702a00000, 0x0000000702c00000, 0x0000000702c00000|100%|HS| |TAMS 0x0000000702c00000, 0x0000000702a00000| Complete -| 2|0x0000000702c00000, 0x0000000702e00000, 0x0000000702e00000|100%| O| |TAMS 0x0000000702e00000, 0x0000000702c00000| Untracked -| 3|0x0000000702e00000, 0x0000000703000000, 0x0000000703000000|100%| O| |TAMS 0x0000000703000000, 0x0000000702e00000| Untracked -| 4|0x0000000703000000, 0x0000000703200000, 0x0000000703200000|100%|HS| |TAMS 0x0000000703200000, 0x0000000703000000| Complete -| 5|0x0000000703200000, 0x0000000703400000, 0x0000000703400000|100%| O| |TAMS 0x0000000703400000, 0x0000000703200000| Untracked -| 6|0x0000000703400000, 0x0000000703600000, 0x0000000703600000|100%| O| |TAMS 0x0000000703600000, 0x0000000703400000| Untracked -| 7|0x0000000703600000, 0x0000000703800000, 0x0000000703800000|100%|HS| |TAMS 0x0000000703800000, 0x0000000703600000| Complete -| 8|0x0000000703800000, 0x0000000703a00000, 0x0000000703a00000|100%|HS| |TAMS 0x0000000703a00000, 0x0000000703800000| Complete -| 9|0x0000000703a00000, 0x0000000703c00000, 0x0000000703c00000|100%| O| |TAMS 0x0000000703c00000, 0x0000000703a00000| Untracked -| 10|0x0000000703c00000, 0x0000000703e00000, 0x0000000703e00000|100%| O| |TAMS 0x0000000703e00000, 0x0000000703c00000| Untracked -| 11|0x0000000703e00000, 0x0000000704000000, 0x0000000704000000|100%| O| |TAMS 0x0000000704000000, 0x0000000703e00000| Untracked -| 12|0x0000000704000000, 0x0000000704200000, 0x0000000704200000|100%| O| |TAMS 0x0000000704200000, 0x0000000704000000| Untracked -| 13|0x0000000704200000, 0x0000000704400000, 0x0000000704400000|100%| O| |TAMS 0x0000000704400000, 0x0000000704200000| Untracked -| 14|0x0000000704400000, 0x0000000704600000, 0x0000000704600000|100%| O| |TAMS 0x0000000704600000, 0x0000000704400000| Untracked -| 15|0x0000000704600000, 0x0000000704800000, 0x0000000704800000|100%| O| |TAMS 0x0000000704800000, 0x0000000704600000| Untracked -| 16|0x0000000704800000, 0x0000000704a00000, 0x0000000704a00000|100%|HS| |TAMS 0x0000000704a00000, 0x0000000704800000| Complete -| 17|0x0000000704a00000, 0x0000000704c00000, 0x0000000704c00000|100%| O| |TAMS 0x0000000704c00000, 0x0000000704a00000| Untracked -| 18|0x0000000704c00000, 0x0000000704e00000, 0x0000000704e00000|100%| O| |TAMS 0x0000000704e00000, 0x0000000704c00000| Untracked -| 19|0x0000000704e00000, 0x0000000705000000, 0x0000000705000000|100%| O| |TAMS 0x0000000705000000, 0x0000000704e00000| Untracked -| 20|0x0000000705000000, 0x0000000705200000, 0x0000000705200000|100%| O| |TAMS 0x0000000705200000, 0x0000000705000000| Untracked -| 21|0x0000000705200000, 0x0000000705400000, 0x0000000705400000|100%| O| |TAMS 0x0000000705400000, 0x0000000705200000| Untracked -| 22|0x0000000705400000, 0x0000000705600000, 0x0000000705600000|100%| O| |TAMS 0x0000000705600000, 0x0000000705400000| Untracked -| 23|0x0000000705600000, 0x0000000705800000, 0x0000000705800000|100%| O| |TAMS 0x0000000705800000, 0x0000000705600000| Untracked -| 24|0x0000000705800000, 0x0000000705a00000, 0x0000000705a00000|100%| O| |TAMS 0x0000000705a00000, 0x0000000705800000| Untracked -| 25|0x0000000705a00000, 0x0000000705c00000, 0x0000000705c00000|100%| O| |TAMS 0x0000000705c00000, 0x0000000705a00000| Untracked -| 26|0x0000000705c00000, 0x0000000705e00000, 0x0000000705e00000|100%| O| |TAMS 0x0000000705e00000, 0x0000000705c00000| Untracked -| 27|0x0000000705e00000, 0x0000000706000000, 0x0000000706000000|100%|HS| |TAMS 0x0000000706000000, 0x0000000705e00000| Complete -| 28|0x0000000706000000, 0x0000000706200000, 0x0000000706200000|100%|HS| |TAMS 0x0000000706200000, 0x0000000706000000| Complete -| 29|0x0000000706200000, 0x0000000706400000, 0x0000000706400000|100%| O| |TAMS 0x0000000706400000, 0x0000000706200000| Untracked -| 30|0x0000000706400000, 0x0000000706600000, 0x0000000706600000|100%| O| |TAMS 0x0000000706600000, 0x0000000706400000| Untracked -| 31|0x0000000706600000, 0x0000000706800000, 0x0000000706800000|100%| O| |TAMS 0x0000000706800000, 0x0000000706600000| Untracked -| 32|0x0000000706800000, 0x0000000706a00000, 0x0000000706a00000|100%| O| |TAMS 0x0000000706a00000, 0x0000000706800000| Untracked -| 33|0x0000000706a00000, 0x0000000706c00000, 0x0000000706c00000|100%| O| |TAMS 0x0000000706c00000, 0x0000000706a00000| Untracked -| 34|0x0000000706c00000, 0x0000000706e00000, 0x0000000706e00000|100%| O| |TAMS 0x0000000706e00000, 0x0000000706c00000| Untracked -| 35|0x0000000706e00000, 0x0000000707000000, 0x0000000707000000|100%| O| |TAMS 0x0000000707000000, 0x0000000706e00000| Untracked -| 36|0x0000000707000000, 0x0000000707200000, 0x0000000707200000|100%| O| |TAMS 0x0000000707200000, 0x0000000707000000| Untracked -| 37|0x0000000707200000, 0x0000000707400000, 0x0000000707400000|100%| O| |TAMS 0x0000000707400000, 0x0000000707200000| Untracked -| 38|0x0000000707400000, 0x0000000707600000, 0x0000000707600000|100%| O| |TAMS 0x0000000707600000, 0x0000000707400000| Untracked -| 39|0x0000000707600000, 0x0000000707800000, 0x0000000707800000|100%| O| |TAMS 0x0000000707800000, 0x0000000707600000| Untracked -| 40|0x0000000707800000, 0x0000000707a00000, 0x0000000707a00000|100%| O| |TAMS 0x0000000707a00000, 0x0000000707800000| Untracked -| 41|0x0000000707a00000, 0x0000000707c00000, 0x0000000707c00000|100%| O| |TAMS 0x0000000707c00000, 0x0000000707a00000| Untracked -| 42|0x0000000707c00000, 0x0000000707e00000, 0x0000000707e00000|100%| O| |TAMS 0x0000000707e00000, 0x0000000707c00000| Untracked -| 43|0x0000000707e00000, 0x0000000708000000, 0x0000000708000000|100%| O| |TAMS 0x0000000708000000, 0x0000000707e00000| Untracked -| 44|0x0000000708000000, 0x0000000708200000, 0x0000000708200000|100%| O| |TAMS 0x0000000708200000, 0x0000000708000000| Untracked -| 45|0x0000000708200000, 0x0000000708400000, 0x0000000708400000|100%| O| |TAMS 0x0000000708400000, 0x0000000708200000| Untracked -| 46|0x0000000708400000, 0x0000000708600000, 0x0000000708600000|100%| O| |TAMS 0x0000000708600000, 0x0000000708400000| Untracked -| 47|0x0000000708600000, 0x0000000708800000, 0x0000000708800000|100%| O| |TAMS 0x0000000708800000, 0x0000000708600000| Untracked -| 48|0x0000000708800000, 0x0000000708a00000, 0x0000000708a00000|100%| O| |TAMS 0x0000000708a00000, 0x0000000708800000| Untracked -| 49|0x0000000708a00000, 0x0000000708c00000, 0x0000000708c00000|100%| O| |TAMS 0x0000000708c00000, 0x0000000708a00000| Untracked -| 50|0x0000000708c00000, 0x0000000708e00000, 0x0000000708e00000|100%| O| |TAMS 0x0000000708e00000, 0x0000000708c00000| Untracked -| 51|0x0000000708e00000, 0x0000000709000000, 0x0000000709000000|100%| O| |TAMS 0x0000000709000000, 0x0000000708e00000| Untracked -| 52|0x0000000709000000, 0x0000000709200000, 0x0000000709200000|100%|HS| |TAMS 0x0000000709200000, 0x0000000709000000| Complete -| 53|0x0000000709200000, 0x0000000709400000, 0x0000000709400000|100%|HC| |TAMS 0x0000000709400000, 0x0000000709200000| Complete -| 54|0x0000000709400000, 0x0000000709600000, 0x0000000709600000|100%|HC| |TAMS 0x0000000709600000, 0x0000000709400000| Complete -| 55|0x0000000709600000, 0x0000000709800000, 0x0000000709800000|100%|HC| |TAMS 0x0000000709800000, 0x0000000709600000| Complete -| 56|0x0000000709800000, 0x0000000709a00000, 0x0000000709a00000|100%|HC| |TAMS 0x0000000709a00000, 0x0000000709800000| Complete -| 57|0x0000000709a00000, 0x0000000709c00000, 0x0000000709c00000|100%|HC| |TAMS 0x0000000709c00000, 0x0000000709a00000| Complete -| 58|0x0000000709c00000, 0x0000000709e00000, 0x0000000709e00000|100%| O| |TAMS 0x0000000709e00000, 0x0000000709c00000| Untracked -| 59|0x0000000709e00000, 0x000000070a000000, 0x000000070a000000|100%| O| |TAMS 0x000000070a000000, 0x0000000709e00000| Untracked -| 60|0x000000070a000000, 0x000000070a200000, 0x000000070a200000|100%| O| |TAMS 0x000000070a200000, 0x000000070a000000| Untracked -| 61|0x000000070a200000, 0x000000070a400000, 0x000000070a400000|100%| O| |TAMS 0x000000070a400000, 0x000000070a200000| Untracked -| 62|0x000000070a400000, 0x000000070a600000, 0x000000070a600000|100%| O| |TAMS 0x000000070a600000, 0x000000070a400000| Untracked -| 63|0x000000070a600000, 0x000000070a800000, 0x000000070a800000|100%| O| |TAMS 0x000000070a800000, 0x000000070a600000| Untracked -| 64|0x000000070a800000, 0x000000070aa00000, 0x000000070aa00000|100%| O| |TAMS 0x000000070aa00000, 0x000000070a800000| Untracked -| 65|0x000000070aa00000, 0x000000070ac00000, 0x000000070ac00000|100%| O| |TAMS 0x000000070ac00000, 0x000000070aa00000| Untracked -| 66|0x000000070ac00000, 0x000000070ae00000, 0x000000070ae00000|100%| O| |TAMS 0x000000070ae00000, 0x000000070ac00000| Untracked -| 67|0x000000070ae00000, 0x000000070b000000, 0x000000070b000000|100%| O| |TAMS 0x000000070b000000, 0x000000070ae00000| Untracked -| 68|0x000000070b000000, 0x000000070b200000, 0x000000070b200000|100%| O| |TAMS 0x000000070b200000, 0x000000070b000000| Untracked -| 69|0x000000070b200000, 0x000000070b400000, 0x000000070b400000|100%| O| |TAMS 0x000000070b400000, 0x000000070b200000| Untracked -| 70|0x000000070b400000, 0x000000070b600000, 0x000000070b600000|100%| O| |TAMS 0x000000070b600000, 0x000000070b400000| Untracked -| 71|0x000000070b600000, 0x000000070b800000, 0x000000070b800000|100%| O| |TAMS 0x000000070b800000, 0x000000070b600000| Untracked -| 72|0x000000070b800000, 0x000000070ba00000, 0x000000070ba00000|100%| O| |TAMS 0x000000070ba00000, 0x000000070b800000| Untracked -| 73|0x000000070ba00000, 0x000000070bc00000, 0x000000070bc00000|100%| O| |TAMS 0x000000070bc00000, 0x000000070ba00000| Untracked -| 74|0x000000070bc00000, 0x000000070be00000, 0x000000070be00000|100%| O| |TAMS 0x000000070be00000, 0x000000070bc00000| Untracked -| 75|0x000000070be00000, 0x000000070c000000, 0x000000070c000000|100%| O| |TAMS 0x000000070c000000, 0x000000070be00000| Untracked -| 76|0x000000070c000000, 0x000000070c200000, 0x000000070c200000|100%| O| |TAMS 0x000000070c200000, 0x000000070c000000| Untracked -| 77|0x000000070c200000, 0x000000070c400000, 0x000000070c400000|100%| O| |TAMS 0x000000070c400000, 0x000000070c200000| Untracked -| 78|0x000000070c400000, 0x000000070c600000, 0x000000070c600000|100%| O| |TAMS 0x000000070c600000, 0x000000070c400000| Untracked -| 79|0x000000070c600000, 0x000000070c800000, 0x000000070c800000|100%| O| |TAMS 0x000000070c800000, 0x000000070c600000| Untracked -| 80|0x000000070c800000, 0x000000070ca00000, 0x000000070ca00000|100%| O| |TAMS 0x000000070ca00000, 0x000000070c800000| Untracked -| 81|0x000000070ca00000, 0x000000070cc00000, 0x000000070cc00000|100%| O| |TAMS 0x000000070cc00000, 0x000000070ca00000| Untracked -| 82|0x000000070cc00000, 0x000000070ce00000, 0x000000070ce00000|100%| O| |TAMS 0x000000070ce00000, 0x000000070cc00000| Untracked -| 83|0x000000070ce00000, 0x000000070d000000, 0x000000070d000000|100%| O| |TAMS 0x000000070d000000, 0x000000070ce00000| Untracked -| 84|0x000000070d000000, 0x000000070d200000, 0x000000070d200000|100%| O| |TAMS 0x000000070d200000, 0x000000070d000000| Untracked -| 85|0x000000070d200000, 0x000000070d400000, 0x000000070d400000|100%| O| |TAMS 0x000000070d400000, 0x000000070d200000| Untracked -| 86|0x000000070d400000, 0x000000070d600000, 0x000000070d600000|100%| O| |TAMS 0x000000070d600000, 0x000000070d400000| Untracked -| 87|0x000000070d600000, 0x000000070d800000, 0x000000070d800000|100%| O| |TAMS 0x000000070d800000, 0x000000070d600000| Untracked -| 88|0x000000070d800000, 0x000000070da00000, 0x000000070da00000|100%| O| |TAMS 0x000000070da00000, 0x000000070d800000| Untracked -| 89|0x000000070da00000, 0x000000070dc00000, 0x000000070dc00000|100%| O| |TAMS 0x000000070dc00000, 0x000000070da00000| Untracked -| 90|0x000000070dc00000, 0x000000070de00000, 0x000000070de00000|100%| O| |TAMS 0x000000070de00000, 0x000000070dc00000| Untracked -| 91|0x000000070de00000, 0x000000070e000000, 0x000000070e000000|100%| O| |TAMS 0x000000070e000000, 0x000000070de00000| Untracked -| 92|0x000000070e000000, 0x000000070e200000, 0x000000070e200000|100%| O| |TAMS 0x000000070e200000, 0x000000070e000000| Untracked -| 93|0x000000070e200000, 0x000000070e400000, 0x000000070e400000|100%| O| |TAMS 0x000000070e400000, 0x000000070e200000| Untracked -| 94|0x000000070e400000, 0x000000070e600000, 0x000000070e600000|100%| O| |TAMS 0x000000070e600000, 0x000000070e400000| Untracked -| 95|0x000000070e600000, 0x000000070e800000, 0x000000070e800000|100%| O| |TAMS 0x000000070e800000, 0x000000070e600000| Untracked -| 96|0x000000070e800000, 0x000000070ea00000, 0x000000070ea00000|100%| O| |TAMS 0x000000070ea00000, 0x000000070e800000| Untracked -| 97|0x000000070ea00000, 0x000000070ec00000, 0x000000070ec00000|100%| O| |TAMS 0x000000070ec00000, 0x000000070ea00000| Untracked -| 98|0x000000070ec00000, 0x000000070ee00000, 0x000000070ee00000|100%| O| |TAMS 0x000000070ee00000, 0x000000070ec00000| Untracked -| 99|0x000000070ee00000, 0x000000070f000000, 0x000000070f000000|100%| O| |TAMS 0x000000070f000000, 0x000000070ee00000| Untracked -| 100|0x000000070f000000, 0x000000070f200000, 0x000000070f200000|100%| O| |TAMS 0x000000070f200000, 0x000000070f000000| Untracked -| 101|0x000000070f200000, 0x000000070f400000, 0x000000070f400000|100%| O| |TAMS 0x000000070f400000, 0x000000070f200000| Untracked -| 102|0x000000070f400000, 0x000000070f600000, 0x000000070f600000|100%| O| |TAMS 0x000000070f600000, 0x000000070f400000| Untracked -| 103|0x000000070f600000, 0x000000070f800000, 0x000000070f800000|100%| O| |TAMS 0x000000070f800000, 0x000000070f600000| Untracked -| 104|0x000000070f800000, 0x000000070fa00000, 0x000000070fa00000|100%| O| |TAMS 0x000000070fa00000, 0x000000070f800000| Untracked -| 105|0x000000070fa00000, 0x000000070fc00000, 0x000000070fc00000|100%| O| |TAMS 0x000000070fc00000, 0x000000070fa00000| Untracked -| 106|0x000000070fc00000, 0x000000070fe00000, 0x000000070fe00000|100%| O| |TAMS 0x000000070fe00000, 0x000000070fc00000| Untracked -| 107|0x000000070fe00000, 0x0000000710000000, 0x0000000710000000|100%| O| |TAMS 0x0000000710000000, 0x000000070fe00000| Untracked -| 108|0x0000000710000000, 0x0000000710200000, 0x0000000710200000|100%| O| |TAMS 0x0000000710200000, 0x0000000710000000| Untracked -| 109|0x0000000710200000, 0x0000000710400000, 0x0000000710400000|100%| O| |TAMS 0x0000000710400000, 0x0000000710200000| Untracked -| 110|0x0000000710400000, 0x0000000710600000, 0x0000000710600000|100%| O| |TAMS 0x0000000710600000, 0x0000000710400000| Untracked -| 111|0x0000000710600000, 0x0000000710800000, 0x0000000710800000|100%| O| |TAMS 0x0000000710800000, 0x0000000710600000| Untracked -| 112|0x0000000710800000, 0x0000000710a00000, 0x0000000710a00000|100%| O| |TAMS 0x0000000710a00000, 0x0000000710800000| Untracked -| 113|0x0000000710a00000, 0x0000000710c00000, 0x0000000710c00000|100%| O| |TAMS 0x0000000710c00000, 0x0000000710a00000| Untracked -| 114|0x0000000710c00000, 0x0000000710e00000, 0x0000000710e00000|100%| O| |TAMS 0x0000000710e00000, 0x0000000710c00000| Untracked -| 115|0x0000000710e00000, 0x0000000711000000, 0x0000000711000000|100%| O| |TAMS 0x0000000711000000, 0x0000000710e00000| Untracked -| 116|0x0000000711000000, 0x0000000711200000, 0x0000000711200000|100%| O| |TAMS 0x0000000711200000, 0x0000000711000000| Untracked -| 117|0x0000000711200000, 0x0000000711400000, 0x0000000711400000|100%| O| |TAMS 0x0000000711400000, 0x0000000711200000| Untracked -| 118|0x0000000711400000, 0x0000000711600000, 0x0000000711600000|100%| O| |TAMS 0x0000000711600000, 0x0000000711400000| Untracked -| 119|0x0000000711600000, 0x0000000711800000, 0x0000000711800000|100%| O| |TAMS 0x0000000711800000, 0x0000000711600000| Untracked -| 120|0x0000000711800000, 0x0000000711a00000, 0x0000000711a00000|100%| O| |TAMS 0x0000000711a00000, 0x0000000711800000| Untracked -| 121|0x0000000711a00000, 0x0000000711c00000, 0x0000000711c00000|100%| O| |TAMS 0x0000000711c00000, 0x0000000711a00000| Untracked -| 122|0x0000000711c00000, 0x0000000711e00000, 0x0000000711e00000|100%| O| |TAMS 0x0000000711e00000, 0x0000000711c00000| Untracked -| 123|0x0000000711e00000, 0x0000000712000000, 0x0000000712000000|100%| O| |TAMS 0x0000000712000000, 0x0000000711e00000| Untracked -| 124|0x0000000712000000, 0x0000000712200000, 0x0000000712200000|100%| O| |TAMS 0x0000000712200000, 0x0000000712000000| Untracked -| 125|0x0000000712200000, 0x0000000712400000, 0x0000000712400000|100%| O| |TAMS 0x0000000712400000, 0x0000000712200000| Untracked -| 126|0x0000000712400000, 0x0000000712600000, 0x0000000712600000|100%| O| |TAMS 0x0000000712600000, 0x0000000712400000| Untracked -| 127|0x0000000712600000, 0x0000000712800000, 0x0000000712800000|100%| O| |TAMS 0x0000000712800000, 0x0000000712600000| Untracked -| 128|0x0000000712800000, 0x0000000712a00000, 0x0000000712a00000|100%| O| |TAMS 0x0000000712a00000, 0x0000000712800000| Untracked -| 129|0x0000000712a00000, 0x0000000712c00000, 0x0000000712c00000|100%| O| |TAMS 0x0000000712c00000, 0x0000000712a00000| Untracked -| 130|0x0000000712c00000, 0x0000000712e00000, 0x0000000712e00000|100%| O| |TAMS 0x0000000712e00000, 0x0000000712c00000| Untracked -| 131|0x0000000712e00000, 0x0000000713000000, 0x0000000713000000|100%| O| |TAMS 0x0000000713000000, 0x0000000712e00000| Untracked -| 132|0x0000000713000000, 0x0000000713200000, 0x0000000713200000|100%| O| |TAMS 0x0000000713200000, 0x0000000713000000| Untracked -| 133|0x0000000713200000, 0x0000000713400000, 0x0000000713400000|100%| O| |TAMS 0x0000000713400000, 0x0000000713200000| Untracked -| 134|0x0000000713400000, 0x0000000713600000, 0x0000000713600000|100%| O| |TAMS 0x0000000713600000, 0x0000000713400000| Untracked -| 135|0x0000000713600000, 0x0000000713800000, 0x0000000713800000|100%| O| |TAMS 0x0000000713800000, 0x0000000713600000| Untracked -| 136|0x0000000713800000, 0x0000000713a00000, 0x0000000713a00000|100%| O| |TAMS 0x0000000713a00000, 0x0000000713800000| Untracked -| 137|0x0000000713a00000, 0x0000000713c00000, 0x0000000713c00000|100%| O| |TAMS 0x0000000713c00000, 0x0000000713a00000| Untracked -| 138|0x0000000713c00000, 0x0000000713e00000, 0x0000000713e00000|100%| O| |TAMS 0x0000000713e00000, 0x0000000713c00000| Untracked -| 139|0x0000000713e00000, 0x0000000714000000, 0x0000000714000000|100%| O| |TAMS 0x0000000714000000, 0x0000000713e00000| Untracked -| 140|0x0000000714000000, 0x0000000714200000, 0x0000000714200000|100%| O| |TAMS 0x0000000714200000, 0x0000000714000000| Untracked -| 141|0x0000000714200000, 0x0000000714400000, 0x0000000714400000|100%| O| |TAMS 0x0000000714400000, 0x0000000714200000| Untracked -| 142|0x0000000714400000, 0x0000000714600000, 0x0000000714600000|100%| O| |TAMS 0x0000000714600000, 0x0000000714400000| Untracked -| 143|0x0000000714600000, 0x0000000714800000, 0x0000000714800000|100%| O| |TAMS 0x0000000714800000, 0x0000000714600000| Untracked -| 144|0x0000000714800000, 0x0000000714a00000, 0x0000000714a00000|100%| O| |TAMS 0x0000000714a00000, 0x0000000714800000| Untracked -| 145|0x0000000714a00000, 0x0000000714c00000, 0x0000000714c00000|100%| O| |TAMS 0x0000000714c00000, 0x0000000714a00000| Untracked -| 146|0x0000000714c00000, 0x0000000714e00000, 0x0000000714e00000|100%| O| |TAMS 0x0000000714e00000, 0x0000000714c00000| Untracked -| 147|0x0000000714e00000, 0x0000000715000000, 0x0000000715000000|100%| O| |TAMS 0x0000000715000000, 0x0000000714e00000| Untracked -| 148|0x0000000715000000, 0x0000000715200000, 0x0000000715200000|100%| O| |TAMS 0x0000000715200000, 0x0000000715000000| Untracked -| 149|0x0000000715200000, 0x0000000715400000, 0x0000000715400000|100%| O| |TAMS 0x0000000715400000, 0x0000000715200000| Untracked -| 150|0x0000000715400000, 0x0000000715600000, 0x0000000715600000|100%| O| |TAMS 0x0000000715600000, 0x0000000715400000| Untracked -| 151|0x0000000715600000, 0x0000000715800000, 0x0000000715800000|100%| O| |TAMS 0x0000000715800000, 0x0000000715600000| Untracked -| 152|0x0000000715800000, 0x0000000715a00000, 0x0000000715a00000|100%| O| |TAMS 0x0000000715a00000, 0x0000000715800000| Untracked -| 153|0x0000000715a00000, 0x0000000715c00000, 0x0000000715c00000|100%| O| |TAMS 0x0000000715c00000, 0x0000000715a00000| Untracked -| 154|0x0000000715c00000, 0x0000000715e00000, 0x0000000715e00000|100%| O| |TAMS 0x0000000715e00000, 0x0000000715c00000| Untracked -| 155|0x0000000715e00000, 0x0000000716000000, 0x0000000716000000|100%| O| |TAMS 0x0000000716000000, 0x0000000715e00000| Untracked -| 156|0x0000000716000000, 0x0000000716200000, 0x0000000716200000|100%| O| |TAMS 0x0000000716200000, 0x0000000716000000| Untracked -| 157|0x0000000716200000, 0x0000000716400000, 0x0000000716400000|100%| O| |TAMS 0x0000000716400000, 0x0000000716200000| Untracked -| 158|0x0000000716400000, 0x0000000716600000, 0x0000000716600000|100%| O| |TAMS 0x0000000716600000, 0x0000000716400000| Untracked -| 159|0x0000000716600000, 0x0000000716800000, 0x0000000716800000|100%| O| |TAMS 0x0000000716800000, 0x0000000716600000| Untracked -| 160|0x0000000716800000, 0x0000000716a00000, 0x0000000716a00000|100%| O| |TAMS 0x0000000716a00000, 0x0000000716800000| Untracked -| 161|0x0000000716a00000, 0x0000000716c00000, 0x0000000716c00000|100%| O| |TAMS 0x0000000716c00000, 0x0000000716a00000| Untracked -| 162|0x0000000716c00000, 0x0000000716e00000, 0x0000000716e00000|100%| O| |TAMS 0x0000000716e00000, 0x0000000716c00000| Untracked -| 163|0x0000000716e00000, 0x0000000717000000, 0x0000000717000000|100%| O| |TAMS 0x0000000717000000, 0x0000000716e00000| Untracked -| 164|0x0000000717000000, 0x0000000717200000, 0x0000000717200000|100%| O| |TAMS 0x0000000717200000, 0x0000000717000000| Untracked -| 165|0x0000000717200000, 0x0000000717400000, 0x0000000717400000|100%| O| |TAMS 0x0000000717400000, 0x0000000717200000| Untracked -| 166|0x0000000717400000, 0x0000000717600000, 0x0000000717600000|100%| O| |TAMS 0x0000000717600000, 0x0000000717400000| Untracked -| 167|0x0000000717600000, 0x0000000717800000, 0x0000000717800000|100%| O| |TAMS 0x0000000717800000, 0x0000000717600000| Untracked -| 168|0x0000000717800000, 0x0000000717a00000, 0x0000000717a00000|100%| O| |TAMS 0x0000000717a00000, 0x0000000717800000| Untracked -| 169|0x0000000717a00000, 0x0000000717c00000, 0x0000000717c00000|100%| O| |TAMS 0x0000000717c00000, 0x0000000717a00000| Untracked -| 170|0x0000000717c00000, 0x0000000717e00000, 0x0000000717e00000|100%| O| |TAMS 0x0000000717e00000, 0x0000000717c00000| Untracked -| 171|0x0000000717e00000, 0x0000000718000000, 0x0000000718000000|100%| O| |TAMS 0x0000000718000000, 0x0000000717e00000| Untracked -| 172|0x0000000718000000, 0x0000000718200000, 0x0000000718200000|100%| O| |TAMS 0x0000000718200000, 0x0000000718000000| Untracked -| 173|0x0000000718200000, 0x0000000718400000, 0x0000000718400000|100%| O| |TAMS 0x0000000718400000, 0x0000000718200000| Untracked -| 174|0x0000000718400000, 0x0000000718600000, 0x0000000718600000|100%| O| |TAMS 0x0000000718600000, 0x0000000718400000| Untracked -| 175|0x0000000718600000, 0x0000000718800000, 0x0000000718800000|100%| O| |TAMS 0x0000000718800000, 0x0000000718600000| Untracked -| 176|0x0000000718800000, 0x0000000718a00000, 0x0000000718a00000|100%| O| |TAMS 0x0000000718a00000, 0x0000000718800000| Untracked -| 177|0x0000000718a00000, 0x0000000718c00000, 0x0000000718c00000|100%| O| |TAMS 0x0000000718c00000, 0x0000000718a00000| Untracked -| 178|0x0000000718c00000, 0x0000000718e00000, 0x0000000718e00000|100%| O| |TAMS 0x0000000718e00000, 0x0000000718c00000| Untracked -| 179|0x0000000718e00000, 0x0000000719000000, 0x0000000719000000|100%| O| |TAMS 0x0000000719000000, 0x0000000718e00000| Untracked -| 180|0x0000000719000000, 0x0000000719200000, 0x0000000719200000|100%| O| |TAMS 0x0000000719200000, 0x0000000719000000| Untracked -| 181|0x0000000719200000, 0x0000000719400000, 0x0000000719400000|100%| O| |TAMS 0x0000000719400000, 0x0000000719200000| Untracked -| 182|0x0000000719400000, 0x0000000719600000, 0x0000000719600000|100%| O| |TAMS 0x0000000719600000, 0x0000000719400000| Untracked -| 183|0x0000000719600000, 0x0000000719800000, 0x0000000719800000|100%|HS| |TAMS 0x0000000719800000, 0x0000000719600000| Complete -| 184|0x0000000719800000, 0x0000000719a00000, 0x0000000719a00000|100%| O| |TAMS 0x0000000719a00000, 0x0000000719800000| Untracked -| 185|0x0000000719a00000, 0x0000000719c00000, 0x0000000719c00000|100%| O| |TAMS 0x0000000719c00000, 0x0000000719a00000| Untracked -| 186|0x0000000719c00000, 0x0000000719e00000, 0x0000000719e00000|100%| O| |TAMS 0x0000000719e00000, 0x0000000719c00000| Untracked -| 187|0x0000000719e00000, 0x000000071a000000, 0x000000071a000000|100%| O| |TAMS 0x000000071a000000, 0x0000000719e00000| Untracked -| 188|0x000000071a000000, 0x000000071a200000, 0x000000071a200000|100%| O| |TAMS 0x000000071a200000, 0x000000071a000000| Untracked -| 189|0x000000071a200000, 0x000000071a400000, 0x000000071a400000|100%| O| |TAMS 0x000000071a400000, 0x000000071a200000| Untracked -| 190|0x000000071a400000, 0x000000071a600000, 0x000000071a600000|100%| O| |TAMS 0x000000071a600000, 0x000000071a400000| Untracked -| 191|0x000000071a600000, 0x000000071a800000, 0x000000071a800000|100%| O| |TAMS 0x000000071a800000, 0x000000071a600000| Untracked -| 192|0x000000071a800000, 0x000000071aa00000, 0x000000071aa00000|100%| O| |TAMS 0x000000071aa00000, 0x000000071a800000| Untracked -| 193|0x000000071aa00000, 0x000000071ac00000, 0x000000071ac00000|100%| O| |TAMS 0x000000071ac00000, 0x000000071aa00000| Untracked -| 194|0x000000071ac00000, 0x000000071ae00000, 0x000000071ae00000|100%| O| |TAMS 0x000000071ae00000, 0x000000071ac00000| Untracked -| 195|0x000000071ae00000, 0x000000071b000000, 0x000000071b000000|100%| O| |TAMS 0x000000071b000000, 0x000000071ae00000| Untracked -| 196|0x000000071b000000, 0x000000071b200000, 0x000000071b200000|100%| O| |TAMS 0x000000071b200000, 0x000000071b000000| Untracked -| 197|0x000000071b200000, 0x000000071b400000, 0x000000071b400000|100%| O| |TAMS 0x000000071b400000, 0x000000071b200000| Untracked -| 198|0x000000071b400000, 0x000000071b600000, 0x000000071b600000|100%| O| |TAMS 0x000000071b600000, 0x000000071b400000| Untracked -| 199|0x000000071b600000, 0x000000071b800000, 0x000000071b800000|100%| O| |TAMS 0x000000071b800000, 0x000000071b600000| Untracked -| 200|0x000000071b800000, 0x000000071ba00000, 0x000000071ba00000|100%| O| |TAMS 0x000000071ba00000, 0x000000071b800000| Untracked -| 201|0x000000071ba00000, 0x000000071bc00000, 0x000000071bc00000|100%| O| |TAMS 0x000000071bc00000, 0x000000071ba00000| Untracked -| 202|0x000000071bc00000, 0x000000071be00000, 0x000000071be00000|100%| O| |TAMS 0x000000071be00000, 0x000000071bc00000| Untracked -| 203|0x000000071be00000, 0x000000071c000000, 0x000000071c000000|100%| O| |TAMS 0x000000071c000000, 0x000000071be00000| Untracked -| 204|0x000000071c000000, 0x000000071c200000, 0x000000071c200000|100%| O| |TAMS 0x000000071c200000, 0x000000071c000000| Untracked -| 205|0x000000071c200000, 0x000000071c400000, 0x000000071c400000|100%| O| |TAMS 0x000000071c400000, 0x000000071c200000| Untracked -| 206|0x000000071c400000, 0x000000071c600000, 0x000000071c600000|100%| O| |TAMS 0x000000071c600000, 0x000000071c400000| Untracked -| 207|0x000000071c600000, 0x000000071c800000, 0x000000071c800000|100%| O| |TAMS 0x000000071c800000, 0x000000071c600000| Untracked -| 208|0x000000071c800000, 0x000000071ca00000, 0x000000071ca00000|100%| O| |TAMS 0x000000071ca00000, 0x000000071c800000| Untracked -| 209|0x000000071ca00000, 0x000000071cc00000, 0x000000071cc00000|100%| O| |TAMS 0x000000071cc00000, 0x000000071ca00000| Untracked -| 210|0x000000071cc00000, 0x000000071ce00000, 0x000000071ce00000|100%| O| |TAMS 0x000000071ce00000, 0x000000071cc00000| Untracked -| 211|0x000000071ce00000, 0x000000071d000000, 0x000000071d000000|100%| O| |TAMS 0x000000071d000000, 0x000000071ce00000| Untracked -| 212|0x000000071d000000, 0x000000071d200000, 0x000000071d200000|100%| O| |TAMS 0x000000071d200000, 0x000000071d000000| Untracked -| 213|0x000000071d200000, 0x000000071d400000, 0x000000071d400000|100%| O| |TAMS 0x000000071d400000, 0x000000071d200000| Untracked -| 214|0x000000071d400000, 0x000000071d600000, 0x000000071d600000|100%| O| |TAMS 0x000000071d600000, 0x000000071d400000| Untracked -| 215|0x000000071d600000, 0x000000071d800000, 0x000000071d800000|100%| O| |TAMS 0x000000071d800000, 0x000000071d600000| Untracked -| 216|0x000000071d800000, 0x000000071da00000, 0x000000071da00000|100%| O| |TAMS 0x000000071da00000, 0x000000071d800000| Untracked -| 217|0x000000071da00000, 0x000000071dc00000, 0x000000071dc00000|100%| O| |TAMS 0x000000071dc00000, 0x000000071da00000| Untracked -| 218|0x000000071dc00000, 0x000000071de00000, 0x000000071de00000|100%| O| |TAMS 0x000000071de00000, 0x000000071dc00000| Untracked -| 219|0x000000071de00000, 0x000000071e000000, 0x000000071e000000|100%| O| |TAMS 0x000000071e000000, 0x000000071de00000| Untracked -| 220|0x000000071e000000, 0x000000071e200000, 0x000000071e200000|100%| O| |TAMS 0x000000071e200000, 0x000000071e000000| Untracked -| 221|0x000000071e200000, 0x000000071e400000, 0x000000071e400000|100%| O| |TAMS 0x000000071e400000, 0x000000071e200000| Untracked -| 222|0x000000071e400000, 0x000000071e600000, 0x000000071e600000|100%| O| |TAMS 0x000000071e600000, 0x000000071e400000| Untracked -| 223|0x000000071e600000, 0x000000071e800000, 0x000000071e800000|100%| O| |TAMS 0x000000071e800000, 0x000000071e600000| Untracked -| 224|0x000000071e800000, 0x000000071ea00000, 0x000000071ea00000|100%| O| |TAMS 0x000000071ea00000, 0x000000071e800000| Untracked -| 225|0x000000071ea00000, 0x000000071ec00000, 0x000000071ec00000|100%| O| |TAMS 0x000000071ec00000, 0x000000071ea00000| Untracked -| 226|0x000000071ec00000, 0x000000071ee00000, 0x000000071ee00000|100%| O| |TAMS 0x000000071ee00000, 0x000000071ec00000| Untracked -| 227|0x000000071ee00000, 0x000000071f000000, 0x000000071f000000|100%| O| |TAMS 0x000000071f000000, 0x000000071ee00000| Untracked -| 228|0x000000071f000000, 0x000000071f200000, 0x000000071f200000|100%| O| |TAMS 0x000000071f200000, 0x000000071f000000| Untracked -| 229|0x000000071f200000, 0x000000071f400000, 0x000000071f400000|100%| O| |TAMS 0x000000071f400000, 0x000000071f200000| Untracked -| 230|0x000000071f400000, 0x000000071f600000, 0x000000071f600000|100%| O| |TAMS 0x000000071f600000, 0x000000071f400000| Untracked -| 231|0x000000071f600000, 0x000000071f800000, 0x000000071f800000|100%| O| |TAMS 0x000000071f800000, 0x000000071f600000| Untracked -| 232|0x000000071f800000, 0x000000071fa00000, 0x000000071fa00000|100%| O| |TAMS 0x000000071fa00000, 0x000000071f800000| Untracked -| 233|0x000000071fa00000, 0x000000071fc00000, 0x000000071fc00000|100%| O| |TAMS 0x000000071fc00000, 0x000000071fa00000| Untracked -| 234|0x000000071fc00000, 0x000000071fe00000, 0x000000071fe00000|100%| O| |TAMS 0x000000071fe00000, 0x000000071fc00000| Untracked -| 235|0x000000071fe00000, 0x0000000720000000, 0x0000000720000000|100%| O| |TAMS 0x0000000720000000, 0x000000071fe00000| Untracked -| 236|0x0000000720000000, 0x0000000720200000, 0x0000000720200000|100%| O| |TAMS 0x0000000720200000, 0x0000000720000000| Untracked -| 237|0x0000000720200000, 0x0000000720400000, 0x0000000720400000|100%| O| |TAMS 0x0000000720400000, 0x0000000720200000| Untracked -| 238|0x0000000720400000, 0x0000000720600000, 0x0000000720600000|100%| O| |TAMS 0x0000000720600000, 0x0000000720400000| Untracked -| 239|0x0000000720600000, 0x0000000720800000, 0x0000000720800000|100%| O| |TAMS 0x0000000720800000, 0x0000000720600000| Untracked -| 240|0x0000000720800000, 0x0000000720a00000, 0x0000000720a00000|100%| O| |TAMS 0x0000000720a00000, 0x0000000720800000| Untracked -| 241|0x0000000720a00000, 0x0000000720c00000, 0x0000000720c00000|100%| O| |TAMS 0x0000000720c00000, 0x0000000720a00000| Untracked -| 242|0x0000000720c00000, 0x0000000720e00000, 0x0000000720e00000|100%| O| |TAMS 0x0000000720e00000, 0x0000000720c00000| Untracked -| 243|0x0000000720e00000, 0x0000000721000000, 0x0000000721000000|100%| O| |TAMS 0x0000000721000000, 0x0000000720e00000| Untracked -| 244|0x0000000721000000, 0x0000000721200000, 0x0000000721200000|100%| O| |TAMS 0x0000000721200000, 0x0000000721000000| Untracked -| 245|0x0000000721200000, 0x0000000721400000, 0x0000000721400000|100%| O| |TAMS 0x0000000721400000, 0x0000000721200000| Untracked -| 246|0x0000000721400000, 0x0000000721600000, 0x0000000721600000|100%| O| |TAMS 0x0000000721600000, 0x0000000721400000| Untracked -| 247|0x0000000721600000, 0x0000000721800000, 0x0000000721800000|100%| O| |TAMS 0x0000000721800000, 0x0000000721600000| Untracked -| 248|0x0000000721800000, 0x0000000721a00000, 0x0000000721a00000|100%| O| |TAMS 0x0000000721a00000, 0x0000000721800000| Untracked -| 249|0x0000000721a00000, 0x0000000721c00000, 0x0000000721c00000|100%| O| |TAMS 0x0000000721c00000, 0x0000000721a00000| Untracked -| 250|0x0000000721c00000, 0x0000000721e00000, 0x0000000721e00000|100%| O| |TAMS 0x0000000721e00000, 0x0000000721c00000| Untracked -| 251|0x0000000721e00000, 0x0000000722000000, 0x0000000722000000|100%| O| |TAMS 0x0000000722000000, 0x0000000721e00000| Untracked -| 252|0x0000000722000000, 0x0000000722200000, 0x0000000722200000|100%| O| |TAMS 0x0000000722200000, 0x0000000722000000| Untracked -| 253|0x0000000722200000, 0x0000000722400000, 0x0000000722400000|100%| O| |TAMS 0x0000000722400000, 0x0000000722200000| Untracked -| 254|0x0000000722400000, 0x0000000722600000, 0x0000000722600000|100%| O| |TAMS 0x0000000722600000, 0x0000000722400000| Untracked -| 255|0x0000000722600000, 0x0000000722800000, 0x0000000722800000|100%| O| |TAMS 0x0000000722800000, 0x0000000722600000| Untracked -| 256|0x0000000722800000, 0x0000000722a00000, 0x0000000722a00000|100%| O| |TAMS 0x0000000722a00000, 0x0000000722800000| Untracked -| 257|0x0000000722a00000, 0x0000000722c00000, 0x0000000722c00000|100%| O| |TAMS 0x0000000722c00000, 0x0000000722a00000| Untracked -| 258|0x0000000722c00000, 0x0000000722e00000, 0x0000000722e00000|100%|HS| |TAMS 0x0000000722c00000, 0x0000000722c00000| Complete -| 259|0x0000000722e00000, 0x0000000723000000, 0x0000000723000000|100%| O| |TAMS 0x0000000723000000, 0x0000000722e00000| Untracked -| 260|0x0000000723000000, 0x0000000723200000, 0x0000000723200000|100%| O| |TAMS 0x0000000723200000, 0x0000000723000000| Untracked -| 261|0x0000000723200000, 0x0000000723400000, 0x0000000723400000|100%| O| |TAMS 0x0000000723400000, 0x0000000723200000| Untracked -| 262|0x0000000723400000, 0x0000000723600000, 0x0000000723600000|100%| O| |TAMS 0x0000000723600000, 0x0000000723400000| Untracked -| 263|0x0000000723600000, 0x0000000723800000, 0x0000000723800000|100%| O| |TAMS 0x0000000723800000, 0x0000000723600000| Untracked -| 264|0x0000000723800000, 0x0000000723a00000, 0x0000000723a00000|100%| O| |TAMS 0x0000000723a00000, 0x0000000723800000| Untracked -| 265|0x0000000723a00000, 0x0000000723c00000, 0x0000000723c00000|100%| O| |TAMS 0x0000000723c00000, 0x0000000723a00000| Untracked -| 266|0x0000000723c00000, 0x0000000723e00000, 0x0000000723e00000|100%| O| |TAMS 0x0000000723c00000, 0x0000000723c00000| Untracked -| 267|0x0000000723e00000, 0x0000000724000000, 0x0000000724000000|100%| O| |TAMS 0x0000000724000000, 0x0000000723e00000| Untracked -| 268|0x0000000724000000, 0x0000000724200000, 0x0000000724200000|100%| O| |TAMS 0x0000000724200000, 0x0000000724000000| Untracked -| 269|0x0000000724200000, 0x0000000724400000, 0x0000000724400000|100%| O| |TAMS 0x0000000724400000, 0x0000000724200000| Untracked -| 270|0x0000000724400000, 0x0000000724600000, 0x0000000724600000|100%| O| |TAMS 0x0000000724600000, 0x0000000724400000| Untracked -| 271|0x0000000724600000, 0x0000000724800000, 0x0000000724800000|100%| O| |TAMS 0x0000000724800000, 0x0000000724600000| Untracked -| 272|0x0000000724800000, 0x0000000724a00000, 0x0000000724a00000|100%| O| |TAMS 0x0000000724a00000, 0x0000000724800000| Untracked -| 273|0x0000000724a00000, 0x0000000724c00000, 0x0000000724c00000|100%| O| |TAMS 0x0000000724a00000, 0x0000000724a00000| Untracked -| 274|0x0000000724c00000, 0x0000000724e00000, 0x0000000724e00000|100%| O| |TAMS 0x0000000724e00000, 0x0000000724c00000| Untracked -| 275|0x0000000724e00000, 0x0000000725000000, 0x0000000725000000|100%|HS| |TAMS 0x0000000724e00000, 0x0000000724e00000| Complete -| 276|0x0000000725000000, 0x0000000725200000, 0x0000000725200000|100%|HC| |TAMS 0x0000000725000000, 0x0000000725000000| Complete -| 277|0x0000000725200000, 0x0000000725400000, 0x0000000725400000|100%| O| |TAMS 0x0000000725200000, 0x0000000725200000| Untracked -| 278|0x0000000725400000, 0x0000000725600000, 0x0000000725600000|100%| O| |TAMS 0x0000000725400000, 0x0000000725400000| Untracked -| 279|0x0000000725600000, 0x0000000725800000, 0x0000000725800000|100%| O| |TAMS 0x0000000725600000, 0x0000000725600000| Untracked -| 280|0x0000000725800000, 0x0000000725a00000, 0x0000000725a00000|100%| O| |TAMS 0x0000000725800000, 0x0000000725800000| Untracked -| 281|0x0000000725a00000, 0x0000000725c00000, 0x0000000725c00000|100%| O| |TAMS 0x0000000725a00000, 0x0000000725a00000| Untracked -| 282|0x0000000725c00000, 0x0000000725e00000, 0x0000000725e00000|100%| O| |TAMS 0x0000000725c00000, 0x0000000725c00000| Untracked -| 283|0x0000000725e00000, 0x0000000726000000, 0x0000000726000000|100%| O| |TAMS 0x0000000725e00000, 0x0000000725e00000| Untracked -| 284|0x0000000726000000, 0x0000000726200000, 0x0000000726200000|100%| O| |TAMS 0x0000000726000000, 0x0000000726000000| Untracked -| 285|0x0000000726200000, 0x0000000726400000, 0x0000000726400000|100%| O| |TAMS 0x0000000726200000, 0x0000000726200000| Untracked -| 286|0x0000000726400000, 0x0000000726600000, 0x0000000726600000|100%| O| |TAMS 0x0000000726400000, 0x0000000726400000| Untracked -| 287|0x0000000726600000, 0x0000000726800000, 0x0000000726800000|100%| O| |TAMS 0x0000000726600000, 0x0000000726600000| Untracked -| 288|0x0000000726800000, 0x0000000726a00000, 0x0000000726a00000|100%| O| |TAMS 0x0000000726800000, 0x0000000726800000| Untracked -| 289|0x0000000726a00000, 0x0000000726c00000, 0x0000000726c00000|100%| O| |TAMS 0x0000000726a00000, 0x0000000726a00000| Untracked -| 290|0x0000000726c00000, 0x0000000726e00000, 0x0000000726e00000|100%| O| |TAMS 0x0000000726c00000, 0x0000000726c00000| Untracked -| 291|0x0000000726e00000, 0x0000000727000000, 0x0000000727000000|100%| O| |TAMS 0x0000000726e00000, 0x0000000726e00000| Untracked -| 292|0x0000000727000000, 0x0000000727200000, 0x0000000727200000|100%| O| |TAMS 0x0000000727000000, 0x0000000727000000| Untracked -| 293|0x0000000727200000, 0x0000000727400000, 0x0000000727400000|100%| O| |TAMS 0x0000000727400000, 0x0000000727200000| Untracked -| 294|0x0000000727400000, 0x0000000727600000, 0x0000000727600000|100%| O| |TAMS 0x0000000727600000, 0x0000000727400000| Untracked -| 295|0x0000000727600000, 0x0000000727800000, 0x0000000727800000|100%| O| |TAMS 0x0000000727800000, 0x0000000727600000| Untracked -| 296|0x0000000727800000, 0x0000000727a00000, 0x0000000727a00000|100%| O| |TAMS 0x0000000727a00000, 0x0000000727800000| Untracked -| 297|0x0000000727a00000, 0x0000000727c00000, 0x0000000727c00000|100%| O| |TAMS 0x0000000727c00000, 0x0000000727a00000| Untracked -| 298|0x0000000727c00000, 0x0000000727e00000, 0x0000000727e00000|100%| O| |TAMS 0x0000000727e00000, 0x0000000727c00000| Untracked -| 299|0x0000000727e00000, 0x0000000728000000, 0x0000000728000000|100%| O| |TAMS 0x0000000728000000, 0x0000000727e00000| Untracked -| 300|0x0000000728000000, 0x0000000728200000, 0x0000000728200000|100%| O| |TAMS 0x0000000728200000, 0x0000000728000000| Untracked -| 301|0x0000000728200000, 0x0000000728400000, 0x0000000728400000|100%| O| |TAMS 0x0000000728400000, 0x0000000728200000| Untracked -| 302|0x0000000728400000, 0x0000000728600000, 0x0000000728600000|100%| O| |TAMS 0x0000000728600000, 0x0000000728400000| Untracked -| 303|0x0000000728600000, 0x0000000728800000, 0x0000000728800000|100%| O| |TAMS 0x0000000728600000, 0x0000000728600000| Untracked -| 304|0x0000000728800000, 0x0000000728a00000, 0x0000000728a00000|100%| O| |TAMS 0x0000000728a00000, 0x0000000728800000| Untracked -| 305|0x0000000728a00000, 0x0000000728c00000, 0x0000000728c00000|100%| O| |TAMS 0x0000000728c00000, 0x0000000728a00000| Untracked -| 306|0x0000000728c00000, 0x0000000728e00000, 0x0000000728e00000|100%| O| |TAMS 0x0000000728e00000, 0x0000000728c00000| Untracked -| 307|0x0000000728e00000, 0x0000000729000000, 0x0000000729000000|100%| O| |TAMS 0x0000000729000000, 0x0000000728e00000| Untracked -| 308|0x0000000729000000, 0x0000000729200000, 0x0000000729200000|100%| O| |TAMS 0x0000000729200000, 0x0000000729000000| Untracked -| 309|0x0000000729200000, 0x0000000729400000, 0x0000000729400000|100%| O| |TAMS 0x0000000729400000, 0x0000000729200000| Untracked -| 310|0x0000000729400000, 0x0000000729600000, 0x0000000729600000|100%| O| |TAMS 0x0000000729600000, 0x0000000729400000| Untracked -| 311|0x0000000729600000, 0x0000000729800000, 0x0000000729800000|100%| O| |TAMS 0x0000000729800000, 0x0000000729600000| Untracked -| 312|0x0000000729800000, 0x0000000729a00000, 0x0000000729a00000|100%| O| |TAMS 0x0000000729a00000, 0x0000000729800000| Untracked -| 313|0x0000000729a00000, 0x0000000729c00000, 0x0000000729c00000|100%| O| |TAMS 0x0000000729c00000, 0x0000000729a00000| Untracked -| 314|0x0000000729c00000, 0x0000000729e00000, 0x0000000729e00000|100%| O| |TAMS 0x0000000729e00000, 0x0000000729c00000| Untracked -| 315|0x0000000729e00000, 0x000000072a000000, 0x000000072a000000|100%| O| |TAMS 0x000000072a000000, 0x0000000729e00000| Untracked -| 316|0x000000072a000000, 0x000000072a200000, 0x000000072a200000|100%| O| |TAMS 0x000000072a200000, 0x000000072a000000| Untracked -| 317|0x000000072a200000, 0x000000072a400000, 0x000000072a400000|100%| O| |TAMS 0x000000072a400000, 0x000000072a200000| Untracked -| 318|0x000000072a400000, 0x000000072a600000, 0x000000072a600000|100%| O| |TAMS 0x000000072a600000, 0x000000072a400000| Untracked -| 319|0x000000072a600000, 0x000000072a800000, 0x000000072a800000|100%| O| |TAMS 0x000000072a800000, 0x000000072a600000| Untracked -| 320|0x000000072a800000, 0x000000072aa00000, 0x000000072aa00000|100%| O| |TAMS 0x000000072aa00000, 0x000000072a800000| Untracked -| 321|0x000000072aa00000, 0x000000072ac00000, 0x000000072ac00000|100%| O| |TAMS 0x000000072ac00000, 0x000000072aa00000| Untracked -| 322|0x000000072ac00000, 0x000000072ae00000, 0x000000072ae00000|100%| O| |TAMS 0x000000072ae00000, 0x000000072ac00000| Untracked -| 323|0x000000072ae00000, 0x000000072b000000, 0x000000072b000000|100%| O| |TAMS 0x000000072b000000, 0x000000072ae00000| Untracked -| 324|0x000000072b000000, 0x000000072b200000, 0x000000072b200000|100%| O| |TAMS 0x000000072b000000, 0x000000072b000000| Untracked -| 325|0x000000072b200000, 0x000000072b400000, 0x000000072b400000|100%| O| |TAMS 0x000000072b400000, 0x000000072b200000| Untracked -| 326|0x000000072b400000, 0x000000072b600000, 0x000000072b600000|100%| O| |TAMS 0x000000072b400000, 0x000000072b400000| Untracked -| 327|0x000000072b600000, 0x000000072b800000, 0x000000072b800000|100%| O| |TAMS 0x000000072b600000, 0x000000072b600000| Untracked -| 328|0x000000072b800000, 0x000000072ba00000, 0x000000072ba00000|100%| O| |TAMS 0x000000072b800000, 0x000000072b800000| Untracked -| 329|0x000000072ba00000, 0x000000072bc00000, 0x000000072bc00000|100%| O| |TAMS 0x000000072ba00000, 0x000000072ba00000| Untracked -| 330|0x000000072bc00000, 0x000000072be00000, 0x000000072be00000|100%| O| |TAMS 0x000000072bc00000, 0x000000072bc00000| Untracked -| 331|0x000000072be00000, 0x000000072c000000, 0x000000072c000000|100%| O| |TAMS 0x000000072be00000, 0x000000072be00000| Untracked -| 332|0x000000072c000000, 0x000000072c200000, 0x000000072c200000|100%| O| |TAMS 0x000000072c000000, 0x000000072c000000| Untracked -| 333|0x000000072c200000, 0x000000072c400000, 0x000000072c400000|100%| O| |TAMS 0x000000072c400000, 0x000000072c200000| Untracked -| 334|0x000000072c400000, 0x000000072c600000, 0x000000072c600000|100%| O| |TAMS 0x000000072c600000, 0x000000072c400000| Untracked -| 335|0x000000072c600000, 0x000000072c800000, 0x000000072c800000|100%| O| |TAMS 0x000000072c800000, 0x000000072c600000| Untracked -| 336|0x000000072c800000, 0x000000072ca00000, 0x000000072ca00000|100%| O| |TAMS 0x000000072c800000, 0x000000072c800000| Untracked -| 337|0x000000072ca00000, 0x000000072cc00000, 0x000000072cc00000|100%| O| |TAMS 0x000000072ca00000, 0x000000072ca00000| Untracked -| 338|0x000000072cc00000, 0x000000072ce00000, 0x000000072ce00000|100%| O| |TAMS 0x000000072cc00000, 0x000000072cc00000| Untracked -| 339|0x000000072ce00000, 0x000000072d000000, 0x000000072d000000|100%| O| |TAMS 0x000000072ce00000, 0x000000072ce00000| Untracked -| 340|0x000000072d000000, 0x000000072d200000, 0x000000072d200000|100%| O| |TAMS 0x000000072d000000, 0x000000072d000000| Untracked -| 341|0x000000072d200000, 0x000000072d400000, 0x000000072d400000|100%| O| |TAMS 0x000000072d200000, 0x000000072d200000| Untracked -| 342|0x000000072d400000, 0x000000072d600000, 0x000000072d600000|100%| O| |TAMS 0x000000072d400000, 0x000000072d400000| Untracked -| 343|0x000000072d600000, 0x000000072d800000, 0x000000072d800000|100%| O| |TAMS 0x000000072d600000, 0x000000072d600000| Untracked -| 344|0x000000072d800000, 0x000000072da00000, 0x000000072da00000|100%| O| |TAMS 0x000000072d800000, 0x000000072d800000| Untracked -| 345|0x000000072da00000, 0x000000072dc00000, 0x000000072dc00000|100%| O| |TAMS 0x000000072da00000, 0x000000072da00000| Untracked -| 346|0x000000072dc00000, 0x000000072de00000, 0x000000072de00000|100%| O| |TAMS 0x000000072dc00000, 0x000000072dc00000| Untracked -| 347|0x000000072de00000, 0x000000072e000000, 0x000000072e000000|100%| O| |TAMS 0x000000072de00000, 0x000000072de00000| Untracked -| 348|0x000000072e000000, 0x000000072e000000, 0x000000072e200000| 0%| F| |TAMS 0x000000072e000000, 0x000000072e000000| Untracked -| 349|0x000000072e200000, 0x000000072e400000, 0x000000072e400000|100%| O| |TAMS 0x000000072e400000, 0x000000072e200000| Untracked -| 350|0x000000072e400000, 0x000000072e600000, 0x000000072e600000|100%| O| |TAMS 0x000000072e600000, 0x000000072e400000| Untracked -| 351|0x000000072e600000, 0x000000072e800000, 0x000000072e800000|100%| O| |TAMS 0x000000072e800000, 0x000000072e600000| Untracked -| 352|0x000000072e800000, 0x000000072e800000, 0x000000072ea00000| 0%| F| |TAMS 0x000000072e800000, 0x000000072e800000| Untracked -| 353|0x000000072ea00000, 0x000000072ea00000, 0x000000072ec00000| 0%| F| |TAMS 0x000000072ea00000, 0x000000072ea00000| Untracked -| 354|0x000000072ec00000, 0x000000072ec00000, 0x000000072ee00000| 0%| F| |TAMS 0x000000072ec00000, 0x000000072ec00000| Untracked -| 355|0x000000072ee00000, 0x000000072ee00000, 0x000000072f000000| 0%| F| |TAMS 0x000000072ee00000, 0x000000072ee00000| Untracked -| 356|0x000000072f000000, 0x000000072f000000, 0x000000072f200000| 0%| F| |TAMS 0x000000072f000000, 0x000000072f000000| Untracked -| 357|0x000000072f200000, 0x000000072f200000, 0x000000072f400000| 0%| F| |TAMS 0x000000072f200000, 0x000000072f200000| Untracked -| 358|0x000000072f400000, 0x000000072f400000, 0x000000072f600000| 0%| F| |TAMS 0x000000072f400000, 0x000000072f400000| Untracked -| 359|0x000000072f600000, 0x000000072f600000, 0x000000072f800000| 0%| F| |TAMS 0x000000072f600000, 0x000000072f600000| Untracked -| 360|0x000000072f800000, 0x000000072f800000, 0x000000072fa00000| 0%| F| |TAMS 0x000000072f800000, 0x000000072f800000| Untracked -| 361|0x000000072fa00000, 0x000000072fa00000, 0x000000072fc00000| 0%| F| |TAMS 0x000000072fa00000, 0x000000072fa00000| Untracked -| 362|0x000000072fc00000, 0x000000072fc00000, 0x000000072fe00000| 0%| F| |TAMS 0x000000072fc00000, 0x000000072fc00000| Untracked -| 363|0x000000072fe00000, 0x000000072fe00000, 0x0000000730000000| 0%| F| |TAMS 0x000000072fe00000, 0x000000072fe00000| Untracked -| 364|0x0000000730000000, 0x0000000730000000, 0x0000000730200000| 0%| F| |TAMS 0x0000000730000000, 0x0000000730000000| Untracked -| 365|0x0000000730200000, 0x0000000730200000, 0x0000000730400000| 0%| F| |TAMS 0x0000000730200000, 0x0000000730200000| Untracked -| 366|0x0000000730400000, 0x0000000730400000, 0x0000000730600000| 0%| F| |TAMS 0x0000000730400000, 0x0000000730400000| Untracked -| 367|0x0000000730600000, 0x0000000730600000, 0x0000000730800000| 0%| F| |TAMS 0x0000000730600000, 0x0000000730600000| Untracked -| 368|0x0000000730800000, 0x0000000730800000, 0x0000000730a00000| 0%| F| |TAMS 0x0000000730800000, 0x0000000730800000| Untracked -| 369|0x0000000730a00000, 0x0000000730a00000, 0x0000000730c00000| 0%| F| |TAMS 0x0000000730a00000, 0x0000000730a00000| Untracked -| 370|0x0000000730c00000, 0x0000000730c00000, 0x0000000730e00000| 0%| F| |TAMS 0x0000000730c00000, 0x0000000730c00000| Untracked -| 371|0x0000000730e00000, 0x0000000730e00000, 0x0000000731000000| 0%| F| |TAMS 0x0000000730e00000, 0x0000000730e00000| Untracked -| 372|0x0000000731000000, 0x0000000731000000, 0x0000000731200000| 0%| F| |TAMS 0x0000000731000000, 0x0000000731000000| Untracked -| 373|0x0000000731200000, 0x0000000731200000, 0x0000000731400000| 0%| F| |TAMS 0x0000000731200000, 0x0000000731200000| Untracked -| 374|0x0000000731400000, 0x0000000731400000, 0x0000000731600000| 0%| F| |TAMS 0x0000000731400000, 0x0000000731400000| Untracked -| 375|0x0000000731600000, 0x0000000731600000, 0x0000000731800000| 0%| F| |TAMS 0x0000000731600000, 0x0000000731600000| Untracked -| 376|0x0000000731800000, 0x0000000731800000, 0x0000000731a00000| 0%| F| |TAMS 0x0000000731800000, 0x0000000731800000| Untracked -| 377|0x0000000731a00000, 0x0000000731a00000, 0x0000000731c00000| 0%| F| |TAMS 0x0000000731a00000, 0x0000000731a00000| Untracked -| 378|0x0000000731c00000, 0x0000000731c00000, 0x0000000731e00000| 0%| F| |TAMS 0x0000000731c00000, 0x0000000731c00000| Untracked -| 379|0x0000000731e00000, 0x0000000732000000, 0x0000000732000000|100%| O| |TAMS 0x0000000732000000, 0x0000000731e00000| Untracked -| 380|0x0000000732000000, 0x0000000732000000, 0x0000000732200000| 0%| F| |TAMS 0x0000000732000000, 0x0000000732000000| Untracked -| 381|0x0000000732200000, 0x0000000732200000, 0x0000000732400000| 0%| F| |TAMS 0x0000000732200000, 0x0000000732200000| Untracked -| 382|0x0000000732400000, 0x0000000732400000, 0x0000000732600000| 0%| F| |TAMS 0x0000000732400000, 0x0000000732400000| Untracked -| 383|0x0000000732600000, 0x0000000732600000, 0x0000000732800000| 0%| F| |TAMS 0x0000000732600000, 0x0000000732600000| Untracked -| 384|0x0000000732800000, 0x0000000732a00000, 0x0000000732a00000|100%| O| |TAMS 0x0000000732a00000, 0x0000000732800000| Untracked -| 385|0x0000000732a00000, 0x0000000732a00000, 0x0000000732c00000| 0%| F| |TAMS 0x0000000732a00000, 0x0000000732a00000| Untracked -| 386|0x0000000732c00000, 0x0000000732e00000, 0x0000000732e00000|100%| O| |TAMS 0x0000000732e00000, 0x0000000732c00000| Untracked -| 387|0x0000000732e00000, 0x0000000732e00000, 0x0000000733000000| 0%| F| |TAMS 0x0000000732e00000, 0x0000000732e00000| Untracked -| 388|0x0000000733000000, 0x0000000733000000, 0x0000000733200000| 0%| F| |TAMS 0x0000000733000000, 0x0000000733000000| Untracked -| 389|0x0000000733200000, 0x0000000733400000, 0x0000000733400000|100%| O| |TAMS 0x0000000733400000, 0x0000000733200000| Untracked -| 390|0x0000000733400000, 0x0000000733600000, 0x0000000733600000|100%| O| |TAMS 0x0000000733600000, 0x0000000733400000| Untracked -| 391|0x0000000733600000, 0x0000000733800000, 0x0000000733800000|100%| O| |TAMS 0x0000000733800000, 0x0000000733600000| Untracked -| 392|0x0000000733800000, 0x0000000733a00000, 0x0000000733a00000|100%| O| |TAMS 0x0000000733a00000, 0x0000000733800000| Untracked -| 393|0x0000000733a00000, 0x0000000733c00000, 0x0000000733c00000|100%| O| |TAMS 0x0000000733c00000, 0x0000000733a00000| Untracked -| 394|0x0000000733c00000, 0x0000000733e00000, 0x0000000733e00000|100%| O| |TAMS 0x0000000733e00000, 0x0000000733c00000| Untracked -| 395|0x0000000733e00000, 0x0000000734000000, 0x0000000734000000|100%| O| |TAMS 0x0000000734000000, 0x0000000733e00000| Untracked -| 396|0x0000000734000000, 0x0000000734200000, 0x0000000734200000|100%| O| |TAMS 0x0000000734200000, 0x0000000734000000| Untracked -| 397|0x0000000734200000, 0x0000000734400000, 0x0000000734400000|100%| O| |TAMS 0x0000000734400000, 0x0000000734200000| Untracked -| 398|0x0000000734400000, 0x0000000734600000, 0x0000000734600000|100%| O| |TAMS 0x0000000734600000, 0x0000000734400000| Untracked -| 399|0x0000000734600000, 0x0000000734800000, 0x0000000734800000|100%| O| |TAMS 0x0000000734800000, 0x0000000734600000| Untracked -| 400|0x0000000734800000, 0x0000000734a00000, 0x0000000734a00000|100%| O| |TAMS 0x0000000734a00000, 0x0000000734800000| Untracked -| 401|0x0000000734a00000, 0x0000000734c00000, 0x0000000734c00000|100%| O| |TAMS 0x0000000734c00000, 0x0000000734a00000| Untracked -| 402|0x0000000734c00000, 0x0000000734e00000, 0x0000000734e00000|100%| O| |TAMS 0x0000000734e00000, 0x0000000734c00000| Untracked -| 403|0x0000000734e00000, 0x0000000735000000, 0x0000000735000000|100%| O| |TAMS 0x0000000735000000, 0x0000000734e00000| Untracked -| 404|0x0000000735000000, 0x0000000735200000, 0x0000000735200000|100%| O| |TAMS 0x0000000735200000, 0x0000000735000000| Untracked -| 405|0x0000000735200000, 0x0000000735200000, 0x0000000735400000| 0%| F| |TAMS 0x0000000735200000, 0x0000000735200000| Untracked -| 406|0x0000000735400000, 0x0000000735400000, 0x0000000735600000| 0%| F| |TAMS 0x0000000735400000, 0x0000000735400000| Untracked -| 407|0x0000000735600000, 0x0000000735600000, 0x0000000735800000| 0%| F| |TAMS 0x0000000735600000, 0x0000000735600000| Untracked -| 408|0x0000000735800000, 0x0000000735800000, 0x0000000735a00000| 0%| F| |TAMS 0x0000000735800000, 0x0000000735800000| Untracked -| 409|0x0000000735a00000, 0x0000000735a00000, 0x0000000735c00000| 0%| F| |TAMS 0x0000000735a00000, 0x0000000735a00000| Untracked -| 410|0x0000000735c00000, 0x0000000735c00000, 0x0000000735e00000| 0%| F| |TAMS 0x0000000735c00000, 0x0000000735c00000| Untracked -| 411|0x0000000735e00000, 0x0000000735e00000, 0x0000000736000000| 0%| F| |TAMS 0x0000000735e00000, 0x0000000735e00000| Untracked -| 412|0x0000000736000000, 0x0000000736000000, 0x0000000736200000| 0%| F| |TAMS 0x0000000736000000, 0x0000000736000000| Untracked -| 413|0x0000000736200000, 0x0000000736200000, 0x0000000736400000| 0%| F| |TAMS 0x0000000736200000, 0x0000000736200000| Untracked -| 414|0x0000000736400000, 0x0000000736400000, 0x0000000736600000| 0%| F| |TAMS 0x0000000736400000, 0x0000000736400000| Untracked -| 415|0x0000000736600000, 0x0000000736600000, 0x0000000736800000| 0%| F| |TAMS 0x0000000736600000, 0x0000000736600000| Untracked -| 416|0x0000000736800000, 0x0000000736800000, 0x0000000736a00000| 0%| F| |TAMS 0x0000000736800000, 0x0000000736800000| Untracked -| 417|0x0000000736a00000, 0x0000000736a00000, 0x0000000736c00000| 0%| F| |TAMS 0x0000000736a00000, 0x0000000736a00000| Untracked -| 418|0x0000000736c00000, 0x0000000736c00000, 0x0000000736e00000| 0%| F| |TAMS 0x0000000736c00000, 0x0000000736c00000| Untracked -| 419|0x0000000736e00000, 0x0000000736e00000, 0x0000000737000000| 0%| F| |TAMS 0x0000000736e00000, 0x0000000736e00000| Untracked -| 420|0x0000000737000000, 0x0000000737000000, 0x0000000737200000| 0%| F| |TAMS 0x0000000737000000, 0x0000000737000000| Untracked -| 421|0x0000000737200000, 0x0000000737200000, 0x0000000737400000| 0%| F| |TAMS 0x0000000737200000, 0x0000000737200000| Untracked -| 422|0x0000000737400000, 0x0000000737400000, 0x0000000737600000| 0%| F| |TAMS 0x0000000737400000, 0x0000000737400000| Untracked -| 423|0x0000000737600000, 0x0000000737600000, 0x0000000737800000| 0%| F| |TAMS 0x0000000737600000, 0x0000000737600000| Untracked -| 424|0x0000000737800000, 0x0000000737800000, 0x0000000737a00000| 0%| F| |TAMS 0x0000000737800000, 0x0000000737800000| Untracked -| 425|0x0000000737a00000, 0x0000000737a00000, 0x0000000737c00000| 0%| F| |TAMS 0x0000000737a00000, 0x0000000737a00000| Untracked -| 426|0x0000000737c00000, 0x0000000737c00000, 0x0000000737e00000| 0%| F| |TAMS 0x0000000737c00000, 0x0000000737c00000| Untracked -| 427|0x0000000737e00000, 0x0000000738000000, 0x0000000738000000|100%| O| |TAMS 0x0000000738000000, 0x0000000737e00000| Untracked -| 428|0x0000000738000000, 0x0000000738000000, 0x0000000738200000| 0%| F| |TAMS 0x0000000738000000, 0x0000000738000000| Untracked -| 429|0x0000000738200000, 0x0000000738200000, 0x0000000738400000| 0%| F| |TAMS 0x0000000738200000, 0x0000000738200000| Untracked -| 430|0x0000000738400000, 0x0000000738400000, 0x0000000738600000| 0%| F| |TAMS 0x0000000738400000, 0x0000000738400000| Untracked -| 431|0x0000000738600000, 0x0000000738600000, 0x0000000738800000| 0%| F| |TAMS 0x0000000738600000, 0x0000000738600000| Untracked -| 432|0x0000000738800000, 0x0000000738800000, 0x0000000738a00000| 0%| F| |TAMS 0x0000000738800000, 0x0000000738800000| Untracked -| 433|0x0000000738a00000, 0x0000000738a00000, 0x0000000738c00000| 0%| F| |TAMS 0x0000000738a00000, 0x0000000738a00000| Untracked -| 434|0x0000000738c00000, 0x0000000738c00000, 0x0000000738e00000| 0%| F| |TAMS 0x0000000738c00000, 0x0000000738c00000| Untracked -| 435|0x0000000738e00000, 0x0000000738e00000, 0x0000000739000000| 0%| F| |TAMS 0x0000000738e00000, 0x0000000738e00000| Untracked -| 436|0x0000000739000000, 0x0000000739000000, 0x0000000739200000| 0%| F| |TAMS 0x0000000739000000, 0x0000000739000000| Untracked -| 437|0x0000000739200000, 0x0000000739200000, 0x0000000739400000| 0%| F| |TAMS 0x0000000739200000, 0x0000000739200000| Untracked -| 438|0x0000000739400000, 0x0000000739400000, 0x0000000739600000| 0%| F| |TAMS 0x0000000739400000, 0x0000000739400000| Untracked -| 439|0x0000000739600000, 0x0000000739600000, 0x0000000739800000| 0%| F| |TAMS 0x0000000739600000, 0x0000000739600000| Untracked -| 440|0x0000000739800000, 0x0000000739800000, 0x0000000739a00000| 0%| F| |TAMS 0x0000000739800000, 0x0000000739800000| Untracked -| 441|0x0000000739a00000, 0x0000000739a00000, 0x0000000739c00000| 0%| F| |TAMS 0x0000000739a00000, 0x0000000739a00000| Untracked -| 442|0x0000000739c00000, 0x0000000739c00000, 0x0000000739e00000| 0%| F| |TAMS 0x0000000739c00000, 0x0000000739c00000| Untracked -| 443|0x0000000739e00000, 0x0000000739e00000, 0x000000073a000000| 0%| F| |TAMS 0x0000000739e00000, 0x0000000739e00000| Untracked -| 444|0x000000073a000000, 0x000000073a000000, 0x000000073a200000| 0%| F| |TAMS 0x000000073a000000, 0x000000073a000000| Untracked -| 445|0x000000073a200000, 0x000000073a200000, 0x000000073a400000| 0%| F| |TAMS 0x000000073a200000, 0x000000073a200000| Untracked -| 446|0x000000073a400000, 0x000000073a400000, 0x000000073a600000| 0%| F| |TAMS 0x000000073a400000, 0x000000073a400000| Untracked -| 447|0x000000073a600000, 0x000000073a600000, 0x000000073a800000| 0%| F| |TAMS 0x000000073a600000, 0x000000073a600000| Untracked -| 448|0x000000073a800000, 0x000000073aa00000, 0x000000073aa00000|100%| O| |TAMS 0x000000073aa00000, 0x000000073a800000| Untracked -| 449|0x000000073aa00000, 0x000000073ac00000, 0x000000073ac00000|100%| O| |TAMS 0x000000073ac00000, 0x000000073aa00000| Untracked -| 450|0x000000073ac00000, 0x000000073ac00000, 0x000000073ae00000| 0%| F| |TAMS 0x000000073ac00000, 0x000000073ac00000| Untracked -| 451|0x000000073ae00000, 0x000000073ae00000, 0x000000073b000000| 0%| F| |TAMS 0x000000073ae00000, 0x000000073ae00000| Untracked -| 452|0x000000073b000000, 0x000000073b000000, 0x000000073b200000| 0%| F| |TAMS 0x000000073b000000, 0x000000073b000000| Untracked -| 453|0x000000073b200000, 0x000000073b200000, 0x000000073b400000| 0%| F| |TAMS 0x000000073b200000, 0x000000073b200000| Untracked -| 454|0x000000073b400000, 0x000000073b400000, 0x000000073b600000| 0%| F| |TAMS 0x000000073b400000, 0x000000073b400000| Untracked -| 455|0x000000073b600000, 0x000000073b800000, 0x000000073b800000|100%| O| |TAMS 0x000000073b800000, 0x000000073b600000| Untracked -| 456|0x000000073b800000, 0x000000073b800000, 0x000000073ba00000| 0%| F| |TAMS 0x000000073b800000, 0x000000073b800000| Untracked -| 457|0x000000073ba00000, 0x000000073ba00000, 0x000000073bc00000| 0%| F| |TAMS 0x000000073ba00000, 0x000000073ba00000| Untracked -| 458|0x000000073bc00000, 0x000000073bc00000, 0x000000073be00000| 0%| F| |TAMS 0x000000073bc00000, 0x000000073bc00000| Untracked -| 459|0x000000073be00000, 0x000000073be00000, 0x000000073c000000| 0%| F| |TAMS 0x000000073be00000, 0x000000073be00000| Untracked -| 460|0x000000073c000000, 0x000000073c000000, 0x000000073c200000| 0%| F| |TAMS 0x000000073c000000, 0x000000073c000000| Untracked -| 461|0x000000073c200000, 0x000000073c400000, 0x000000073c400000|100%| O| |TAMS 0x000000073c400000, 0x000000073c200000| Untracked -| 462|0x000000073c400000, 0x000000073c400000, 0x000000073c600000| 0%| F| |TAMS 0x000000073c400000, 0x000000073c400000| Untracked -| 463|0x000000073c600000, 0x000000073c600000, 0x000000073c800000| 0%| F| |TAMS 0x000000073c600000, 0x000000073c600000| Untracked -| 464|0x000000073c800000, 0x000000073c800000, 0x000000073ca00000| 0%| F| |TAMS 0x000000073c800000, 0x000000073c800000| Untracked -| 465|0x000000073ca00000, 0x000000073ca00000, 0x000000073cc00000| 0%| F| |TAMS 0x000000073ca00000, 0x000000073ca00000| Untracked -| 466|0x000000073cc00000, 0x000000073cc00000, 0x000000073ce00000| 0%| F| |TAMS 0x000000073cc00000, 0x000000073cc00000| Untracked -| 467|0x000000073ce00000, 0x000000073d000000, 0x000000073d000000|100%| O| |TAMS 0x000000073d000000, 0x000000073ce00000| Untracked -| 468|0x000000073d000000, 0x000000073d200000, 0x000000073d200000|100%| O| |TAMS 0x000000073d200000, 0x000000073d000000| Untracked -| 469|0x000000073d200000, 0x000000073d400000, 0x000000073d400000|100%| O| |TAMS 0x000000073d400000, 0x000000073d200000| Untracked -| 470|0x000000073d400000, 0x000000073d600000, 0x000000073d600000|100%| O| |TAMS 0x000000073d600000, 0x000000073d400000| Untracked -| 471|0x000000073d600000, 0x000000073d800000, 0x000000073d800000|100%| O| |TAMS 0x000000073d800000, 0x000000073d600000| Untracked -| 472|0x000000073d800000, 0x000000073d800000, 0x000000073da00000| 0%| F| |TAMS 0x000000073d800000, 0x000000073d800000| Untracked -| 473|0x000000073da00000, 0x000000073da00000, 0x000000073dc00000| 0%| F| |TAMS 0x000000073da00000, 0x000000073da00000| Untracked -| 474|0x000000073dc00000, 0x000000073dc00000, 0x000000073de00000| 0%| F| |TAMS 0x000000073dc00000, 0x000000073dc00000| Untracked -| 475|0x000000073de00000, 0x000000073de00000, 0x000000073e000000| 0%| F| |TAMS 0x000000073de00000, 0x000000073de00000| Untracked -| 476|0x000000073e000000, 0x000000073e000000, 0x000000073e200000| 0%| F| |TAMS 0x000000073e000000, 0x000000073e000000| Untracked -| 477|0x000000073e200000, 0x000000073e200000, 0x000000073e400000| 0%| F| |TAMS 0x000000073e200000, 0x000000073e200000| Untracked -| 478|0x000000073e400000, 0x000000073e600000, 0x000000073e600000|100%| O| |TAMS 0x000000073e600000, 0x000000073e400000| Untracked -| 479|0x000000073e600000, 0x000000073e800000, 0x000000073e800000|100%| O| |TAMS 0x000000073e800000, 0x000000073e600000| Untracked -| 480|0x000000073e800000, 0x000000073ea00000, 0x000000073ea00000|100%| O| |TAMS 0x000000073ea00000, 0x000000073e800000| Untracked -| 481|0x000000073ea00000, 0x000000073ec00000, 0x000000073ec00000|100%| O| |TAMS 0x000000073ec00000, 0x000000073ea00000| Untracked -| 482|0x000000073ec00000, 0x000000073ee00000, 0x000000073ee00000|100%| O| |TAMS 0x000000073ee00000, 0x000000073ec00000| Untracked -| 483|0x000000073ee00000, 0x000000073f000000, 0x000000073f000000|100%| O| |TAMS 0x000000073f000000, 0x000000073ee00000| Untracked -| 484|0x000000073f000000, 0x000000073f200000, 0x000000073f200000|100%| O| |TAMS 0x000000073f200000, 0x000000073f000000| Untracked -| 485|0x000000073f200000, 0x000000073f400000, 0x000000073f400000|100%| O| |TAMS 0x000000073f400000, 0x000000073f200000| Untracked -| 486|0x000000073f400000, 0x000000073f600000, 0x000000073f600000|100%| O| |TAMS 0x000000073f600000, 0x000000073f400000| Untracked -| 487|0x000000073f600000, 0x000000073f800000, 0x000000073f800000|100%| O| |TAMS 0x000000073f800000, 0x000000073f600000| Untracked -| 488|0x000000073f800000, 0x000000073fa00000, 0x000000073fa00000|100%| O| |TAMS 0x000000073fa00000, 0x000000073f800000| Untracked -| 489|0x000000073fa00000, 0x000000073fc00000, 0x000000073fc00000|100%| O| |TAMS 0x000000073fc00000, 0x000000073fa00000| Untracked -| 490|0x000000073fc00000, 0x000000073fe00000, 0x000000073fe00000|100%| O| |TAMS 0x000000073fe00000, 0x000000073fc00000| Untracked -| 491|0x000000073fe00000, 0x0000000740000000, 0x0000000740000000|100%| O| |TAMS 0x0000000740000000, 0x000000073fe00000| Untracked -| 492|0x0000000740000000, 0x0000000740200000, 0x0000000740200000|100%| O| |TAMS 0x0000000740200000, 0x0000000740000000| Untracked -| 493|0x0000000740200000, 0x0000000740400000, 0x0000000740400000|100%| O| |TAMS 0x0000000740400000, 0x0000000740200000| Untracked -| 494|0x0000000740400000, 0x0000000740600000, 0x0000000740600000|100%| O| |TAMS 0x0000000740600000, 0x0000000740400000| Untracked -| 495|0x0000000740600000, 0x0000000740800000, 0x0000000740800000|100%| O| |TAMS 0x0000000740800000, 0x0000000740600000| Untracked -| 496|0x0000000740800000, 0x0000000740a00000, 0x0000000740a00000|100%| O| |TAMS 0x0000000740a00000, 0x0000000740800000| Untracked -| 497|0x0000000740a00000, 0x0000000740c00000, 0x0000000740c00000|100%| O| |TAMS 0x0000000740c00000, 0x0000000740a00000| Untracked -| 498|0x0000000740c00000, 0x0000000740e00000, 0x0000000740e00000|100%| O| |TAMS 0x0000000740e00000, 0x0000000740c00000| Untracked -| 499|0x0000000740e00000, 0x0000000741000000, 0x0000000741000000|100%| O| |TAMS 0x0000000741000000, 0x0000000740e00000| Untracked -| 500|0x0000000741000000, 0x0000000741200000, 0x0000000741200000|100%| O| |TAMS 0x0000000741200000, 0x0000000741000000| Untracked -| 501|0x0000000741200000, 0x0000000741400000, 0x0000000741400000|100%| O| |TAMS 0x0000000741400000, 0x0000000741200000| Untracked -| 502|0x0000000741400000, 0x0000000741600000, 0x0000000741600000|100%| O| |TAMS 0x0000000741600000, 0x0000000741400000| Untracked -| 503|0x0000000741600000, 0x0000000741800000, 0x0000000741800000|100%| O| |TAMS 0x0000000741800000, 0x0000000741600000| Untracked -| 504|0x0000000741800000, 0x0000000741a00000, 0x0000000741a00000|100%| O| |TAMS 0x0000000741a00000, 0x0000000741800000| Untracked -| 505|0x0000000741a00000, 0x0000000741c00000, 0x0000000741c00000|100%| O| |TAMS 0x0000000741c00000, 0x0000000741a00000| Untracked -| 506|0x0000000741c00000, 0x0000000741e00000, 0x0000000741e00000|100%| O| |TAMS 0x0000000741e00000, 0x0000000741c00000| Untracked -| 507|0x0000000741e00000, 0x0000000742000000, 0x0000000742000000|100%| O| |TAMS 0x0000000742000000, 0x0000000741e00000| Untracked -| 508|0x0000000742000000, 0x0000000742200000, 0x0000000742200000|100%| O| |TAMS 0x0000000742200000, 0x0000000742000000| Untracked -| 509|0x0000000742200000, 0x0000000742400000, 0x0000000742400000|100%| O| |TAMS 0x0000000742400000, 0x0000000742200000| Untracked -| 510|0x0000000742400000, 0x0000000742600000, 0x0000000742600000|100%| O| |TAMS 0x0000000742600000, 0x0000000742400000| Untracked -| 511|0x0000000742600000, 0x0000000742800000, 0x0000000742800000|100%| O| |TAMS 0x0000000742800000, 0x0000000742600000| Untracked -| 512|0x0000000742800000, 0x0000000742a00000, 0x0000000742a00000|100%| O| |TAMS 0x0000000742a00000, 0x0000000742800000| Untracked -| 513|0x0000000742a00000, 0x0000000742c00000, 0x0000000742c00000|100%| O| |TAMS 0x0000000742c00000, 0x0000000742a00000| Untracked -| 514|0x0000000742c00000, 0x0000000742e00000, 0x0000000742e00000|100%| O| |TAMS 0x0000000742e00000, 0x0000000742c00000| Untracked -| 515|0x0000000742e00000, 0x0000000743000000, 0x0000000743000000|100%| O| |TAMS 0x0000000743000000, 0x0000000742e00000| Untracked -| 516|0x0000000743000000, 0x0000000743200000, 0x0000000743200000|100%| O| |TAMS 0x0000000743200000, 0x0000000743000000| Untracked -| 517|0x0000000743200000, 0x0000000743400000, 0x0000000743400000|100%| O| |TAMS 0x0000000743400000, 0x0000000743200000| Untracked -| 518|0x0000000743400000, 0x0000000743600000, 0x0000000743600000|100%| O| |TAMS 0x0000000743600000, 0x0000000743400000| Untracked -| 519|0x0000000743600000, 0x0000000743800000, 0x0000000743800000|100%| O| |TAMS 0x0000000743800000, 0x0000000743600000| Untracked -| 520|0x0000000743800000, 0x0000000743a00000, 0x0000000743a00000|100%| O| |TAMS 0x0000000743a00000, 0x0000000743800000| Untracked -| 521|0x0000000743a00000, 0x0000000743c00000, 0x0000000743c00000|100%| O| |TAMS 0x0000000743c00000, 0x0000000743a00000| Untracked -| 522|0x0000000743c00000, 0x0000000743e00000, 0x0000000743e00000|100%| O| |TAMS 0x0000000743e00000, 0x0000000743c00000| Untracked -| 523|0x0000000743e00000, 0x0000000744000000, 0x0000000744000000|100%| O| |TAMS 0x0000000744000000, 0x0000000743e00000| Untracked -| 524|0x0000000744000000, 0x0000000744000000, 0x0000000744200000| 0%| F| |TAMS 0x0000000744000000, 0x0000000744000000| Untracked -| 525|0x0000000744200000, 0x0000000744400000, 0x0000000744400000|100%| O| |TAMS 0x0000000744400000, 0x0000000744200000| Untracked -| 526|0x0000000744400000, 0x0000000744600000, 0x0000000744600000|100%| O| |TAMS 0x0000000744600000, 0x0000000744400000| Untracked -| 527|0x0000000744600000, 0x0000000744800000, 0x0000000744800000|100%| O| |TAMS 0x0000000744800000, 0x0000000744600000| Untracked -| 528|0x0000000744800000, 0x0000000744a00000, 0x0000000744a00000|100%| O| |TAMS 0x0000000744a00000, 0x0000000744800000| Untracked -| 529|0x0000000744a00000, 0x0000000744c00000, 0x0000000744c00000|100%| O| |TAMS 0x0000000744c00000, 0x0000000744a00000| Untracked -| 530|0x0000000744c00000, 0x0000000744e00000, 0x0000000744e00000|100%| O| |TAMS 0x0000000744e00000, 0x0000000744c00000| Untracked -| 531|0x0000000744e00000, 0x0000000745000000, 0x0000000745000000|100%| O| |TAMS 0x0000000745000000, 0x0000000744e00000| Untracked -| 532|0x0000000745000000, 0x0000000745200000, 0x0000000745200000|100%| O| |TAMS 0x0000000745200000, 0x0000000745000000| Untracked -| 533|0x0000000745200000, 0x0000000745400000, 0x0000000745400000|100%| O| |TAMS 0x0000000745400000, 0x0000000745200000| Untracked -| 534|0x0000000745400000, 0x0000000745600000, 0x0000000745600000|100%| O| |TAMS 0x0000000745600000, 0x0000000745400000| Untracked -| 535|0x0000000745600000, 0x0000000745800000, 0x0000000745800000|100%| O| |TAMS 0x0000000745800000, 0x0000000745600000| Untracked -| 536|0x0000000745800000, 0x0000000745a00000, 0x0000000745a00000|100%| O| |TAMS 0x0000000745a00000, 0x0000000745800000| Untracked -| 537|0x0000000745a00000, 0x0000000745c00000, 0x0000000745c00000|100%| O| |TAMS 0x0000000745c00000, 0x0000000745a00000| Untracked -| 538|0x0000000745c00000, 0x0000000745e00000, 0x0000000745e00000|100%| O| |TAMS 0x0000000745e00000, 0x0000000745c00000| Untracked -| 539|0x0000000745e00000, 0x0000000746000000, 0x0000000746000000|100%| O| |TAMS 0x0000000746000000, 0x0000000745e00000| Untracked -| 540|0x0000000746000000, 0x0000000746200000, 0x0000000746200000|100%| O| |TAMS 0x0000000746200000, 0x0000000746000000| Untracked -| 541|0x0000000746200000, 0x0000000746400000, 0x0000000746400000|100%| O| |TAMS 0x0000000746400000, 0x0000000746200000| Untracked -| 542|0x0000000746400000, 0x0000000746600000, 0x0000000746600000|100%| O| |TAMS 0x0000000746600000, 0x0000000746400000| Untracked -| 543|0x0000000746600000, 0x0000000746800000, 0x0000000746800000|100%| O| |TAMS 0x0000000746800000, 0x0000000746600000| Untracked -| 544|0x0000000746800000, 0x0000000746a00000, 0x0000000746a00000|100%| O| |TAMS 0x0000000746a00000, 0x0000000746800000| Untracked -| 545|0x0000000746a00000, 0x0000000746c00000, 0x0000000746c00000|100%| O| |TAMS 0x0000000746c00000, 0x0000000746a00000| Untracked -| 546|0x0000000746c00000, 0x0000000746e00000, 0x0000000746e00000|100%| O| |TAMS 0x0000000746e00000, 0x0000000746c00000| Untracked -| 547|0x0000000746e00000, 0x0000000747000000, 0x0000000747000000|100%| O| |TAMS 0x0000000747000000, 0x0000000746e00000| Untracked -| 548|0x0000000747000000, 0x0000000747200000, 0x0000000747200000|100%| O| |TAMS 0x0000000747200000, 0x0000000747000000| Untracked -| 549|0x0000000747200000, 0x0000000747400000, 0x0000000747400000|100%| O| |TAMS 0x0000000747400000, 0x0000000747200000| Untracked -| 550|0x0000000747400000, 0x0000000747600000, 0x0000000747600000|100%| O| |TAMS 0x0000000747600000, 0x0000000747400000| Untracked -| 551|0x0000000747600000, 0x0000000747800000, 0x0000000747800000|100%| O| |TAMS 0x0000000747800000, 0x0000000747600000| Untracked -| 552|0x0000000747800000, 0x0000000747a00000, 0x0000000747a00000|100%| O| |TAMS 0x0000000747a00000, 0x0000000747800000| Untracked -| 553|0x0000000747a00000, 0x0000000747c00000, 0x0000000747c00000|100%| O| |TAMS 0x0000000747c00000, 0x0000000747a00000| Untracked -| 554|0x0000000747c00000, 0x0000000747e00000, 0x0000000747e00000|100%| O| |TAMS 0x0000000747e00000, 0x0000000747c00000| Untracked -| 555|0x0000000747e00000, 0x0000000748000000, 0x0000000748000000|100%| O| |TAMS 0x0000000748000000, 0x0000000747e00000| Untracked -| 556|0x0000000748000000, 0x0000000748200000, 0x0000000748200000|100%| O| |TAMS 0x0000000748200000, 0x0000000748000000| Untracked -| 557|0x0000000748200000, 0x0000000748400000, 0x0000000748400000|100%| O| |TAMS 0x0000000748400000, 0x0000000748200000| Untracked -| 558|0x0000000748400000, 0x0000000748600000, 0x0000000748600000|100%| O| |TAMS 0x0000000748600000, 0x0000000748400000| Untracked -| 559|0x0000000748600000, 0x0000000748800000, 0x0000000748800000|100%| O| |TAMS 0x0000000748800000, 0x0000000748600000| Untracked -| 560|0x0000000748800000, 0x0000000748a00000, 0x0000000748a00000|100%| O| |TAMS 0x0000000748a00000, 0x0000000748800000| Untracked -| 561|0x0000000748a00000, 0x0000000748c00000, 0x0000000748c00000|100%| O| |TAMS 0x0000000748c00000, 0x0000000748a00000| Untracked -| 562|0x0000000748c00000, 0x0000000748e00000, 0x0000000748e00000|100%| O| |TAMS 0x0000000748e00000, 0x0000000748c00000| Untracked -| 563|0x0000000748e00000, 0x0000000749000000, 0x0000000749000000|100%| O| |TAMS 0x0000000749000000, 0x0000000748e00000| Untracked -| 564|0x0000000749000000, 0x0000000749200000, 0x0000000749200000|100%| O| |TAMS 0x0000000749200000, 0x0000000749000000| Untracked -| 565|0x0000000749200000, 0x0000000749400000, 0x0000000749400000|100%| O| |TAMS 0x0000000749400000, 0x0000000749200000| Untracked -| 566|0x0000000749400000, 0x0000000749600000, 0x0000000749600000|100%| O| |TAMS 0x0000000749600000, 0x0000000749400000| Untracked -| 567|0x0000000749600000, 0x0000000749800000, 0x0000000749800000|100%| O| |TAMS 0x0000000749800000, 0x0000000749600000| Untracked -| 568|0x0000000749800000, 0x0000000749a00000, 0x0000000749a00000|100%| O| |TAMS 0x0000000749a00000, 0x0000000749800000| Untracked -| 569|0x0000000749a00000, 0x0000000749c00000, 0x0000000749c00000|100%| O| |TAMS 0x0000000749c00000, 0x0000000749a00000| Untracked -| 570|0x0000000749c00000, 0x0000000749e00000, 0x0000000749e00000|100%| O| |TAMS 0x0000000749e00000, 0x0000000749c00000| Untracked -| 571|0x0000000749e00000, 0x000000074a000000, 0x000000074a000000|100%| O| |TAMS 0x000000074a000000, 0x0000000749e00000| Untracked -| 572|0x000000074a000000, 0x000000074a200000, 0x000000074a200000|100%| O| |TAMS 0x000000074a200000, 0x000000074a000000| Untracked -| 573|0x000000074a200000, 0x000000074a400000, 0x000000074a400000|100%| O| |TAMS 0x000000074a400000, 0x000000074a200000| Untracked -| 574|0x000000074a400000, 0x000000074a600000, 0x000000074a600000|100%| O| |TAMS 0x000000074a600000, 0x000000074a400000| Untracked -| 575|0x000000074a600000, 0x000000074a800000, 0x000000074a800000|100%| O| |TAMS 0x000000074a800000, 0x000000074a600000| Untracked -| 576|0x000000074a800000, 0x000000074aa00000, 0x000000074aa00000|100%| O| |TAMS 0x000000074aa00000, 0x000000074a800000| Untracked -| 577|0x000000074aa00000, 0x000000074ac00000, 0x000000074ac00000|100%| O| |TAMS 0x000000074ac00000, 0x000000074aa00000| Untracked -| 578|0x000000074ac00000, 0x000000074ae00000, 0x000000074ae00000|100%| O| |TAMS 0x000000074ae00000, 0x000000074ac00000| Untracked -| 579|0x000000074ae00000, 0x000000074b000000, 0x000000074b000000|100%| O| |TAMS 0x000000074b000000, 0x000000074ae00000| Untracked -| 580|0x000000074b000000, 0x000000074b200000, 0x000000074b200000|100%| O| |TAMS 0x000000074b200000, 0x000000074b000000| Untracked -| 581|0x000000074b200000, 0x000000074b400000, 0x000000074b400000|100%| O| |TAMS 0x000000074b400000, 0x000000074b200000| Untracked -| 582|0x000000074b400000, 0x000000074b600000, 0x000000074b600000|100%| O| |TAMS 0x000000074b600000, 0x000000074b400000| Untracked -| 583|0x000000074b600000, 0x000000074b800000, 0x000000074b800000|100%| O| |TAMS 0x000000074b800000, 0x000000074b600000| Untracked -| 584|0x000000074b800000, 0x000000074ba00000, 0x000000074ba00000|100%| O| |TAMS 0x000000074ba00000, 0x000000074b800000| Untracked -| 585|0x000000074ba00000, 0x000000074bc00000, 0x000000074bc00000|100%| O| |TAMS 0x000000074bc00000, 0x000000074ba00000| Untracked -| 586|0x000000074bc00000, 0x000000074be00000, 0x000000074be00000|100%| O| |TAMS 0x000000074be00000, 0x000000074bc00000| Untracked -| 587|0x000000074be00000, 0x000000074c000000, 0x000000074c000000|100%| O| |TAMS 0x000000074c000000, 0x000000074be00000| Untracked -| 588|0x000000074c000000, 0x000000074c200000, 0x000000074c200000|100%| O| |TAMS 0x000000074c200000, 0x000000074c000000| Untracked -| 589|0x000000074c200000, 0x000000074c400000, 0x000000074c400000|100%| O| |TAMS 0x000000074c400000, 0x000000074c200000| Untracked -| 590|0x000000074c400000, 0x000000074c600000, 0x000000074c600000|100%| O| |TAMS 0x000000074c600000, 0x000000074c400000| Untracked -| 591|0x000000074c600000, 0x000000074c800000, 0x000000074c800000|100%| O| |TAMS 0x000000074c800000, 0x000000074c600000| Untracked -| 592|0x000000074c800000, 0x000000074ca00000, 0x000000074ca00000|100%| O| |TAMS 0x000000074ca00000, 0x000000074c800000| Untracked -| 593|0x000000074ca00000, 0x000000074cc00000, 0x000000074cc00000|100%| O| |TAMS 0x000000074cc00000, 0x000000074ca00000| Untracked -| 594|0x000000074cc00000, 0x000000074ce00000, 0x000000074ce00000|100%| O| |TAMS 0x000000074ce00000, 0x000000074cc00000| Untracked -| 595|0x000000074ce00000, 0x000000074d000000, 0x000000074d000000|100%| O| |TAMS 0x000000074d000000, 0x000000074ce00000| Untracked -| 596|0x000000074d000000, 0x000000074d200000, 0x000000074d200000|100%| O| |TAMS 0x000000074d200000, 0x000000074d000000| Untracked -| 597|0x000000074d200000, 0x000000074d400000, 0x000000074d400000|100%| O| |TAMS 0x000000074d400000, 0x000000074d200000| Untracked -| 598|0x000000074d400000, 0x000000074d600000, 0x000000074d600000|100%| O| |TAMS 0x000000074d600000, 0x000000074d400000| Untracked -| 599|0x000000074d600000, 0x000000074d800000, 0x000000074d800000|100%| O| |TAMS 0x000000074d800000, 0x000000074d600000| Untracked -| 600|0x000000074d800000, 0x000000074da00000, 0x000000074da00000|100%| O| |TAMS 0x000000074da00000, 0x000000074d800000| Untracked -| 601|0x000000074da00000, 0x000000074dc00000, 0x000000074dc00000|100%| O| |TAMS 0x000000074dc00000, 0x000000074da00000| Untracked -| 602|0x000000074dc00000, 0x000000074de00000, 0x000000074de00000|100%| O| |TAMS 0x000000074de00000, 0x000000074dc00000| Untracked -| 603|0x000000074de00000, 0x000000074e000000, 0x000000074e000000|100%| O| |TAMS 0x000000074e000000, 0x000000074de00000| Untracked -| 604|0x000000074e000000, 0x000000074e200000, 0x000000074e200000|100%| O| |TAMS 0x000000074e200000, 0x000000074e000000| Untracked -| 605|0x000000074e200000, 0x000000074e400000, 0x000000074e400000|100%| O| |TAMS 0x000000074e400000, 0x000000074e200000| Untracked -| 606|0x000000074e400000, 0x000000074e600000, 0x000000074e600000|100%| O| |TAMS 0x000000074e600000, 0x000000074e400000| Untracked -| 607|0x000000074e600000, 0x000000074e800000, 0x000000074e800000|100%| O| |TAMS 0x000000074e800000, 0x000000074e600000| Untracked -| 608|0x000000074e800000, 0x000000074ea00000, 0x000000074ea00000|100%| O| |TAMS 0x000000074ea00000, 0x000000074e800000| Untracked -| 609|0x000000074ea00000, 0x000000074ec00000, 0x000000074ec00000|100%| O| |TAMS 0x000000074ec00000, 0x000000074ea00000| Untracked -| 610|0x000000074ec00000, 0x000000074ee00000, 0x000000074ee00000|100%| O| |TAMS 0x000000074ee00000, 0x000000074ec00000| Untracked -| 611|0x000000074ee00000, 0x000000074f000000, 0x000000074f000000|100%| O| |TAMS 0x000000074f000000, 0x000000074ee00000| Untracked -| 612|0x000000074f000000, 0x000000074f200000, 0x000000074f200000|100%| O| |TAMS 0x000000074f200000, 0x000000074f000000| Untracked -| 613|0x000000074f200000, 0x000000074f400000, 0x000000074f400000|100%| O| |TAMS 0x000000074f400000, 0x000000074f200000| Untracked -| 614|0x000000074f400000, 0x000000074f600000, 0x000000074f600000|100%| O| |TAMS 0x000000074f600000, 0x000000074f400000| Untracked -| 615|0x000000074f600000, 0x000000074f800000, 0x000000074f800000|100%| O| |TAMS 0x000000074f800000, 0x000000074f600000| Untracked -| 616|0x000000074f800000, 0x000000074fa00000, 0x000000074fa00000|100%| O| |TAMS 0x000000074fa00000, 0x000000074f800000| Untracked -| 617|0x000000074fa00000, 0x000000074fc00000, 0x000000074fc00000|100%| O| |TAMS 0x000000074fc00000, 0x000000074fa00000| Untracked -| 618|0x000000074fc00000, 0x000000074fe00000, 0x000000074fe00000|100%| O| |TAMS 0x000000074fe00000, 0x000000074fc00000| Untracked -| 619|0x000000074fe00000, 0x0000000750000000, 0x0000000750000000|100%| O| |TAMS 0x0000000750000000, 0x000000074fe00000| Untracked -| 620|0x0000000750000000, 0x0000000750200000, 0x0000000750200000|100%| O| |TAMS 0x0000000750200000, 0x0000000750000000| Untracked -| 621|0x0000000750200000, 0x0000000750400000, 0x0000000750400000|100%| O| |TAMS 0x0000000750400000, 0x0000000750200000| Untracked -| 622|0x0000000750400000, 0x0000000750600000, 0x0000000750600000|100%| O| |TAMS 0x0000000750600000, 0x0000000750400000| Untracked -| 623|0x0000000750600000, 0x0000000750800000, 0x0000000750800000|100%| O| |TAMS 0x0000000750800000, 0x0000000750600000| Untracked -| 624|0x0000000750800000, 0x0000000750a00000, 0x0000000750a00000|100%| O| |TAMS 0x0000000750a00000, 0x0000000750800000| Untracked -| 625|0x0000000750a00000, 0x0000000750c00000, 0x0000000750c00000|100%| O| |TAMS 0x0000000750c00000, 0x0000000750a00000| Untracked -| 626|0x0000000750c00000, 0x0000000750e00000, 0x0000000750e00000|100%| O| |TAMS 0x0000000750e00000, 0x0000000750c00000| Untracked -| 627|0x0000000750e00000, 0x0000000751000000, 0x0000000751000000|100%| O| |TAMS 0x0000000751000000, 0x0000000750e00000| Untracked -| 628|0x0000000751000000, 0x0000000751200000, 0x0000000751200000|100%| O| |TAMS 0x0000000751200000, 0x0000000751000000| Untracked -| 629|0x0000000751200000, 0x0000000751400000, 0x0000000751400000|100%| O| |TAMS 0x0000000751400000, 0x0000000751200000| Untracked -| 630|0x0000000751400000, 0x0000000751600000, 0x0000000751600000|100%| O| |TAMS 0x0000000751600000, 0x0000000751400000| Untracked -| 631|0x0000000751600000, 0x0000000751800000, 0x0000000751800000|100%| O| |TAMS 0x0000000751800000, 0x0000000751600000| Untracked -| 632|0x0000000751800000, 0x0000000751a00000, 0x0000000751a00000|100%| O| |TAMS 0x0000000751a00000, 0x0000000751800000| Untracked -| 633|0x0000000751a00000, 0x0000000751c00000, 0x0000000751c00000|100%| O| |TAMS 0x0000000751c00000, 0x0000000751a00000| Untracked -| 634|0x0000000751c00000, 0x0000000751e00000, 0x0000000751e00000|100%| O| |TAMS 0x0000000751e00000, 0x0000000751c00000| Untracked -| 635|0x0000000751e00000, 0x0000000752000000, 0x0000000752000000|100%| O| |TAMS 0x0000000752000000, 0x0000000751e00000| Untracked -| 636|0x0000000752000000, 0x0000000752200000, 0x0000000752200000|100%| O| |TAMS 0x0000000752200000, 0x0000000752000000| Untracked -| 637|0x0000000752200000, 0x0000000752400000, 0x0000000752400000|100%| O| |TAMS 0x0000000752400000, 0x0000000752200000| Untracked -| 638|0x0000000752400000, 0x0000000752600000, 0x0000000752600000|100%| O| |TAMS 0x0000000752600000, 0x0000000752400000| Untracked -| 639|0x0000000752600000, 0x0000000752800000, 0x0000000752800000|100%| O| |TAMS 0x0000000752800000, 0x0000000752600000| Untracked -| 640|0x0000000752800000, 0x0000000752a00000, 0x0000000752a00000|100%| O| |TAMS 0x0000000752a00000, 0x0000000752800000| Untracked -| 641|0x0000000752a00000, 0x0000000752c00000, 0x0000000752c00000|100%| O| |TAMS 0x0000000752c00000, 0x0000000752a00000| Untracked -| 642|0x0000000752c00000, 0x0000000752e00000, 0x0000000752e00000|100%| O| |TAMS 0x0000000752e00000, 0x0000000752c00000| Untracked -| 643|0x0000000752e00000, 0x0000000753000000, 0x0000000753000000|100%| O| |TAMS 0x0000000753000000, 0x0000000752e00000| Untracked -| 644|0x0000000753000000, 0x0000000753200000, 0x0000000753200000|100%| O| |TAMS 0x0000000753200000, 0x0000000753000000| Untracked -| 645|0x0000000753200000, 0x0000000753400000, 0x0000000753400000|100%| O| |TAMS 0x0000000753400000, 0x0000000753200000| Untracked -| 646|0x0000000753400000, 0x0000000753600000, 0x0000000753600000|100%| O| |TAMS 0x0000000753600000, 0x0000000753400000| Untracked -| 647|0x0000000753600000, 0x0000000753800000, 0x0000000753800000|100%| O| |TAMS 0x0000000753800000, 0x0000000753600000| Untracked -| 648|0x0000000753800000, 0x0000000753a00000, 0x0000000753a00000|100%| O| |TAMS 0x0000000753a00000, 0x0000000753800000| Untracked -| 649|0x0000000753a00000, 0x0000000753c00000, 0x0000000753c00000|100%| O| |TAMS 0x0000000753c00000, 0x0000000753a00000| Untracked -| 650|0x0000000753c00000, 0x0000000753e00000, 0x0000000753e00000|100%| O| |TAMS 0x0000000753e00000, 0x0000000753c00000| Untracked -| 651|0x0000000753e00000, 0x0000000754000000, 0x0000000754000000|100%| O| |TAMS 0x0000000754000000, 0x0000000753e00000| Untracked -| 652|0x0000000754000000, 0x0000000754200000, 0x0000000754200000|100%| O| |TAMS 0x0000000754200000, 0x0000000754000000| Untracked -| 653|0x0000000754200000, 0x0000000754400000, 0x0000000754400000|100%| O| |TAMS 0x0000000754400000, 0x0000000754200000| Untracked -| 654|0x0000000754400000, 0x0000000754600000, 0x0000000754600000|100%| O| |TAMS 0x0000000754600000, 0x0000000754400000| Untracked -| 655|0x0000000754600000, 0x0000000754800000, 0x0000000754800000|100%| O| |TAMS 0x0000000754800000, 0x0000000754600000| Untracked -| 656|0x0000000754800000, 0x0000000754a00000, 0x0000000754a00000|100%| O| |TAMS 0x0000000754a00000, 0x0000000754800000| Untracked -| 657|0x0000000754a00000, 0x0000000754c00000, 0x0000000754c00000|100%| O| |TAMS 0x0000000754c00000, 0x0000000754a00000| Untracked -| 658|0x0000000754c00000, 0x0000000754e00000, 0x0000000754e00000|100%| O| |TAMS 0x0000000754e00000, 0x0000000754c00000| Untracked -| 659|0x0000000754e00000, 0x0000000755000000, 0x0000000755000000|100%| O| |TAMS 0x0000000755000000, 0x0000000754e00000| Untracked -| 660|0x0000000755000000, 0x0000000755200000, 0x0000000755200000|100%| O| |TAMS 0x0000000755200000, 0x0000000755000000| Untracked -| 661|0x0000000755200000, 0x0000000755400000, 0x0000000755400000|100%| O| |TAMS 0x0000000755400000, 0x0000000755200000| Untracked -| 662|0x0000000755400000, 0x0000000755600000, 0x0000000755600000|100%| O| |TAMS 0x0000000755600000, 0x0000000755400000| Untracked -| 663|0x0000000755600000, 0x0000000755800000, 0x0000000755800000|100%| O| |TAMS 0x0000000755800000, 0x0000000755600000| Untracked -| 664|0x0000000755800000, 0x0000000755a00000, 0x0000000755a00000|100%| O| |TAMS 0x0000000755a00000, 0x0000000755800000| Untracked -| 665|0x0000000755a00000, 0x0000000755c00000, 0x0000000755c00000|100%| O| |TAMS 0x0000000755c00000, 0x0000000755a00000| Untracked -| 666|0x0000000755c00000, 0x0000000755e00000, 0x0000000755e00000|100%| O| |TAMS 0x0000000755e00000, 0x0000000755c00000| Untracked -| 667|0x0000000755e00000, 0x0000000756000000, 0x0000000756000000|100%| O| |TAMS 0x0000000756000000, 0x0000000755e00000| Untracked -| 668|0x0000000756000000, 0x0000000756200000, 0x0000000756200000|100%| O| |TAMS 0x0000000756200000, 0x0000000756000000| Untracked -| 669|0x0000000756200000, 0x0000000756400000, 0x0000000756400000|100%| O| |TAMS 0x0000000756400000, 0x0000000756200000| Untracked -| 670|0x0000000756400000, 0x0000000756600000, 0x0000000756600000|100%| O| |TAMS 0x0000000756600000, 0x0000000756400000| Untracked -| 671|0x0000000756600000, 0x0000000756800000, 0x0000000756800000|100%| O| |TAMS 0x0000000756800000, 0x0000000756600000| Untracked -| 672|0x0000000756800000, 0x0000000756a00000, 0x0000000756a00000|100%| O| |TAMS 0x0000000756a00000, 0x0000000756800000| Untracked -| 673|0x0000000756a00000, 0x0000000756c00000, 0x0000000756c00000|100%| O| |TAMS 0x0000000756c00000, 0x0000000756a00000| Untracked -| 674|0x0000000756c00000, 0x0000000756e00000, 0x0000000756e00000|100%| O| |TAMS 0x0000000756e00000, 0x0000000756c00000| Untracked -| 675|0x0000000756e00000, 0x0000000757000000, 0x0000000757000000|100%| O| |TAMS 0x0000000757000000, 0x0000000756e00000| Untracked -| 676|0x0000000757000000, 0x0000000757200000, 0x0000000757200000|100%| O| |TAMS 0x0000000757200000, 0x0000000757000000| Untracked -| 677|0x0000000757200000, 0x0000000757400000, 0x0000000757400000|100%| O| |TAMS 0x0000000757400000, 0x0000000757200000| Untracked -| 678|0x0000000757400000, 0x0000000757600000, 0x0000000757600000|100%| O| |TAMS 0x0000000757600000, 0x0000000757400000| Untracked -| 679|0x0000000757600000, 0x0000000757800000, 0x0000000757800000|100%| O| |TAMS 0x0000000757800000, 0x0000000757600000| Untracked -| 680|0x0000000757800000, 0x0000000757a00000, 0x0000000757a00000|100%| O| |TAMS 0x0000000757a00000, 0x0000000757800000| Untracked -| 681|0x0000000757a00000, 0x0000000757c00000, 0x0000000757c00000|100%| O| |TAMS 0x0000000757c00000, 0x0000000757a00000| Untracked -| 682|0x0000000757c00000, 0x0000000757e00000, 0x0000000757e00000|100%| O| |TAMS 0x0000000757e00000, 0x0000000757c00000| Untracked -| 683|0x0000000757e00000, 0x0000000758000000, 0x0000000758000000|100%| O| |TAMS 0x0000000758000000, 0x0000000757e00000| Untracked -| 684|0x0000000758000000, 0x0000000758200000, 0x0000000758200000|100%| O| |TAMS 0x0000000758200000, 0x0000000758000000| Untracked -| 685|0x0000000758200000, 0x0000000758400000, 0x0000000758400000|100%| O| |TAMS 0x0000000758400000, 0x0000000758200000| Untracked -| 686|0x0000000758400000, 0x0000000758600000, 0x0000000758600000|100%| O| |TAMS 0x0000000758600000, 0x0000000758400000| Untracked -| 687|0x0000000758600000, 0x0000000758800000, 0x0000000758800000|100%| O| |TAMS 0x0000000758800000, 0x0000000758600000| Untracked -| 688|0x0000000758800000, 0x0000000758a00000, 0x0000000758a00000|100%| O| |TAMS 0x0000000758a00000, 0x0000000758800000| Untracked -| 689|0x0000000758a00000, 0x0000000758c00000, 0x0000000758c00000|100%| O| |TAMS 0x0000000758c00000, 0x0000000758a00000| Untracked -| 690|0x0000000758c00000, 0x0000000758e00000, 0x0000000758e00000|100%| O| |TAMS 0x0000000758e00000, 0x0000000758c00000| Untracked -| 691|0x0000000758e00000, 0x0000000759000000, 0x0000000759000000|100%| O| |TAMS 0x0000000759000000, 0x0000000758e00000| Untracked -| 692|0x0000000759000000, 0x0000000759200000, 0x0000000759200000|100%| O| |TAMS 0x0000000759200000, 0x0000000759000000| Untracked -| 693|0x0000000759200000, 0x0000000759400000, 0x0000000759400000|100%| O| |TAMS 0x0000000759400000, 0x0000000759200000| Untracked -| 694|0x0000000759400000, 0x0000000759600000, 0x0000000759600000|100%| O| |TAMS 0x0000000759600000, 0x0000000759400000| Untracked -| 695|0x0000000759600000, 0x0000000759800000, 0x0000000759800000|100%| O| |TAMS 0x0000000759800000, 0x0000000759600000| Untracked -| 696|0x0000000759800000, 0x0000000759a00000, 0x0000000759a00000|100%| O| |TAMS 0x0000000759a00000, 0x0000000759800000| Untracked -| 697|0x0000000759a00000, 0x0000000759c00000, 0x0000000759c00000|100%| O| |TAMS 0x0000000759c00000, 0x0000000759a00000| Untracked -| 698|0x0000000759c00000, 0x0000000759e00000, 0x0000000759e00000|100%| O| |TAMS 0x0000000759e00000, 0x0000000759c00000| Untracked -| 699|0x0000000759e00000, 0x000000075a000000, 0x000000075a000000|100%| O| |TAMS 0x000000075a000000, 0x0000000759e00000| Untracked -| 700|0x000000075a000000, 0x000000075a200000, 0x000000075a200000|100%| O| |TAMS 0x000000075a200000, 0x000000075a000000| Untracked -| 701|0x000000075a200000, 0x000000075a400000, 0x000000075a400000|100%| O| |TAMS 0x000000075a400000, 0x000000075a200000| Untracked -| 702|0x000000075a400000, 0x000000075a600000, 0x000000075a600000|100%| O| |TAMS 0x000000075a600000, 0x000000075a400000| Untracked -| 703|0x000000075a600000, 0x000000075a800000, 0x000000075a800000|100%| O| |TAMS 0x000000075a800000, 0x000000075a600000| Untracked -| 704|0x000000075a800000, 0x000000075aa00000, 0x000000075aa00000|100%| O| |TAMS 0x000000075aa00000, 0x000000075a800000| Untracked -| 705|0x000000075aa00000, 0x000000075ac00000, 0x000000075ac00000|100%| O| |TAMS 0x000000075ac00000, 0x000000075aa00000| Untracked -| 706|0x000000075ac00000, 0x000000075ae00000, 0x000000075ae00000|100%| O| |TAMS 0x000000075ae00000, 0x000000075ac00000| Untracked -| 707|0x000000075ae00000, 0x000000075b000000, 0x000000075b000000|100%| O| |TAMS 0x000000075b000000, 0x000000075ae00000| Untracked -| 708|0x000000075b000000, 0x000000075b200000, 0x000000075b200000|100%| O| |TAMS 0x000000075b200000, 0x000000075b000000| Untracked -| 709|0x000000075b200000, 0x000000075b400000, 0x000000075b400000|100%| O| |TAMS 0x000000075b400000, 0x000000075b200000| Untracked -| 710|0x000000075b400000, 0x000000075b600000, 0x000000075b600000|100%| O| |TAMS 0x000000075b600000, 0x000000075b400000| Untracked -| 711|0x000000075b600000, 0x000000075b800000, 0x000000075b800000|100%| O| |TAMS 0x000000075b800000, 0x000000075b600000| Untracked -| 712|0x000000075b800000, 0x000000075ba00000, 0x000000075ba00000|100%| O| |TAMS 0x000000075ba00000, 0x000000075b800000| Untracked -| 713|0x000000075ba00000, 0x000000075bc00000, 0x000000075bc00000|100%| O| |TAMS 0x000000075bc00000, 0x000000075ba00000| Untracked -| 714|0x000000075bc00000, 0x000000075be00000, 0x000000075be00000|100%| O| |TAMS 0x000000075be00000, 0x000000075bc00000| Untracked -| 715|0x000000075be00000, 0x000000075c000000, 0x000000075c000000|100%| O| |TAMS 0x000000075c000000, 0x000000075be00000| Untracked -| 716|0x000000075c000000, 0x000000075c200000, 0x000000075c200000|100%| O| |TAMS 0x000000075c200000, 0x000000075c000000| Untracked -| 717|0x000000075c200000, 0x000000075c400000, 0x000000075c400000|100%| O| |TAMS 0x000000075c400000, 0x000000075c200000| Untracked -| 718|0x000000075c400000, 0x000000075c600000, 0x000000075c600000|100%| O| |TAMS 0x000000075c600000, 0x000000075c400000| Untracked -| 719|0x000000075c600000, 0x000000075c800000, 0x000000075c800000|100%| O| |TAMS 0x000000075c800000, 0x000000075c600000| Untracked -| 720|0x000000075c800000, 0x000000075ca00000, 0x000000075ca00000|100%| O| |TAMS 0x000000075ca00000, 0x000000075c800000| Untracked -| 721|0x000000075ca00000, 0x000000075cc00000, 0x000000075cc00000|100%| O| |TAMS 0x000000075cc00000, 0x000000075ca00000| Untracked -| 722|0x000000075cc00000, 0x000000075ce00000, 0x000000075ce00000|100%| O| |TAMS 0x000000075ce00000, 0x000000075cc00000| Untracked -| 723|0x000000075ce00000, 0x000000075d000000, 0x000000075d000000|100%| O| |TAMS 0x000000075d000000, 0x000000075ce00000| Untracked -| 724|0x000000075d000000, 0x000000075d200000, 0x000000075d200000|100%| O| |TAMS 0x000000075d200000, 0x000000075d000000| Untracked -| 725|0x000000075d200000, 0x000000075d400000, 0x000000075d400000|100%| O| |TAMS 0x000000075d400000, 0x000000075d200000| Untracked -| 726|0x000000075d400000, 0x000000075d600000, 0x000000075d600000|100%| O| |TAMS 0x000000075d600000, 0x000000075d400000| Untracked -| 727|0x000000075d600000, 0x000000075d800000, 0x000000075d800000|100%| O| |TAMS 0x000000075d800000, 0x000000075d600000| Untracked -| 728|0x000000075d800000, 0x000000075da00000, 0x000000075da00000|100%| O| |TAMS 0x000000075da00000, 0x000000075d800000| Untracked -| 729|0x000000075da00000, 0x000000075dc00000, 0x000000075dc00000|100%| O| |TAMS 0x000000075dc00000, 0x000000075da00000| Untracked -| 730|0x000000075dc00000, 0x000000075de00000, 0x000000075de00000|100%| O| |TAMS 0x000000075de00000, 0x000000075dc00000| Untracked -| 731|0x000000075de00000, 0x000000075e000000, 0x000000075e000000|100%| O| |TAMS 0x000000075e000000, 0x000000075de00000| Untracked -| 732|0x000000075e000000, 0x000000075e200000, 0x000000075e200000|100%| O| |TAMS 0x000000075e200000, 0x000000075e000000| Untracked -| 733|0x000000075e200000, 0x000000075e400000, 0x000000075e400000|100%| O| |TAMS 0x000000075e400000, 0x000000075e200000| Untracked -| 734|0x000000075e400000, 0x000000075e600000, 0x000000075e600000|100%| O| |TAMS 0x000000075e600000, 0x000000075e400000| Untracked -| 735|0x000000075e600000, 0x000000075e800000, 0x000000075e800000|100%| O| |TAMS 0x000000075e800000, 0x000000075e600000| Untracked -| 736|0x000000075e800000, 0x000000075ea00000, 0x000000075ea00000|100%| O| |TAMS 0x000000075ea00000, 0x000000075e800000| Untracked -| 737|0x000000075ea00000, 0x000000075ec00000, 0x000000075ec00000|100%| O| |TAMS 0x000000075ec00000, 0x000000075ea00000| Untracked -| 738|0x000000075ec00000, 0x000000075ee00000, 0x000000075ee00000|100%| O| |TAMS 0x000000075ee00000, 0x000000075ec00000| Untracked -| 739|0x000000075ee00000, 0x000000075f000000, 0x000000075f000000|100%| O| |TAMS 0x000000075f000000, 0x000000075ee00000| Untracked -| 740|0x000000075f000000, 0x000000075f200000, 0x000000075f200000|100%| O| |TAMS 0x000000075f200000, 0x000000075f000000| Untracked -| 741|0x000000075f200000, 0x000000075f400000, 0x000000075f400000|100%| O| |TAMS 0x000000075f400000, 0x000000075f200000| Untracked -| 742|0x000000075f400000, 0x000000075f600000, 0x000000075f600000|100%| O| |TAMS 0x000000075f600000, 0x000000075f400000| Untracked -| 743|0x000000075f600000, 0x000000075f800000, 0x000000075f800000|100%| O| |TAMS 0x000000075f800000, 0x000000075f600000| Untracked -| 744|0x000000075f800000, 0x000000075fa00000, 0x000000075fa00000|100%| O| |TAMS 0x000000075fa00000, 0x000000075f800000| Untracked -| 745|0x000000075fa00000, 0x000000075fc00000, 0x000000075fc00000|100%| O| |TAMS 0x000000075fc00000, 0x000000075fa00000| Untracked -| 746|0x000000075fc00000, 0x000000075fe00000, 0x000000075fe00000|100%| O| |TAMS 0x000000075fe00000, 0x000000075fc00000| Untracked -| 747|0x000000075fe00000, 0x0000000760000000, 0x0000000760000000|100%| O| |TAMS 0x0000000760000000, 0x000000075fe00000| Untracked -| 748|0x0000000760000000, 0x0000000760200000, 0x0000000760200000|100%| O| |TAMS 0x0000000760200000, 0x0000000760000000| Untracked -| 749|0x0000000760200000, 0x0000000760400000, 0x0000000760400000|100%| O| |TAMS 0x0000000760400000, 0x0000000760200000| Untracked -| 750|0x0000000760400000, 0x0000000760600000, 0x0000000760600000|100%| O| |TAMS 0x0000000760600000, 0x0000000760400000| Untracked -| 751|0x0000000760600000, 0x0000000760800000, 0x0000000760800000|100%| O| |TAMS 0x0000000760800000, 0x0000000760600000| Untracked -| 752|0x0000000760800000, 0x0000000760a00000, 0x0000000760a00000|100%| O| |TAMS 0x0000000760a00000, 0x0000000760800000| Untracked -| 753|0x0000000760a00000, 0x0000000760c00000, 0x0000000760c00000|100%| O| |TAMS 0x0000000760c00000, 0x0000000760a00000| Untracked -| 754|0x0000000760c00000, 0x0000000760e00000, 0x0000000760e00000|100%| O| |TAMS 0x0000000760e00000, 0x0000000760c00000| Untracked -| 755|0x0000000760e00000, 0x0000000761000000, 0x0000000761000000|100%| O| |TAMS 0x0000000761000000, 0x0000000760e00000| Untracked -| 756|0x0000000761000000, 0x0000000761200000, 0x0000000761200000|100%| O| |TAMS 0x0000000761200000, 0x0000000761000000| Untracked -| 757|0x0000000761200000, 0x0000000761400000, 0x0000000761400000|100%| O| |TAMS 0x0000000761400000, 0x0000000761200000| Untracked -| 758|0x0000000761400000, 0x0000000761600000, 0x0000000761600000|100%| O| |TAMS 0x0000000761600000, 0x0000000761400000| Untracked -| 759|0x0000000761600000, 0x0000000761800000, 0x0000000761800000|100%| O| |TAMS 0x0000000761800000, 0x0000000761600000| Untracked -| 760|0x0000000761800000, 0x0000000761a00000, 0x0000000761a00000|100%| O| |TAMS 0x0000000761a00000, 0x0000000761800000| Untracked -| 761|0x0000000761a00000, 0x0000000761c00000, 0x0000000761c00000|100%| O| |TAMS 0x0000000761c00000, 0x0000000761a00000| Untracked -| 762|0x0000000761c00000, 0x0000000761e00000, 0x0000000761e00000|100%| O| |TAMS 0x0000000761e00000, 0x0000000761c00000| Untracked -| 763|0x0000000761e00000, 0x0000000762000000, 0x0000000762000000|100%| O| |TAMS 0x0000000762000000, 0x0000000761e00000| Untracked -| 764|0x0000000762000000, 0x0000000762200000, 0x0000000762200000|100%| O| |TAMS 0x0000000762200000, 0x0000000762000000| Untracked -| 765|0x0000000762200000, 0x0000000762400000, 0x0000000762400000|100%| O| |TAMS 0x0000000762400000, 0x0000000762200000| Untracked -| 766|0x0000000762400000, 0x0000000762600000, 0x0000000762600000|100%| O| |TAMS 0x0000000762600000, 0x0000000762400000| Untracked -| 767|0x0000000762600000, 0x0000000762800000, 0x0000000762800000|100%| O| |TAMS 0x0000000762800000, 0x0000000762600000| Untracked -| 768|0x0000000762800000, 0x0000000762a00000, 0x0000000762a00000|100%| O| |TAMS 0x0000000762a00000, 0x0000000762800000| Untracked -| 769|0x0000000762a00000, 0x0000000762c00000, 0x0000000762c00000|100%| O| |TAMS 0x0000000762c00000, 0x0000000762a00000| Untracked -| 770|0x0000000762c00000, 0x0000000762e00000, 0x0000000762e00000|100%| O| |TAMS 0x0000000762e00000, 0x0000000762c00000| Untracked -| 771|0x0000000762e00000, 0x0000000763000000, 0x0000000763000000|100%| O| |TAMS 0x0000000763000000, 0x0000000762e00000| Untracked -| 772|0x0000000763000000, 0x0000000763200000, 0x0000000763200000|100%| O| |TAMS 0x0000000763200000, 0x0000000763000000| Untracked -| 773|0x0000000763200000, 0x0000000763400000, 0x0000000763400000|100%| O| |TAMS 0x0000000763400000, 0x0000000763200000| Untracked -| 774|0x0000000763400000, 0x0000000763600000, 0x0000000763600000|100%| O| |TAMS 0x0000000763600000, 0x0000000763400000| Untracked -| 775|0x0000000763600000, 0x0000000763800000, 0x0000000763800000|100%| O| |TAMS 0x0000000763800000, 0x0000000763600000| Untracked -| 776|0x0000000763800000, 0x0000000763a00000, 0x0000000763a00000|100%| O| |TAMS 0x0000000763a00000, 0x0000000763800000| Untracked -| 777|0x0000000763a00000, 0x0000000763c00000, 0x0000000763c00000|100%| O| |TAMS 0x0000000763c00000, 0x0000000763a00000| Untracked -| 778|0x0000000763c00000, 0x0000000763e00000, 0x0000000763e00000|100%| O| |TAMS 0x0000000763e00000, 0x0000000763c00000| Untracked -| 779|0x0000000763e00000, 0x0000000764000000, 0x0000000764000000|100%| O| |TAMS 0x0000000763e00000, 0x0000000763e00000| Untracked -| 780|0x0000000764000000, 0x0000000764200000, 0x0000000764200000|100%| O| |TAMS 0x0000000764000000, 0x0000000764000000| Untracked -| 781|0x0000000764200000, 0x0000000764400000, 0x0000000764400000|100%| O| |TAMS 0x0000000764200000, 0x0000000764200000| Untracked -| 782|0x0000000764400000, 0x0000000764600000, 0x0000000764600000|100%| O| |TAMS 0x0000000764400000, 0x0000000764400000| Untracked -| 783|0x0000000764600000, 0x0000000764800000, 0x0000000764800000|100%| O| |TAMS 0x0000000764600000, 0x0000000764600000| Untracked -| 784|0x0000000764800000, 0x0000000764a00000, 0x0000000764a00000|100%| O| |TAMS 0x0000000764800000, 0x0000000764800000| Untracked -| 785|0x0000000764a00000, 0x0000000764c00000, 0x0000000764c00000|100%| O| |TAMS 0x0000000764a00000, 0x0000000764a00000| Untracked -| 786|0x0000000764c00000, 0x0000000764e00000, 0x0000000764e00000|100%| O| |TAMS 0x0000000764c00000, 0x0000000764c00000| Untracked -| 787|0x0000000764e00000, 0x0000000765000000, 0x0000000765000000|100%| O| |TAMS 0x0000000764e00000, 0x0000000764e00000| Untracked -| 788|0x0000000765000000, 0x0000000765200000, 0x0000000765200000|100%| O| |TAMS 0x0000000765000000, 0x0000000765000000| Untracked -| 789|0x0000000765200000, 0x0000000765400000, 0x0000000765400000|100%| O| |TAMS 0x0000000765200000, 0x0000000765200000| Untracked -| 790|0x0000000765400000, 0x0000000765600000, 0x0000000765600000|100%| O| |TAMS 0x0000000765400000, 0x0000000765400000| Untracked -| 791|0x0000000765600000, 0x0000000765800000, 0x0000000765800000|100%| O| |TAMS 0x0000000765600000, 0x0000000765600000| Untracked -| 792|0x0000000765800000, 0x0000000765a00000, 0x0000000765a00000|100%| O| |TAMS 0x0000000765800000, 0x0000000765800000| Untracked -| 793|0x0000000765a00000, 0x0000000765c00000, 0x0000000765c00000|100%| O| |TAMS 0x0000000765a00000, 0x0000000765a00000| Untracked -| 794|0x0000000765c00000, 0x0000000765e00000, 0x0000000765e00000|100%| O| |TAMS 0x0000000765c00000, 0x0000000765c00000| Untracked -| 795|0x0000000765e00000, 0x0000000766000000, 0x0000000766000000|100%| O| |TAMS 0x0000000765e00000, 0x0000000765e00000| Untracked -| 796|0x0000000766000000, 0x0000000766200000, 0x0000000766200000|100%| O| |TAMS 0x0000000766000000, 0x0000000766000000| Untracked -| 797|0x0000000766200000, 0x0000000766400000, 0x0000000766400000|100%| O| |TAMS 0x0000000766200000, 0x0000000766200000| Untracked -| 798|0x0000000766400000, 0x0000000766600000, 0x0000000766600000|100%| O| |TAMS 0x0000000766400000, 0x0000000766400000| Untracked -| 799|0x0000000766600000, 0x0000000766800000, 0x0000000766800000|100%| O| |TAMS 0x0000000766600000, 0x0000000766600000| Untracked -| 800|0x0000000766800000, 0x0000000766a00000, 0x0000000766a00000|100%| O| |TAMS 0x0000000766800000, 0x0000000766800000| Untracked -| 801|0x0000000766a00000, 0x0000000766c00000, 0x0000000766c00000|100%| O| |TAMS 0x0000000766a00000, 0x0000000766a00000| Untracked -| 802|0x0000000766c00000, 0x0000000766e00000, 0x0000000766e00000|100%| O| |TAMS 0x0000000766c00000, 0x0000000766c00000| Untracked -| 803|0x0000000766e00000, 0x0000000767000000, 0x0000000767000000|100%| O| |TAMS 0x0000000766e00000, 0x0000000766e00000| Untracked -| 804|0x0000000767000000, 0x0000000767200000, 0x0000000767200000|100%| O| |TAMS 0x0000000767000000, 0x0000000767000000| Untracked -| 805|0x0000000767200000, 0x0000000767400000, 0x0000000767400000|100%| O| |TAMS 0x0000000767200000, 0x0000000767200000| Untracked -| 806|0x0000000767400000, 0x0000000767600000, 0x0000000767600000|100%| O| |TAMS 0x0000000767400000, 0x0000000767400000| Untracked -| 807|0x0000000767600000, 0x0000000767800000, 0x0000000767800000|100%| O| |TAMS 0x0000000767600000, 0x0000000767600000| Untracked -| 808|0x0000000767800000, 0x0000000767a00000, 0x0000000767a00000|100%| O| |TAMS 0x0000000767800000, 0x0000000767800000| Untracked -| 809|0x0000000767a00000, 0x0000000767c00000, 0x0000000767c00000|100%| O| |TAMS 0x0000000767a00000, 0x0000000767a00000| Untracked -| 810|0x0000000767c00000, 0x0000000767e00000, 0x0000000767e00000|100%| O| |TAMS 0x0000000767c00000, 0x0000000767c00000| Untracked -| 811|0x0000000767e00000, 0x0000000768000000, 0x0000000768000000|100%| O| |TAMS 0x0000000767e00000, 0x0000000767e00000| Untracked -| 812|0x0000000768000000, 0x0000000768200000, 0x0000000768200000|100%| O| |TAMS 0x0000000768000000, 0x0000000768000000| Untracked -| 813|0x0000000768200000, 0x0000000768400000, 0x0000000768400000|100%| O| |TAMS 0x0000000768200000, 0x0000000768200000| Untracked -| 814|0x0000000768400000, 0x0000000768600000, 0x0000000768600000|100%| O| |TAMS 0x0000000768400000, 0x0000000768400000| Untracked -| 815|0x0000000768600000, 0x0000000768800000, 0x0000000768800000|100%| O| |TAMS 0x0000000768600000, 0x0000000768600000| Untracked -| 816|0x0000000768800000, 0x0000000768a00000, 0x0000000768a00000|100%| O| |TAMS 0x0000000768800000, 0x0000000768800000| Untracked -| 817|0x0000000768a00000, 0x0000000768c00000, 0x0000000768c00000|100%| O| |TAMS 0x0000000768a00000, 0x0000000768a00000| Untracked -| 818|0x0000000768c00000, 0x0000000768e00000, 0x0000000768e00000|100%| O| |TAMS 0x0000000768c00000, 0x0000000768c00000| Untracked -| 819|0x0000000768e00000, 0x0000000769000000, 0x0000000769000000|100%| O| |TAMS 0x0000000769000000, 0x0000000768e00000| Untracked -| 820|0x0000000769000000, 0x0000000769200000, 0x0000000769200000|100%| O| |TAMS 0x0000000769200000, 0x0000000769000000| Untracked -| 821|0x0000000769200000, 0x0000000769400000, 0x0000000769400000|100%| O| |TAMS 0x0000000769400000, 0x0000000769200000| Untracked -| 822|0x0000000769400000, 0x0000000769600000, 0x0000000769600000|100%| O| |TAMS 0x0000000769600000, 0x0000000769400000| Untracked -| 823|0x0000000769600000, 0x0000000769800000, 0x0000000769800000|100%| O| |TAMS 0x0000000769700000, 0x0000000769600000| Untracked -| 824|0x0000000769800000, 0x0000000769a00000, 0x0000000769a00000|100%| O| |TAMS 0x0000000769800000, 0x0000000769800000| Untracked -| 825|0x0000000769a00000, 0x0000000769c00000, 0x0000000769c00000|100%| O| |TAMS 0x0000000769a00000, 0x0000000769a00000| Untracked -| 826|0x0000000769c00000, 0x0000000769e00000, 0x0000000769e00000|100%| O| |TAMS 0x0000000769c00000, 0x0000000769c00000| Untracked -| 827|0x0000000769e00000, 0x000000076a000000, 0x000000076a000000|100%| O| |TAMS 0x0000000769e00000, 0x0000000769e00000| Untracked -| 828|0x000000076a000000, 0x000000076a200000, 0x000000076a200000|100%| O| |TAMS 0x000000076a000000, 0x000000076a000000| Untracked -| 829|0x000000076a200000, 0x000000076a400000, 0x000000076a400000|100%| O| |TAMS 0x000000076a200000, 0x000000076a200000| Untracked -| 830|0x000000076a400000, 0x000000076a600000, 0x000000076a600000|100%| O| |TAMS 0x000000076a400000, 0x000000076a400000| Untracked -| 831|0x000000076a600000, 0x000000076a800000, 0x000000076a800000|100%| O| |TAMS 0x000000076a600000, 0x000000076a600000| Untracked -| 832|0x000000076a800000, 0x000000076aa00000, 0x000000076aa00000|100%| O| |TAMS 0x000000076a800000, 0x000000076a800000| Untracked -| 833|0x000000076aa00000, 0x000000076ac00000, 0x000000076ac00000|100%| O| |TAMS 0x000000076aa00000, 0x000000076aa00000| Untracked -| 834|0x000000076ac00000, 0x000000076ae00000, 0x000000076ae00000|100%| O| |TAMS 0x000000076ac00000, 0x000000076ac00000| Untracked -| 835|0x000000076ae00000, 0x000000076b000000, 0x000000076b000000|100%| O| |TAMS 0x000000076ae00000, 0x000000076ae00000| Untracked -| 836|0x000000076b000000, 0x000000076b200000, 0x000000076b200000|100%| O| |TAMS 0x000000076b000000, 0x000000076b000000| Untracked -| 837|0x000000076b200000, 0x000000076b400000, 0x000000076b400000|100%| O| |TAMS 0x000000076b200000, 0x000000076b200000| Untracked -| 838|0x000000076b400000, 0x000000076b600000, 0x000000076b600000|100%| O| |TAMS 0x000000076b400000, 0x000000076b400000| Untracked -| 839|0x000000076b600000, 0x000000076b800000, 0x000000076b800000|100%| O| |TAMS 0x000000076b600000, 0x000000076b600000| Untracked -| 840|0x000000076b800000, 0x000000076ba00000, 0x000000076ba00000|100%| O| |TAMS 0x000000076b800000, 0x000000076b800000| Untracked -| 841|0x000000076ba00000, 0x000000076bc00000, 0x000000076bc00000|100%| O| |TAMS 0x000000076ba00000, 0x000000076ba00000| Untracked -| 842|0x000000076bc00000, 0x000000076be00000, 0x000000076be00000|100%| O| |TAMS 0x000000076bc00000, 0x000000076bc00000| Untracked -| 843|0x000000076be00000, 0x000000076c000000, 0x000000076c000000|100%| O| |TAMS 0x000000076be00000, 0x000000076be00000| Untracked -| 844|0x000000076c000000, 0x000000076c200000, 0x000000076c200000|100%| O| |TAMS 0x000000076c000000, 0x000000076c000000| Untracked -| 845|0x000000076c200000, 0x000000076c400000, 0x000000076c400000|100%| O| |TAMS 0x000000076c200000, 0x000000076c200000| Untracked -| 846|0x000000076c400000, 0x000000076c600000, 0x000000076c600000|100%| O| |TAMS 0x000000076c400000, 0x000000076c400000| Untracked -| 847|0x000000076c600000, 0x000000076c800000, 0x000000076c800000|100%| O| |TAMS 0x000000076c600000, 0x000000076c600000| Untracked -| 848|0x000000076c800000, 0x000000076ca00000, 0x000000076ca00000|100%| O| |TAMS 0x000000076c800000, 0x000000076c800000| Untracked -| 849|0x000000076ca00000, 0x000000076cc00000, 0x000000076cc00000|100%| O| |TAMS 0x000000076ca00000, 0x000000076ca00000| Untracked -| 850|0x000000076cc00000, 0x000000076ce00000, 0x000000076ce00000|100%| O| |TAMS 0x000000076cc00000, 0x000000076cc00000| Untracked -| 851|0x000000076ce00000, 0x000000076d000000, 0x000000076d000000|100%| O| |TAMS 0x000000076ce00000, 0x000000076ce00000| Untracked -| 852|0x000000076d000000, 0x000000076d200000, 0x000000076d200000|100%| O| |TAMS 0x000000076d000000, 0x000000076d000000| Untracked -| 853|0x000000076d200000, 0x000000076d400000, 0x000000076d400000|100%| O| |TAMS 0x000000076d200000, 0x000000076d200000| Untracked -| 854|0x000000076d400000, 0x000000076d600000, 0x000000076d600000|100%| O| |TAMS 0x000000076d400000, 0x000000076d400000| Untracked -| 855|0x000000076d600000, 0x000000076d800000, 0x000000076d800000|100%| O| |TAMS 0x000000076d600000, 0x000000076d600000| Untracked -| 856|0x000000076d800000, 0x000000076da00000, 0x000000076da00000|100%| O| |TAMS 0x000000076d800000, 0x000000076d800000| Untracked -| 857|0x000000076da00000, 0x000000076dc00000, 0x000000076dc00000|100%| O| |TAMS 0x000000076da00000, 0x000000076da00000| Untracked -| 858|0x000000076dc00000, 0x000000076de00000, 0x000000076de00000|100%| O| |TAMS 0x000000076dc00000, 0x000000076dc00000| Untracked -| 859|0x000000076de00000, 0x000000076e000000, 0x000000076e000000|100%| O| |TAMS 0x000000076de00000, 0x000000076de00000| Untracked -| 860|0x000000076e000000, 0x000000076e200000, 0x000000076e200000|100%| O| |TAMS 0x000000076e000000, 0x000000076e000000| Untracked -| 861|0x000000076e200000, 0x000000076e400000, 0x000000076e400000|100%| O| |TAMS 0x000000076e200000, 0x000000076e200000| Untracked -| 862|0x000000076e400000, 0x000000076e600000, 0x000000076e600000|100%| O| |TAMS 0x000000076e400000, 0x000000076e400000| Untracked -| 863|0x000000076e600000, 0x000000076e800000, 0x000000076e800000|100%| O| |TAMS 0x000000076e600000, 0x000000076e600000| Untracked -| 864|0x000000076e800000, 0x000000076ea00000, 0x000000076ea00000|100%| O| |TAMS 0x000000076e800000, 0x000000076e800000| Untracked -| 865|0x000000076ea00000, 0x000000076ec00000, 0x000000076ec00000|100%| O| |TAMS 0x000000076ea00000, 0x000000076ea00000| Untracked -| 866|0x000000076ec00000, 0x000000076ee00000, 0x000000076ee00000|100%| O| |TAMS 0x000000076ec00000, 0x000000076ec00000| Untracked -| 867|0x000000076ee00000, 0x000000076f000000, 0x000000076f000000|100%| O| |TAMS 0x000000076ee00000, 0x000000076ee00000| Untracked -| 868|0x000000076f000000, 0x000000076f200000, 0x000000076f200000|100%| O| |TAMS 0x000000076f000000, 0x000000076f000000| Untracked -| 869|0x000000076f200000, 0x000000076f400000, 0x000000076f400000|100%| O| |TAMS 0x000000076f200000, 0x000000076f200000| Untracked -| 870|0x000000076f400000, 0x000000076f600000, 0x000000076f600000|100%| O| |TAMS 0x000000076f400000, 0x000000076f400000| Untracked -| 871|0x000000076f600000, 0x000000076f800000, 0x000000076f800000|100%| O| |TAMS 0x000000076f600000, 0x000000076f600000| Untracked -| 872|0x000000076f800000, 0x000000076fa00000, 0x000000076fa00000|100%| O| |TAMS 0x000000076f800000, 0x000000076f800000| Untracked -| 873|0x000000076fa00000, 0x000000076fc00000, 0x000000076fc00000|100%| O| |TAMS 0x000000076fa00000, 0x000000076fa00000| Untracked -| 874|0x000000076fc00000, 0x000000076fe00000, 0x000000076fe00000|100%| O| |TAMS 0x000000076fc00000, 0x000000076fc00000| Untracked -| 875|0x000000076fe00000, 0x0000000770000000, 0x0000000770000000|100%| O| |TAMS 0x000000076fe00000, 0x000000076fe00000| Untracked -| 876|0x0000000770000000, 0x0000000770200000, 0x0000000770200000|100%| O| |TAMS 0x0000000770000000, 0x0000000770000000| Untracked -| 877|0x0000000770200000, 0x0000000770400000, 0x0000000770400000|100%| O| |TAMS 0x0000000770200000, 0x0000000770200000| Untracked -| 878|0x0000000770400000, 0x0000000770600000, 0x0000000770600000|100%| O| |TAMS 0x0000000770400000, 0x0000000770400000| Untracked -| 879|0x0000000770600000, 0x0000000770800000, 0x0000000770800000|100%| O| |TAMS 0x0000000770600000, 0x0000000770600000| Untracked -| 880|0x0000000770800000, 0x0000000770a00000, 0x0000000770a00000|100%| O| |TAMS 0x0000000770800000, 0x0000000770800000| Untracked -| 881|0x0000000770a00000, 0x0000000770c00000, 0x0000000770c00000|100%| O| |TAMS 0x0000000770a00000, 0x0000000770a00000| Untracked -| 882|0x0000000770c00000, 0x0000000770e00000, 0x0000000770e00000|100%| O| |TAMS 0x0000000770c00000, 0x0000000770c00000| Untracked -| 883|0x0000000770e00000, 0x0000000771000000, 0x0000000771000000|100%| O| |TAMS 0x0000000770e00000, 0x0000000770e00000| Untracked -| 884|0x0000000771000000, 0x0000000771200000, 0x0000000771200000|100%| O| |TAMS 0x0000000771000000, 0x0000000771000000| Untracked -| 885|0x0000000771200000, 0x0000000771400000, 0x0000000771400000|100%| O| |TAMS 0x0000000771200000, 0x0000000771200000| Untracked -| 886|0x0000000771400000, 0x0000000771600000, 0x0000000771600000|100%| O| |TAMS 0x0000000771400000, 0x0000000771400000| Untracked -| 887|0x0000000771600000, 0x0000000771800000, 0x0000000771800000|100%| O| |TAMS 0x0000000771600000, 0x0000000771600000| Untracked -| 888|0x0000000771800000, 0x0000000771a00000, 0x0000000771a00000|100%| O| |TAMS 0x0000000771800000, 0x0000000771800000| Untracked -| 889|0x0000000771a00000, 0x0000000771c00000, 0x0000000771c00000|100%| O| |TAMS 0x0000000771a00000, 0x0000000771a00000| Untracked -| 890|0x0000000771c00000, 0x0000000771e00000, 0x0000000771e00000|100%| O| |TAMS 0x0000000771c00000, 0x0000000771c00000| Untracked -| 891|0x0000000771e00000, 0x0000000772000000, 0x0000000772000000|100%| O| |TAMS 0x0000000771e00000, 0x0000000771e00000| Untracked -| 892|0x0000000772000000, 0x0000000772200000, 0x0000000772200000|100%| O| |TAMS 0x0000000772000000, 0x0000000772000000| Untracked -| 893|0x0000000772200000, 0x0000000772400000, 0x0000000772400000|100%| O| |TAMS 0x0000000772200000, 0x0000000772200000| Untracked -| 894|0x0000000772400000, 0x0000000772600000, 0x0000000772600000|100%| O| |TAMS 0x0000000772400000, 0x0000000772400000| Untracked -| 895|0x0000000772600000, 0x0000000772800000, 0x0000000772800000|100%| O| |TAMS 0x0000000772600000, 0x0000000772600000| Untracked -| 896|0x0000000772800000, 0x0000000772a00000, 0x0000000772a00000|100%| O| |TAMS 0x0000000772800000, 0x0000000772800000| Untracked -| 897|0x0000000772a00000, 0x0000000772c00000, 0x0000000772c00000|100%| O| |TAMS 0x0000000772a00000, 0x0000000772a00000| Untracked -| 898|0x0000000772c00000, 0x0000000772e00000, 0x0000000772e00000|100%| O| |TAMS 0x0000000772c00000, 0x0000000772c00000| Untracked -| 899|0x0000000772e00000, 0x0000000773000000, 0x0000000773000000|100%| O| |TAMS 0x0000000772e00000, 0x0000000772e00000| Untracked -| 900|0x0000000773000000, 0x0000000773200000, 0x0000000773200000|100%| O| |TAMS 0x0000000773000000, 0x0000000773000000| Untracked -| 901|0x0000000773200000, 0x0000000773400000, 0x0000000773400000|100%| O| |TAMS 0x0000000773200000, 0x0000000773200000| Untracked -| 902|0x0000000773400000, 0x0000000773600000, 0x0000000773600000|100%| O| |TAMS 0x0000000773400000, 0x0000000773400000| Untracked -| 903|0x0000000773600000, 0x0000000773800000, 0x0000000773800000|100%| O| |TAMS 0x0000000773600000, 0x0000000773600000| Untracked -| 904|0x0000000773800000, 0x0000000773a00000, 0x0000000773a00000|100%| O| |TAMS 0x0000000773800000, 0x0000000773800000| Untracked -| 905|0x0000000773a00000, 0x0000000773c00000, 0x0000000773c00000|100%| O| |TAMS 0x0000000773a00000, 0x0000000773a00000| Untracked -| 906|0x0000000773c00000, 0x0000000773e00000, 0x0000000773e00000|100%| O| |TAMS 0x0000000773c00000, 0x0000000773c00000| Untracked -| 907|0x0000000773e00000, 0x0000000774000000, 0x0000000774000000|100%| O| |TAMS 0x0000000773e00000, 0x0000000773e00000| Untracked -| 908|0x0000000774000000, 0x0000000774200000, 0x0000000774200000|100%| O| |TAMS 0x0000000774000000, 0x0000000774000000| Untracked -| 909|0x0000000774200000, 0x0000000774400000, 0x0000000774400000|100%| O| |TAMS 0x0000000774200000, 0x0000000774200000| Untracked -| 910|0x0000000774400000, 0x0000000774600000, 0x0000000774600000|100%| O| |TAMS 0x0000000774400000, 0x0000000774400000| Untracked -| 911|0x0000000774600000, 0x0000000774800000, 0x0000000774800000|100%| O| |TAMS 0x0000000774600000, 0x0000000774600000| Untracked -| 912|0x0000000774800000, 0x0000000774a00000, 0x0000000774a00000|100%| O| |TAMS 0x0000000774800000, 0x0000000774800000| Untracked -| 913|0x0000000774a00000, 0x0000000774c00000, 0x0000000774c00000|100%| O| |TAMS 0x0000000774a00000, 0x0000000774a00000| Untracked -| 914|0x0000000774c00000, 0x0000000774e00000, 0x0000000774e00000|100%| O| |TAMS 0x0000000774c00000, 0x0000000774c00000| Untracked -| 915|0x0000000774e00000, 0x0000000775000000, 0x0000000775000000|100%| O| |TAMS 0x0000000774e00000, 0x0000000774e00000| Untracked -| 916|0x0000000775000000, 0x0000000775200000, 0x0000000775200000|100%| O| |TAMS 0x0000000775000000, 0x0000000775000000| Untracked -| 917|0x0000000775200000, 0x0000000775400000, 0x0000000775400000|100%| O| |TAMS 0x0000000775200000, 0x0000000775200000| Untracked -| 918|0x0000000775400000, 0x0000000775600000, 0x0000000775600000|100%| O| |TAMS 0x0000000775400000, 0x0000000775400000| Untracked -| 919|0x0000000775600000, 0x0000000775800000, 0x0000000775800000|100%| O| |TAMS 0x0000000775600000, 0x0000000775600000| Untracked -| 920|0x0000000775800000, 0x0000000775a00000, 0x0000000775a00000|100%| O| |TAMS 0x0000000775800000, 0x0000000775800000| Untracked -| 921|0x0000000775a00000, 0x0000000775c00000, 0x0000000775c00000|100%| O| |TAMS 0x0000000775a00000, 0x0000000775a00000| Untracked -| 922|0x0000000775c00000, 0x0000000775e00000, 0x0000000775e00000|100%| O| |TAMS 0x0000000775c00000, 0x0000000775c00000| Untracked -| 923|0x0000000775e00000, 0x0000000776000000, 0x0000000776000000|100%| O| |TAMS 0x0000000775e00000, 0x0000000775e00000| Untracked -| 924|0x0000000776000000, 0x0000000776200000, 0x0000000776200000|100%| O| |TAMS 0x0000000776000000, 0x0000000776000000| Untracked -| 925|0x0000000776200000, 0x0000000776400000, 0x0000000776400000|100%| O| |TAMS 0x0000000776200000, 0x0000000776200000| Untracked -| 926|0x0000000776400000, 0x0000000776600000, 0x0000000776600000|100%| O| |TAMS 0x0000000776400000, 0x0000000776400000| Untracked -| 927|0x0000000776600000, 0x0000000776800000, 0x0000000776800000|100%| O| |TAMS 0x0000000776600000, 0x0000000776600000| Untracked -| 928|0x0000000776800000, 0x0000000776a00000, 0x0000000776a00000|100%| O| |TAMS 0x0000000776800000, 0x0000000776800000| Untracked -| 929|0x0000000776a00000, 0x0000000776c00000, 0x0000000776c00000|100%| O| |TAMS 0x0000000776a00000, 0x0000000776a00000| Untracked -| 930|0x0000000776c00000, 0x0000000776e00000, 0x0000000776e00000|100%| O| |TAMS 0x0000000776c00000, 0x0000000776c00000| Untracked -| 931|0x0000000776e00000, 0x0000000777000000, 0x0000000777000000|100%| O| |TAMS 0x0000000776e00000, 0x0000000776e00000| Untracked -| 932|0x0000000777000000, 0x0000000777200000, 0x0000000777200000|100%| O| |TAMS 0x0000000777000000, 0x0000000777000000| Untracked -| 933|0x0000000777200000, 0x0000000777400000, 0x0000000777400000|100%| O| |TAMS 0x0000000777200000, 0x0000000777200000| Untracked -| 934|0x0000000777400000, 0x0000000777600000, 0x0000000777600000|100%| O| |TAMS 0x0000000777400000, 0x0000000777400000| Untracked -| 935|0x0000000777600000, 0x0000000777800000, 0x0000000777800000|100%| O| |TAMS 0x0000000777600000, 0x0000000777600000| Untracked -| 936|0x0000000777800000, 0x0000000777a00000, 0x0000000777a00000|100%| O| |TAMS 0x0000000777800000, 0x0000000777800000| Untracked -| 937|0x0000000777a00000, 0x0000000777c00000, 0x0000000777c00000|100%| O| |TAMS 0x0000000777a00000, 0x0000000777a00000| Untracked -| 938|0x0000000777c00000, 0x0000000777e00000, 0x0000000777e00000|100%| O| |TAMS 0x0000000777c00000, 0x0000000777c00000| Untracked -| 939|0x0000000777e00000, 0x0000000778000000, 0x0000000778000000|100%| O| |TAMS 0x0000000777e00000, 0x0000000777e00000| Untracked -| 940|0x0000000778000000, 0x0000000778200000, 0x0000000778200000|100%| O| |TAMS 0x0000000778000000, 0x0000000778000000| Untracked -| 941|0x0000000778200000, 0x0000000778400000, 0x0000000778400000|100%| O| |TAMS 0x0000000778200000, 0x0000000778200000| Untracked -| 942|0x0000000778400000, 0x0000000778600000, 0x0000000778600000|100%| O| |TAMS 0x0000000778400000, 0x0000000778400000| Untracked -| 943|0x0000000778600000, 0x0000000778800000, 0x0000000778800000|100%| O| |TAMS 0x0000000778600000, 0x0000000778600000| Untracked -| 944|0x0000000778800000, 0x0000000778a00000, 0x0000000778a00000|100%| O| |TAMS 0x0000000778800000, 0x0000000778800000| Untracked -| 945|0x0000000778a00000, 0x0000000778c00000, 0x0000000778c00000|100%| O| |TAMS 0x0000000778a00000, 0x0000000778a00000| Untracked -| 946|0x0000000778c00000, 0x0000000778e00000, 0x0000000778e00000|100%| O| |TAMS 0x0000000778c00000, 0x0000000778c00000| Untracked -| 947|0x0000000778e00000, 0x0000000779000000, 0x0000000779000000|100%| O| |TAMS 0x0000000778e00000, 0x0000000778e00000| Untracked -| 948|0x0000000779000000, 0x0000000779200000, 0x0000000779200000|100%| O| |TAMS 0x0000000779000000, 0x0000000779000000| Untracked -| 949|0x0000000779200000, 0x0000000779400000, 0x0000000779400000|100%| O| |TAMS 0x0000000779200000, 0x0000000779200000| Untracked -| 950|0x0000000779400000, 0x0000000779600000, 0x0000000779600000|100%| O| |TAMS 0x0000000779400000, 0x0000000779400000| Untracked -| 951|0x0000000779600000, 0x0000000779800000, 0x0000000779800000|100%| O| |TAMS 0x0000000779600000, 0x0000000779600000| Untracked -| 952|0x0000000779800000, 0x0000000779a00000, 0x0000000779a00000|100%| O| |TAMS 0x0000000779800000, 0x0000000779800000| Untracked -| 953|0x0000000779a00000, 0x0000000779c00000, 0x0000000779c00000|100%| O| |TAMS 0x0000000779a00000, 0x0000000779a00000| Untracked -| 954|0x0000000779c00000, 0x0000000779e00000, 0x0000000779e00000|100%| O| |TAMS 0x0000000779c00000, 0x0000000779c00000| Untracked -| 955|0x0000000779e00000, 0x000000077a000000, 0x000000077a000000|100%| O| |TAMS 0x0000000779e00000, 0x0000000779e00000| Untracked -| 956|0x000000077a000000, 0x000000077a200000, 0x000000077a200000|100%| O| |TAMS 0x000000077a000000, 0x000000077a000000| Untracked -| 957|0x000000077a200000, 0x000000077a400000, 0x000000077a400000|100%| O| |TAMS 0x000000077a200000, 0x000000077a200000| Untracked -| 958|0x000000077a400000, 0x000000077a600000, 0x000000077a600000|100%| O| |TAMS 0x000000077a400000, 0x000000077a400000| Untracked -| 959|0x000000077a600000, 0x000000077a800000, 0x000000077a800000|100%| O| |TAMS 0x000000077a600000, 0x000000077a600000| Untracked -| 960|0x000000077a800000, 0x000000077aa00000, 0x000000077aa00000|100%| O| |TAMS 0x000000077a800000, 0x000000077a800000| Untracked -| 961|0x000000077aa00000, 0x000000077ac00000, 0x000000077ac00000|100%| O| |TAMS 0x000000077aa00000, 0x000000077aa00000| Untracked -| 962|0x000000077ac00000, 0x000000077ae00000, 0x000000077ae00000|100%| O| |TAMS 0x000000077ac00000, 0x000000077ac00000| Untracked -| 963|0x000000077ae00000, 0x000000077b000000, 0x000000077b000000|100%| O| |TAMS 0x000000077ae00000, 0x000000077ae00000| Untracked -| 964|0x000000077b000000, 0x000000077b200000, 0x000000077b200000|100%| O| |TAMS 0x000000077b000000, 0x000000077b000000| Untracked -| 965|0x000000077b200000, 0x000000077b400000, 0x000000077b400000|100%| O| |TAMS 0x000000077b200000, 0x000000077b200000| Untracked -| 966|0x000000077b400000, 0x000000077b600000, 0x000000077b600000|100%| O| |TAMS 0x000000077b400000, 0x000000077b400000| Untracked -| 967|0x000000077b600000, 0x000000077b800000, 0x000000077b800000|100%| O| |TAMS 0x000000077b600000, 0x000000077b600000| Untracked -| 968|0x000000077b800000, 0x000000077ba00000, 0x000000077ba00000|100%| O| |TAMS 0x000000077b800000, 0x000000077b800000| Untracked -| 969|0x000000077ba00000, 0x000000077bc00000, 0x000000077bc00000|100%| O| |TAMS 0x000000077ba00000, 0x000000077ba00000| Untracked -| 970|0x000000077bc00000, 0x000000077be00000, 0x000000077be00000|100%| O| |TAMS 0x000000077bc00000, 0x000000077bc00000| Untracked -| 971|0x000000077be00000, 0x000000077c000000, 0x000000077c000000|100%| O| |TAMS 0x000000077be00000, 0x000000077be00000| Untracked -| 972|0x000000077c000000, 0x000000077c200000, 0x000000077c200000|100%| O| |TAMS 0x000000077c000000, 0x000000077c000000| Untracked -| 973|0x000000077c200000, 0x000000077c400000, 0x000000077c400000|100%| O| |TAMS 0x000000077c200000, 0x000000077c200000| Untracked -| 974|0x000000077c400000, 0x000000077c600000, 0x000000077c600000|100%| O| |TAMS 0x000000077c400000, 0x000000077c400000| Untracked -| 975|0x000000077c600000, 0x000000077c800000, 0x000000077c800000|100%| O| |TAMS 0x000000077c600000, 0x000000077c600000| Untracked -| 976|0x000000077c800000, 0x000000077ca00000, 0x000000077ca00000|100%| O| |TAMS 0x000000077c800000, 0x000000077c800000| Untracked -| 977|0x000000077ca00000, 0x000000077cc00000, 0x000000077cc00000|100%| O| |TAMS 0x000000077ca00000, 0x000000077ca00000| Untracked -| 978|0x000000077cc00000, 0x000000077ce00000, 0x000000077ce00000|100%| O| |TAMS 0x000000077cc00000, 0x000000077cc00000| Untracked -| 979|0x000000077ce00000, 0x000000077d000000, 0x000000077d000000|100%| O| |TAMS 0x000000077ce00000, 0x000000077ce00000| Untracked -| 980|0x000000077d000000, 0x000000077d200000, 0x000000077d200000|100%| O| |TAMS 0x000000077d000000, 0x000000077d000000| Untracked -| 981|0x000000077d200000, 0x000000077d400000, 0x000000077d400000|100%| O| |TAMS 0x000000077d200000, 0x000000077d200000| Untracked -| 982|0x000000077d400000, 0x000000077d600000, 0x000000077d600000|100%| O| |TAMS 0x000000077d400000, 0x000000077d400000| Untracked -| 983|0x000000077d600000, 0x000000077d800000, 0x000000077d800000|100%| O| |TAMS 0x000000077d600000, 0x000000077d600000| Untracked -| 984|0x000000077d800000, 0x000000077da00000, 0x000000077da00000|100%| O| |TAMS 0x000000077d800000, 0x000000077d800000| Untracked -| 985|0x000000077da00000, 0x000000077dc00000, 0x000000077dc00000|100%| O| |TAMS 0x000000077da00000, 0x000000077da00000| Untracked -| 986|0x000000077dc00000, 0x000000077de00000, 0x000000077de00000|100%| O| |TAMS 0x000000077dc00000, 0x000000077dc00000| Untracked -| 987|0x000000077de00000, 0x000000077e000000, 0x000000077e000000|100%| O| |TAMS 0x000000077de00000, 0x000000077de00000| Untracked -| 988|0x000000077e000000, 0x000000077e200000, 0x000000077e200000|100%| O| |TAMS 0x000000077e000000, 0x000000077e000000| Untracked -| 989|0x000000077e200000, 0x000000077e400000, 0x000000077e400000|100%| O| |TAMS 0x000000077e200000, 0x000000077e200000| Untracked -| 990|0x000000077e400000, 0x000000077e600000, 0x000000077e600000|100%| O| |TAMS 0x000000077e400000, 0x000000077e400000| Untracked -| 991|0x000000077e600000, 0x000000077e800000, 0x000000077e800000|100%| O| |TAMS 0x000000077e600000, 0x000000077e600000| Untracked -| 992|0x000000077e800000, 0x000000077ea00000, 0x000000077ea00000|100%| O| |TAMS 0x000000077e800000, 0x000000077e800000| Untracked -| 993|0x000000077ea00000, 0x000000077ec00000, 0x000000077ec00000|100%| O| |TAMS 0x000000077ea00000, 0x000000077ea00000| Untracked -| 994|0x000000077ec00000, 0x000000077ee00000, 0x000000077ee00000|100%| O| |TAMS 0x000000077ec00000, 0x000000077ec00000| Untracked -| 995|0x000000077ee00000, 0x000000077f000000, 0x000000077f000000|100%| O| |TAMS 0x000000077ee00000, 0x000000077ee00000| Untracked -| 996|0x000000077f000000, 0x000000077f200000, 0x000000077f200000|100%| O| |TAMS 0x000000077f000000, 0x000000077f000000| Untracked -| 997|0x000000077f200000, 0x000000077f400000, 0x000000077f400000|100%| O| |TAMS 0x000000077f200000, 0x000000077f200000| Untracked -| 998|0x000000077f400000, 0x000000077f600000, 0x000000077f600000|100%| O| |TAMS 0x000000077f400000, 0x000000077f400000| Untracked -| 999|0x000000077f600000, 0x000000077f800000, 0x000000077f800000|100%| O| |TAMS 0x000000077f600000, 0x000000077f600000| Untracked -|1000|0x000000077f800000, 0x000000077fa00000, 0x000000077fa00000|100%| O| |TAMS 0x000000077f800000, 0x000000077f800000| Untracked -|1001|0x000000077fa00000, 0x000000077fc00000, 0x000000077fc00000|100%| O| |TAMS 0x000000077fa00000, 0x000000077fa00000| Untracked -|1002|0x000000077fc00000, 0x000000077fe00000, 0x000000077fe00000|100%| O| |TAMS 0x000000077fc00000, 0x000000077fc00000| Untracked -|1003|0x000000077fe00000, 0x0000000780000000, 0x0000000780000000|100%| O| |TAMS 0x000000077fe00000, 0x000000077fe00000| Untracked -|1004|0x0000000780000000, 0x0000000780200000, 0x0000000780200000|100%| O| |TAMS 0x0000000780000000, 0x0000000780000000| Untracked -|1005|0x0000000780200000, 0x0000000780400000, 0x0000000780400000|100%| O| |TAMS 0x0000000780200000, 0x0000000780200000| Untracked -|1006|0x0000000780400000, 0x0000000780600000, 0x0000000780600000|100%| O| |TAMS 0x0000000780400000, 0x0000000780400000| Untracked -|1007|0x0000000780600000, 0x0000000780800000, 0x0000000780800000|100%| O| |TAMS 0x0000000780600000, 0x0000000780600000| Untracked -|1008|0x0000000780800000, 0x0000000780a00000, 0x0000000780a00000|100%| O| |TAMS 0x0000000780800000, 0x0000000780800000| Untracked -|1009|0x0000000780a00000, 0x0000000780c00000, 0x0000000780c00000|100%| O| |TAMS 0x0000000780a00000, 0x0000000780a00000| Untracked -|1010|0x0000000780c00000, 0x0000000780e00000, 0x0000000780e00000|100%| O| |TAMS 0x0000000780c00000, 0x0000000780c00000| Untracked -|1011|0x0000000780e00000, 0x0000000781000000, 0x0000000781000000|100%| O| |TAMS 0x0000000780e00000, 0x0000000780e00000| Untracked -|1012|0x0000000781000000, 0x0000000781200000, 0x0000000781200000|100%| O| |TAMS 0x0000000781000000, 0x0000000781000000| Untracked -|1013|0x0000000781200000, 0x0000000781400000, 0x0000000781400000|100%| O| |TAMS 0x0000000781200000, 0x0000000781200000| Untracked -|1014|0x0000000781400000, 0x0000000781600000, 0x0000000781600000|100%| O| |TAMS 0x0000000781400000, 0x0000000781400000| Untracked -|1015|0x0000000781600000, 0x0000000781800000, 0x0000000781800000|100%| O| |TAMS 0x0000000781600000, 0x0000000781600000| Untracked -|1016|0x0000000781800000, 0x0000000781a00000, 0x0000000781a00000|100%| O| |TAMS 0x0000000781800000, 0x0000000781800000| Untracked -|1017|0x0000000781a00000, 0x0000000781c00000, 0x0000000781c00000|100%| O| |TAMS 0x0000000781a00000, 0x0000000781a00000| Untracked -|1018|0x0000000781c00000, 0x0000000781e00000, 0x0000000781e00000|100%| O| |TAMS 0x0000000781c00000, 0x0000000781c00000| Untracked -|1019|0x0000000781e00000, 0x0000000782000000, 0x0000000782000000|100%| O| |TAMS 0x0000000781e00000, 0x0000000781e00000| Untracked -|1020|0x0000000782000000, 0x0000000782200000, 0x0000000782200000|100%| O| |TAMS 0x0000000782000000, 0x0000000782000000| Untracked -|1021|0x0000000782200000, 0x0000000782400000, 0x0000000782400000|100%| O| |TAMS 0x0000000782200000, 0x0000000782200000| Untracked -|1022|0x0000000782400000, 0x0000000782600000, 0x0000000782600000|100%| O| |TAMS 0x0000000782400000, 0x0000000782400000| Untracked -|1023|0x0000000782600000, 0x0000000782800000, 0x0000000782800000|100%| O| |TAMS 0x0000000782600000, 0x0000000782600000| Untracked -|1024|0x0000000782800000, 0x0000000782a00000, 0x0000000782a00000|100%| O| |TAMS 0x0000000782800000, 0x0000000782800000| Untracked -|1025|0x0000000782a00000, 0x0000000782c00000, 0x0000000782c00000|100%| O| |TAMS 0x0000000782a00000, 0x0000000782a00000| Untracked -|1026|0x0000000782c00000, 0x0000000782e00000, 0x0000000782e00000|100%| O| |TAMS 0x0000000782c00000, 0x0000000782c00000| Untracked -|1027|0x0000000782e00000, 0x0000000783000000, 0x0000000783000000|100%| O| |TAMS 0x0000000782e00000, 0x0000000782e00000| Untracked -|1028|0x0000000783000000, 0x0000000783200000, 0x0000000783200000|100%| O| |TAMS 0x0000000783000000, 0x0000000783000000| Untracked -|1029|0x0000000783200000, 0x0000000783400000, 0x0000000783400000|100%| O| |TAMS 0x0000000783200000, 0x0000000783200000| Untracked -|1030|0x0000000783400000, 0x0000000783600000, 0x0000000783600000|100%| O| |TAMS 0x0000000783400000, 0x0000000783400000| Untracked -|1031|0x0000000783600000, 0x0000000783800000, 0x0000000783800000|100%| O| |TAMS 0x0000000783600000, 0x0000000783600000| Untracked -|1032|0x0000000783800000, 0x0000000783a00000, 0x0000000783a00000|100%| O| |TAMS 0x0000000783800000, 0x0000000783800000| Untracked -|1033|0x0000000783a00000, 0x0000000783c00000, 0x0000000783c00000|100%| O| |TAMS 0x0000000783a00000, 0x0000000783a00000| Untracked -|1034|0x0000000783c00000, 0x0000000783e00000, 0x0000000783e00000|100%| O| |TAMS 0x0000000783c00000, 0x0000000783c00000| Untracked -|1035|0x0000000783e00000, 0x0000000784000000, 0x0000000784000000|100%| O| |TAMS 0x0000000783e00000, 0x0000000783e00000| Untracked -|1036|0x0000000784000000, 0x0000000784200000, 0x0000000784200000|100%| O| |TAMS 0x0000000784000000, 0x0000000784000000| Untracked -|1037|0x0000000784200000, 0x0000000784400000, 0x0000000784400000|100%| O| |TAMS 0x0000000784200000, 0x0000000784200000| Untracked -|1038|0x0000000784400000, 0x0000000784400000, 0x0000000784600000| 0%| F| |TAMS 0x0000000784400000, 0x0000000784400000| Untracked -|1039|0x0000000784600000, 0x0000000784800000, 0x0000000784800000|100%| O| |TAMS 0x0000000784600000, 0x0000000784600000| Untracked -|1040|0x0000000784800000, 0x0000000784a00000, 0x0000000784a00000|100%| O| |TAMS 0x0000000784800000, 0x0000000784800000| Untracked -|1041|0x0000000784a00000, 0x0000000784c00000, 0x0000000784c00000|100%| O| |TAMS 0x0000000784a00000, 0x0000000784a00000| Untracked -|1042|0x0000000784c00000, 0x0000000784e00000, 0x0000000784e00000|100%| O| |TAMS 0x0000000784c00000, 0x0000000784c00000| Untracked -|1043|0x0000000784e00000, 0x0000000785000000, 0x0000000785000000|100%| O| |TAMS 0x0000000784e00000, 0x0000000784e00000| Untracked -|1044|0x0000000785000000, 0x0000000785200000, 0x0000000785200000|100%| O| |TAMS 0x0000000785000000, 0x0000000785000000| Untracked -|1045|0x0000000785200000, 0x0000000785400000, 0x0000000785400000|100%| O| |TAMS 0x0000000785200000, 0x0000000785200000| Untracked -|1046|0x0000000785400000, 0x0000000785600000, 0x0000000785600000|100%| O| |TAMS 0x0000000785400000, 0x0000000785400000| Untracked -|1047|0x0000000785600000, 0x0000000785800000, 0x0000000785800000|100%| O| |TAMS 0x0000000785600000, 0x0000000785600000| Untracked -|1048|0x0000000785800000, 0x0000000785a00000, 0x0000000785a00000|100%| O| |TAMS 0x0000000785800000, 0x0000000785800000| Untracked -|1049|0x0000000785a00000, 0x0000000785c00000, 0x0000000785c00000|100%| O| |TAMS 0x0000000785a00000, 0x0000000785a00000| Untracked -|1050|0x0000000785c00000, 0x0000000785e00000, 0x0000000785e00000|100%| O| |TAMS 0x0000000785c00000, 0x0000000785c00000| Untracked -|1051|0x0000000785e00000, 0x0000000786000000, 0x0000000786000000|100%| O| |TAMS 0x0000000785e00000, 0x0000000785e00000| Untracked -|1052|0x0000000786000000, 0x0000000786200000, 0x0000000786200000|100%| O| |TAMS 0x0000000786000000, 0x0000000786000000| Untracked -|1053|0x0000000786200000, 0x0000000786400000, 0x0000000786400000|100%| O| |TAMS 0x0000000786200000, 0x0000000786200000| Untracked -|1054|0x0000000786400000, 0x0000000786600000, 0x0000000786600000|100%| O| |TAMS 0x0000000786400000, 0x0000000786400000| Untracked -|1055|0x0000000786600000, 0x0000000786800000, 0x0000000786800000|100%| O| |TAMS 0x0000000786600000, 0x0000000786600000| Untracked -|1056|0x0000000786800000, 0x0000000786a00000, 0x0000000786a00000|100%| O| |TAMS 0x0000000786800000, 0x0000000786800000| Untracked -|1057|0x0000000786a00000, 0x0000000786c00000, 0x0000000786c00000|100%| O| |TAMS 0x0000000786a00000, 0x0000000786a00000| Untracked -|1058|0x0000000786c00000, 0x0000000786e00000, 0x0000000786e00000|100%| O| |TAMS 0x0000000786c00000, 0x0000000786c00000| Untracked -|1059|0x0000000786e00000, 0x0000000787000000, 0x0000000787000000|100%| O| |TAMS 0x0000000786e00000, 0x0000000786e00000| Untracked -|1060|0x0000000787000000, 0x0000000787200000, 0x0000000787200000|100%| O| |TAMS 0x0000000787000000, 0x0000000787000000| Untracked -|1061|0x0000000787200000, 0x0000000787400000, 0x0000000787400000|100%| O| |TAMS 0x0000000787200000, 0x0000000787200000| Untracked -|1062|0x0000000787400000, 0x0000000787600000, 0x0000000787600000|100%| O| |TAMS 0x0000000787400000, 0x0000000787400000| Untracked -|1063|0x0000000787600000, 0x0000000787800000, 0x0000000787800000|100%| O| |TAMS 0x0000000787600000, 0x0000000787600000| Untracked -|1064|0x0000000787800000, 0x0000000787a00000, 0x0000000787a00000|100%| O| |TAMS 0x0000000787800000, 0x0000000787800000| Untracked -|1065|0x0000000787a00000, 0x0000000787c00000, 0x0000000787c00000|100%| O| |TAMS 0x0000000787a00000, 0x0000000787a00000| Untracked -|1066|0x0000000787c00000, 0x0000000787e00000, 0x0000000787e00000|100%| O| |TAMS 0x0000000787c00000, 0x0000000787c00000| Untracked -|1067|0x0000000787e00000, 0x0000000788000000, 0x0000000788000000|100%| O| |TAMS 0x0000000787e00000, 0x0000000787e00000| Untracked -|1068|0x0000000788000000, 0x0000000788200000, 0x0000000788200000|100%| O| |TAMS 0x0000000788000000, 0x0000000788000000| Untracked -|1069|0x0000000788200000, 0x0000000788400000, 0x0000000788400000|100%| O| |TAMS 0x0000000788200000, 0x0000000788200000| Untracked -|1070|0x0000000788400000, 0x0000000788600000, 0x0000000788600000|100%| O| |TAMS 0x0000000788400000, 0x0000000788400000| Untracked -|1071|0x0000000788600000, 0x0000000788800000, 0x0000000788800000|100%| O| |TAMS 0x0000000788600000, 0x0000000788600000| Untracked -|1072|0x0000000788800000, 0x0000000788a00000, 0x0000000788a00000|100%| O| |TAMS 0x0000000788800000, 0x0000000788800000| Untracked -|1073|0x0000000788a00000, 0x0000000788c00000, 0x0000000788c00000|100%| O| |TAMS 0x0000000788a00000, 0x0000000788a00000| Untracked -|1074|0x0000000788c00000, 0x0000000788e00000, 0x0000000788e00000|100%| O| |TAMS 0x0000000788c00000, 0x0000000788c00000| Untracked -|1075|0x0000000788e00000, 0x0000000789000000, 0x0000000789000000|100%| O| |TAMS 0x0000000788e00000, 0x0000000788e00000| Untracked -|1076|0x0000000789000000, 0x0000000789200000, 0x0000000789200000|100%| O| |TAMS 0x0000000789000000, 0x0000000789000000| Untracked -|1077|0x0000000789200000, 0x0000000789400000, 0x0000000789400000|100%| O| |TAMS 0x0000000789200000, 0x0000000789200000| Untracked -|1078|0x0000000789400000, 0x0000000789600000, 0x0000000789600000|100%| O| |TAMS 0x0000000789400000, 0x0000000789400000| Untracked -|1079|0x0000000789600000, 0x0000000789800000, 0x0000000789800000|100%| O| |TAMS 0x0000000789600000, 0x0000000789600000| Untracked -|1080|0x0000000789800000, 0x0000000789a00000, 0x0000000789a00000|100%| O| |TAMS 0x0000000789800000, 0x0000000789800000| Untracked -|1081|0x0000000789a00000, 0x0000000789c00000, 0x0000000789c00000|100%| O| |TAMS 0x0000000789a00000, 0x0000000789a00000| Untracked -|1082|0x0000000789c00000, 0x0000000789e00000, 0x0000000789e00000|100%| O| |TAMS 0x0000000789c00000, 0x0000000789c00000| Untracked -|1083|0x0000000789e00000, 0x000000078a000000, 0x000000078a000000|100%| O| |TAMS 0x0000000789e00000, 0x0000000789e00000| Untracked -|1084|0x000000078a000000, 0x000000078a200000, 0x000000078a200000|100%| O| |TAMS 0x000000078a000000, 0x000000078a000000| Untracked -|1085|0x000000078a200000, 0x000000078a400000, 0x000000078a400000|100%| O| |TAMS 0x000000078a200000, 0x000000078a200000| Untracked -|1086|0x000000078a400000, 0x000000078a600000, 0x000000078a600000|100%| O| |TAMS 0x000000078a400000, 0x000000078a400000| Untracked -|1087|0x000000078a600000, 0x000000078a800000, 0x000000078a800000|100%| O| |TAMS 0x000000078a600000, 0x000000078a600000| Untracked -|1088|0x000000078a800000, 0x000000078aa00000, 0x000000078aa00000|100%| O| |TAMS 0x000000078a800000, 0x000000078a800000| Untracked -|1089|0x000000078aa00000, 0x000000078ac00000, 0x000000078ac00000|100%| O| |TAMS 0x000000078aa00000, 0x000000078aa00000| Untracked -|1090|0x000000078ac00000, 0x000000078ae00000, 0x000000078ae00000|100%| O| |TAMS 0x000000078ac00000, 0x000000078ac00000| Untracked -|1091|0x000000078ae00000, 0x000000078b000000, 0x000000078b000000|100%| O| |TAMS 0x000000078ae00000, 0x000000078ae00000| Untracked -|1092|0x000000078b000000, 0x000000078b200000, 0x000000078b200000|100%| O| |TAMS 0x000000078b000000, 0x000000078b000000| Untracked -|1093|0x000000078b200000, 0x000000078b400000, 0x000000078b400000|100%| O| |TAMS 0x000000078b200000, 0x000000078b200000| Untracked -|1094|0x000000078b400000, 0x000000078b600000, 0x000000078b600000|100%| O| |TAMS 0x000000078b400000, 0x000000078b400000| Untracked -|1095|0x000000078b600000, 0x000000078b800000, 0x000000078b800000|100%| O| |TAMS 0x000000078b600000, 0x000000078b600000| Untracked -|1096|0x000000078b800000, 0x000000078ba00000, 0x000000078ba00000|100%| O| |TAMS 0x000000078b800000, 0x000000078b800000| Untracked -|1097|0x000000078ba00000, 0x000000078bc00000, 0x000000078bc00000|100%| O| |TAMS 0x000000078ba00000, 0x000000078ba00000| Untracked -|1098|0x000000078bc00000, 0x000000078be00000, 0x000000078be00000|100%| O| |TAMS 0x000000078bc00000, 0x000000078bc00000| Untracked -|1099|0x000000078be00000, 0x000000078c000000, 0x000000078c000000|100%| O| |TAMS 0x000000078be00000, 0x000000078be00000| Untracked -|1100|0x000000078c000000, 0x000000078c200000, 0x000000078c200000|100%| O| |TAMS 0x000000078c000000, 0x000000078c000000| Untracked -|1101|0x000000078c200000, 0x000000078c400000, 0x000000078c400000|100%| O| |TAMS 0x000000078c200000, 0x000000078c200000| Untracked -|1102|0x000000078c400000, 0x000000078c600000, 0x000000078c600000|100%| O| |TAMS 0x000000078c400000, 0x000000078c400000| Untracked -|1103|0x000000078c600000, 0x000000078c800000, 0x000000078c800000|100%| O| |TAMS 0x000000078c600000, 0x000000078c600000| Untracked -|1104|0x000000078c800000, 0x000000078ca00000, 0x000000078ca00000|100%| O| |TAMS 0x000000078c800000, 0x000000078c800000| Untracked -|1105|0x000000078ca00000, 0x000000078cc00000, 0x000000078cc00000|100%| O| |TAMS 0x000000078ca00000, 0x000000078ca00000| Untracked -|1106|0x000000078cc00000, 0x000000078ce00000, 0x000000078ce00000|100%| O| |TAMS 0x000000078cc00000, 0x000000078cc00000| Untracked -|1107|0x000000078ce00000, 0x000000078d000000, 0x000000078d000000|100%| O| |TAMS 0x000000078ce00000, 0x000000078ce00000| Untracked -|1108|0x000000078d000000, 0x000000078d200000, 0x000000078d200000|100%| O| |TAMS 0x000000078d000000, 0x000000078d000000| Untracked -|1109|0x000000078d200000, 0x000000078d400000, 0x000000078d400000|100%| O| |TAMS 0x000000078d200000, 0x000000078d200000| Untracked -|1110|0x000000078d400000, 0x000000078d600000, 0x000000078d600000|100%| O| |TAMS 0x000000078d400000, 0x000000078d400000| Untracked -|1111|0x000000078d600000, 0x000000078d800000, 0x000000078d800000|100%| O| |TAMS 0x000000078d600000, 0x000000078d600000| Untracked -|1112|0x000000078d800000, 0x000000078da00000, 0x000000078da00000|100%| O| |TAMS 0x000000078d800000, 0x000000078d800000| Untracked -|1113|0x000000078da00000, 0x000000078dc00000, 0x000000078dc00000|100%| O| |TAMS 0x000000078da00000, 0x000000078da00000| Untracked -|1114|0x000000078dc00000, 0x000000078de00000, 0x000000078de00000|100%| O| |TAMS 0x000000078dc00000, 0x000000078dc00000| Untracked -|1115|0x000000078de00000, 0x000000078e000000, 0x000000078e000000|100%| O| |TAMS 0x000000078de00000, 0x000000078de00000| Untracked -|1116|0x000000078e000000, 0x000000078e200000, 0x000000078e200000|100%| O| |TAMS 0x000000078e000000, 0x000000078e000000| Untracked -|1117|0x000000078e200000, 0x000000078e400000, 0x000000078e400000|100%| O| |TAMS 0x000000078e200000, 0x000000078e200000| Untracked -|1118|0x000000078e400000, 0x000000078e400000, 0x000000078e600000| 0%| F| |TAMS 0x000000078e400000, 0x000000078e400000| Untracked -|1119|0x000000078e600000, 0x000000078e600000, 0x000000078e800000| 0%| F| |TAMS 0x000000078e600000, 0x000000078e600000| Untracked -|1120|0x000000078e800000, 0x000000078e800000, 0x000000078ea00000| 0%| F| |TAMS 0x000000078e800000, 0x000000078e800000| Untracked -|1121|0x000000078ea00000, 0x000000078ea00000, 0x000000078ec00000| 0%| F| |TAMS 0x000000078ea00000, 0x000000078ea00000| Untracked -|1122|0x000000078ec00000, 0x000000078ec00000, 0x000000078ee00000| 0%| F| |TAMS 0x000000078ec00000, 0x000000078ec00000| Untracked -|1123|0x000000078ee00000, 0x000000078ee00000, 0x000000078f000000| 0%| F| |TAMS 0x000000078ee00000, 0x000000078ee00000| Untracked -|1124|0x000000078f000000, 0x000000078f000000, 0x000000078f200000| 0%| F| |TAMS 0x000000078f000000, 0x000000078f000000| Untracked -|1125|0x000000078f200000, 0x000000078f200000, 0x000000078f400000| 0%| F| |TAMS 0x000000078f200000, 0x000000078f200000| Untracked -|1126|0x000000078f400000, 0x000000078f400000, 0x000000078f600000| 0%| F| |TAMS 0x000000078f400000, 0x000000078f400000| Untracked -|1127|0x000000078f600000, 0x000000078f600000, 0x000000078f800000| 0%| F| |TAMS 0x000000078f600000, 0x000000078f600000| Untracked -|1128|0x000000078f800000, 0x000000078f800000, 0x000000078fa00000| 0%| F| |TAMS 0x000000078f800000, 0x000000078f800000| Untracked -|1129|0x000000078fa00000, 0x000000078fa00000, 0x000000078fc00000| 0%| F| |TAMS 0x000000078fa00000, 0x000000078fa00000| Untracked -|1130|0x000000078fc00000, 0x000000078fc00000, 0x000000078fe00000| 0%| F| |TAMS 0x000000078fc00000, 0x000000078fc00000| Untracked -|1131|0x000000078fe00000, 0x000000078fe00000, 0x0000000790000000| 0%| F| |TAMS 0x000000078fe00000, 0x000000078fe00000| Untracked -|1132|0x0000000790000000, 0x0000000790000000, 0x0000000790200000| 0%| F| |TAMS 0x0000000790000000, 0x0000000790000000| Untracked -|1133|0x0000000790200000, 0x0000000790200000, 0x0000000790400000| 0%| F| |TAMS 0x0000000790200000, 0x0000000790200000| Untracked -|1134|0x0000000790400000, 0x0000000790400000, 0x0000000790600000| 0%| F| |TAMS 0x0000000790400000, 0x0000000790400000| Untracked -|1135|0x0000000790600000, 0x0000000790600000, 0x0000000790800000| 0%| F| |TAMS 0x0000000790600000, 0x0000000790600000| Untracked -|1136|0x0000000790800000, 0x0000000790800000, 0x0000000790a00000| 0%| F| |TAMS 0x0000000790800000, 0x0000000790800000| Untracked -|1137|0x0000000790a00000, 0x0000000790a00000, 0x0000000790c00000| 0%| F| |TAMS 0x0000000790a00000, 0x0000000790a00000| Untracked -|1138|0x0000000790c00000, 0x0000000790c00000, 0x0000000790e00000| 0%| F| |TAMS 0x0000000790c00000, 0x0000000790c00000| Untracked -|1139|0x0000000790e00000, 0x0000000790e00000, 0x0000000791000000| 0%| F| |TAMS 0x0000000790e00000, 0x0000000790e00000| Untracked -|1140|0x0000000791000000, 0x0000000791000000, 0x0000000791200000| 0%| F| |TAMS 0x0000000791000000, 0x0000000791000000| Untracked -|1141|0x0000000791200000, 0x0000000791200000, 0x0000000791400000| 0%| F| |TAMS 0x0000000791200000, 0x0000000791200000| Untracked -|1142|0x0000000791400000, 0x0000000791400000, 0x0000000791600000| 0%| F| |TAMS 0x0000000791400000, 0x0000000791400000| Untracked -|1143|0x0000000791600000, 0x0000000791600000, 0x0000000791800000| 0%| F| |TAMS 0x0000000791600000, 0x0000000791600000| Untracked -|1144|0x0000000791800000, 0x0000000791800000, 0x0000000791a00000| 0%| F| |TAMS 0x0000000791800000, 0x0000000791800000| Untracked -|1145|0x0000000791a00000, 0x0000000791a00000, 0x0000000791c00000| 0%| F| |TAMS 0x0000000791a00000, 0x0000000791a00000| Untracked -|1146|0x0000000791c00000, 0x0000000791c00000, 0x0000000791e00000| 0%| F| |TAMS 0x0000000791c00000, 0x0000000791c00000| Untracked -|1147|0x0000000791e00000, 0x0000000791e00000, 0x0000000792000000| 0%| F| |TAMS 0x0000000791e00000, 0x0000000791e00000| Untracked -|1148|0x0000000792000000, 0x0000000792000000, 0x0000000792200000| 0%| F| |TAMS 0x0000000792000000, 0x0000000792000000| Untracked -|1149|0x0000000792200000, 0x0000000792200000, 0x0000000792400000| 0%| F| |TAMS 0x0000000792200000, 0x0000000792200000| Untracked -|1150|0x0000000792400000, 0x0000000792400000, 0x0000000792600000| 0%| F| |TAMS 0x0000000792400000, 0x0000000792400000| Untracked -|1151|0x0000000792600000, 0x0000000792600000, 0x0000000792800000| 0%| F| |TAMS 0x0000000792600000, 0x0000000792600000| Untracked -|1152|0x0000000792800000, 0x0000000792800000, 0x0000000792a00000| 0%| F| |TAMS 0x0000000792800000, 0x0000000792800000| Untracked -|1153|0x0000000792a00000, 0x0000000792a00000, 0x0000000792c00000| 0%| F| |TAMS 0x0000000792a00000, 0x0000000792a00000| Untracked -|1154|0x0000000792c00000, 0x0000000792c00000, 0x0000000792e00000| 0%| F| |TAMS 0x0000000792c00000, 0x0000000792c00000| Untracked -|1155|0x0000000792e00000, 0x0000000792e00000, 0x0000000793000000| 0%| F| |TAMS 0x0000000792e00000, 0x0000000792e00000| Untracked -|1156|0x0000000793000000, 0x0000000793000000, 0x0000000793200000| 0%| F| |TAMS 0x0000000793000000, 0x0000000793000000| Untracked -|1157|0x0000000793200000, 0x0000000793200000, 0x0000000793400000| 0%| F| |TAMS 0x0000000793200000, 0x0000000793200000| Untracked -|1158|0x0000000793400000, 0x0000000793400000, 0x0000000793600000| 0%| F| |TAMS 0x0000000793400000, 0x0000000793400000| Untracked -|1159|0x0000000793600000, 0x0000000793600000, 0x0000000793800000| 0%| F| |TAMS 0x0000000793600000, 0x0000000793600000| Untracked -|1160|0x0000000793800000, 0x0000000793800000, 0x0000000793a00000| 0%| F| |TAMS 0x0000000793800000, 0x0000000793800000| Untracked -|1161|0x0000000793a00000, 0x0000000793a00000, 0x0000000793c00000| 0%| F| |TAMS 0x0000000793a00000, 0x0000000793a00000| Untracked -|1162|0x0000000793c00000, 0x0000000793c00000, 0x0000000793e00000| 0%| F| |TAMS 0x0000000793c00000, 0x0000000793c00000| Untracked -|1163|0x0000000793e00000, 0x0000000793e00000, 0x0000000794000000| 0%| F| |TAMS 0x0000000793e00000, 0x0000000793e00000| Untracked -|1164|0x0000000794000000, 0x0000000794000000, 0x0000000794200000| 0%| F| |TAMS 0x0000000794000000, 0x0000000794000000| Untracked -|1165|0x0000000794200000, 0x0000000794200000, 0x0000000794400000| 0%| F| |TAMS 0x0000000794200000, 0x0000000794200000| Untracked -|1166|0x0000000794400000, 0x0000000794400000, 0x0000000794600000| 0%| F| |TAMS 0x0000000794400000, 0x0000000794400000| Untracked -|1167|0x0000000794600000, 0x0000000794600000, 0x0000000794800000| 0%| F| |TAMS 0x0000000794600000, 0x0000000794600000| Untracked -|1168|0x0000000794800000, 0x0000000794800000, 0x0000000794a00000| 0%| F| |TAMS 0x0000000794800000, 0x0000000794800000| Untracked -|1169|0x0000000794a00000, 0x0000000794a00000, 0x0000000794c00000| 0%| F| |TAMS 0x0000000794a00000, 0x0000000794a00000| Untracked -|1170|0x0000000794c00000, 0x0000000794c00000, 0x0000000794e00000| 0%| F| |TAMS 0x0000000794c00000, 0x0000000794c00000| Untracked -|1171|0x0000000794e00000, 0x0000000794e00000, 0x0000000795000000| 0%| F| |TAMS 0x0000000794e00000, 0x0000000794e00000| Untracked -|1172|0x0000000795000000, 0x0000000795000000, 0x0000000795200000| 0%| F| |TAMS 0x0000000795000000, 0x0000000795000000| Untracked -|1173|0x0000000795200000, 0x0000000795200000, 0x0000000795400000| 0%| F| |TAMS 0x0000000795200000, 0x0000000795200000| Untracked -|1174|0x0000000795400000, 0x0000000795400000, 0x0000000795600000| 0%| F| |TAMS 0x0000000795400000, 0x0000000795400000| Untracked -|1175|0x0000000795600000, 0x0000000795600000, 0x0000000795800000| 0%| F| |TAMS 0x0000000795600000, 0x0000000795600000| Untracked -|1176|0x0000000795800000, 0x0000000795800000, 0x0000000795a00000| 0%| F| |TAMS 0x0000000795800000, 0x0000000795800000| Untracked -|1177|0x0000000795a00000, 0x0000000795a00000, 0x0000000795c00000| 0%| F| |TAMS 0x0000000795a00000, 0x0000000795a00000| Untracked -|1178|0x0000000795c00000, 0x0000000795c00000, 0x0000000795e00000| 0%| F| |TAMS 0x0000000795c00000, 0x0000000795c00000| Untracked -|1179|0x0000000795e00000, 0x0000000795e00000, 0x0000000796000000| 0%| F| |TAMS 0x0000000795e00000, 0x0000000795e00000| Untracked -|1180|0x0000000796000000, 0x0000000796000000, 0x0000000796200000| 0%| F| |TAMS 0x0000000796000000, 0x0000000796000000| Untracked -|1181|0x0000000796200000, 0x0000000796200000, 0x0000000796400000| 0%| F| |TAMS 0x0000000796200000, 0x0000000796200000| Untracked -|1182|0x0000000796400000, 0x0000000796400000, 0x0000000796600000| 0%| F| |TAMS 0x0000000796400000, 0x0000000796400000| Untracked -|1183|0x0000000796600000, 0x0000000796600000, 0x0000000796800000| 0%| F| |TAMS 0x0000000796600000, 0x0000000796600000| Untracked -|1184|0x0000000796800000, 0x0000000796800000, 0x0000000796a00000| 0%| F| |TAMS 0x0000000796800000, 0x0000000796800000| Untracked -|1185|0x0000000796a00000, 0x0000000796a00000, 0x0000000796c00000| 0%| F| |TAMS 0x0000000796a00000, 0x0000000796a00000| Untracked -|1186|0x0000000796c00000, 0x0000000796c00000, 0x0000000796e00000| 0%| F| |TAMS 0x0000000796c00000, 0x0000000796c00000| Untracked -|1187|0x0000000796e00000, 0x0000000796e00000, 0x0000000797000000| 0%| F| |TAMS 0x0000000796e00000, 0x0000000796e00000| Untracked -|1188|0x0000000797000000, 0x0000000797000000, 0x0000000797200000| 0%| F| |TAMS 0x0000000797000000, 0x0000000797000000| Untracked -|1189|0x0000000797200000, 0x0000000797200000, 0x0000000797400000| 0%| F| |TAMS 0x0000000797200000, 0x0000000797200000| Untracked -|1190|0x0000000797400000, 0x0000000797400000, 0x0000000797600000| 0%| F| |TAMS 0x0000000797400000, 0x0000000797400000| Untracked -|1191|0x0000000797600000, 0x0000000797600000, 0x0000000797800000| 0%| F| |TAMS 0x0000000797600000, 0x0000000797600000| Untracked -|1192|0x0000000797800000, 0x0000000797800000, 0x0000000797a00000| 0%| F| |TAMS 0x0000000797800000, 0x0000000797800000| Untracked -|1193|0x0000000797a00000, 0x0000000797a00000, 0x0000000797c00000| 0%| F| |TAMS 0x0000000797a00000, 0x0000000797a00000| Untracked -|1194|0x0000000797c00000, 0x0000000797c00000, 0x0000000797e00000| 0%| F| |TAMS 0x0000000797c00000, 0x0000000797c00000| Untracked -|1195|0x0000000797e00000, 0x0000000797e00000, 0x0000000798000000| 0%| F| |TAMS 0x0000000797e00000, 0x0000000797e00000| Untracked -|1196|0x0000000798000000, 0x0000000798000000, 0x0000000798200000| 0%| F| |TAMS 0x0000000798000000, 0x0000000798000000| Untracked -|1197|0x0000000798200000, 0x0000000798200000, 0x0000000798400000| 0%| F| |TAMS 0x0000000798200000, 0x0000000798200000| Untracked -|1198|0x0000000798400000, 0x0000000798400000, 0x0000000798600000| 0%| F| |TAMS 0x0000000798400000, 0x0000000798400000| Untracked -|1199|0x0000000798600000, 0x0000000798600000, 0x0000000798800000| 0%| F| |TAMS 0x0000000798600000, 0x0000000798600000| Untracked -|1200|0x0000000798800000, 0x0000000798800000, 0x0000000798a00000| 0%| F| |TAMS 0x0000000798800000, 0x0000000798800000| Untracked -|1201|0x0000000798a00000, 0x0000000798a00000, 0x0000000798c00000| 0%| F| |TAMS 0x0000000798a00000, 0x0000000798a00000| Untracked -|1202|0x0000000798c00000, 0x0000000798c00000, 0x0000000798e00000| 0%| F| |TAMS 0x0000000798c00000, 0x0000000798c00000| Untracked -|1203|0x0000000798e00000, 0x0000000798e00000, 0x0000000799000000| 0%| F| |TAMS 0x0000000798e00000, 0x0000000798e00000| Untracked -|1204|0x0000000799000000, 0x0000000799000000, 0x0000000799200000| 0%| F| |TAMS 0x0000000799000000, 0x0000000799000000| Untracked -|1205|0x0000000799200000, 0x0000000799200000, 0x0000000799400000| 0%| F| |TAMS 0x0000000799200000, 0x0000000799200000| Untracked -|1206|0x0000000799400000, 0x0000000799400000, 0x0000000799600000| 0%| F| |TAMS 0x0000000799400000, 0x0000000799400000| Untracked -|1207|0x0000000799600000, 0x0000000799600000, 0x0000000799800000| 0%| F| |TAMS 0x0000000799600000, 0x0000000799600000| Untracked -|1208|0x0000000799800000, 0x0000000799800000, 0x0000000799a00000| 0%| F| |TAMS 0x0000000799800000, 0x0000000799800000| Untracked -|1209|0x0000000799a00000, 0x0000000799a00000, 0x0000000799c00000| 0%| F| |TAMS 0x0000000799a00000, 0x0000000799a00000| Untracked -|1210|0x0000000799c00000, 0x0000000799c00000, 0x0000000799e00000| 0%| F| |TAMS 0x0000000799c00000, 0x0000000799c00000| Untracked -|1211|0x0000000799e00000, 0x0000000799e00000, 0x000000079a000000| 0%| F| |TAMS 0x0000000799e00000, 0x0000000799e00000| Untracked -|1212|0x000000079a000000, 0x000000079a000000, 0x000000079a200000| 0%| F| |TAMS 0x000000079a000000, 0x000000079a000000| Untracked -|1213|0x000000079a200000, 0x000000079a200000, 0x000000079a400000| 0%| F| |TAMS 0x000000079a200000, 0x000000079a200000| Untracked -|1214|0x000000079a400000, 0x000000079a400000, 0x000000079a600000| 0%| F| |TAMS 0x000000079a400000, 0x000000079a400000| Untracked -|1215|0x000000079a600000, 0x000000079a600000, 0x000000079a800000| 0%| F| |TAMS 0x000000079a600000, 0x000000079a600000| Untracked -|1216|0x000000079a800000, 0x000000079a800000, 0x000000079aa00000| 0%| F| |TAMS 0x000000079a800000, 0x000000079a800000| Untracked -|1217|0x000000079aa00000, 0x000000079aa00000, 0x000000079ac00000| 0%| F| |TAMS 0x000000079aa00000, 0x000000079aa00000| Untracked -|1218|0x000000079ac00000, 0x000000079ac00000, 0x000000079ae00000| 0%| F| |TAMS 0x000000079ac00000, 0x000000079ac00000| Untracked -|1219|0x000000079ae00000, 0x000000079ae00000, 0x000000079b000000| 0%| F| |TAMS 0x000000079ae00000, 0x000000079ae00000| Untracked -|1220|0x000000079b000000, 0x000000079b000000, 0x000000079b200000| 0%| F| |TAMS 0x000000079b000000, 0x000000079b000000| Untracked -|1221|0x000000079b200000, 0x000000079b200000, 0x000000079b400000| 0%| F| |TAMS 0x000000079b200000, 0x000000079b200000| Untracked -|1222|0x000000079b400000, 0x000000079b400000, 0x000000079b600000| 0%| F| |TAMS 0x000000079b400000, 0x000000079b400000| Untracked -|1223|0x000000079b600000, 0x000000079b600000, 0x000000079b800000| 0%| F| |TAMS 0x000000079b600000, 0x000000079b600000| Untracked -|1224|0x000000079b800000, 0x000000079b800000, 0x000000079ba00000| 0%| F| |TAMS 0x000000079b800000, 0x000000079b800000| Untracked -|1225|0x000000079ba00000, 0x000000079ba00000, 0x000000079bc00000| 0%| F| |TAMS 0x000000079ba00000, 0x000000079ba00000| Untracked -|1226|0x000000079bc00000, 0x000000079bc00000, 0x000000079be00000| 0%| F| |TAMS 0x000000079bc00000, 0x000000079bc00000| Untracked -|1227|0x000000079be00000, 0x000000079be00000, 0x000000079c000000| 0%| F| |TAMS 0x000000079be00000, 0x000000079be00000| Untracked -|1228|0x000000079c000000, 0x000000079c000000, 0x000000079c200000| 0%| F| |TAMS 0x000000079c000000, 0x000000079c000000| Untracked -|1229|0x000000079c200000, 0x000000079c200000, 0x000000079c400000| 0%| F| |TAMS 0x000000079c200000, 0x000000079c200000| Untracked -|1230|0x000000079c400000, 0x000000079c400000, 0x000000079c600000| 0%| F| |TAMS 0x000000079c400000, 0x000000079c400000| Untracked -|1231|0x000000079c600000, 0x000000079c600000, 0x000000079c800000| 0%| F| |TAMS 0x000000079c600000, 0x000000079c600000| Untracked -|1232|0x000000079c800000, 0x000000079c800000, 0x000000079ca00000| 0%| F| |TAMS 0x000000079c800000, 0x000000079c800000| Untracked -|1233|0x000000079ca00000, 0x000000079ca00000, 0x000000079cc00000| 0%| F| |TAMS 0x000000079ca00000, 0x000000079ca00000| Untracked -|1234|0x000000079cc00000, 0x000000079cc00000, 0x000000079ce00000| 0%| F| |TAMS 0x000000079cc00000, 0x000000079cc00000| Untracked -|1235|0x000000079ce00000, 0x000000079ce00000, 0x000000079d000000| 0%| F| |TAMS 0x000000079ce00000, 0x000000079ce00000| Untracked -|1236|0x000000079d000000, 0x000000079d000000, 0x000000079d200000| 0%| F| |TAMS 0x000000079d000000, 0x000000079d000000| Untracked -|1237|0x000000079d200000, 0x000000079d200000, 0x000000079d400000| 0%| F| |TAMS 0x000000079d200000, 0x000000079d200000| Untracked -|1238|0x000000079d400000, 0x000000079d400000, 0x000000079d600000| 0%| F| |TAMS 0x000000079d400000, 0x000000079d400000| Untracked -|1239|0x000000079d600000, 0x000000079d600000, 0x000000079d800000| 0%| F| |TAMS 0x000000079d600000, 0x000000079d600000| Untracked -|1240|0x000000079d800000, 0x000000079d800000, 0x000000079da00000| 0%| F| |TAMS 0x000000079d800000, 0x000000079d800000| Untracked -|1241|0x000000079da00000, 0x000000079da00000, 0x000000079dc00000| 0%| F| |TAMS 0x000000079da00000, 0x000000079da00000| Untracked -|1242|0x000000079dc00000, 0x000000079dc00000, 0x000000079de00000| 0%| F| |TAMS 0x000000079dc00000, 0x000000079dc00000| Untracked -|1243|0x000000079de00000, 0x000000079de00000, 0x000000079e000000| 0%| F| |TAMS 0x000000079de00000, 0x000000079de00000| Untracked -|1244|0x000000079e000000, 0x000000079e000000, 0x000000079e200000| 0%| F| |TAMS 0x000000079e000000, 0x000000079e000000| Untracked -|1245|0x000000079e200000, 0x000000079e200000, 0x000000079e400000| 0%| F| |TAMS 0x000000079e200000, 0x000000079e200000| Untracked -|1246|0x000000079e400000, 0x000000079e400000, 0x000000079e600000| 0%| F| |TAMS 0x000000079e400000, 0x000000079e400000| Untracked -|1247|0x000000079e600000, 0x000000079e600000, 0x000000079e800000| 0%| F| |TAMS 0x000000079e600000, 0x000000079e600000| Untracked -|1248|0x000000079e800000, 0x000000079e800000, 0x000000079ea00000| 0%| F| |TAMS 0x000000079e800000, 0x000000079e800000| Untracked -|1249|0x000000079ea00000, 0x000000079ea00000, 0x000000079ec00000| 0%| F| |TAMS 0x000000079ea00000, 0x000000079ea00000| Untracked -|1250|0x000000079ec00000, 0x000000079ec00000, 0x000000079ee00000| 0%| F| |TAMS 0x000000079ec00000, 0x000000079ec00000| Untracked -|1251|0x000000079ee00000, 0x000000079ee00000, 0x000000079f000000| 0%| F| |TAMS 0x000000079ee00000, 0x000000079ee00000| Untracked -|1252|0x000000079f000000, 0x000000079f000000, 0x000000079f200000| 0%| F| |TAMS 0x000000079f000000, 0x000000079f000000| Untracked -|1253|0x000000079f200000, 0x000000079f200000, 0x000000079f400000| 0%| F| |TAMS 0x000000079f200000, 0x000000079f200000| Untracked -|1254|0x000000079f400000, 0x000000079f400000, 0x000000079f600000| 0%| F| |TAMS 0x000000079f400000, 0x000000079f400000| Untracked -|1255|0x000000079f600000, 0x000000079f600000, 0x000000079f800000| 0%| F| |TAMS 0x000000079f600000, 0x000000079f600000| Untracked -|1256|0x000000079f800000, 0x000000079f800000, 0x000000079fa00000| 0%| F| |TAMS 0x000000079f800000, 0x000000079f800000| Untracked -|1257|0x000000079fa00000, 0x000000079fa00000, 0x000000079fc00000| 0%| F| |TAMS 0x000000079fa00000, 0x000000079fa00000| Untracked -|1258|0x000000079fc00000, 0x000000079fc00000, 0x000000079fe00000| 0%| F| |TAMS 0x000000079fc00000, 0x000000079fc00000| Untracked -|1259|0x000000079fe00000, 0x000000079fe00000, 0x00000007a0000000| 0%| F| |TAMS 0x000000079fe00000, 0x000000079fe00000| Untracked -|1260|0x00000007a0000000, 0x00000007a0000000, 0x00000007a0200000| 0%| F| |TAMS 0x00000007a0000000, 0x00000007a0000000| Untracked -|1261|0x00000007a0200000, 0x00000007a0200000, 0x00000007a0400000| 0%| F| |TAMS 0x00000007a0200000, 0x00000007a0200000| Untracked -|1262|0x00000007a0400000, 0x00000007a0400000, 0x00000007a0600000| 0%| F| |TAMS 0x00000007a0400000, 0x00000007a0400000| Untracked -|1263|0x00000007a0600000, 0x00000007a0600000, 0x00000007a0800000| 0%| F| |TAMS 0x00000007a0600000, 0x00000007a0600000| Untracked -|1264|0x00000007a0800000, 0x00000007a0800000, 0x00000007a0a00000| 0%| F| |TAMS 0x00000007a0800000, 0x00000007a0800000| Untracked -|1265|0x00000007a0a00000, 0x00000007a0a00000, 0x00000007a0c00000| 0%| F| |TAMS 0x00000007a0a00000, 0x00000007a0a00000| Untracked -|1266|0x00000007a0c00000, 0x00000007a0c00000, 0x00000007a0e00000| 0%| F| |TAMS 0x00000007a0c00000, 0x00000007a0c00000| Untracked -|1267|0x00000007a0e00000, 0x00000007a0e00000, 0x00000007a1000000| 0%| F| |TAMS 0x00000007a0e00000, 0x00000007a0e00000| Untracked -|1268|0x00000007a1000000, 0x00000007a1000000, 0x00000007a1200000| 0%| F| |TAMS 0x00000007a1000000, 0x00000007a1000000| Untracked -|1269|0x00000007a1200000, 0x00000007a1200000, 0x00000007a1400000| 0%| F| |TAMS 0x00000007a1200000, 0x00000007a1200000| Untracked -|1270|0x00000007a1400000, 0x00000007a1400000, 0x00000007a1600000| 0%| F| |TAMS 0x00000007a1400000, 0x00000007a1400000| Untracked -|1271|0x00000007a1600000, 0x00000007a1600000, 0x00000007a1800000| 0%| F| |TAMS 0x00000007a1600000, 0x00000007a1600000| Untracked -|1272|0x00000007a1800000, 0x00000007a1800000, 0x00000007a1a00000| 0%| F| |TAMS 0x00000007a1800000, 0x00000007a1800000| Untracked -|1273|0x00000007a1a00000, 0x00000007a1a00000, 0x00000007a1c00000| 0%| F| |TAMS 0x00000007a1a00000, 0x00000007a1a00000| Untracked -|1274|0x00000007a1c00000, 0x00000007a1c00000, 0x00000007a1e00000| 0%| F| |TAMS 0x00000007a1c00000, 0x00000007a1c00000| Untracked -|1275|0x00000007a1e00000, 0x00000007a1e00000, 0x00000007a2000000| 0%| F| |TAMS 0x00000007a1e00000, 0x00000007a1e00000| Untracked -|1276|0x00000007a2000000, 0x00000007a2000000, 0x00000007a2200000| 0%| F| |TAMS 0x00000007a2000000, 0x00000007a2000000| Untracked -|1277|0x00000007a2200000, 0x00000007a2200000, 0x00000007a2400000| 0%| F| |TAMS 0x00000007a2200000, 0x00000007a2200000| Untracked -|1278|0x00000007a2400000, 0x00000007a2400000, 0x00000007a2600000| 0%| F| |TAMS 0x00000007a2400000, 0x00000007a2400000| Untracked -|1279|0x00000007a2600000, 0x00000007a2600000, 0x00000007a2800000| 0%| F| |TAMS 0x00000007a2600000, 0x00000007a2600000| Untracked -|1280|0x00000007a2800000, 0x00000007a2800000, 0x00000007a2a00000| 0%| F| |TAMS 0x00000007a2800000, 0x00000007a2800000| Untracked -|1281|0x00000007a2a00000, 0x00000007a2a00000, 0x00000007a2c00000| 0%| F| |TAMS 0x00000007a2a00000, 0x00000007a2a00000| Untracked -|1282|0x00000007a2c00000, 0x00000007a2c00000, 0x00000007a2e00000| 0%| F| |TAMS 0x00000007a2c00000, 0x00000007a2c00000| Untracked -|1283|0x00000007a2e00000, 0x00000007a2e00000, 0x00000007a3000000| 0%| F| |TAMS 0x00000007a2e00000, 0x00000007a2e00000| Untracked -|1284|0x00000007a3000000, 0x00000007a3000000, 0x00000007a3200000| 0%| F| |TAMS 0x00000007a3000000, 0x00000007a3000000| Untracked -|1285|0x00000007a3200000, 0x00000007a3200000, 0x00000007a3400000| 0%| F| |TAMS 0x00000007a3200000, 0x00000007a3200000| Untracked -|1286|0x00000007a3400000, 0x00000007a3400000, 0x00000007a3600000| 0%| F| |TAMS 0x00000007a3400000, 0x00000007a3400000| Untracked -|1287|0x00000007a3600000, 0x00000007a3600000, 0x00000007a3800000| 0%| F| |TAMS 0x00000007a3600000, 0x00000007a3600000| Untracked -|1288|0x00000007a3800000, 0x00000007a3800000, 0x00000007a3a00000| 0%| F| |TAMS 0x00000007a3800000, 0x00000007a3800000| Untracked -|1289|0x00000007a3a00000, 0x00000007a3a00000, 0x00000007a3c00000| 0%| F| |TAMS 0x00000007a3a00000, 0x00000007a3a00000| Untracked -|1290|0x00000007a3c00000, 0x00000007a3c00000, 0x00000007a3e00000| 0%| F| |TAMS 0x00000007a3c00000, 0x00000007a3c00000| Untracked -|1291|0x00000007a3e00000, 0x00000007a3e00000, 0x00000007a4000000| 0%| F| |TAMS 0x00000007a3e00000, 0x00000007a3e00000| Untracked -|1292|0x00000007a4000000, 0x00000007a4000000, 0x00000007a4200000| 0%| F| |TAMS 0x00000007a4000000, 0x00000007a4000000| Untracked -|1293|0x00000007a4200000, 0x00000007a4200000, 0x00000007a4400000| 0%| F| |TAMS 0x00000007a4200000, 0x00000007a4200000| Untracked -|1294|0x00000007a4400000, 0x00000007a4400000, 0x00000007a4600000| 0%| F| |TAMS 0x00000007a4400000, 0x00000007a4400000| Untracked -|1295|0x00000007a4600000, 0x00000007a4600000, 0x00000007a4800000| 0%| F| |TAMS 0x00000007a4600000, 0x00000007a4600000| Untracked -|1296|0x00000007a4800000, 0x00000007a4800000, 0x00000007a4a00000| 0%| F| |TAMS 0x00000007a4800000, 0x00000007a4800000| Untracked -|1297|0x00000007a4a00000, 0x00000007a4a00000, 0x00000007a4c00000| 0%| F| |TAMS 0x00000007a4a00000, 0x00000007a4a00000| Untracked -|1298|0x00000007a4c00000, 0x00000007a4c00000, 0x00000007a4e00000| 0%| F| |TAMS 0x00000007a4c00000, 0x00000007a4c00000| Untracked -|1299|0x00000007a4e00000, 0x00000007a4e00000, 0x00000007a5000000| 0%| F| |TAMS 0x00000007a4e00000, 0x00000007a4e00000| Untracked -|1300|0x00000007a5000000, 0x00000007a5000000, 0x00000007a5200000| 0%| F| |TAMS 0x00000007a5000000, 0x00000007a5000000| Untracked -|1301|0x00000007a5200000, 0x00000007a5200000, 0x00000007a5400000| 0%| F| |TAMS 0x00000007a5200000, 0x00000007a5200000| Untracked -|1302|0x00000007a5400000, 0x00000007a5400000, 0x00000007a5600000| 0%| F| |TAMS 0x00000007a5400000, 0x00000007a5400000| Untracked -|1303|0x00000007a5600000, 0x00000007a5600000, 0x00000007a5800000| 0%| F| |TAMS 0x00000007a5600000, 0x00000007a5600000| Untracked -|1304|0x00000007a5800000, 0x00000007a5800000, 0x00000007a5a00000| 0%| F| |TAMS 0x00000007a5800000, 0x00000007a5800000| Untracked -|1305|0x00000007a5a00000, 0x00000007a5a00000, 0x00000007a5c00000| 0%| F| |TAMS 0x00000007a5a00000, 0x00000007a5a00000| Untracked -|1306|0x00000007a5c00000, 0x00000007a5c00000, 0x00000007a5e00000| 0%| F| |TAMS 0x00000007a5c00000, 0x00000007a5c00000| Untracked -|1307|0x00000007a5e00000, 0x00000007a5e00000, 0x00000007a6000000| 0%| F| |TAMS 0x00000007a5e00000, 0x00000007a5e00000| Untracked -|1308|0x00000007a6000000, 0x00000007a6000000, 0x00000007a6200000| 0%| F| |TAMS 0x00000007a6000000, 0x00000007a6000000| Untracked -|1309|0x00000007a6200000, 0x00000007a6200000, 0x00000007a6400000| 0%| F| |TAMS 0x00000007a6200000, 0x00000007a6200000| Untracked -|1310|0x00000007a6400000, 0x00000007a6400000, 0x00000007a6600000| 0%| F| |TAMS 0x00000007a6400000, 0x00000007a6400000| Untracked -|1311|0x00000007a6600000, 0x00000007a6600000, 0x00000007a6800000| 0%| F| |TAMS 0x00000007a6600000, 0x00000007a6600000| Untracked -|1312|0x00000007a6800000, 0x00000007a6800000, 0x00000007a6a00000| 0%| F| |TAMS 0x00000007a6800000, 0x00000007a6800000| Untracked -|1313|0x00000007a6a00000, 0x00000007a6a00000, 0x00000007a6c00000| 0%| F| |TAMS 0x00000007a6a00000, 0x00000007a6a00000| Untracked -|1314|0x00000007a6c00000, 0x00000007a6c00000, 0x00000007a6e00000| 0%| F| |TAMS 0x00000007a6c00000, 0x00000007a6c00000| Untracked -|1315|0x00000007a6e00000, 0x00000007a6e00000, 0x00000007a7000000| 0%| F| |TAMS 0x00000007a6e00000, 0x00000007a6e00000| Untracked -|1316|0x00000007a7000000, 0x00000007a7000000, 0x00000007a7200000| 0%| F| |TAMS 0x00000007a7000000, 0x00000007a7000000| Untracked -|1317|0x00000007a7200000, 0x00000007a7200000, 0x00000007a7400000| 0%| F| |TAMS 0x00000007a7200000, 0x00000007a7200000| Untracked -|1318|0x00000007a7400000, 0x00000007a7400000, 0x00000007a7600000| 0%| F| |TAMS 0x00000007a7400000, 0x00000007a7400000| Untracked -|1319|0x00000007a7600000, 0x00000007a7600000, 0x00000007a7800000| 0%| F| |TAMS 0x00000007a7600000, 0x00000007a7600000| Untracked -|1320|0x00000007a7800000, 0x00000007a7800000, 0x00000007a7a00000| 0%| F| |TAMS 0x00000007a7800000, 0x00000007a7800000| Untracked -|1321|0x00000007a7a00000, 0x00000007a7a00000, 0x00000007a7c00000| 0%| F| |TAMS 0x00000007a7a00000, 0x00000007a7a00000| Untracked -|1322|0x00000007a7c00000, 0x00000007a7c00000, 0x00000007a7e00000| 0%| F| |TAMS 0x00000007a7c00000, 0x00000007a7c00000| Untracked -|1323|0x00000007a7e00000, 0x00000007a7e00000, 0x00000007a8000000| 0%| F| |TAMS 0x00000007a7e00000, 0x00000007a7e00000| Untracked -|1324|0x00000007a8000000, 0x00000007a8000000, 0x00000007a8200000| 0%| F| |TAMS 0x00000007a8000000, 0x00000007a8000000| Untracked -|1325|0x00000007a8200000, 0x00000007a8200000, 0x00000007a8400000| 0%| F| |TAMS 0x00000007a8200000, 0x00000007a8200000| Untracked -|1326|0x00000007a8400000, 0x00000007a8400000, 0x00000007a8600000| 0%| F| |TAMS 0x00000007a8400000, 0x00000007a8400000| Untracked -|1327|0x00000007a8600000, 0x00000007a8600000, 0x00000007a8800000| 0%| F| |TAMS 0x00000007a8600000, 0x00000007a8600000| Untracked -|1328|0x00000007a8800000, 0x00000007a8800000, 0x00000007a8a00000| 0%| F| |TAMS 0x00000007a8800000, 0x00000007a8800000| Untracked -|1329|0x00000007a8a00000, 0x00000007a8a00000, 0x00000007a8c00000| 0%| F| |TAMS 0x00000007a8a00000, 0x00000007a8a00000| Untracked -|1330|0x00000007a8c00000, 0x00000007a8c00000, 0x00000007a8e00000| 0%| F| |TAMS 0x00000007a8c00000, 0x00000007a8c00000| Untracked -|1331|0x00000007a8e00000, 0x00000007a8e00000, 0x00000007a9000000| 0%| F| |TAMS 0x00000007a8e00000, 0x00000007a8e00000| Untracked -|1332|0x00000007a9000000, 0x00000007a9000000, 0x00000007a9200000| 0%| F| |TAMS 0x00000007a9000000, 0x00000007a9000000| Untracked -|1333|0x00000007a9200000, 0x00000007a9200000, 0x00000007a9400000| 0%| F| |TAMS 0x00000007a9200000, 0x00000007a9200000| Untracked -|1334|0x00000007a9400000, 0x00000007a9400000, 0x00000007a9600000| 0%| F| |TAMS 0x00000007a9400000, 0x00000007a9400000| Untracked -|1335|0x00000007a9600000, 0x00000007a9600000, 0x00000007a9800000| 0%| F| |TAMS 0x00000007a9600000, 0x00000007a9600000| Untracked -|1336|0x00000007a9800000, 0x00000007a9800000, 0x00000007a9a00000| 0%| F| |TAMS 0x00000007a9800000, 0x00000007a9800000| Untracked -|1337|0x00000007a9a00000, 0x00000007a9a00000, 0x00000007a9c00000| 0%| F| |TAMS 0x00000007a9a00000, 0x00000007a9a00000| Untracked -|1338|0x00000007a9c00000, 0x00000007a9c00000, 0x00000007a9e00000| 0%| F| |TAMS 0x00000007a9c00000, 0x00000007a9c00000| Untracked -|1339|0x00000007a9e00000, 0x00000007a9e00000, 0x00000007aa000000| 0%| F| |TAMS 0x00000007a9e00000, 0x00000007a9e00000| Untracked -|1340|0x00000007aa000000, 0x00000007aa000000, 0x00000007aa200000| 0%| F| |TAMS 0x00000007aa000000, 0x00000007aa000000| Untracked -|1341|0x00000007aa200000, 0x00000007aa200000, 0x00000007aa400000| 0%| F| |TAMS 0x00000007aa200000, 0x00000007aa200000| Untracked -|1342|0x00000007aa400000, 0x00000007aa400000, 0x00000007aa600000| 0%| F| |TAMS 0x00000007aa400000, 0x00000007aa400000| Untracked -|1343|0x00000007aa600000, 0x00000007aa600000, 0x00000007aa800000| 0%| F| |TAMS 0x00000007aa600000, 0x00000007aa600000| Untracked -|1344|0x00000007aa800000, 0x00000007aa800000, 0x00000007aaa00000| 0%| F| |TAMS 0x00000007aa800000, 0x00000007aa800000| Untracked -|1345|0x00000007aaa00000, 0x00000007aaa00000, 0x00000007aac00000| 0%| F| |TAMS 0x00000007aaa00000, 0x00000007aaa00000| Untracked -|1346|0x00000007aac00000, 0x00000007aac00000, 0x00000007aae00000| 0%| F| |TAMS 0x00000007aac00000, 0x00000007aac00000| Untracked -|1347|0x00000007aae00000, 0x00000007aae00000, 0x00000007ab000000| 0%| F| |TAMS 0x00000007aae00000, 0x00000007aae00000| Untracked -|1348|0x00000007ab000000, 0x00000007ab000000, 0x00000007ab200000| 0%| F| |TAMS 0x00000007ab000000, 0x00000007ab000000| Untracked -|1349|0x00000007ab200000, 0x00000007ab200000, 0x00000007ab400000| 0%| F| |TAMS 0x00000007ab200000, 0x00000007ab200000| Untracked -|1350|0x00000007ab400000, 0x00000007ab400000, 0x00000007ab600000| 0%| F| |TAMS 0x00000007ab400000, 0x00000007ab400000| Untracked -|1351|0x00000007ab600000, 0x00000007ab600000, 0x00000007ab800000| 0%| F| |TAMS 0x00000007ab600000, 0x00000007ab600000| Untracked -|1352|0x00000007ab800000, 0x00000007ab800000, 0x00000007aba00000| 0%| F| |TAMS 0x00000007ab800000, 0x00000007ab800000| Untracked -|1353|0x00000007aba00000, 0x00000007aba00000, 0x00000007abc00000| 0%| F| |TAMS 0x00000007aba00000, 0x00000007aba00000| Untracked -|1354|0x00000007abc00000, 0x00000007abc00000, 0x00000007abe00000| 0%| F| |TAMS 0x00000007abc00000, 0x00000007abc00000| Untracked -|1355|0x00000007abe00000, 0x00000007abe00000, 0x00000007ac000000| 0%| F| |TAMS 0x00000007abe00000, 0x00000007abe00000| Untracked -|1356|0x00000007ac000000, 0x00000007ac000000, 0x00000007ac200000| 0%| F| |TAMS 0x00000007ac000000, 0x00000007ac000000| Untracked -|1357|0x00000007ac200000, 0x00000007ac200000, 0x00000007ac400000| 0%| F| |TAMS 0x00000007ac200000, 0x00000007ac200000| Untracked -|1358|0x00000007ac400000, 0x00000007ac400000, 0x00000007ac600000| 0%| F| |TAMS 0x00000007ac400000, 0x00000007ac400000| Untracked -|1359|0x00000007ac600000, 0x00000007ac600000, 0x00000007ac800000| 0%| F| |TAMS 0x00000007ac600000, 0x00000007ac600000| Untracked -|1360|0x00000007ac800000, 0x00000007ac800000, 0x00000007aca00000| 0%| F| |TAMS 0x00000007ac800000, 0x00000007ac800000| Untracked -|1361|0x00000007aca00000, 0x00000007aca00000, 0x00000007acc00000| 0%| F| |TAMS 0x00000007aca00000, 0x00000007aca00000| Untracked -|1362|0x00000007acc00000, 0x00000007acc00000, 0x00000007ace00000| 0%| F| |TAMS 0x00000007acc00000, 0x00000007acc00000| Untracked -|1363|0x00000007ace00000, 0x00000007ace00000, 0x00000007ad000000| 0%| F| |TAMS 0x00000007ace00000, 0x00000007ace00000| Untracked -|1364|0x00000007ad000000, 0x00000007ad000000, 0x00000007ad200000| 0%| F| |TAMS 0x00000007ad000000, 0x00000007ad000000| Untracked -|1365|0x00000007ad200000, 0x00000007ad200000, 0x00000007ad400000| 0%| F| |TAMS 0x00000007ad200000, 0x00000007ad200000| Untracked -|1366|0x00000007ad400000, 0x00000007ad400000, 0x00000007ad600000| 0%| F| |TAMS 0x00000007ad400000, 0x00000007ad400000| Untracked -|1367|0x00000007ad600000, 0x00000007ad600000, 0x00000007ad800000| 0%| F| |TAMS 0x00000007ad600000, 0x00000007ad600000| Untracked -|1368|0x00000007ad800000, 0x00000007ad800000, 0x00000007ada00000| 0%| F| |TAMS 0x00000007ad800000, 0x00000007ad800000| Untracked -|1369|0x00000007ada00000, 0x00000007ada00000, 0x00000007adc00000| 0%| F| |TAMS 0x00000007ada00000, 0x00000007ada00000| Untracked -|1370|0x00000007adc00000, 0x00000007adc00000, 0x00000007ade00000| 0%| F| |TAMS 0x00000007adc00000, 0x00000007adc00000| Untracked -|1371|0x00000007ade00000, 0x00000007ade00000, 0x00000007ae000000| 0%| F| |TAMS 0x00000007ade00000, 0x00000007ade00000| Untracked -|1372|0x00000007ae000000, 0x00000007ae000000, 0x00000007ae200000| 0%| F| |TAMS 0x00000007ae000000, 0x00000007ae000000| Untracked -|1373|0x00000007ae200000, 0x00000007ae200000, 0x00000007ae400000| 0%| F| |TAMS 0x00000007ae200000, 0x00000007ae200000| Untracked -|1374|0x00000007ae400000, 0x00000007ae400000, 0x00000007ae600000| 0%| F| |TAMS 0x00000007ae400000, 0x00000007ae400000| Untracked -|1375|0x00000007ae600000, 0x00000007ae600000, 0x00000007ae800000| 0%| F| |TAMS 0x00000007ae600000, 0x00000007ae600000| Untracked -|1376|0x00000007ae800000, 0x00000007ae800000, 0x00000007aea00000| 0%| F| |TAMS 0x00000007ae800000, 0x00000007ae800000| Untracked -|1377|0x00000007aea00000, 0x00000007aea00000, 0x00000007aec00000| 0%| F| |TAMS 0x00000007aea00000, 0x00000007aea00000| Untracked -|1378|0x00000007aec00000, 0x00000007aec00000, 0x00000007aee00000| 0%| F| |TAMS 0x00000007aec00000, 0x00000007aec00000| Untracked -|1379|0x00000007aee00000, 0x00000007aee00000, 0x00000007af000000| 0%| F| |TAMS 0x00000007aee00000, 0x00000007aee00000| Untracked -|1380|0x00000007af000000, 0x00000007af000000, 0x00000007af200000| 0%| F| |TAMS 0x00000007af000000, 0x00000007af000000| Untracked -|1381|0x00000007af200000, 0x00000007af200000, 0x00000007af400000| 0%| F| |TAMS 0x00000007af200000, 0x00000007af200000| Untracked -|1382|0x00000007af400000, 0x00000007af400000, 0x00000007af600000| 0%| F| |TAMS 0x00000007af400000, 0x00000007af400000| Untracked -|1383|0x00000007af600000, 0x00000007af600000, 0x00000007af800000| 0%| F| |TAMS 0x00000007af600000, 0x00000007af600000| Untracked -|1384|0x00000007af800000, 0x00000007af800000, 0x00000007afa00000| 0%| F| |TAMS 0x00000007af800000, 0x00000007af800000| Untracked -|1385|0x00000007afa00000, 0x00000007afa00000, 0x00000007afc00000| 0%| F| |TAMS 0x00000007afa00000, 0x00000007afa00000| Untracked -|1386|0x00000007afc00000, 0x00000007afc00000, 0x00000007afe00000| 0%| F| |TAMS 0x00000007afc00000, 0x00000007afc00000| Untracked -|1387|0x00000007afe00000, 0x00000007afe00000, 0x00000007b0000000| 0%| F| |TAMS 0x00000007afe00000, 0x00000007afe00000| Untracked -|1388|0x00000007b0000000, 0x00000007b0000000, 0x00000007b0200000| 0%| F| |TAMS 0x00000007b0000000, 0x00000007b0000000| Untracked -|1389|0x00000007b0200000, 0x00000007b0200000, 0x00000007b0400000| 0%| F| |TAMS 0x00000007b0200000, 0x00000007b0200000| Untracked -|1390|0x00000007b0400000, 0x00000007b0400000, 0x00000007b0600000| 0%| F| |TAMS 0x00000007b0400000, 0x00000007b0400000| Untracked -|1391|0x00000007b0600000, 0x00000007b0600000, 0x00000007b0800000| 0%| F| |TAMS 0x00000007b0600000, 0x00000007b0600000| Untracked -|1392|0x00000007b0800000, 0x00000007b0800000, 0x00000007b0a00000| 0%| F| |TAMS 0x00000007b0800000, 0x00000007b0800000| Untracked -|1393|0x00000007b0a00000, 0x00000007b0a00000, 0x00000007b0c00000| 0%| F| |TAMS 0x00000007b0a00000, 0x00000007b0a00000| Untracked -|1394|0x00000007b0c00000, 0x00000007b0c00000, 0x00000007b0e00000| 0%| F| |TAMS 0x00000007b0c00000, 0x00000007b0c00000| Untracked -|1395|0x00000007b0e00000, 0x00000007b0e00000, 0x00000007b1000000| 0%| F| |TAMS 0x00000007b0e00000, 0x00000007b0e00000| Untracked -|1396|0x00000007b1000000, 0x00000007b1000000, 0x00000007b1200000| 0%| F| |TAMS 0x00000007b1000000, 0x00000007b1000000| Untracked -|1397|0x00000007b1200000, 0x00000007b1200000, 0x00000007b1400000| 0%| F| |TAMS 0x00000007b1200000, 0x00000007b1200000| Untracked -|1398|0x00000007b1400000, 0x00000007b1400000, 0x00000007b1600000| 0%| F| |TAMS 0x00000007b1400000, 0x00000007b1400000| Untracked -|1399|0x00000007b1600000, 0x00000007b1600000, 0x00000007b1800000| 0%| F| |TAMS 0x00000007b1600000, 0x00000007b1600000| Untracked -|1400|0x00000007b1800000, 0x00000007b1800000, 0x00000007b1a00000| 0%| F| |TAMS 0x00000007b1800000, 0x00000007b1800000| Untracked -|1401|0x00000007b1a00000, 0x00000007b1a00000, 0x00000007b1c00000| 0%| F| |TAMS 0x00000007b1a00000, 0x00000007b1a00000| Untracked -|1402|0x00000007b1c00000, 0x00000007b1c00000, 0x00000007b1e00000| 0%| F| |TAMS 0x00000007b1c00000, 0x00000007b1c00000| Untracked -|1403|0x00000007b1e00000, 0x00000007b1e00000, 0x00000007b2000000| 0%| F| |TAMS 0x00000007b1e00000, 0x00000007b1e00000| Untracked -|1404|0x00000007b2000000, 0x00000007b2000000, 0x00000007b2200000| 0%| F| |TAMS 0x00000007b2000000, 0x00000007b2000000| Untracked -|1405|0x00000007b2200000, 0x00000007b2200000, 0x00000007b2400000| 0%| F| |TAMS 0x00000007b2200000, 0x00000007b2200000| Untracked -|1406|0x00000007b2400000, 0x00000007b2400000, 0x00000007b2600000| 0%| F| |TAMS 0x00000007b2400000, 0x00000007b2400000| Untracked -|1407|0x00000007b2600000, 0x00000007b2600000, 0x00000007b2800000| 0%| F| |TAMS 0x00000007b2600000, 0x00000007b2600000| Untracked -|1408|0x00000007b2800000, 0x00000007b2800000, 0x00000007b2a00000| 0%| F| |TAMS 0x00000007b2800000, 0x00000007b2800000| Untracked -|1409|0x00000007b2a00000, 0x00000007b2a00000, 0x00000007b2c00000| 0%| F| |TAMS 0x00000007b2a00000, 0x00000007b2a00000| Untracked -|1410|0x00000007b2c00000, 0x00000007b2c00000, 0x00000007b2e00000| 0%| F| |TAMS 0x00000007b2c00000, 0x00000007b2c00000| Untracked -|1411|0x00000007b2e00000, 0x00000007b2e00000, 0x00000007b3000000| 0%| F| |TAMS 0x00000007b2e00000, 0x00000007b2e00000| Untracked -|1412|0x00000007b3000000, 0x00000007b3000000, 0x00000007b3200000| 0%| F| |TAMS 0x00000007b3000000, 0x00000007b3000000| Untracked -|1413|0x00000007b3200000, 0x00000007b3200000, 0x00000007b3400000| 0%| F| |TAMS 0x00000007b3200000, 0x00000007b3200000| Untracked -|1414|0x00000007b3400000, 0x00000007b3400000, 0x00000007b3600000| 0%| F| |TAMS 0x00000007b3400000, 0x00000007b3400000| Untracked -|1415|0x00000007b3600000, 0x00000007b3600000, 0x00000007b3800000| 0%| F| |TAMS 0x00000007b3600000, 0x00000007b3600000| Untracked -|1416|0x00000007b3800000, 0x00000007b3800000, 0x00000007b3a00000| 0%| F| |TAMS 0x00000007b3800000, 0x00000007b3800000| Untracked -|1417|0x00000007b3a00000, 0x00000007b3a00000, 0x00000007b3c00000| 0%| F| |TAMS 0x00000007b3a00000, 0x00000007b3a00000| Untracked -|1418|0x00000007b3c00000, 0x00000007b3c00000, 0x00000007b3e00000| 0%| F| |TAMS 0x00000007b3c00000, 0x00000007b3c00000| Untracked -|1419|0x00000007b3e00000, 0x00000007b3e00000, 0x00000007b4000000| 0%| F| |TAMS 0x00000007b3e00000, 0x00000007b3e00000| Untracked -|1420|0x00000007b4000000, 0x00000007b4000000, 0x00000007b4200000| 0%| F| |TAMS 0x00000007b4000000, 0x00000007b4000000| Untracked -|1421|0x00000007b4200000, 0x00000007b4200000, 0x00000007b4400000| 0%| F| |TAMS 0x00000007b4200000, 0x00000007b4200000| Untracked -|1422|0x00000007b4400000, 0x00000007b4400000, 0x00000007b4600000| 0%| F| |TAMS 0x00000007b4400000, 0x00000007b4400000| Untracked -|1423|0x00000007b4600000, 0x00000007b4600000, 0x00000007b4800000| 0%| F| |TAMS 0x00000007b4600000, 0x00000007b4600000| Untracked -|1424|0x00000007b4800000, 0x00000007b4800000, 0x00000007b4a00000| 0%| F| |TAMS 0x00000007b4800000, 0x00000007b4800000| Untracked -|1425|0x00000007b4a00000, 0x00000007b4a00000, 0x00000007b4c00000| 0%| F| |TAMS 0x00000007b4a00000, 0x00000007b4a00000| Untracked -|1426|0x00000007b4c00000, 0x00000007b4c00000, 0x00000007b4e00000| 0%| F| |TAMS 0x00000007b4c00000, 0x00000007b4c00000| Untracked -|1427|0x00000007b4e00000, 0x00000007b4e00000, 0x00000007b5000000| 0%| F| |TAMS 0x00000007b4e00000, 0x00000007b4e00000| Untracked -|1428|0x00000007b5000000, 0x00000007b5000000, 0x00000007b5200000| 0%| F| |TAMS 0x00000007b5000000, 0x00000007b5000000| Untracked -|1429|0x00000007b5200000, 0x00000007b5200000, 0x00000007b5400000| 0%| F| |TAMS 0x00000007b5200000, 0x00000007b5200000| Untracked -|1430|0x00000007b5400000, 0x00000007b5400000, 0x00000007b5600000| 0%| F| |TAMS 0x00000007b5400000, 0x00000007b5400000| Untracked -|1431|0x00000007b5600000, 0x00000007b5600000, 0x00000007b5800000| 0%| F| |TAMS 0x00000007b5600000, 0x00000007b5600000| Untracked -|1432|0x00000007b5800000, 0x00000007b5800000, 0x00000007b5a00000| 0%| F| |TAMS 0x00000007b5800000, 0x00000007b5800000| Untracked -|1433|0x00000007b5a00000, 0x00000007b5a00000, 0x00000007b5c00000| 0%| F| |TAMS 0x00000007b5a00000, 0x00000007b5a00000| Untracked -|1434|0x00000007b5c00000, 0x00000007b5c00000, 0x00000007b5e00000| 0%| F| |TAMS 0x00000007b5c00000, 0x00000007b5c00000| Untracked -|1435|0x00000007b5e00000, 0x00000007b5e00000, 0x00000007b6000000| 0%| F| |TAMS 0x00000007b5e00000, 0x00000007b5e00000| Untracked -|1436|0x00000007b6000000, 0x00000007b6000000, 0x00000007b6200000| 0%| F| |TAMS 0x00000007b6000000, 0x00000007b6000000| Untracked -|1437|0x00000007b6200000, 0x00000007b6200000, 0x00000007b6400000| 0%| F| |TAMS 0x00000007b6200000, 0x00000007b6200000| Untracked -|1438|0x00000007b6400000, 0x00000007b6400000, 0x00000007b6600000| 0%| F| |TAMS 0x00000007b6400000, 0x00000007b6400000| Untracked -|1439|0x00000007b6600000, 0x00000007b6600000, 0x00000007b6800000| 0%| F| |TAMS 0x00000007b6600000, 0x00000007b6600000| Untracked -|1440|0x00000007b6800000, 0x00000007b6800000, 0x00000007b6a00000| 0%| F| |TAMS 0x00000007b6800000, 0x00000007b6800000| Untracked -|1441|0x00000007b6a00000, 0x00000007b6a00000, 0x00000007b6c00000| 0%| F| |TAMS 0x00000007b6a00000, 0x00000007b6a00000| Untracked -|1442|0x00000007b6c00000, 0x00000007b6e00000, 0x00000007b6e00000|100%| S|CS|TAMS 0x00000007b6c00000, 0x00000007b6c00000| Complete -|1443|0x00000007b6e00000, 0x00000007b7000000, 0x00000007b7000000|100%| S|CS|TAMS 0x00000007b6e00000, 0x00000007b6e00000| Complete -|1444|0x00000007b7000000, 0x00000007b7200000, 0x00000007b7200000|100%| S|CS|TAMS 0x00000007b7000000, 0x00000007b7000000| Complete -|1445|0x00000007b7200000, 0x00000007b7400000, 0x00000007b7400000|100%| S|CS|TAMS 0x00000007b7200000, 0x00000007b7200000| Complete -|1446|0x00000007b7400000, 0x00000007b7600000, 0x00000007b7600000|100%| S|CS|TAMS 0x00000007b7400000, 0x00000007b7400000| Complete -|1447|0x00000007b7600000, 0x00000007b7800000, 0x00000007b7800000|100%| S|CS|TAMS 0x00000007b7600000, 0x00000007b7600000| Complete -|1448|0x00000007b7800000, 0x00000007b7a00000, 0x00000007b7a00000|100%| S|CS|TAMS 0x00000007b7800000, 0x00000007b7800000| Complete -|1449|0x00000007b7a00000, 0x00000007b7c00000, 0x00000007b7c00000|100%| S|CS|TAMS 0x00000007b7a00000, 0x00000007b7a00000| Complete -|1450|0x00000007b7c00000, 0x00000007b7e00000, 0x00000007b7e00000|100%| S|CS|TAMS 0x00000007b7c00000, 0x00000007b7c00000| Complete -|1451|0x00000007b7e00000, 0x00000007b8000000, 0x00000007b8000000|100%| S|CS|TAMS 0x00000007b7e00000, 0x00000007b7e00000| Complete -|1452|0x00000007b8000000, 0x00000007b8200000, 0x00000007b8200000|100%| S|CS|TAMS 0x00000007b8000000, 0x00000007b8000000| Complete -|1453|0x00000007b8200000, 0x00000007b8400000, 0x00000007b8400000|100%| S|CS|TAMS 0x00000007b8200000, 0x00000007b8200000| Complete -|1454|0x00000007b8400000, 0x00000007b8600000, 0x00000007b8600000|100%| S|CS|TAMS 0x00000007b8400000, 0x00000007b8400000| Complete -|1455|0x00000007b8600000, 0x00000007b8800000, 0x00000007b8800000|100%| S|CS|TAMS 0x00000007b8600000, 0x00000007b8600000| Complete -|1456|0x00000007b8800000, 0x00000007b8a00000, 0x00000007b8a00000|100%| S|CS|TAMS 0x00000007b8800000, 0x00000007b8800000| Complete -|1457|0x00000007b8a00000, 0x00000007b8c00000, 0x00000007b8c00000|100%| S|CS|TAMS 0x00000007b8a00000, 0x00000007b8a00000| Complete -|1458|0x00000007b8c00000, 0x00000007b8e00000, 0x00000007b8e00000|100%| S|CS|TAMS 0x00000007b8c00000, 0x00000007b8c00000| Complete -|1459|0x00000007b8e00000, 0x00000007b9000000, 0x00000007b9000000|100%| S|CS|TAMS 0x00000007b8e00000, 0x00000007b8e00000| Complete -|1460|0x00000007b9000000, 0x00000007b9200000, 0x00000007b9200000|100%| S|CS|TAMS 0x00000007b9000000, 0x00000007b9000000| Complete -|1461|0x00000007b9200000, 0x00000007b9400000, 0x00000007b9400000|100%| S|CS|TAMS 0x00000007b9200000, 0x00000007b9200000| Complete -|1462|0x00000007b9400000, 0x00000007b9600000, 0x00000007b9600000|100%| S|CS|TAMS 0x00000007b9400000, 0x00000007b9400000| Complete -|1463|0x00000007b9600000, 0x00000007b9800000, 0x00000007b9800000|100%| S|CS|TAMS 0x00000007b9600000, 0x00000007b9600000| Complete -|1464|0x00000007b9800000, 0x00000007b9a00000, 0x00000007b9a00000|100%| S|CS|TAMS 0x00000007b9800000, 0x00000007b9800000| Complete -|1465|0x00000007b9a00000, 0x00000007b9c00000, 0x00000007b9c00000|100%| S|CS|TAMS 0x00000007b9a00000, 0x00000007b9a00000| Complete -|1466|0x00000007b9c00000, 0x00000007b9e00000, 0x00000007b9e00000|100%| S|CS|TAMS 0x00000007b9c00000, 0x00000007b9c00000| Complete -|1467|0x00000007b9e00000, 0x00000007ba000000, 0x00000007ba000000|100%| S|CS|TAMS 0x00000007b9e00000, 0x00000007b9e00000| Complete -|1468|0x00000007ba000000, 0x00000007ba200000, 0x00000007ba200000|100%| S|CS|TAMS 0x00000007ba000000, 0x00000007ba000000| Complete -|1469|0x00000007ba200000, 0x00000007ba400000, 0x00000007ba400000|100%| S|CS|TAMS 0x00000007ba200000, 0x00000007ba200000| Complete -|1470|0x00000007ba400000, 0x00000007ba600000, 0x00000007ba600000|100%| S|CS|TAMS 0x00000007ba400000, 0x00000007ba400000| Complete -|1471|0x00000007ba600000, 0x00000007ba800000, 0x00000007ba800000|100%| S|CS|TAMS 0x00000007ba600000, 0x00000007ba600000| Complete -|1472|0x00000007ba800000, 0x00000007baa00000, 0x00000007baa00000|100%| S|CS|TAMS 0x00000007ba800000, 0x00000007ba800000| Complete -|1473|0x00000007baa00000, 0x00000007bac00000, 0x00000007bac00000|100%| S|CS|TAMS 0x00000007baa00000, 0x00000007baa00000| Complete -|1474|0x00000007bac00000, 0x00000007bae00000, 0x00000007bae00000|100%| S|CS|TAMS 0x00000007bac00000, 0x00000007bac00000| Complete -|1475|0x00000007bae00000, 0x00000007bb000000, 0x00000007bb000000|100%| S|CS|TAMS 0x00000007bae00000, 0x00000007bae00000| Complete -|1476|0x00000007bb000000, 0x00000007bb200000, 0x00000007bb200000|100%| S|CS|TAMS 0x00000007bb000000, 0x00000007bb000000| Complete -|1477|0x00000007bb200000, 0x00000007bb400000, 0x00000007bb400000|100%| S|CS|TAMS 0x00000007bb200000, 0x00000007bb200000| Complete -|1478|0x00000007bb400000, 0x00000007bb600000, 0x00000007bb600000|100%| S|CS|TAMS 0x00000007bb400000, 0x00000007bb400000| Complete -|1479|0x00000007bb600000, 0x00000007bb800000, 0x00000007bb800000|100%| S|CS|TAMS 0x00000007bb600000, 0x00000007bb600000| Complete -|1480|0x00000007bb800000, 0x00000007bb800000, 0x00000007bba00000| 0%| F| |TAMS 0x00000007bb800000, 0x00000007bb800000| Untracked -|1481|0x00000007bba00000, 0x00000007bba00000, 0x00000007bbc00000| 0%| F| |TAMS 0x00000007bba00000, 0x00000007bba00000| Untracked -|1482|0x00000007bbc00000, 0x00000007bbc00000, 0x00000007bbe00000| 0%| F| |TAMS 0x00000007bbc00000, 0x00000007bbc00000| Untracked -|1483|0x00000007bbe00000, 0x00000007bbe00000, 0x00000007bc000000| 0%| F| |TAMS 0x00000007bbe00000, 0x00000007bbe00000| Untracked -|1484|0x00000007bc000000, 0x00000007bc000000, 0x00000007bc200000| 0%| F| |TAMS 0x00000007bc000000, 0x00000007bc000000| Untracked -|1485|0x00000007bc200000, 0x00000007bc200000, 0x00000007bc400000| 0%| F| |TAMS 0x00000007bc200000, 0x00000007bc200000| Untracked -|1486|0x00000007bc400000, 0x00000007bc400000, 0x00000007bc600000| 0%| F| |TAMS 0x00000007bc400000, 0x00000007bc400000| Untracked -|1487|0x00000007bc600000, 0x00000007bc600000, 0x00000007bc800000| 0%| F| |TAMS 0x00000007bc600000, 0x00000007bc600000| Untracked -|1488|0x00000007bc800000, 0x00000007bc800000, 0x00000007bca00000| 0%| F| |TAMS 0x00000007bc800000, 0x00000007bc800000| Untracked -|1489|0x00000007bca00000, 0x00000007bca00000, 0x00000007bcc00000| 0%| F| |TAMS 0x00000007bca00000, 0x00000007bca00000| Untracked -|1490|0x00000007bcc00000, 0x00000007bcc00000, 0x00000007bce00000| 0%| F| |TAMS 0x00000007bcc00000, 0x00000007bcc00000| Untracked -|1491|0x00000007bce00000, 0x00000007bce00000, 0x00000007bd000000| 0%| F| |TAMS 0x00000007bce00000, 0x00000007bce00000| Untracked -|1492|0x00000007bd000000, 0x00000007bd000000, 0x00000007bd200000| 0%| F| |TAMS 0x00000007bd000000, 0x00000007bd000000| Untracked -|1493|0x00000007bd200000, 0x00000007bd200000, 0x00000007bd400000| 0%| F| |TAMS 0x00000007bd200000, 0x00000007bd200000| Untracked -|1494|0x00000007bd400000, 0x00000007bd400000, 0x00000007bd600000| 0%| F| |TAMS 0x00000007bd400000, 0x00000007bd400000| Untracked -|1495|0x00000007bd600000, 0x00000007bd600000, 0x00000007bd800000| 0%| F| |TAMS 0x00000007bd600000, 0x00000007bd600000| Untracked -|1496|0x00000007bd800000, 0x00000007bd800000, 0x00000007bda00000| 0%| F| |TAMS 0x00000007bd800000, 0x00000007bd800000| Untracked -|1497|0x00000007bda00000, 0x00000007bda00000, 0x00000007bdc00000| 0%| F| |TAMS 0x00000007bda00000, 0x00000007bda00000| Untracked -|1498|0x00000007bdc00000, 0x00000007bdc00000, 0x00000007bde00000| 0%| F| |TAMS 0x00000007bdc00000, 0x00000007bdc00000| Untracked -|1499|0x00000007bde00000, 0x00000007bde00000, 0x00000007be000000| 0%| F| |TAMS 0x00000007bde00000, 0x00000007bde00000| Untracked -|1500|0x00000007be000000, 0x00000007be000000, 0x00000007be200000| 0%| F| |TAMS 0x00000007be000000, 0x00000007be000000| Untracked -|1501|0x00000007be200000, 0x00000007be200000, 0x00000007be400000| 0%| F| |TAMS 0x00000007be200000, 0x00000007be200000| Untracked -|1502|0x00000007be400000, 0x00000007be400000, 0x00000007be600000| 0%| F| |TAMS 0x00000007be400000, 0x00000007be400000| Untracked -|1503|0x00000007be600000, 0x00000007be600000, 0x00000007be800000| 0%| F| |TAMS 0x00000007be600000, 0x00000007be600000| Untracked -|1504|0x00000007be800000, 0x00000007be800000, 0x00000007bea00000| 0%| F| |TAMS 0x00000007be800000, 0x00000007be800000| Untracked -|1505|0x00000007bea00000, 0x00000007bea00000, 0x00000007bec00000| 0%| F| |TAMS 0x00000007bea00000, 0x00000007bea00000| Untracked -|1506|0x00000007bec00000, 0x00000007bec00000, 0x00000007bee00000| 0%| F| |TAMS 0x00000007bec00000, 0x00000007bec00000| Untracked -|1507|0x00000007bee00000, 0x00000007bee00000, 0x00000007bf000000| 0%| F| |TAMS 0x00000007bee00000, 0x00000007bee00000| Untracked -|1508|0x00000007bf000000, 0x00000007bf000000, 0x00000007bf200000| 0%| F| |TAMS 0x00000007bf000000, 0x00000007bf000000| Untracked -|1509|0x00000007bf200000, 0x00000007bf200000, 0x00000007bf400000| 0%| F| |TAMS 0x00000007bf200000, 0x00000007bf200000| Untracked -|1510|0x00000007bf400000, 0x00000007bf400000, 0x00000007bf600000| 0%| F| |TAMS 0x00000007bf400000, 0x00000007bf400000| Untracked -|1511|0x00000007bf600000, 0x00000007bf600000, 0x00000007bf800000| 0%| F| |TAMS 0x00000007bf600000, 0x00000007bf600000| Untracked -|1512|0x00000007bf800000, 0x00000007bf800000, 0x00000007bfa00000| 0%| F| |TAMS 0x00000007bf800000, 0x00000007bf800000| Untracked -|1513|0x00000007bfa00000, 0x00000007bfa00000, 0x00000007bfc00000| 0%| F| |TAMS 0x00000007bfa00000, 0x00000007bfa00000| Untracked -|1514|0x00000007bfc00000, 0x00000007bfc00000, 0x00000007bfe00000| 0%| F| |TAMS 0x00000007bfc00000, 0x00000007bfc00000| Untracked -|1515|0x00000007bfe00000, 0x00000007bfe00000, 0x00000007c0000000| 0%| F| |TAMS 0x00000007bfe00000, 0x00000007bfe00000| Untracked -|1516|0x00000007c0000000, 0x00000007c0000000, 0x00000007c0200000| 0%| F| |TAMS 0x00000007c0000000, 0x00000007c0000000| Untracked -|1517|0x00000007c0200000, 0x00000007c0200000, 0x00000007c0400000| 0%| F| |TAMS 0x00000007c0200000, 0x00000007c0200000| Untracked -|1518|0x00000007c0400000, 0x00000007c0400000, 0x00000007c0600000| 0%| F| |TAMS 0x00000007c0400000, 0x00000007c0400000| Untracked -|1519|0x00000007c0600000, 0x00000007c0600000, 0x00000007c0800000| 0%| F| |TAMS 0x00000007c0600000, 0x00000007c0600000| Untracked -|1520|0x00000007c0800000, 0x00000007c0800000, 0x00000007c0a00000| 0%| F| |TAMS 0x00000007c0800000, 0x00000007c0800000| Untracked -|1521|0x00000007c0a00000, 0x00000007c0a00000, 0x00000007c0c00000| 0%| F| |TAMS 0x00000007c0a00000, 0x00000007c0a00000| Untracked -|1522|0x00000007c0c00000, 0x00000007c0c00000, 0x00000007c0e00000| 0%| F| |TAMS 0x00000007c0c00000, 0x00000007c0c00000| Untracked -|1523|0x00000007c0e00000, 0x00000007c0e00000, 0x00000007c1000000| 0%| F| |TAMS 0x00000007c0e00000, 0x00000007c0e00000| Untracked -|1524|0x00000007c1000000, 0x00000007c1000000, 0x00000007c1200000| 0%| F| |TAMS 0x00000007c1000000, 0x00000007c1000000| Untracked -|1525|0x00000007c1200000, 0x00000007c1200000, 0x00000007c1400000| 0%| F| |TAMS 0x00000007c1200000, 0x00000007c1200000| Untracked -|1526|0x00000007c1400000, 0x00000007c1400000, 0x00000007c1600000| 0%| F| |TAMS 0x00000007c1400000, 0x00000007c1400000| Untracked -|1527|0x00000007c1600000, 0x00000007c1600000, 0x00000007c1800000| 0%| F| |TAMS 0x00000007c1600000, 0x00000007c1600000| Untracked -|1528|0x00000007c1800000, 0x00000007c1800000, 0x00000007c1a00000| 0%| F| |TAMS 0x00000007c1800000, 0x00000007c1800000| Untracked -|1529|0x00000007c1a00000, 0x00000007c1a00000, 0x00000007c1c00000| 0%| F| |TAMS 0x00000007c1a00000, 0x00000007c1a00000| Untracked -|1530|0x00000007c1c00000, 0x00000007c1c00000, 0x00000007c1e00000| 0%| F| |TAMS 0x00000007c1c00000, 0x00000007c1c00000| Untracked -|1531|0x00000007c1e00000, 0x00000007c1e00000, 0x00000007c2000000| 0%| F| |TAMS 0x00000007c1e00000, 0x00000007c1e00000| Untracked -|1532|0x00000007c2000000, 0x00000007c2000000, 0x00000007c2200000| 0%| F| |TAMS 0x00000007c2000000, 0x00000007c2000000| Untracked -|1533|0x00000007c2200000, 0x00000007c2200000, 0x00000007c2400000| 0%| F| |TAMS 0x00000007c2200000, 0x00000007c2200000| Untracked -|1534|0x00000007c2400000, 0x00000007c2400000, 0x00000007c2600000| 0%| F| |TAMS 0x00000007c2400000, 0x00000007c2400000| Untracked -|1535|0x00000007c2600000, 0x00000007c2600000, 0x00000007c2800000| 0%| F| |TAMS 0x00000007c2600000, 0x00000007c2600000| Untracked -|1536|0x00000007c2800000, 0x00000007c2800000, 0x00000007c2a00000| 0%| F| |TAMS 0x00000007c2800000, 0x00000007c2800000| Untracked -|1537|0x00000007c2a00000, 0x00000007c2a00000, 0x00000007c2c00000| 0%| F| |TAMS 0x00000007c2a00000, 0x00000007c2a00000| Untracked -|1538|0x00000007c2c00000, 0x00000007c2c00000, 0x00000007c2e00000| 0%| F| |TAMS 0x00000007c2c00000, 0x00000007c2c00000| Untracked -|1539|0x00000007c2e00000, 0x00000007c2e00000, 0x00000007c3000000| 0%| F| |TAMS 0x00000007c2e00000, 0x00000007c2e00000| Untracked -|1540|0x00000007c3000000, 0x00000007c3000000, 0x00000007c3200000| 0%| F| |TAMS 0x00000007c3000000, 0x00000007c3000000| Untracked -|1541|0x00000007c3200000, 0x00000007c3200000, 0x00000007c3400000| 0%| F| |TAMS 0x00000007c3200000, 0x00000007c3200000| Untracked -|1542|0x00000007c3400000, 0x00000007c3400000, 0x00000007c3600000| 0%| F| |TAMS 0x00000007c3400000, 0x00000007c3400000| Untracked -|1543|0x00000007c3600000, 0x00000007c3600000, 0x00000007c3800000| 0%| F| |TAMS 0x00000007c3600000, 0x00000007c3600000| Untracked -|1544|0x00000007c3800000, 0x00000007c3800000, 0x00000007c3a00000| 0%| F| |TAMS 0x00000007c3800000, 0x00000007c3800000| Untracked -|1545|0x00000007c3a00000, 0x00000007c3a00000, 0x00000007c3c00000| 0%| F| |TAMS 0x00000007c3a00000, 0x00000007c3a00000| Untracked -|1546|0x00000007c3c00000, 0x00000007c3c00000, 0x00000007c3e00000| 0%| F| |TAMS 0x00000007c3c00000, 0x00000007c3c00000| Untracked -|1547|0x00000007c3e00000, 0x00000007c3e00000, 0x00000007c4000000| 0%| F| |TAMS 0x00000007c3e00000, 0x00000007c3e00000| Untracked -|1548|0x00000007c4000000, 0x00000007c4000000, 0x00000007c4200000| 0%| F| |TAMS 0x00000007c4000000, 0x00000007c4000000| Untracked -|1549|0x00000007c4200000, 0x00000007c4200000, 0x00000007c4400000| 0%| F| |TAMS 0x00000007c4200000, 0x00000007c4200000| Untracked -|1550|0x00000007c4400000, 0x00000007c4400000, 0x00000007c4600000| 0%| F| |TAMS 0x00000007c4400000, 0x00000007c4400000| Untracked -|1551|0x00000007c4600000, 0x00000007c4600000, 0x00000007c4800000| 0%| F| |TAMS 0x00000007c4600000, 0x00000007c4600000| Untracked -|1552|0x00000007c4800000, 0x00000007c4800000, 0x00000007c4a00000| 0%| F| |TAMS 0x00000007c4800000, 0x00000007c4800000| Untracked -|1553|0x00000007c4a00000, 0x00000007c4a00000, 0x00000007c4c00000| 0%| F| |TAMS 0x00000007c4a00000, 0x00000007c4a00000| Untracked -|1554|0x00000007c4c00000, 0x00000007c4c00000, 0x00000007c4e00000| 0%| F| |TAMS 0x00000007c4c00000, 0x00000007c4c00000| Untracked -|1555|0x00000007c4e00000, 0x00000007c4e00000, 0x00000007c5000000| 0%| F| |TAMS 0x00000007c4e00000, 0x00000007c4e00000| Untracked -|1556|0x00000007c5000000, 0x00000007c5000000, 0x00000007c5200000| 0%| F| |TAMS 0x00000007c5000000, 0x00000007c5000000| Untracked -|1557|0x00000007c5200000, 0x00000007c5200000, 0x00000007c5400000| 0%| F| |TAMS 0x00000007c5200000, 0x00000007c5200000| Untracked -|1558|0x00000007c5400000, 0x00000007c5400000, 0x00000007c5600000| 0%| F| |TAMS 0x00000007c5400000, 0x00000007c5400000| Untracked -|1559|0x00000007c5600000, 0x00000007c5600000, 0x00000007c5800000| 0%| F| |TAMS 0x00000007c5600000, 0x00000007c5600000| Untracked -|1560|0x00000007c5800000, 0x00000007c5800000, 0x00000007c5a00000| 0%| F| |TAMS 0x00000007c5800000, 0x00000007c5800000| Untracked -|1561|0x00000007c5a00000, 0x00000007c5a00000, 0x00000007c5c00000| 0%| F| |TAMS 0x00000007c5a00000, 0x00000007c5a00000| Untracked -|1562|0x00000007c5c00000, 0x00000007c5c00000, 0x00000007c5e00000| 0%| F| |TAMS 0x00000007c5c00000, 0x00000007c5c00000| Untracked -|1563|0x00000007c5e00000, 0x00000007c5e00000, 0x00000007c6000000| 0%| F| |TAMS 0x00000007c5e00000, 0x00000007c5e00000| Untracked -|1564|0x00000007c6000000, 0x00000007c6000000, 0x00000007c6200000| 0%| F| |TAMS 0x00000007c6000000, 0x00000007c6000000| Untracked -|1565|0x00000007c6200000, 0x00000007c6200000, 0x00000007c6400000| 0%| F| |TAMS 0x00000007c6200000, 0x00000007c6200000| Untracked -|1566|0x00000007c6400000, 0x00000007c6400000, 0x00000007c6600000| 0%| F| |TAMS 0x00000007c6400000, 0x00000007c6400000| Untracked -|1567|0x00000007c6600000, 0x00000007c6600000, 0x00000007c6800000| 0%| F| |TAMS 0x00000007c6600000, 0x00000007c6600000| Untracked -|1568|0x00000007c6800000, 0x00000007c6800000, 0x00000007c6a00000| 0%| F| |TAMS 0x00000007c6800000, 0x00000007c6800000| Untracked -|1569|0x00000007c6a00000, 0x00000007c6a00000, 0x00000007c6c00000| 0%| F| |TAMS 0x00000007c6a00000, 0x00000007c6a00000| Untracked -|1570|0x00000007c6c00000, 0x00000007c6c00000, 0x00000007c6e00000| 0%| F| |TAMS 0x00000007c6c00000, 0x00000007c6c00000| Untracked -|1571|0x00000007c6e00000, 0x00000007c6e00000, 0x00000007c7000000| 0%| F| |TAMS 0x00000007c6e00000, 0x00000007c6e00000| Untracked -|1572|0x00000007c7000000, 0x00000007c7000000, 0x00000007c7200000| 0%| F| |TAMS 0x00000007c7000000, 0x00000007c7000000| Untracked -|1573|0x00000007c7200000, 0x00000007c7200000, 0x00000007c7400000| 0%| F| |TAMS 0x00000007c7200000, 0x00000007c7200000| Untracked -|1574|0x00000007c7400000, 0x00000007c7400000, 0x00000007c7600000| 0%| F| |TAMS 0x00000007c7400000, 0x00000007c7400000| Untracked -|1575|0x00000007c7600000, 0x00000007c7600000, 0x00000007c7800000| 0%| F| |TAMS 0x00000007c7600000, 0x00000007c7600000| Untracked -|1576|0x00000007c7800000, 0x00000007c7800000, 0x00000007c7a00000| 0%| F| |TAMS 0x00000007c7800000, 0x00000007c7800000| Untracked -|1577|0x00000007c7a00000, 0x00000007c7a00000, 0x00000007c7c00000| 0%| F| |TAMS 0x00000007c7a00000, 0x00000007c7a00000| Untracked -|1578|0x00000007c7c00000, 0x00000007c7c00000, 0x00000007c7e00000| 0%| F| |TAMS 0x00000007c7c00000, 0x00000007c7c00000| Untracked -|1579|0x00000007c7e00000, 0x00000007c7e00000, 0x00000007c8000000| 0%| F| |TAMS 0x00000007c7e00000, 0x00000007c7e00000| Untracked -|1580|0x00000007c8000000, 0x00000007c8000000, 0x00000007c8200000| 0%| F| |TAMS 0x00000007c8000000, 0x00000007c8000000| Untracked -|1581|0x00000007c8200000, 0x00000007c8200000, 0x00000007c8400000| 0%| F| |TAMS 0x00000007c8200000, 0x00000007c8200000| Untracked -|1582|0x00000007c8400000, 0x00000007c8400000, 0x00000007c8600000| 0%| F| |TAMS 0x00000007c8400000, 0x00000007c8400000| Untracked -|1583|0x00000007c8600000, 0x00000007c8600000, 0x00000007c8800000| 0%| F| |TAMS 0x00000007c8600000, 0x00000007c8600000| Untracked -|1584|0x00000007c8800000, 0x00000007c8800000, 0x00000007c8a00000| 0%| F| |TAMS 0x00000007c8800000, 0x00000007c8800000| Untracked -|1585|0x00000007c8a00000, 0x00000007c8a00000, 0x00000007c8c00000| 0%| F| |TAMS 0x00000007c8a00000, 0x00000007c8a00000| Untracked -|1586|0x00000007c8c00000, 0x00000007c8c00000, 0x00000007c8e00000| 0%| F| |TAMS 0x00000007c8c00000, 0x00000007c8c00000| Untracked -|1587|0x00000007c8e00000, 0x00000007c8e00000, 0x00000007c9000000| 0%| F| |TAMS 0x00000007c8e00000, 0x00000007c8e00000| Untracked -|1588|0x00000007c9000000, 0x00000007c9000000, 0x00000007c9200000| 0%| F| |TAMS 0x00000007c9000000, 0x00000007c9000000| Untracked -|1589|0x00000007c9200000, 0x00000007c9200000, 0x00000007c9400000| 0%| F| |TAMS 0x00000007c9200000, 0x00000007c9200000| Untracked -|1590|0x00000007c9400000, 0x00000007c9400000, 0x00000007c9600000| 0%| F| |TAMS 0x00000007c9400000, 0x00000007c9400000| Untracked -|1591|0x00000007c9600000, 0x00000007c9600000, 0x00000007c9800000| 0%| F| |TAMS 0x00000007c9600000, 0x00000007c9600000| Untracked -|1592|0x00000007c9800000, 0x00000007c9800000, 0x00000007c9a00000| 0%| F| |TAMS 0x00000007c9800000, 0x00000007c9800000| Untracked -|1593|0x00000007c9a00000, 0x00000007c9a00000, 0x00000007c9c00000| 0%| F| |TAMS 0x00000007c9a00000, 0x00000007c9a00000| Untracked -|1594|0x00000007c9c00000, 0x00000007c9c00000, 0x00000007c9e00000| 0%| F| |TAMS 0x00000007c9c00000, 0x00000007c9c00000| Untracked -|1595|0x00000007c9e00000, 0x00000007c9e00000, 0x00000007ca000000| 0%| F| |TAMS 0x00000007c9e00000, 0x00000007c9e00000| Untracked -|1596|0x00000007ca000000, 0x00000007ca000000, 0x00000007ca200000| 0%| F| |TAMS 0x00000007ca000000, 0x00000007ca000000| Untracked -|1597|0x00000007ca200000, 0x00000007ca200000, 0x00000007ca400000| 0%| F| |TAMS 0x00000007ca200000, 0x00000007ca200000| Untracked -|1598|0x00000007ca400000, 0x00000007ca400000, 0x00000007ca600000| 0%| F| |TAMS 0x00000007ca400000, 0x00000007ca400000| Untracked -|1599|0x00000007ca600000, 0x00000007ca600000, 0x00000007ca800000| 0%| F| |TAMS 0x00000007ca600000, 0x00000007ca600000| Untracked -|1600|0x00000007ca800000, 0x00000007ca800000, 0x00000007caa00000| 0%| F| |TAMS 0x00000007ca800000, 0x00000007ca800000| Untracked -|1601|0x00000007caa00000, 0x00000007caa00000, 0x00000007cac00000| 0%| F| |TAMS 0x00000007caa00000, 0x00000007caa00000| Untracked -|1602|0x00000007cac00000, 0x00000007cac00000, 0x00000007cae00000| 0%| F| |TAMS 0x00000007cac00000, 0x00000007cac00000| Untracked -|1603|0x00000007cae00000, 0x00000007cae00000, 0x00000007cb000000| 0%| F| |TAMS 0x00000007cae00000, 0x00000007cae00000| Untracked -|1604|0x00000007cb000000, 0x00000007cb000000, 0x00000007cb200000| 0%| F| |TAMS 0x00000007cb000000, 0x00000007cb000000| Untracked -|1605|0x00000007cb200000, 0x00000007cb200000, 0x00000007cb400000| 0%| F| |TAMS 0x00000007cb200000, 0x00000007cb200000| Untracked -|1606|0x00000007cb400000, 0x00000007cb400000, 0x00000007cb600000| 0%| F| |TAMS 0x00000007cb400000, 0x00000007cb400000| Untracked -|1607|0x00000007cb600000, 0x00000007cb600000, 0x00000007cb800000| 0%| F| |TAMS 0x00000007cb600000, 0x00000007cb600000| Untracked -|1608|0x00000007cb800000, 0x00000007cb800000, 0x00000007cba00000| 0%| F| |TAMS 0x00000007cb800000, 0x00000007cb800000| Untracked -|1609|0x00000007cba00000, 0x00000007cba00000, 0x00000007cbc00000| 0%| F| |TAMS 0x00000007cba00000, 0x00000007cba00000| Untracked -|1610|0x00000007cbc00000, 0x00000007cbc00000, 0x00000007cbe00000| 0%| F| |TAMS 0x00000007cbc00000, 0x00000007cbc00000| Untracked -|1611|0x00000007cbe00000, 0x00000007cbe00000, 0x00000007cc000000| 0%| F| |TAMS 0x00000007cbe00000, 0x00000007cbe00000| Untracked -|1612|0x00000007cc000000, 0x00000007cc000000, 0x00000007cc200000| 0%| F| |TAMS 0x00000007cc000000, 0x00000007cc000000| Untracked -|1613|0x00000007cc200000, 0x00000007cc200000, 0x00000007cc400000| 0%| F| |TAMS 0x00000007cc200000, 0x00000007cc200000| Untracked -|1614|0x00000007cc400000, 0x00000007cc400000, 0x00000007cc600000| 0%| F| |TAMS 0x00000007cc400000, 0x00000007cc400000| Untracked -|1615|0x00000007cc600000, 0x00000007cc600000, 0x00000007cc800000| 0%| F| |TAMS 0x00000007cc600000, 0x00000007cc600000| Untracked -|1616|0x00000007cc800000, 0x00000007cc800000, 0x00000007cca00000| 0%| F| |TAMS 0x00000007cc800000, 0x00000007cc800000| Untracked -|1617|0x00000007cca00000, 0x00000007cca00000, 0x00000007ccc00000| 0%| F| |TAMS 0x00000007cca00000, 0x00000007cca00000| Untracked -|1618|0x00000007ccc00000, 0x00000007ccc00000, 0x00000007cce00000| 0%| F| |TAMS 0x00000007ccc00000, 0x00000007ccc00000| Untracked -|1619|0x00000007cce00000, 0x00000007cce00000, 0x00000007cd000000| 0%| F| |TAMS 0x00000007cce00000, 0x00000007cce00000| Untracked -|1620|0x00000007cd000000, 0x00000007cd000000, 0x00000007cd200000| 0%| F| |TAMS 0x00000007cd000000, 0x00000007cd000000| Untracked -|1621|0x00000007cd200000, 0x00000007cd200000, 0x00000007cd400000| 0%| F| |TAMS 0x00000007cd200000, 0x00000007cd200000| Untracked -|1622|0x00000007cd400000, 0x00000007cd400000, 0x00000007cd600000| 0%| F| |TAMS 0x00000007cd400000, 0x00000007cd400000| Untracked -|1623|0x00000007cd600000, 0x00000007cd600000, 0x00000007cd800000| 0%| F| |TAMS 0x00000007cd600000, 0x00000007cd600000| Untracked -|1624|0x00000007cd800000, 0x00000007cd800000, 0x00000007cda00000| 0%| F| |TAMS 0x00000007cd800000, 0x00000007cd800000| Untracked -|1625|0x00000007cda00000, 0x00000007cda00000, 0x00000007cdc00000| 0%| F| |TAMS 0x00000007cda00000, 0x00000007cda00000| Untracked -|1626|0x00000007cdc00000, 0x00000007cdc00000, 0x00000007cde00000| 0%| F| |TAMS 0x00000007cdc00000, 0x00000007cdc00000| Untracked -|1627|0x00000007cde00000, 0x00000007cde00000, 0x00000007ce000000| 0%| F| |TAMS 0x00000007cde00000, 0x00000007cde00000| Untracked -|1628|0x00000007ce000000, 0x00000007ce000000, 0x00000007ce200000| 0%| F| |TAMS 0x00000007ce000000, 0x00000007ce000000| Untracked -|1629|0x00000007ce200000, 0x00000007ce200000, 0x00000007ce400000| 0%| F| |TAMS 0x00000007ce200000, 0x00000007ce200000| Untracked -|1630|0x00000007ce400000, 0x00000007ce400000, 0x00000007ce600000| 0%| F| |TAMS 0x00000007ce400000, 0x00000007ce400000| Untracked -|1631|0x00000007ce600000, 0x00000007ce600000, 0x00000007ce800000| 0%| F| |TAMS 0x00000007ce600000, 0x00000007ce600000| Untracked -|1632|0x00000007ce800000, 0x00000007ce800000, 0x00000007cea00000| 0%| F| |TAMS 0x00000007ce800000, 0x00000007ce800000| Untracked -|1633|0x00000007cea00000, 0x00000007cea00000, 0x00000007cec00000| 0%| F| |TAMS 0x00000007cea00000, 0x00000007cea00000| Untracked -|1634|0x00000007cec00000, 0x00000007cec00000, 0x00000007cee00000| 0%| F| |TAMS 0x00000007cec00000, 0x00000007cec00000| Untracked -|1635|0x00000007cee00000, 0x00000007cee00000, 0x00000007cf000000| 0%| F| |TAMS 0x00000007cee00000, 0x00000007cee00000| Untracked -|1636|0x00000007cf000000, 0x00000007cf000000, 0x00000007cf200000| 0%| F| |TAMS 0x00000007cf000000, 0x00000007cf000000| Untracked -|1637|0x00000007cf200000, 0x00000007cf200000, 0x00000007cf400000| 0%| F| |TAMS 0x00000007cf200000, 0x00000007cf200000| Untracked -|1638|0x00000007cf400000, 0x00000007cf400000, 0x00000007cf600000| 0%| F| |TAMS 0x00000007cf400000, 0x00000007cf400000| Untracked -|1639|0x00000007cf600000, 0x00000007cf600000, 0x00000007cf800000| 0%| F| |TAMS 0x00000007cf600000, 0x00000007cf600000| Untracked -|1640|0x00000007cf800000, 0x00000007cf800000, 0x00000007cfa00000| 0%| F| |TAMS 0x00000007cf800000, 0x00000007cf800000| Untracked -|1641|0x00000007cfa00000, 0x00000007cfa00000, 0x00000007cfc00000| 0%| F| |TAMS 0x00000007cfa00000, 0x00000007cfa00000| Untracked -|1642|0x00000007cfc00000, 0x00000007cfc00000, 0x00000007cfe00000| 0%| F| |TAMS 0x00000007cfc00000, 0x00000007cfc00000| Untracked -|1643|0x00000007cfe00000, 0x00000007cfe00000, 0x00000007d0000000| 0%| F| |TAMS 0x00000007cfe00000, 0x00000007cfe00000| Untracked -|1644|0x00000007d0000000, 0x00000007d0000000, 0x00000007d0200000| 0%| F| |TAMS 0x00000007d0000000, 0x00000007d0000000| Untracked -|1645|0x00000007d0200000, 0x00000007d0200000, 0x00000007d0400000| 0%| F| |TAMS 0x00000007d0200000, 0x00000007d0200000| Untracked -|1646|0x00000007d0400000, 0x00000007d0400000, 0x00000007d0600000| 0%| F| |TAMS 0x00000007d0400000, 0x00000007d0400000| Untracked -|1647|0x00000007d0600000, 0x00000007d0600000, 0x00000007d0800000| 0%| F| |TAMS 0x00000007d0600000, 0x00000007d0600000| Untracked -|1648|0x00000007d0800000, 0x00000007d0800000, 0x00000007d0a00000| 0%| F| |TAMS 0x00000007d0800000, 0x00000007d0800000| Untracked -|1649|0x00000007d0a00000, 0x00000007d0a00000, 0x00000007d0c00000| 0%| F| |TAMS 0x00000007d0a00000, 0x00000007d0a00000| Untracked -|1650|0x00000007d0c00000, 0x00000007d0c00000, 0x00000007d0e00000| 0%| F| |TAMS 0x00000007d0c00000, 0x00000007d0c00000| Untracked -|1651|0x00000007d0e00000, 0x00000007d0e00000, 0x00000007d1000000| 0%| F| |TAMS 0x00000007d0e00000, 0x00000007d0e00000| Untracked -|1652|0x00000007d1000000, 0x00000007d1000000, 0x00000007d1200000| 0%| F| |TAMS 0x00000007d1000000, 0x00000007d1000000| Untracked -|1653|0x00000007d1200000, 0x00000007d1200000, 0x00000007d1400000| 0%| F| |TAMS 0x00000007d1200000, 0x00000007d1200000| Untracked -|1654|0x00000007d1400000, 0x00000007d1400000, 0x00000007d1600000| 0%| F| |TAMS 0x00000007d1400000, 0x00000007d1400000| Untracked -|1655|0x00000007d1600000, 0x00000007d1600000, 0x00000007d1800000| 0%| F| |TAMS 0x00000007d1600000, 0x00000007d1600000| Untracked -|1656|0x00000007d1800000, 0x00000007d1800000, 0x00000007d1a00000| 0%| F| |TAMS 0x00000007d1800000, 0x00000007d1800000| Untracked -|1657|0x00000007d1a00000, 0x00000007d1a00000, 0x00000007d1c00000| 0%| F| |TAMS 0x00000007d1a00000, 0x00000007d1a00000| Untracked -|1658|0x00000007d1c00000, 0x00000007d1c00000, 0x00000007d1e00000| 0%| F| |TAMS 0x00000007d1c00000, 0x00000007d1c00000| Untracked -|1659|0x00000007d1e00000, 0x00000007d1e00000, 0x00000007d2000000| 0%| F| |TAMS 0x00000007d1e00000, 0x00000007d1e00000| Untracked -|1660|0x00000007d2000000, 0x00000007d2000000, 0x00000007d2200000| 0%| F| |TAMS 0x00000007d2000000, 0x00000007d2000000| Untracked -|1661|0x00000007d2200000, 0x00000007d2200000, 0x00000007d2400000| 0%| F| |TAMS 0x00000007d2200000, 0x00000007d2200000| Untracked -|1662|0x00000007d2400000, 0x00000007d2400000, 0x00000007d2600000| 0%| F| |TAMS 0x00000007d2400000, 0x00000007d2400000| Untracked -|1663|0x00000007d2600000, 0x00000007d2600000, 0x00000007d2800000| 0%| F| |TAMS 0x00000007d2600000, 0x00000007d2600000| Untracked -|1664|0x00000007d2800000, 0x00000007d2800000, 0x00000007d2a00000| 0%| F| |TAMS 0x00000007d2800000, 0x00000007d2800000| Untracked -|1665|0x00000007d2a00000, 0x00000007d2a00000, 0x00000007d2c00000| 0%| F| |TAMS 0x00000007d2a00000, 0x00000007d2a00000| Untracked -|1666|0x00000007d2c00000, 0x00000007d2c00000, 0x00000007d2e00000| 0%| F| |TAMS 0x00000007d2c00000, 0x00000007d2c00000| Untracked -|1667|0x00000007d2e00000, 0x00000007d2e00000, 0x00000007d3000000| 0%| F| |TAMS 0x00000007d2e00000, 0x00000007d2e00000| Untracked -|1668|0x00000007d3000000, 0x00000007d3000000, 0x00000007d3200000| 0%| F| |TAMS 0x00000007d3000000, 0x00000007d3000000| Untracked -|1669|0x00000007d3200000, 0x00000007d3200000, 0x00000007d3400000| 0%| F| |TAMS 0x00000007d3200000, 0x00000007d3200000| Untracked -|1670|0x00000007d3400000, 0x00000007d3400000, 0x00000007d3600000| 0%| F| |TAMS 0x00000007d3400000, 0x00000007d3400000| Untracked -|1671|0x00000007d3600000, 0x00000007d3600000, 0x00000007d3800000| 0%| F| |TAMS 0x00000007d3600000, 0x00000007d3600000| Untracked -|1672|0x00000007d3800000, 0x00000007d3800000, 0x00000007d3a00000| 0%| F| |TAMS 0x00000007d3800000, 0x00000007d3800000| Untracked -|1673|0x00000007d3a00000, 0x00000007d3a00000, 0x00000007d3c00000| 0%| F| |TAMS 0x00000007d3a00000, 0x00000007d3a00000| Untracked -|1674|0x00000007d3c00000, 0x00000007d3c00000, 0x00000007d3e00000| 0%| F| |TAMS 0x00000007d3c00000, 0x00000007d3c00000| Untracked -|1675|0x00000007d3e00000, 0x00000007d3e00000, 0x00000007d4000000| 0%| F| |TAMS 0x00000007d3e00000, 0x00000007d3e00000| Untracked -|1676|0x00000007d4000000, 0x00000007d4000000, 0x00000007d4200000| 0%| F| |TAMS 0x00000007d4000000, 0x00000007d4000000| Untracked -|1677|0x00000007d4200000, 0x00000007d4200000, 0x00000007d4400000| 0%| F| |TAMS 0x00000007d4200000, 0x00000007d4200000| Untracked -|1678|0x00000007d4400000, 0x00000007d4400000, 0x00000007d4600000| 0%| F| |TAMS 0x00000007d4400000, 0x00000007d4400000| Untracked -|1679|0x00000007d4600000, 0x00000007d4600000, 0x00000007d4800000| 0%| F| |TAMS 0x00000007d4600000, 0x00000007d4600000| Untracked -|1680|0x00000007d4800000, 0x00000007d4800000, 0x00000007d4a00000| 0%| F| |TAMS 0x00000007d4800000, 0x00000007d4800000| Untracked -|1681|0x00000007d4a00000, 0x00000007d4a00000, 0x00000007d4c00000| 0%| F| |TAMS 0x00000007d4a00000, 0x00000007d4a00000| Untracked -|1682|0x00000007d4c00000, 0x00000007d4c00000, 0x00000007d4e00000| 0%| F| |TAMS 0x00000007d4c00000, 0x00000007d4c00000| Untracked -|1683|0x00000007d4e00000, 0x00000007d4e00000, 0x00000007d5000000| 0%| F| |TAMS 0x00000007d4e00000, 0x00000007d4e00000| Untracked -|1684|0x00000007d5000000, 0x00000007d5000000, 0x00000007d5200000| 0%| F| |TAMS 0x00000007d5000000, 0x00000007d5000000| Untracked -|1685|0x00000007d5200000, 0x00000007d5200000, 0x00000007d5400000| 0%| F| |TAMS 0x00000007d5200000, 0x00000007d5200000| Untracked -|1686|0x00000007d5400000, 0x00000007d5400000, 0x00000007d5600000| 0%| F| |TAMS 0x00000007d5400000, 0x00000007d5400000| Untracked -|1687|0x00000007d5600000, 0x00000007d5600000, 0x00000007d5800000| 0%| F| |TAMS 0x00000007d5600000, 0x00000007d5600000| Untracked -|1688|0x00000007d5800000, 0x00000007d5800000, 0x00000007d5a00000| 0%| F| |TAMS 0x00000007d5800000, 0x00000007d5800000| Untracked -|1689|0x00000007d5a00000, 0x00000007d5a00000, 0x00000007d5c00000| 0%| F| |TAMS 0x00000007d5a00000, 0x00000007d5a00000| Untracked -|1690|0x00000007d5c00000, 0x00000007d5c00000, 0x00000007d5e00000| 0%| F| |TAMS 0x00000007d5c00000, 0x00000007d5c00000| Untracked -|1691|0x00000007d5e00000, 0x00000007d5e00000, 0x00000007d6000000| 0%| F| |TAMS 0x00000007d5e00000, 0x00000007d5e00000| Untracked -|1692|0x00000007d6000000, 0x00000007d6000000, 0x00000007d6200000| 0%| F| |TAMS 0x00000007d6000000, 0x00000007d6000000| Untracked -|1693|0x00000007d6200000, 0x00000007d6200000, 0x00000007d6400000| 0%| F| |TAMS 0x00000007d6200000, 0x00000007d6200000| Untracked -|1694|0x00000007d6400000, 0x00000007d6400000, 0x00000007d6600000| 0%| F| |TAMS 0x00000007d6400000, 0x00000007d6400000| Untracked -|1695|0x00000007d6600000, 0x00000007d6600000, 0x00000007d6800000| 0%| F| |TAMS 0x00000007d6600000, 0x00000007d6600000| Untracked -|1696|0x00000007d6800000, 0x00000007d6800000, 0x00000007d6a00000| 0%| F| |TAMS 0x00000007d6800000, 0x00000007d6800000| Untracked -|1697|0x00000007d6a00000, 0x00000007d6a00000, 0x00000007d6c00000| 0%| F| |TAMS 0x00000007d6a00000, 0x00000007d6a00000| Untracked -|1698|0x00000007d6c00000, 0x00000007d6c00000, 0x00000007d6e00000| 0%| F| |TAMS 0x00000007d6c00000, 0x00000007d6c00000| Untracked -|1699|0x00000007d6e00000, 0x00000007d6e00000, 0x00000007d7000000| 0%| F| |TAMS 0x00000007d6e00000, 0x00000007d6e00000| Untracked -|1700|0x00000007d7000000, 0x00000007d7000000, 0x00000007d7200000| 0%| F| |TAMS 0x00000007d7000000, 0x00000007d7000000| Untracked -|1701|0x00000007d7200000, 0x00000007d7200000, 0x00000007d7400000| 0%| F| |TAMS 0x00000007d7200000, 0x00000007d7200000| Untracked -|1702|0x00000007d7400000, 0x00000007d7400000, 0x00000007d7600000| 0%| F| |TAMS 0x00000007d7400000, 0x00000007d7400000| Untracked -|1703|0x00000007d7600000, 0x00000007d7600000, 0x00000007d7800000| 0%| F| |TAMS 0x00000007d7600000, 0x00000007d7600000| Untracked -|1704|0x00000007d7800000, 0x00000007d7800000, 0x00000007d7a00000| 0%| F| |TAMS 0x00000007d7800000, 0x00000007d7800000| Untracked -|1705|0x00000007d7a00000, 0x00000007d7a00000, 0x00000007d7c00000| 0%| F| |TAMS 0x00000007d7a00000, 0x00000007d7a00000| Untracked -|1706|0x00000007d7c00000, 0x00000007d7c00000, 0x00000007d7e00000| 0%| F| |TAMS 0x00000007d7c00000, 0x00000007d7c00000| Untracked -|1707|0x00000007d7e00000, 0x00000007d7e00000, 0x00000007d8000000| 0%| F| |TAMS 0x00000007d7e00000, 0x00000007d7e00000| Untracked -|1708|0x00000007d8000000, 0x00000007d8000000, 0x00000007d8200000| 0%| F| |TAMS 0x00000007d8000000, 0x00000007d8000000| Untracked -|1709|0x00000007d8200000, 0x00000007d8200000, 0x00000007d8400000| 0%| F| |TAMS 0x00000007d8200000, 0x00000007d8200000| Untracked -|1710|0x00000007d8400000, 0x00000007d8400000, 0x00000007d8600000| 0%| F| |TAMS 0x00000007d8400000, 0x00000007d8400000| Untracked -|1711|0x00000007d8600000, 0x00000007d8600000, 0x00000007d8800000| 0%| F| |TAMS 0x00000007d8600000, 0x00000007d8600000| Untracked -|1712|0x00000007d8800000, 0x00000007d8800000, 0x00000007d8a00000| 0%| F| |TAMS 0x00000007d8800000, 0x00000007d8800000| Untracked -|1713|0x00000007d8a00000, 0x00000007d8a00000, 0x00000007d8c00000| 0%| F| |TAMS 0x00000007d8a00000, 0x00000007d8a00000| Untracked -|1714|0x00000007d8c00000, 0x00000007d8c00000, 0x00000007d8e00000| 0%| F| |TAMS 0x00000007d8c00000, 0x00000007d8c00000| Untracked -|1715|0x00000007d8e00000, 0x00000007d8e00000, 0x00000007d9000000| 0%| F| |TAMS 0x00000007d8e00000, 0x00000007d8e00000| Untracked -|1716|0x00000007d9000000, 0x00000007d9000000, 0x00000007d9200000| 0%| F| |TAMS 0x00000007d9000000, 0x00000007d9000000| Untracked -|1717|0x00000007d9200000, 0x00000007d9200000, 0x00000007d9400000| 0%| F| |TAMS 0x00000007d9200000, 0x00000007d9200000| Untracked -|1718|0x00000007d9400000, 0x00000007d9400000, 0x00000007d9600000| 0%| F| |TAMS 0x00000007d9400000, 0x00000007d9400000| Untracked -|1719|0x00000007d9600000, 0x00000007d9600000, 0x00000007d9800000| 0%| F| |TAMS 0x00000007d9600000, 0x00000007d9600000| Untracked -|1720|0x00000007d9800000, 0x00000007d9800000, 0x00000007d9a00000| 0%| F| |TAMS 0x00000007d9800000, 0x00000007d9800000| Untracked -|1721|0x00000007d9a00000, 0x00000007d9a00000, 0x00000007d9c00000| 0%| F| |TAMS 0x00000007d9a00000, 0x00000007d9a00000| Untracked -|1722|0x00000007d9c00000, 0x00000007d9c00000, 0x00000007d9e00000| 0%| F| |TAMS 0x00000007d9c00000, 0x00000007d9c00000| Untracked -|1723|0x00000007d9e00000, 0x00000007d9e00000, 0x00000007da000000| 0%| F| |TAMS 0x00000007d9e00000, 0x00000007d9e00000| Untracked -|1724|0x00000007da000000, 0x00000007da000000, 0x00000007da200000| 0%| F| |TAMS 0x00000007da000000, 0x00000007da000000| Untracked -|1725|0x00000007da200000, 0x00000007da200000, 0x00000007da400000| 0%| F| |TAMS 0x00000007da200000, 0x00000007da200000| Untracked -|1726|0x00000007da400000, 0x00000007da400000, 0x00000007da600000| 0%| F| |TAMS 0x00000007da400000, 0x00000007da400000| Untracked -|1727|0x00000007da600000, 0x00000007da600000, 0x00000007da800000| 0%| F| |TAMS 0x00000007da600000, 0x00000007da600000| Untracked -|1728|0x00000007da800000, 0x00000007da800000, 0x00000007daa00000| 0%| F| |TAMS 0x00000007da800000, 0x00000007da800000| Untracked -|1729|0x00000007daa00000, 0x00000007daa00000, 0x00000007dac00000| 0%| F| |TAMS 0x00000007daa00000, 0x00000007daa00000| Untracked -|1730|0x00000007dac00000, 0x00000007dac00000, 0x00000007dae00000| 0%| F| |TAMS 0x00000007dac00000, 0x00000007dac00000| Untracked -|1731|0x00000007dae00000, 0x00000007dae00000, 0x00000007db000000| 0%| F| |TAMS 0x00000007dae00000, 0x00000007dae00000| Untracked -|1732|0x00000007db000000, 0x00000007db000000, 0x00000007db200000| 0%| F| |TAMS 0x00000007db000000, 0x00000007db000000| Untracked -|1733|0x00000007db200000, 0x00000007db200000, 0x00000007db400000| 0%| F| |TAMS 0x00000007db200000, 0x00000007db200000| Untracked -|1734|0x00000007db400000, 0x00000007db400000, 0x00000007db600000| 0%| F| |TAMS 0x00000007db400000, 0x00000007db400000| Untracked -|1735|0x00000007db600000, 0x00000007db600000, 0x00000007db800000| 0%| F| |TAMS 0x00000007db600000, 0x00000007db600000| Untracked -|1736|0x00000007db800000, 0x00000007db800000, 0x00000007dba00000| 0%| F| |TAMS 0x00000007db800000, 0x00000007db800000| Untracked -|1737|0x00000007dba00000, 0x00000007dba00000, 0x00000007dbc00000| 0%| F| |TAMS 0x00000007dba00000, 0x00000007dba00000| Untracked -|1738|0x00000007dbc00000, 0x00000007dbc00000, 0x00000007dbe00000| 0%| F| |TAMS 0x00000007dbc00000, 0x00000007dbc00000| Untracked -|1739|0x00000007dbe00000, 0x00000007dbe00000, 0x00000007dc000000| 0%| F| |TAMS 0x00000007dbe00000, 0x00000007dbe00000| Untracked -|1740|0x00000007dc000000, 0x00000007dc000000, 0x00000007dc200000| 0%| F| |TAMS 0x00000007dc000000, 0x00000007dc000000| Untracked -|1741|0x00000007dc200000, 0x00000007dc200000, 0x00000007dc400000| 0%| F| |TAMS 0x00000007dc200000, 0x00000007dc200000| Untracked -|1742|0x00000007dc400000, 0x00000007dc400000, 0x00000007dc600000| 0%| F| |TAMS 0x00000007dc400000, 0x00000007dc400000| Untracked -|1743|0x00000007dc600000, 0x00000007dc600000, 0x00000007dc800000| 0%| F| |TAMS 0x00000007dc600000, 0x00000007dc600000| Untracked -|1744|0x00000007dc800000, 0x00000007dc800000, 0x00000007dca00000| 0%| F| |TAMS 0x00000007dc800000, 0x00000007dc800000| Untracked -|1745|0x00000007dca00000, 0x00000007dca00000, 0x00000007dcc00000| 0%| F| |TAMS 0x00000007dca00000, 0x00000007dca00000| Untracked -|1746|0x00000007dcc00000, 0x00000007dcc00000, 0x00000007dce00000| 0%| F| |TAMS 0x00000007dcc00000, 0x00000007dcc00000| Untracked -|1747|0x00000007dce00000, 0x00000007dce00000, 0x00000007dd000000| 0%| F| |TAMS 0x00000007dce00000, 0x00000007dce00000| Untracked -|1748|0x00000007dd000000, 0x00000007dd000000, 0x00000007dd200000| 0%| F| |TAMS 0x00000007dd000000, 0x00000007dd000000| Untracked -|1749|0x00000007dd200000, 0x00000007dd200000, 0x00000007dd400000| 0%| F| |TAMS 0x00000007dd200000, 0x00000007dd200000| Untracked -|1750|0x00000007dd400000, 0x00000007dd400000, 0x00000007dd600000| 0%| F| |TAMS 0x00000007dd400000, 0x00000007dd400000| Untracked -|1751|0x00000007dd600000, 0x00000007dd600000, 0x00000007dd800000| 0%| F| |TAMS 0x00000007dd600000, 0x00000007dd600000| Untracked -|1752|0x00000007dd800000, 0x00000007dd800000, 0x00000007dda00000| 0%| F| |TAMS 0x00000007dd800000, 0x00000007dd800000| Untracked -|1753|0x00000007dda00000, 0x00000007dda00000, 0x00000007ddc00000| 0%| F| |TAMS 0x00000007dda00000, 0x00000007dda00000| Untracked -|1754|0x00000007ddc00000, 0x00000007ddc00000, 0x00000007dde00000| 0%| F| |TAMS 0x00000007ddc00000, 0x00000007ddc00000| Untracked -|1755|0x00000007dde00000, 0x00000007dde00000, 0x00000007de000000| 0%| F| |TAMS 0x00000007dde00000, 0x00000007dde00000| Untracked -|1756|0x00000007de000000, 0x00000007de000000, 0x00000007de200000| 0%| F| |TAMS 0x00000007de000000, 0x00000007de000000| Untracked -|1757|0x00000007de200000, 0x00000007de200000, 0x00000007de400000| 0%| F| |TAMS 0x00000007de200000, 0x00000007de200000| Untracked -|1758|0x00000007de400000, 0x00000007de400000, 0x00000007de600000| 0%| F| |TAMS 0x00000007de400000, 0x00000007de400000| Untracked -|1759|0x00000007de600000, 0x00000007de600000, 0x00000007de800000| 0%| F| |TAMS 0x00000007de600000, 0x00000007de600000| Untracked -|1760|0x00000007de800000, 0x00000007de800000, 0x00000007dea00000| 0%| F| |TAMS 0x00000007de800000, 0x00000007de800000| Untracked -|1761|0x00000007dea00000, 0x00000007dea00000, 0x00000007dec00000| 0%| F| |TAMS 0x00000007dea00000, 0x00000007dea00000| Untracked -|1762|0x00000007dec00000, 0x00000007dec00000, 0x00000007dee00000| 0%| F| |TAMS 0x00000007dec00000, 0x00000007dec00000| Untracked -|1763|0x00000007dee00000, 0x00000007dee00000, 0x00000007df000000| 0%| F| |TAMS 0x00000007dee00000, 0x00000007dee00000| Untracked -|1764|0x00000007df000000, 0x00000007df000000, 0x00000007df200000| 0%| F| |TAMS 0x00000007df000000, 0x00000007df000000| Untracked -|1765|0x00000007df200000, 0x00000007df200000, 0x00000007df400000| 0%| F| |TAMS 0x00000007df200000, 0x00000007df200000| Untracked -|1766|0x00000007df400000, 0x00000007df400000, 0x00000007df600000| 0%| F| |TAMS 0x00000007df400000, 0x00000007df400000| Untracked -|1767|0x00000007df600000, 0x00000007df600000, 0x00000007df800000| 0%| F| |TAMS 0x00000007df600000, 0x00000007df600000| Untracked -|1768|0x00000007df800000, 0x00000007df800000, 0x00000007dfa00000| 0%| F| |TAMS 0x00000007df800000, 0x00000007df800000| Untracked -|1769|0x00000007dfa00000, 0x00000007dfa00000, 0x00000007dfc00000| 0%| F| |TAMS 0x00000007dfa00000, 0x00000007dfa00000| Untracked -|1770|0x00000007dfc00000, 0x00000007dfc00000, 0x00000007dfe00000| 0%| F| |TAMS 0x00000007dfc00000, 0x00000007dfc00000| Untracked -|1771|0x00000007dfe00000, 0x00000007dfe00000, 0x00000007e0000000| 0%| F| |TAMS 0x00000007dfe00000, 0x00000007dfe00000| Untracked -|1772|0x00000007e0000000, 0x00000007e0000000, 0x00000007e0200000| 0%| F| |TAMS 0x00000007e0000000, 0x00000007e0000000| Untracked -|1773|0x00000007e0200000, 0x00000007e0200000, 0x00000007e0400000| 0%| F| |TAMS 0x00000007e0200000, 0x00000007e0200000| Untracked -|1774|0x00000007e0400000, 0x00000007e0400000, 0x00000007e0600000| 0%| F| |TAMS 0x00000007e0400000, 0x00000007e0400000| Untracked -|1775|0x00000007e0600000, 0x00000007e0600000, 0x00000007e0800000| 0%| F| |TAMS 0x00000007e0600000, 0x00000007e0600000| Untracked -|1776|0x00000007e0800000, 0x00000007e0800000, 0x00000007e0a00000| 0%| F| |TAMS 0x00000007e0800000, 0x00000007e0800000| Untracked - -Card table byte_map: [0x000001fbf8140000,0x000001fbf8930000] _byte_map_base: 0x000001fbf492c000 - -Marking Bits (Prev, Next): (CMBitMap*) 0x000001fbef3d29c0, (CMBitMap*) 0x000001fbef3d2980 - Prev Bits: [0x000001fb8f000000, 0x000001fb92f60000) - Next Bits: [0x000001fbf9120000, 0x000001fbfd080000) - -Polling page: 0x000001fbed530000 - -Metaspace: - -Usage: - Non-class: 122.00 MB used. - Class: 22.20 MB used. - Both: 144.19 MB used. - -Virtual space: - Non-class space: 128.00 MB reserved, 122.94 MB ( 96%) committed, 2 nodes. - Class space: 1.00 GB reserved, 23.00 MB ( 2%) committed, 1 nodes. - Both: 1.12 GB reserved, 145.94 MB ( 13%) committed. - -Chunk freelists: - Non-Class: 5.09 MB - Class: 9.03 MB - Both: 14.13 MB - -MaxMetaspaceSize: unlimited -CompressedClassSpaceSize: 1.00 GB -Initial GC threshold: 21.00 MB -Current GC threshold: 235.12 MB -CDS: on -MetaspaceReclaimPolicy: balanced - - commit_granule_bytes: 65536. - - commit_granule_words: 8192. - - virtual_space_node_default_size: 8388608. - - enlarge_chunks_in_place: 1. - - new_chunks_are_fully_committed: 0. - - uncommit_free_chunks: 1. - - use_allocation_guard: 0. - - handle_deallocations: 1. - - -Internal statistics: - -num_allocs_failed_limit: 12. -num_arena_births: 2830. -num_arena_deaths: 28. -num_vsnodes_births: 3. -num_vsnodes_deaths: 0. -num_space_committed: 2329. -num_space_uncommitted: 0. -num_chunks_returned_to_freelist: 52. -num_chunks_taken_from_freelist: 9150. -num_chunk_merges: 26. -num_chunk_splits: 5882. -num_chunks_enlarged: 3875. -num_inconsistent_stats: 0. - -CodeHeap 'non-profiled nmethods': size=119168Kb used=19388Kb max_used=19388Kb free=99779Kb - bounds [0x000001fb87ba0000, 0x000001fb88e90000, 0x000001fb8f000000] -CodeHeap 'profiled nmethods': size=119104Kb used=30503Kb max_used=30949Kb free=88601Kb - bounds [0x000001fb80000000, 0x000001fb81e70000, 0x000001fb87450000] -CodeHeap 'non-nmethods': size=7488Kb used=3061Kb max_used=4222Kb free=4426Kb - bounds [0x000001fb87450000, 0x000001fb87880000, 0x000001fb87ba0000] - total_blobs=20156 nmethods=17982 adapters=2084 - compilation: enabled - stopped_count=0, restarted_count=0 - full_count=0 - -Compilation events (20 events): -Event: 38.601 Thread 0x000001fbff59f8c0 nmethod 25018 0x000001fb88e8c210 code [0x000001fb88e8c3a0, 0x000001fb88e8c458] -Event: 38.601 Thread 0x000001fbff59f8c0 25011 4 java.util.stream.Nodes$IntArrayNode::asPrimitiveArray (5 bytes) -Event: 38.601 Thread 0x000001fbff59f8c0 nmethod 25011 0x000001fb88e8c510 code [0x000001fb88e8c6a0, 0x000001fb88e8c758] -Event: 38.601 Thread 0x000001fbff59f8c0 25019 4 java.util.stream.Nodes$IntFixedNodeBuilder::begin (52 bytes) -Event: 38.601 Thread 0x000001fbff59f8c0 nmethod 25019 0x000001fb88e8c810 code [0x000001fb88e8c9a0, 0x000001fb88e8ca58] -Event: 38.601 Thread 0x000001fbff59f8c0 25024 4 java.util.stream.Nodes$IntFixedNodeBuilder::build (5 bytes) -Event: 38.602 Thread 0x000001fbff59f8c0 nmethod 25024 0x000001fb88e8cb10 code [0x000001fb88e8cca0, 0x000001fb88e8cd58] -Event: 38.602 Thread 0x000001fbff59f8c0 24989 4 com.mojang.brigadier.tree.ArgumentCommandNode::hashCode (23 bytes) -Event: 38.604 Thread 0x000001fbff59f8c0 nmethod 24989 0x000001fb88e8ce10 code [0x000001fb88e8cfa0, 0x000001fb88e8d288] -Event: 38.604 Thread 0x000001fbff59f8c0 25114 4 java.lang.invoke.LambdaForm$MH/0x000001fb95222000::linkToTargetMethod (10 bytes) -Event: 38.605 Thread 0x000001fbff59f8c0 nmethod 25114 0x000001fb88e8d490 code [0x000001fb88e8d620, 0x000001fb88e8d6f8] -Event: 38.605 Thread 0x000001fbff59f8c0 25115 4 java.lang.invoke.LambdaForm$DMH/0x000001fb95221c00::newInvokeSpecial (27 bytes) -Event: 38.606 Thread 0x000001fbff59f8c0 nmethod 25115 0x000001fb88e8d810 code [0x000001fb88e8d9a0, 0x000001fb88e8dba8] -Event: 38.606 Thread 0x000001fbff59f8c0 24906 4 com.google.common.collect.ImmutableMap::isEmpty (13 bytes) -Event: 38.606 Thread 0x000001fbff59f8c0 nmethod 24906 0x000001fb88e8dd90 code [0x000001fb88e8df20, 0x000001fb88e8dfd8] -Event: 38.606 Thread 0x000001fbff59f8c0 24936 4 net.minecraft.advancements.Advancement::hashCode (8 bytes) -Event: 38.610 Thread 0x000001fbff59f8c0 nmethod 24936 0x000001fb88e8e090 code [0x000001fb88e8e240, 0x000001fb88e8e6f8] -Event: 38.610 Thread 0x000001fbff59f8c0 25002 4 com.mojang.brigadier.tree.ArgumentCommandNode::equals (59 bytes) -Event: 38.612 Thread 0x000001fbff59f8c0 nmethod 25002 0x000001fb88e8ea10 code [0x000001fb88e8ebc0, 0x000001fb88e8eee8] -Event: 38.612 Thread 0x000001fbff59f8c0 24886 4 net.minecraftforge.registries.NamespacedWrapper::getOptional (12 bytes) - -GC Heap History (20 events): -Event: 35.414 GC heap after -{Heap after GC invocations=58 (full 0): - garbage-first heap total 2318336K, used 1069538K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 44 young (90112K), 44 survivors (90112K) - Metaspace used 142581K, committed 144320K, reserved 1179648K - class space used 21935K, committed 22720K, reserved 1048576K -} -Event: 35.444 GC heap before -{Heap before GC invocations=58 (full 0): - garbage-first heap total 2318336K, used 1094114K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 56 young (114688K), 44 survivors (90112K) - Metaspace used 142584K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 35.473 GC heap after -{Heap after GC invocations=59 (full 0): - garbage-first heap total 2318336K, used 1073108K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 7 young (14336K), 7 survivors (14336K) - Metaspace used 142584K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 35.735 GC heap before -{Heap before GC invocations=59 (full 0): - garbage-first heap total 2318336K, used 1699796K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 313 young (641024K), 7 survivors (14336K) - Metaspace used 142590K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 35.883 GC heap after -{Heap after GC invocations=60 (full 0): - garbage-first heap total 2318336K, used 1463269K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 40 young (81920K), 40 survivors (81920K) - Metaspace used 142590K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.003 GC heap before -{Heap before GC invocations=60 (full 0): - garbage-first heap total 2318336K, used 1764325K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 187 young (382976K), 40 survivors (81920K) - Metaspace used 142591K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.103 GC heap after -{Heap after GC invocations=61 (full 0): - garbage-first heap total 2318336K, used 1653760K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 24 young (49152K), 24 survivors (49152K) - Metaspace used 142591K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.181 GC heap before -{Heap before GC invocations=61 (full 0): - garbage-first heap total 2318336K, used 1840128K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 115 young (235520K), 24 survivors (49152K) - Metaspace used 142593K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.236 GC heap after -{Heap after GC invocations=62 (full 0): - garbage-first heap total 2318336K, used 1775616K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 15 young (30720K), 15 survivors (30720K) - Metaspace used 142593K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.295 GC heap before -{Heap before GC invocations=62 (full 0): - garbage-first heap total 2318336K, used 1904640K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 78 young (159744K), 15 survivors (30720K) - Metaspace used 142593K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.596 GC heap after -{Heap after GC invocations=63 (full 0): - garbage-first heap total 3053568K, used 1862656K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 10 young (20480K), 10 survivors (20480K) - Metaspace used 142593K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.754 GC heap before -{Heap before GC invocations=63 (full 0): - garbage-first heap total 3053568K, used 1993728K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 74 young (151552K), 10 survivors (20480K) - Metaspace used 142593K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 36.790 GC heap after -{Heap after GC invocations=64 (full 0): - garbage-first heap total 3053568K, used 1951744K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 10 young (20480K), 10 survivors (20480K) - Metaspace used 142593K, committed 144320K, reserved 1179648K - class space used 21936K, committed 22720K, reserved 1048576K -} -Event: 37.050 GC heap before -{Heap before GC invocations=64 (full 0): - garbage-first heap total 3053568K, used 2291712K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 176 young (360448K), 10 survivors (20480K) - Metaspace used 142607K, committed 144384K, reserved 1179648K - class space used 21939K, committed 22720K, reserved 1048576K -} -Event: 37.125 GC heap after -{Heap after GC invocations=65 (full 0): - garbage-first heap total 3053568K, used 2170880K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 22 young (45056K), 22 survivors (45056K) - Metaspace used 142607K, committed 144384K, reserved 1179648K - class space used 21939K, committed 22720K, reserved 1048576K -} -Event: 37.519 GC heap before -{Heap before GC invocations=66 (full 0): - garbage-first heap total 3639296K, used 2408448K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 138 young (282624K), 22 survivors (45056K) - Metaspace used 144432K, committed 146176K, reserved 1179648K - class space used 22184K, committed 22976K, reserved 1048576K -} -Event: 37.551 GC heap after -{Heap after GC invocations=67 (full 0): - garbage-first heap total 3639296K, used 2264064K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 18 young (36864K), 18 survivors (36864K) - Metaspace used 144432K, committed 146176K, reserved 1179648K - class space used 22184K, committed 22976K, reserved 1048576K -} -Event: 37.694 GC heap before -{Heap before GC invocations=67 (full 0): - garbage-first heap total 3639296K, used 2405376K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 88 young (180224K), 18 survivors (36864K) - Metaspace used 145442K, committed 147200K, reserved 1179648K - class space used 22368K, committed 23168K, reserved 1048576K -} -Event: 37.711 GC heap after -{Heap after GC invocations=68 (full 0): - garbage-first heap total 3639296K, used 2022400K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 11 young (22528K), 11 survivors (22528K) - Metaspace used 145442K, committed 147200K, reserved 1179648K - class space used 22368K, committed 23168K, reserved 1048576K -} -Event: 38.667 GC heap before -{Heap before GC invocations=68 (full 0): - garbage-first heap total 3639296K, used 2612224K [0x0000000702800000, 0x0000000800000000) - region size 2048K, 297 young (608256K), 11 survivors (22528K) - Metaspace used 147655K, committed 149440K, reserved 1179648K - class space used 22729K, committed 23552K, reserved 1048576K -} - -Dll operation events (16 events): -Event: 0.007 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\java.dll -Event: 0.020 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\jsvml.dll -Event: 0.095 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\net.dll -Event: 0.096 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\nio.dll -Event: 0.098 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\zip.dll -Event: 0.144 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\jimage.dll -Event: 0.398 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\verify.dll -Event: 1.796 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\management.dll -Event: 1.800 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\management_ext.dll -Event: 2.531 Loaded shared library C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\lwjgl.dll -Event: 2.857 Loaded shared library C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\lwjgl_stb.dll -Event: 2.918 Loaded shared library C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\lwjgl_opengl.dll -Event: 8.196 Loaded shared library C:\Users\Utilisateur\AppData\Local\Temp\jna-1082121059\jna17725892220550122580.dll -Event: 14.504 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\sunmscapi.dll -Event: 14.705 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\extnet.dll -Event: 35.277 Loaded shared library C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\awt.dll - -Deoptimization events (20 events): -Event: 38.561 Thread 0x000001fbe8a2f800 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c5544feeb0 -Event: 38.561 Thread 0x000001fbe8a2f800 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c5544fe3f0 mode 0 -Event: 38.562 Thread 0x000001fbe787fa80 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c5540fed40 -Event: 38.562 Thread 0x000001fbe787fa80 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c5540fe280 mode 0 -Event: 38.563 Thread 0x000001fbe8a6f6a0 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c553cff190 -Event: 38.563 Thread 0x000001fbe8a6f6a0 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c553cfe6d0 mode 0 -Event: 38.564 Thread 0x000001fbe8a31150 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c5549feee0 -Event: 38.564 Thread 0x000001fbe8a31150 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c5549fe420 mode 0 -Event: 38.566 Thread 0x000001fbdff992d0 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c553fff270 -Event: 38.566 Thread 0x000001fbdff992d0 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c553ffe7b0 mode 0 -Event: 38.567 Thread 0x000001fbe8a339d0 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c554fff3b0 -Event: 38.567 Thread 0x000001fbe8a339d0 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c554ffe8f0 mode 0 -Event: 38.567 Thread 0x000001fbe8a6fbb0 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c553eff230 -Event: 38.567 Thread 0x000001fbe8a6fbb0 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c553efe770 mode 0 -Event: 38.568 Thread 0x000001fbe8a6dd50 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c5523feda0 -Event: 38.568 Thread 0x000001fbe8a6dd50 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c5523fe2e0 mode 0 -Event: 38.569 Thread 0x000001fbe8a2f800 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c5544feeb0 -Event: 38.569 Thread 0x000001fbe8a2f800 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c5544fe3f0 mode 0 -Event: 38.570 Thread 0x000001fbe8a6f6a0 DEOPT PACKING pc=0x000001fb81c357b6 sp=0x000000c553cff190 -Event: 38.570 Thread 0x000001fbe8a6f6a0 DEOPT UNPACKING pc=0x000001fb874a7143 sp=0x000000c553cfe6d0 mode 0 - -Classes loaded (20 events): -Event: 37.471 Loading class java/nio/channels/NotYetConnectedException -Event: 37.471 Loading class java/nio/channels/NotYetConnectedException done -Event: 37.474 Loading class java/util/concurrent/atomic/AtomicLongFieldUpdater -Event: 37.475 Loading class java/util/concurrent/atomic/AtomicLongFieldUpdater done -Event: 37.475 Loading class java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater -Event: 37.475 Loading class java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater done -Event: 37.475 Loading class java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater$1 -Event: 37.476 Loading class java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater$1 done -Event: 37.566 Loading class java/nio/channels/AlreadyConnectedException -Event: 37.567 Loading class java/nio/channels/AlreadyConnectedException done -Event: 37.567 Loading class java/nio/channels/ConnectionPendingException -Event: 37.568 Loading class java/nio/channels/ConnectionPendingException done -Event: 37.578 Loading class java/nio/channels/UnsupportedAddressTypeException -Event: 37.579 Loading class java/nio/channels/UnsupportedAddressTypeException done -Event: 38.187 Loading class java/lang/Math$RandomNumberGeneratorHolder -Event: 38.187 Loading class java/lang/Math$RandomNumberGeneratorHolder done -Event: 38.271 Loading class java/util/IdentityHashMap$EntrySpliterator -Event: 38.273 Loading class java/util/IdentityHashMap$EntrySpliterator done -Event: 38.341 Loading class java/util/concurrent/PriorityBlockingQueue -Event: 38.342 Loading class java/util/concurrent/PriorityBlockingQueue done - -Classes unloaded (14 events): -Event: 17.039 Thread 0x000001fbff57a010 Unloading class 0x000001fb95c19c00 'java/lang/invoke/LambdaForm$DMH+0x000001fb95c19c00' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9642c400 'java/lang/invoke/LambdaForm$DMH+0x000001fb9642c400' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9642c800 'java/lang/invoke/LambdaForm$DMH+0x000001fb9642c800' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9627a800 'java/lang/invoke/LambdaForm$DMH+0x000001fb9627a800' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9627a400 'java/lang/invoke/LambdaForm$DMH+0x000001fb9627a400' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9627a000 'java/lang/invoke/LambdaForm$DMH+0x000001fb9627a000' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb96279c00 'java/lang/invoke/LambdaForm$DMH+0x000001fb96279c00' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb96279400 'java/lang/invoke/LambdaForm$DMH+0x000001fb96279400' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb96279800 'java/lang/invoke/LambdaForm$DMH+0x000001fb96279800' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb96278c00 'java/lang/invoke/LambdaForm$DMH+0x000001fb96278c00' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb96279000 'java/lang/invoke/LambdaForm$DMH+0x000001fb96279000' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb96278800 'java/lang/invoke/LambdaForm$DMH+0x000001fb96278800' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9624cc00 'java/lang/invoke/LambdaForm$DMH+0x000001fb9624cc00' -Event: 33.922 Thread 0x000001fbff57a010 Unloading class 0x000001fb9624c800 'java/lang/invoke/LambdaForm$DMH+0x000001fb9624c800' - -Classes redefined (0 events): -No events - -Internal exceptions (20 events): -Event: 37.329 Thread 0x000001fbe8a35830 Exception (0x00000007db04ecf0) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.407 Thread 0x000001fbef365e40 Exception (0x00000007d815d3f8) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 37.407 Thread 0x000001fbef365e40 Exception (0x00000007d81610d0) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 37.432 Thread 0x000001fbe8a35830 Exception (0x00000007d71d4d68) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.599 Thread 0x000001fbdff53480 Exception (0x00000007de179d98) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.742 Thread 0x000001fbdff501e0 Exception (0x00000007df074bf0) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.767 Thread 0x000001fbdff53480 Exception (0x00000007dd7a2890) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.775 Thread 0x000001fbdff53480 Exception (0x00000007dcc9ab48) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.861 Thread 0x000001fbdff53ea0 Exception (0x00000007d8d77488) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.944 Thread 0x000001fbdff53480 Exception (0x00000007d23e1948) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 37.957 Thread 0x000001fbe8a35830 Exception (0x00000007d17dbb08) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 38.063 Thread 0x000001fbdff53480 Exception (0x00000007cb878568) -thrown [s\src\hotspot\share\prims\jni.cpp, line 516] -Event: 38.214 Thread 0x000001fbdff51620 Exception (0x00000007c5778898) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 826] -Event: 38.313 Thread 0x000001fbef365e40 Exception (0x00000007c4b4a298) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 38.314 Thread 0x000001fbef365e40 Exception (0x00000007c4b4d978) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 38.355 Thread 0x000001fbdff51620 Exception (0x00000007c479aa80) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 38.355 Thread 0x000001fbdff51620 Exception (0x00000007c47a2340) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 38.415 Thread 0x000001fbdff51620 Exception (0x00000007c45a16c0) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 38.425 Thread 0x000001fbdff51620 Exception (0x00000007c45a5790) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] -Event: 38.425 Thread 0x000001fbdff51620 Exception (0x00000007c45a9318) -thrown [s\src\hotspot\share\interpreter\linkResolver.cpp, line 759] - -VM Operations (20 events): -Event: 37.551 Executing VM operation: G1CollectForAllocation done -Event: 37.694 Executing VM operation: G1CollectForAllocation -Event: 37.711 Executing VM operation: G1CollectForAllocation done -Event: 37.799 Executing VM operation: HandshakeAllThreads -Event: 37.799 Executing VM operation: HandshakeAllThreads done -Event: 38.157 Executing VM operation: HandshakeAllThreads -Event: 38.157 Executing VM operation: HandshakeAllThreads done -Event: 38.249 Executing VM operation: HandshakeAllThreads -Event: 38.249 Executing VM operation: HandshakeAllThreads done -Event: 38.287 Executing VM operation: ICBufferFull -Event: 38.288 Executing VM operation: ICBufferFull done -Event: 38.308 Executing VM operation: HandshakeAllThreads -Event: 38.308 Executing VM operation: HandshakeAllThreads done -Event: 38.321 Executing VM operation: HandshakeAllThreads -Event: 38.321 Executing VM operation: HandshakeAllThreads done -Event: 38.325 Executing VM operation: HandshakeAllThreads -Event: 38.325 Executing VM operation: HandshakeAllThreads done -Event: 38.331 Executing VM operation: HandshakeAllThreads -Event: 38.331 Executing VM operation: HandshakeAllThreads done -Event: 38.626 Executing VM operation: G1CollectForAllocation - -Memory protections (0 events): -No events - -Nmethod flushes (20 events): -Event: 38.187 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81b68290 -Event: 38.187 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81b6a790 -Event: 38.187 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81c1ec90 -Event: 38.187 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81c4a410 -Event: 38.187 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81c4fd90 -Event: 38.187 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81c56990 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d10f10 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d53f90 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d56290 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d5ca10 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d64f10 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d6ba10 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d90190 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81d93c90 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81da9490 -Event: 38.188 Thread 0x000001fb93429fc0 flushing osr nmethod 0x000001fb81da9a10 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81df9590 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81e1c210 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81e1f090 -Event: 38.188 Thread 0x000001fb93429fc0 flushing nmethod 0x000001fb81e2aa10 - -Events (20 events): -Event: 33.348 Thread 0x000001fbe8a35830 Thread added: 0x000001fbdff53480 -Event: 33.801 Thread 0x000001fbde3fa920 Thread exited: 0x000001fbde3fa920 -Event: 33.801 Thread 0x000001fbde3f8e90 Thread exited: 0x000001fbde3f8e90 -Event: 33.809 Thread 0x000001fbdc4abc60 Thread added: 0x000001fbde3f9930 -Event: 33.809 Thread 0x000001fbdc4abc60 Thread added: 0x000001fbde3fc3b0 -Event: 33.842 Thread 0x000001fbdff53480 Thread added: 0x000001fbdff501e0 -Event: 33.935 Thread 0x000001fbdff53480 Thread added: 0x000001fbdff53ea0 -Event: 33.938 Thread 0x000001fbe8a35d40 Thread exited: 0x000001fbe8a35d40 -Event: 33.938 Thread 0x000001fbe8a36250 Thread exited: 0x000001fbe8a36250 -Event: 33.938 Thread 0x000001fbe8a34900 Thread exited: 0x000001fbe8a34900 -Event: 35.293 Thread 0x000001fbdff51620 Thread added: 0x000001fbdff57650 -Event: 36.681 Thread 0x000001fbdc4abc60 Thread exited: 0x000001fbdc4abc60 -Event: 36.807 Thread 0x000001fbdc4af6d0 Thread exited: 0x000001fbdc4af6d0 -Event: 36.855 Thread 0x000001fbde3fc3b0 Thread exited: 0x000001fbde3fc3b0 -Event: 37.517 Thread 0x000001fbef365e40 Thread added: 0x000001fbdff552e0 -Event: 37.571 Thread 0x000001fbef365e40 Thread added: 0x000001fbdff543b0 -Event: 37.582 Thread 0x000001fbdff552e0 Thread added: 0x000001fbdff56720 -Event: 37.758 Thread 0x000001fbdff53ea0 Thread added: 0x000001fbdff548c0 -Event: 38.332 Thread 0x000001fbdff50c00 Thread exited: 0x000001fbdff50c00 -Event: 38.332 Thread 0x000001fbef365e40 Thread added: 0x000001fbdff50c00 - - -Dynamic libraries: -0x00007ff709f60000 - 0x00007ff709f6e000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\java.exe -0x00007ffa5a740000 - 0x00007ffa5a9a7000 C:\WINDOWS\SYSTEM32\ntdll.dll -0x00007ffa58c20000 - 0x00007ffa58ce9000 C:\WINDOWS\System32\KERNEL32.DLL -0x00007ffa57350000 - 0x00007ffa57747000 C:\WINDOWS\System32\KERNELBASE.dll -0x00007ffa581c0000 - 0x00007ffa5830b000 C:\WINDOWS\System32\ucrtbase.dll -0x00007ffa1aa70000 - 0x00007ffa1aa88000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\jli.dll -0x00007ff9ef380000 - 0x00007ff9ef39e000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\VCRUNTIME140.dll -0x00007ffa58870000 - 0x00007ffa58a36000 C:\WINDOWS\System32\USER32.dll -0x00007ffa58490000 - 0x00007ffa584b7000 C:\WINDOWS\System32\win32u.dll -0x00007ffa3c770000 - 0x00007ffa3ca02000 C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8457_none_3e0b2faee331e92d\COMCTL32.dll -0x00007ffa592d0000 - 0x00007ffa592fb000 C:\WINDOWS\System32\GDI32.dll -0x00007ffa58d90000 - 0x00007ffa58e39000 C:\WINDOWS\System32\msvcrt.dll -0x00007ffa57220000 - 0x00007ffa5734c000 C:\WINDOWS\System32\gdi32full.dll -0x00007ffa57170000 - 0x00007ffa57213000 C:\WINDOWS\System32\msvcp_win.dll -0x00007ffa587a0000 - 0x00007ffa587d2000 C:\WINDOWS\System32\IMM32.DLL -0x00007ffa23160000 - 0x00007ffa2316c000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\vcruntime140_1.dll -0x00007ff9ed920000 - 0x00007ff9ed9ad000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\msvcp140.dll -0x00007ff971fc0000 - 0x00007ff972c2b000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\server\jvm.dll -0x00007ffa59f70000 - 0x00007ffa5a026000 C:\WINDOWS\System32\ADVAPI32.dll -0x00007ffa59360000 - 0x00007ffa59407000 C:\WINDOWS\System32\sechost.dll -0x00007ffa59e50000 - 0x00007ffa59f68000 C:\WINDOWS\System32\RPCRT4.dll -0x00007ffa587e0000 - 0x00007ffa58860000 C:\WINDOWS\System32\WS2_32.dll -0x00007ffa56e20000 - 0x00007ffa56e7e000 C:\WINDOWS\SYSTEM32\POWRPROF.dll -0x00007ffa4aac0000 - 0x00007ffa4aaf6000 C:\WINDOWS\SYSTEM32\WINMM.dll -0x00007ffa50d10000 - 0x00007ffa50d1b000 C:\WINDOWS\SYSTEM32\VERSION.dll -0x00007ffa56e00000 - 0x00007ffa56e14000 C:\WINDOWS\SYSTEM32\UMPDC.dll -0x00007ffa55ec0000 - 0x00007ffa55edb000 C:\WINDOWS\SYSTEM32\kernel.appcore.dll -0x00007ffa1aa60000 - 0x00007ffa1aa6a000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\jimage.dll -0x00007ffa41410000 - 0x00007ffa41652000 C:\WINDOWS\SYSTEM32\DBGHELP.DLL -0x00007ffa5a290000 - 0x00007ffa5a613000 C:\WINDOWS\System32\combase.dll -0x00007ffa59410000 - 0x00007ffa594e9000 C:\WINDOWS\System32\OLEAUT32.dll -0x00007ffa38cb0000 - 0x00007ffa38ceb000 C:\WINDOWS\SYSTEM32\dbgcore.DLL -0x00007ffa57750000 - 0x00007ffa577f8000 C:\WINDOWS\System32\bcryptPrimitives.dll -0x00007ff9ef350000 - 0x00007ff9ef375000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\java.dll -0x00007ff97dbb0000 - 0x00007ff97dc87000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\jsvml.dll -0x00007ffa59570000 - 0x00007ffa59cde000 C:\WINDOWS\System32\SHELL32.dll -0x00007ffa57890000 - 0x00007ffa580fc000 C:\WINDOWS\System32\windows.storage.dll -0x00007ffa5a190000 - 0x00007ffa5a286000 C:\WINDOWS\System32\SHCORE.dll -0x00007ffa59500000 - 0x00007ffa59566000 C:\WINDOWS\System32\shlwapi.dll -0x00007ffa57090000 - 0x00007ffa570b9000 C:\WINDOWS\SYSTEM32\profapi.dll -0x00007ff9ef330000 - 0x00007ff9ef34a000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\net.dll -0x00007ffa51820000 - 0x00007ffa51949000 C:\WINDOWS\SYSTEM32\WINHTTP.dll -0x00007ffa56410000 - 0x00007ffa5647c000 C:\WINDOWS\system32\mswsock.dll -0x00007ff9ee060000 - 0x00007ff9ee076000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\nio.dll -0x00007ff9ee040000 - 0x00007ff9ee058000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\zip.dll -0x00007ff9ee030000 - 0x00007ff9ee040000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\verify.dll -0x00007ff9efe10000 - 0x00007ff9efe1a000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\management.dll -0x00007ff9efe00000 - 0x00007ff9efe0c000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\management_ext.dll -0x00007ffa594f0000 - 0x00007ffa594f8000 C:\WINDOWS\System32\PSAPI.DLL -0x00007ffa30ca0000 - 0x00007ffa30cb8000 C:\WINDOWS\system32\napinsp.dll -0x00007ffa558f0000 - 0x00007ffa55a22000 C:\WINDOWS\SYSTEM32\DNSAPI.dll -0x00007ffa558b0000 - 0x00007ffa558e2000 C:\WINDOWS\SYSTEM32\IPHLPAPI.DLL -0x00007ffa58cf0000 - 0x00007ffa58cfa000 C:\WINDOWS\System32\NSI.dll -0x00007ffa30c80000 - 0x00007ffa30c93000 C:\WINDOWS\System32\winrnr.dll -0x00007ffa30c50000 - 0x00007ffa30c72000 C:\WINDOWS\system32\nlansp_c.dll -0x00007ffa30c30000 - 0x00007ffa30c46000 C:\WINDOWS\system32\wshbth.dll -0x00007ffa50a30000 - 0x00007ffa50a3b000 C:\Windows\System32\rasadhlp.dll -0x00007ffa50df0000 - 0x00007ffa50e76000 C:\WINDOWS\System32\fwpuclnt.dll -0x00007ff9ed890000 - 0x00007ff9ed905000 C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\lwjgl.dll -0x00007ff97db40000 - 0x00007ff97dba1000 C:\Users\UTILIS~1\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\glfw.dll -0x00007ff97daf0000 - 0x00007ff97db3b000 C:\WINDOWS\SYSTEM32\dinput8.dll -0x00007ff9d3570000 - 0x00007ff9d358c000 C:\WINDOWS\SYSTEM32\xinput1_4.dll -0x00007ffa56d40000 - 0x00007ffa56d6d000 C:\WINDOWS\SYSTEM32\DEVOBJ.dll -0x00007ffa56d70000 - 0x00007ffa56dc1000 C:\WINDOWS\SYSTEM32\cfgmgr32.dll -0x00007ffa54ef0000 - 0x00007ffa54f1f000 C:\WINDOWS\SYSTEM32\dwmapi.dll -0x00007ffa233f0000 - 0x00007ffa235d3000 C:\WINDOWS\SYSTEM32\inputhost.dll -0x00007ffa54430000 - 0x00007ffa54557000 C:\WINDOWS\SYSTEM32\CoreMessaging.dll -0x00007ffa54c10000 - 0x00007ffa54cba000 C:\WINDOWS\system32\uxtheme.dll -0x00007ffa56670000 - 0x00007ffa5667c000 C:\WINDOWS\SYSTEM32\CRYPTBASE.DLL -0x00007ffa59cf0000 - 0x00007ffa59e4c000 C:\WINDOWS\System32\MSCTF.dll -0x00007ffa39ec0000 - 0x00007ffa39fcf000 C:\WINDOWS\SYSTEM32\opengl32.dll -0x00007ffa398a0000 - 0x00007ffa398cd000 C:\WINDOWS\SYSTEM32\GLU32.dll -0x00007ffa54d10000 - 0x00007ffa54d55000 C:\WINDOWS\SYSTEM32\dxcore.dll -0x00007ffa52ae0000 - 0x00007ffa52afd000 C:\WINDOWS\SYSTEM32\windows.staterepositorycore.dll -0x00007ff9ac740000 - 0x00007ff9af065000 C:\WINDOWS\System32\DriverStore\FileRepository\nv_dispig.inf_amd64_f4c7a2fd13e0f763\nvoglv64.dll -0x00007ffa58e40000 - 0x00007ffa592c7000 C:\WINDOWS\System32\SETUPAPI.dll -0x00007ffa585d0000 - 0x00007ffa58767000 C:\WINDOWS\System32\ole32.dll -0x00007ffa54a80000 - 0x00007ffa54aa9000 C:\WINDOWS\SYSTEM32\WTSAPI32.dll -0x00007ffa58310000 - 0x00007ffa58488000 C:\WINDOWS\System32\CRYPT32.dll -0x00007ffa56160000 - 0x00007ffa561a9000 C:\WINDOWS\SYSTEM32\SspiCli.dll -0x00007ffa56870000 - 0x00007ffa56883000 C:\WINDOWS\SYSTEM32\msasn1.dll -0x00007ffa50cd0000 - 0x00007ffa50d0b000 C:\WINDOWS\SYSTEM32\cryptnet.dll -0x00007ffa56710000 - 0x00007ffa5677a000 C:\WINDOWS\SYSTEM32\wldp.dll -0x00007ffa50b50000 - 0x00007ffa50cc8000 C:\WINDOWS\SYSTEM32\drvstore.dll -0x00007ffa57800000 - 0x00007ffa57882000 C:\WINDOWS\System32\WINTRUST.dll -0x00007ffa55fe0000 - 0x00007ffa56016000 C:\WINDOWS\SYSTEM32\ntmarta.dll -0x00007ffa58770000 - 0x00007ffa58790000 C:\WINDOWS\System32\imagehlp.dll -0x00007ffa56810000 - 0x00007ffa5682b000 C:\WINDOWS\System32\CRYPTSP.dll -0x00007ffa55e20000 - 0x00007ffa55e59000 C:\WINDOWS\system32\rsaenh.dll -0x00007ffa57060000 - 0x00007ffa5708a000 C:\WINDOWS\System32\bcrypt.dll -0x00007ffa4bc30000 - 0x00007ffa5092f000 C:\WINDOWS\System32\DriverStore\FileRepository\nv_dispig.inf_amd64_f4c7a2fd13e0f763\nvgpucomp64.dll -0x00007ffa56920000 - 0x00007ffa56982000 C:\WINDOWS\SYSTEM32\WINSTA.dll -0x00007ff97d890000 - 0x00007ff97dae9000 C:\Users\UTILIS~1\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\jemalloc.dll -0x00007ff97d800000 - 0x00007ff97d881000 C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\lwjgl_stb.dll -0x00007ffa1fc10000 - 0x00007ffa1fd56000 C:\WINDOWS\SYSTEM32\textinputframework.dll -0x00007ff97d7a0000 - 0x00007ff97d7fd000 C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\lwjgl_opengl.dll -0x00007ff9d9ca0000 - 0x00007ff9d9cf6000 C:\WINDOWS\SYSTEM32\pdh.dll -0x00007ff9efde0000 - 0x00007ff9efdf2000 C:\WINDOWS\System32\perfproc.dll -0x00007ffa396f0000 - 0x00007ffa39701000 C:\WINDOWS\System32\perfos.dll -0x00007ffa54cc0000 - 0x00007ffa54cd2000 C:\WINDOWS\SYSTEM32\pfclient.dll -0x00007ffa564c0000 - 0x00007ffa564f3000 C:\WINDOWS\SYSTEM32\USERENV.dll -0x00007ffa517f0000 - 0x00007ffa5180d000 C:\WINDOWS\SYSTEM32\dhcpcsvc6.DLL -0x00007ffa51540000 - 0x00007ffa51565000 C:\WINDOWS\SYSTEM32\dhcpcsvc.DLL -0x00007ff9ef3a0000 - 0x00007ff9ef3e0000 C:\Users\Utilisateur\AppData\Local\Temp\jna-1082121059\jna17725892220550122580.dll -0x00007ffa5a050000 - 0x00007ffa5a0fe000 C:\WINDOWS\System32\clbcatq.dll -0x00007ffa43770000 - 0x00007ffa4378d000 C:\WINDOWS\SYSTEM32\amsi.dll -0x00007ff9efdd0000 - 0x00007ff9efdde000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\sunmscapi.dll -0x00007ffa569e0000 - 0x00007ffa56a10000 C:\WINDOWS\SYSTEM32\ncrypt.dll -0x00007ffa56990000 - 0x00007ffa569cf000 C:\WINDOWS\SYSTEM32\NTASN1.dll -0x00007ffa39740000 - 0x00007ffa397ff000 C:\WINDOWS\SYSTEM32\mscms.dll -0x00007ff978160000 - 0x00007ff9781a9000 C:\WINDOWS\SYSTEM32\icm32.dll -0x00007ff9ee020000 - 0x00007ff9ee029000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\extnet.dll -0x00007ff97d110000 - 0x00007ff97d2a7000 C:\Users\UTILIS~1\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7\OpenAL.dll -0x00007ffa497d0000 - 0x00007ffa49869000 C:\WINDOWS\System32\MMDevApi.dll -0x00007ff9a2d70000 - 0x00007ff9a2ee3000 C:\WINDOWS\System32\Speech\Common\sapi.dll -0x00007ffa136c0000 - 0x00007ffa136c8000 C:\WINDOWS\system32\wshunix.dll -0x00007ffa41780000 - 0x00007ffa41933000 C:\WINDOWS\SYSTEM32\AUDIOSES.DLL -0x00007ffa55180000 - 0x00007ffa55194000 C:\WINDOWS\SYSTEM32\resourcepolicyclient.dll -0x00007ffa3a170000 - 0x00007ffa3a34d000 C:\WINDOWS\system32\urlmon.dll -0x00007ffa3dd70000 - 0x00007ffa3e034000 C:\WINDOWS\SYSTEM32\iertutil.dll -0x00007ffa558a0000 - 0x00007ffa558ad000 C:\WINDOWS\SYSTEM32\netutils.dll -0x00007ffa4b490000 - 0x00007ffa4b4b9000 C:\WINDOWS\SYSTEM32\srvcli.dll -0x00007ffa51250000 - 0x00007ffa51532000 C:\WINDOWS\SYSTEM32\CoreUIComponents.dll -0x00007ffa51b00000 - 0x00007ffa51c6a000 C:\WINDOWS\SYSTEM32\wintypes.dll -0x00007ff979de0000 - 0x00007ff979f71000 C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\awt.dll -0x00007ffa549c0000 - 0x00007ffa54a60000 C:\WINDOWS\SYSTEM32\apphelp.dll - -dbghelp: loaded successfully - version: 4.0.5 - missing functions: none -symbol engine: initialized successfully - sym options: 0x614 - pdb path: .;C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin;C:\WINDOWS\SYSTEM32;C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8457_none_3e0b2faee331e92d;C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin\server;C:\Users\Utilisateur\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7;C:\Users\UTILIS~1\AppData\Local\Temp\lwjglUtilisateur\3.3.1-build-7;C:\WINDOWS\System32\DriverStore\FileRepository\nv_dispig.inf_amd64_f4c7a2fd13e0f763;C:\Users\Utilisateur\AppData\Local\Temp\jna-1082121059;C:\WINDOWS\System32\Speech\Common - -VM Arguments: -jvm_args: -Dforge.enableGameTest=true -Dforge.logging.console.level=debug -Dforge.logging.markers=REGISTRIES -DignoreList=bootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,JarJarFileSystems,client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,forge- -Djava.net.preferIPv6Addresses=system -DlegacyClassPath.file=C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\classpath\runClient_minecraftClasspath.txt -DmergeModules=jna-5.10.0.jar,jna-platform-5.10.0.jar -Dmixin.debug.export=true -Dmixin.debug.verbose=true -Dmixin.env.refMapRemappingFile=C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge/build/createSrgToMcp/output.srg -Dmixin.env.remapRefMap=true -Dnet.minecraftforge.gradle.GradleStart.srg.srg-mcp=C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\createSrgToMcp\output.srg --module-path=C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\cpw.mods\bootstraplauncher\1.1.2\c546e00443d8432cda6baa1c860346980742628\bootstraplauncher-1.1.2.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\cpw.mods\securejarhandler\2.1.10\51e6a22c6c716beb11e244bf5b8be480f51dd6b5\securejarhandler-2.1.10.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.5\19ab5b5800a3910d30d3a3e64fdb00fd0cb42de0\asm-commons-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.5\64b5a1fc8c1b15ed2efd6a063e976bc8d3dc5ffe\asm-util-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.5\490bacc77de7cbc0be1a30bb3471072d705be4a4\asm-analysis-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.5\fd33c8b6373abaa675be407082fdfda35021254a\asm-tree-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.5\dc6ea1875f4d64fbc85e1691c95b96a3d8569c90\asm-9.5.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\net.minecraftforge\JarJarFileSystems\0.3.19\2464eb7d6b9ddb9db36a82cf8a95193e5c6fe020\JarJarFileSystems-0.3.19.jar --add-modules=ALL-MODULE-PATH --add-opens=java.base/java.util.jar=cpw.mods.securejarhandler --add-opens=java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports=java.base/sun.security.util=cpw.mods.securejarhandler --add-exports=jdk.naming.dns/com.sun.jndi.dns=java.naming -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump -Dfile.encoding=UTF-8 -Duser.country=FR -Duser.language=fr -Duser.variant -java_command: cpw.mods.bootstraplauncher.BootstrapLauncher --launchTarget forgeclientuserdev --version MOD_DEV --assetIndex 5 --assetsDir C:\Users\Utilisateur\.gradle\caches\forge_gradle\assets --gameDir . --fml.forgeVersion 47.2.6 --fml.mcVersion 1.20.1 --fml.forgeGroup net.minecraftforge --fml.mcpVersion 20230612.114412 --mixin.config createnuclear.forge.mixins.json -java_class_path (initial): C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\classes\java\main;C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\resources\main;C:\Users\Utilisateur\.gradle\caches\forge_gradle\deobf_dependencies\curse\maven\jade-324717\6106101_mapped_parchment_2023.09.03-1.20.1\jade-324717-6106101_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\Utilisateur\.gradle\caches\forge_gradle\deobf_dependencies\com\simibubi\create\create-1.20.1\6.0.8-289_mapped_parchment_2023.09.03-1.20.1\create-1.20.1-6.0.8-289_mapped_parchment_2023.09.03-1.20.1-slim.jar;C:\Users\Utilisateur\.gradle\caches\forge_gradle\deobf_dependencies\net\createmod\ponder\Ponder-Forge-1.20.1\1.0.91_mapped_parchment_2023.09.03-1.20.1\Ponder-Forge-1.20.1-1.0.91_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\Utilisateur\.gradle\caches\forge_gradle\deobf_dependencies\com\tterrag\registrate\Registrate\MC1.20-1.3.3_mapped_parchment_2023.09.03-1.20.1\Registrate-MC1.20-1.3.3_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\Utilisateur\.gradle\caches\modules-2\files-2.1\io.github.llamalad7\mixinextras-forge\0.4.1\5c35573a7b76103724799ca1174a69699b8a9aec\mixinextras-forge-0.4.1.jar;C:\Users\Utilisateur\Documents\travail\ynov\ydays\CreateNuclearForge\build\fg_cache\net\minecraftforge\forge\1.20.1-47.2.6_mapped_parchment_2023.09.03-1.20.1\forge-1.20.1-47.2.6_mapped_parchment_2023.09.03-1.20.1-recomp.jar;C:\Users\Utilisateur\.gradle\caches\forge_gradle\deobf_dependencies\dev\engine-room\flywheel\flywheel-forge-1.20.1\1.0.5_mapped_parchment_2023.09.03-1.20.1\flywheel-forge-1.20.1-1.0.5_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\Utilisateur\.gradle\caches\forge_gradle\deobf_dependencies\mezz\jei\jei-1.20.1-forge\15.20.0.105_mapped_parchment_2023.09.03-1.20.1\jei-1.20.1-forge-15.20.0.105_mapped_parchment_2023.09.03-1.20.1.jar;C:\Users\Utilisateur\.gradle\caches\forge_gradle\minecraft_repo\versions\1.20.1\client-extra.jar;C:\Users\Utilisateur\.gradl -Launcher Type: SUN_STANDARD - -[Global flags] - intx CICompilerCount = 12 {product} {ergonomic} - uint ConcGCThreads = 4 {product} {ergonomic} - uint G1ConcRefinementThreads = 15 {product} {ergonomic} - size_t G1HeapRegionSize = 2097152 {product} {ergonomic} - uintx GCDrainStackTargetSize = 64 {product} {ergonomic} - ccstr HeapDumpPath = MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump {manageable} {command line} - size_t InitialHeapSize = 266338304 {product} {ergonomic} - size_t MarkStackSize = 4194304 {product} {ergonomic} - size_t MaxHeapSize = 4253024256 {product} {ergonomic} - size_t MaxNewSize = 2550136832 {product} {ergonomic} - size_t MinHeapDeltaBytes = 2097152 {product} {ergonomic} - size_t MinHeapSize = 8388608 {product} {ergonomic} - uintx NonNMethodCodeHeapSize = 7602480 {pd product} {ergonomic} - uintx NonProfiledCodeHeapSize = 122027880 {pd product} {ergonomic} - uintx ProfiledCodeHeapSize = 122027880 {pd product} {ergonomic} - uintx ReservedCodeCacheSize = 251658240 {pd product} {ergonomic} - bool SegmentedCodeCache = true {product} {ergonomic} - size_t SoftMaxHeapSize = 4253024256 {manageable} {ergonomic} - bool UseCompressedClassPointers = true {product lp64_product} {ergonomic} - bool UseCompressedOops = true {product lp64_product} {ergonomic} - bool UseG1GC = true {product} {ergonomic} - bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} - -Logging: -Log output configuration: - #0: stdout all=warning uptime,level,tags - #1: stderr all=off uptime,level,tags - -Environment Variables: -JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-21.0.10.7-hotspot\ -PATH=C:\Program Files\Eclipse Adoptium\jdk-21.0.10.7-hotspot\bin;C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot\bin;C:\Program Files\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Users\Utilisateur\Documents\flutter\bin;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\WINDOWS\system32\config\systemprofile\AppData\Local\Muse Hub\lib;C:\Users\Utilisateur\Documents\Mc-Maven\apache-maven-3.9.14\bin;C:\Users\Utilisateur\AppData\Local\Programs\Python\Python311\Scripts\;C:\Users\Utilisateur\AppData\Local\Programs\Python\Python311\;C:\Users\Utilisateur\AppData\Local\Programs\Python\Launcher\;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\Users\Utilisateur\AppData\Local\Microsoft\WindowsApps;C:\Users\Utilisateur\.dotnet\tools;C:\Users\Utilisateur\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\Utilisateur\AppData\Roaming\npm;C:\Users\Utilisateur\AppData\Local\GitHubDesktop\bin;C:\Users\Utilisateur\AppData\Local\Programs\MiKTeX\miktex\bin\x64\;C:\Users\Utilisateur\AppData\Local\Muse Hub\lib;C:\Users\Utilisateur\AppData\Local\Programs\Antigravity\bin -USERNAME=Utilisateur -OS=Windows_NT -PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 151 Stepping 2, GenuineIntel -TMP=C:\Users\UTILIS~1\AppData\Local\Temp -TEMP=C:\Users\UTILIS~1\AppData\Local\Temp - - - -Periodic native trim disabled - - ---------------- S Y S T E M --------------- - -OS: - Windows 11 , 64 bit Build 26100 (10.0.26100.8328) -OS uptime: 0 days 4:42 hours -Hyper-V role detected - -CPU: total 20 (initial active 20) (10 cores per cpu, 2 threads per core) family 6 model 151 stepping 2 microcode 0x26, cx8, cmov, fxsr, ht, mmx, 3dnowpref, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, lzcnt, tsc, tscinvbit, avx, avx2, aes, erms, clmul, bmi1, bmi2, adx, sha, fma, vzeroupper, clflush, clflushopt, clwb, hv -Processor Information for all 20 processors : - Max Mhz: 2100, Current Mhz: 2100, Mhz Limit: 2100 - -Memory: 4k page, system-wide physical 16222M (1217M free) -TotalPageFile size 43363M (AvailPageFile size 1114M) -current process WorkingSet (physical memory assigned to process): 3095M, peak: 3114M -current process commit charge ("private bytes"): 5054M, peak: 5277M - -vm_info: OpenJDK 64-Bit Server VM (17.0.17+10) for windows-amd64 JRE (17.0.17+10), built on Oct 21 2025 23:25:32 by "admin" with unknown MS VC++:1942 - -END. diff --git a/run/imgui.ini b/run/imgui.ini deleted file mode 100644 index 4594f475..00000000 --- a/run/imgui.ini +++ /dev/null @@ -1,25 +0,0 @@ -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[Window][2231374] -Pos=1375,100 -Size=525,750 -Collapsed=0 - -[Window][1510026] -Pos=1375,100 -Size=525,750 -Collapsed=0 - -[Window][2099590] -Pos=1375,100 -Size=525,750 -Collapsed=0 - -[Window][1378774] -Pos=1375,100 -Size=525,750 -Collapsed=0 - diff --git a/run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled b/run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled deleted file mode 100644 index 5cecec75ccbd71058c27d89c8535a3c5377ec97a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 547818 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

mJZ)f)FeYT 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

(%%vzjv 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 ) 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

m; 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¨Z#%&WZ@dq&b_)a3AP$a_;y{~{e*EN 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 Date: Sun, 28 Jun 2026 16:29:26 +0200 Subject: [PATCH 120/171] perf: stop including damage value in inventory radiation hash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop stack.getDamageValue() from InventoryHashUtil.stackHash(...): no IRadiationSource implementation (UraniumOreItem, RadiationItem, RadiationBucketItem) or RadiationEffect reads item durability, so including it in the hash only triggered an unnecessary RadiationCapability.computeItemRadiation recompute on every durability change (mining, combat) — exactly the hot paths the hash was meant to shield from redundant recomputation. Update the surrounding javadoc to match. --- AUDIT_ACTUEL.md | 9 +++++---- .../foundation/utility/InventoryHashUtil.java | 13 +++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index a16de078..05b998c1 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -26,7 +26,6 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to |---|---|---|---| | **isNotDanger tautologie** | `content/multiblock/IHeat.java:88-90` | 🟠 | `return of(heat,size) != DANGER \|\| of(heat,size) != NONE;` — toujours `true`. Appelant unique confirmé `ReactorControllerBlockEntity.java:428` (la classe a grossi, la ligne a bougé). La garde « ne pas faire tourner les sorties en `DANGER` » reste **inopérante** : les sorties tournent même en surchauffe. Correctif d'1 ligne (`!= DANGER` seul), à confirmer côté balance. | | **ReactorInputFluidManager — sur-extraction** | `controller/manager/ReactorInputFluidManager.java:137-155` | 🟠 | `fluidNeeded` (paramètre de `extractFluids`) n'est **toujours jamais décrémenté** entre handlers (l.146-151) → chaque handler de la boucle tente d'extraire le besoin complet, sur-extraction possible avec plusieurs inputs. `if (toExtract > 1)` (l.147) ignore toujours les extractions de 1 unité. Toléré aujourd'hui (tank mono-slot), reste une violation de contrat latente. | -| **InventoryHashUtil — resync durabilité** | `foundation/utility/InventoryHashUtil.java:90-91` | 🟡 | Toujours `h = 31*h + stack.getDamageValue()` pour tout item endommageable → resync à chaque variation de durabilité. | --- @@ -96,8 +95,8 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to - `content/multiblock/output/ReactorOutput.java:43,52,93` — propriété `SPEED` toujours entièrement commentée (pas supprimée). - `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. -**Reliquats Git (`run/`)** — confirmé via `git ls-files run/` : il reste **6 fichiers de debug/env trackés** malgré `.gitignore` : -`run/hs_err_pid21100.log`, `run/hs_err_pid27848.log`, `run/imgui.ini`, `run/servers.dat`, `run/servers.dat_old`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`. +~~**Reliquats Git (`run/`)** — confirmé via `git ls-files run/` : il reste **6 fichiers de debug/env trackés** malgré `.gitignore` : +`run/hs_err_pid21100.log`, `run/hs_err_pid27848.log`, `run/imgui.ini`, `run/servers.dat`, `run/servers.dat_old`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`.~~ ⚠️ **Conserver** les 10 `run/schematics/*.nbt` (assets de gameplay légitimes). **Décisions produit (pas du pur dead code — choisir puis exécuter)** @@ -133,6 +132,8 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Confirmé sain, nouveau code 2026-06-25/27** : `CNBuilderTransformers` (extraction propre des builders de modèles d'item/spawn-egg hors de `CNItems`, 97 lignes, SRP respectée) et l'item **Biome Restore Cell** (`BiomeRestoreCellItem`, 75 lignes, logique métier déléguée à `BiomeIrradiationService`, gardes serveur/client correctes) — aucun problème structurel à signaler, rien à ajouter au plan d'action. +**Corrigé le 2026-06-28** : `InventoryHashUtil.stackHash` n'inclut plus `getDamageValue()` (`InventoryHashUtil.java:90-91` retiré). Vérifié : aucune implémentation de `IRadiationSource`/`RadiationRegistry` (`UraniumOreItem`, `RadiationItem`, `RadiationBucketItem`, `RadiationEffect`) ne lit la durabilité, donc l'inclure dans le hash ne faisait que déclencher `RadiationCapability.computeItemRadiation` (`RadiationCapability.java:91-95`) sans raison à chaque variation de durabilité (minage, combat) — précisément sur les hot paths que le cache devait protéger. Pour mémoire, le terme « resync » des audits précédents désignait ce recalcul serveur, pas un trafic réseau (`RadiationProvider` ne fait que sérialiser en NBT, aucun `RadiationSyncPacket` impliqué). + **Corrigé le 2026-06-28** : garde `level.isClientSide` manquante sur la chaîne multiblock et double scan `playerDestroy`/`onRemove` (§2.1). Fix appliqué de façon centralisée plutôt que classe par classe : (1) `if (level.isClientSide) return;` ajouté en tête de `ReactorAssembler.assemble`/`disassemble` — point de convergence unique de toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler` ; (2) l'override `playerDestroy` a été supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput` et `ReactorFluidInput`, généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel de retrait, dans `onRemove`, qui se déclenche systématiquement y compris lors d'une casse joueur). Vérifié par lecture directe des 7 fichiers modifiés. Seul le court-circuit manquant de `findController` (perf pure) reste ouvert — voir §2.1 et §7. **Confirmé neutre** : le commit `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) ne fusionne rien dans le code de jeu — nettoyage cosmétique d'une scène Ponder uniquement. @@ -146,7 +147,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 2. ~~Garde `level.isClientSide()` en tête de `findController`/`findControllerPos`/`ReactorAssembler.assemble/disassemble`.~~ ✅ **fait le 2026-06-28** (garde centralisée dans `ReactorAssembler.assemble`/`disassemble`). 3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. -5. `git rm --cached` sur les 6 fichiers de debug `run/` (§4). +5. ~~`git rm --cached` sur les 6 fichiers de debug `run/` (§4).~~ ✅ **fait le 2026-06-28** 6. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. **Corrections ciblées (risque faible à moyen)** diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/utility/InventoryHashUtil.java b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/InventoryHashUtil.java index 521745f6..1863a8e6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/utility/InventoryHashUtil.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/utility/InventoryHashUtil.java @@ -17,8 +17,9 @@ *

Implementation details: * - Empty stacks contribute {@code 0}. * - Each non-empty stack contributes a value computed from the numeric item id, - * stack count, optional damage value (for damageable items), and the NBT tag's - * {@code hashCode()} when present. + * stack count, and the NBT tag's {@code hashCode()} when present. Damage value + * is intentionally excluded: no radiation source reads it, so including it would + * only cause needless recomputation on every durability change. * - Per-stack contributions are combined using a 31-multiplicative rolling scheme * (similar to {@link String#hashCode()}).

* @@ -45,7 +46,7 @@ public class InventoryHashUtil { * detection but is not collision-resistant. * @throws NullPointerException if {@code player} is {@code null} * @implNote The algorithm uses {@link Item#getId(net.minecraft.world.item.Item)} - * and basic stack properties (count, damage, tag.hashCode()). It is + * and basic stack properties (count, tag.hashCode()). It is * intentionally simple and optimized for speed rather than * cryptographic strength. */ @@ -73,7 +74,7 @@ public static long compute(Player player) { * *

Empty stacks return {@code 0}. For non-empty stacks the returned value * encodes the numeric item id, the stack count, and, when applicable, the - * damage value and the NBT tag's {@code hashCode()}.

+ * NBT tag's {@code hashCode()}.

* * @param stack the item stack to hash; must not be {@code null} * @return a {@code long} representing the stack's contribution; {@code 0} @@ -87,10 +88,6 @@ private static long stackHash(ItemStack stack) { long h = Item.getId(stack.getItem()); h = 31 * h + stack.getCount(); - if (stack.isDamageableItem()) { - h = 31 * h + stack.getDamageValue(); - } - if (stack.hasTag()) { h = 31 * h + stack.getTag().hashCode(); } From 2aaddb4d5ecd4a669729862d430379581647816d Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 16:40:07 +0200 Subject: [PATCH 121/171] chore: remove unused SimpleMultiBlockPattern.test() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete the dead test() method from SimpleMultiBlockPattern — it had no callers anywhere in the codebase and simply returned the record's own multiBlockOffsetPosList field. No behavioral change. --- AUDIT_ACTUEL.md | 6 +++--- src/main/java/lib/multiblock/SimpleMultiBlockPattern.java | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 05b998c1..4209c999 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -87,8 +87,8 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to > **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé par `NuclearMushroomCloudModel`). **Pur dead code (retrait sûr)** -- **`lib/multiblock/SimpleMultiBlockPattern.java` méthode `test()`** (l.72-74) — toujours aucun appelant (grep confirmé). Retrait trivial. -- **`IrradiatedBiomes.monsters()`** — corps toujours vide, appelé avec des arguments (95, 5, 100) silencieusement ignorés. À retirer ou implémenter. +- ~~**`lib/multiblock/SimpleMultiBlockPattern.java` méthode `test()`**~~ ✅ **Retiré** — confirmé par `git diff` : la méthode a disparu du fichier de travail, aucun appelant n'était présent. +- **`IrradiatedBiomes.monsters()`** — corps toujours vide (`IrradiatedBiomes.java:17-18`), appelé avec des arguments (95, 5, 100) silencieusement ignorés (l.55). À retirer ou implémenter. **Code commencé puis abandonné (hygiène de fin de PR)** - `content/multiblock/input/fluid/PlayerInteracteReactorFluidInput.java:57-61` — bloc d'interaction fluide toujours commenté/inachevé (non touché par le récent nettoyage de `ReactorOutput`). @@ -148,7 +148,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. 5. ~~`git rm --cached` sur les 6 fichiers de debug `run/` (§4).~~ ✅ **fait le 2026-06-28** -6. Retirer `SimpleMultiBlockPattern.test()` et `IrradiatedBiomes.monsters()`. +6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait** et retirer `IrradiatedBiomes.monsters()` (toujours à faire). **Corrections ciblées (risque faible à moyen)** 7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). diff --git a/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java b/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java index a460167b..0d8ef6aa 100644 --- a/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java +++ b/src/main/java/lib/multiblock/SimpleMultiBlockPattern.java @@ -68,8 +68,4 @@ public void construct(Level level, BlockPos blockPos, BiPredicate test() { - return this.multiBlockOffsetPosList; - } } From 562ce99dcdaf4509d557a7e244868905922e9bbf Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 17:14:50 +0200 Subject: [PATCH 122/171] refactor: classify fuel/cooler rods solely via RodType, not item tags TypeRodPredicate.IS_FUEL/IS_COOLED used to OR a hardcoded tag check (CNItemTags.FUEL/COOLER) with the data-driven RodType lookup, and several call sites repeated that same OR'd check manually (ReactorBluePrintMenu, ReactorRodInputInventory, DefaultHeatCalculator). Since RodType.resolveRodType(item, level) already resolves type correctly for any registered rod (datapack-driven, see ItemRodTypesValue), the tag check was redundant duplication of the same classification through a second mechanism. Replace the two static Predicate fields with isFuel(stack, level)/ isCooled(stack, level) methods that only consult RodType.resolveRodType(...), and thread a Level parameter through to every caller that needs it: IHeat.getFormattedItemText, IHeatCalculator.computeHeat/DefaultHeatCalculator/HeatManager, ReactorInputManager, ReactorRodInputInventory, CoolerDisplaySource/FuelDisplaySource/ReactorSummaryDisplaySource (via context.level()), and ReactorBluePrintMenu (via playerInventory.player.level()). Restore the FUEL item tag on CNItems' thorium rod registration, which had been dropped previously but is still meaningful as a recipe/tag-matching aid independent of this classification cleanup, and regenerate the corresponding fuel.json item tag datagen output. --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 4 ++-- .../data/createnuclear/tags/items/fuel.json | 3 ++- .../nuclearteam/createnuclear/CNItems.java | 10 +-------- .../api/multiblock/rods/RodType.java | 21 ++++++++----------- .../content/multiblock/IHeat.java | 9 ++++---- .../bluePrintItem/ReactorBluePrintMenu.java | 6 +++--- .../manager/ReactorInputManager.java | 8 +++---- .../input/item/ReactorRodInputInventory.java | 10 ++++----- .../reactorLogic/DefaultHeatCalculator.java | 13 ++++++------ .../multiblock/reactorLogic/HeatManager.java | 2 +- .../reactorLogic/IHeatCalculator.java | 3 ++- .../source/CoolerDisplaySource.java | 2 +- .../displayLink/source/FuelDisplaySource.java | 2 +- .../source/ReactorSummaryDisplaySource.java | 4 ++-- 14 files changed, 44 insertions(+), 53 deletions(-) diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 4beeb6b5..423cf4ff 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-27T22:58:21.7694379 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-06-28T17:14:06.741002 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -612,7 +612,7 @@ bfd5a561b60a7d59d7f7c248ec75e3571a0f2fed data/createnuclear/tags/fluids/uranium. bce34f53cb2d00f7dee84683e8fdd429dabbcc1d data/createnuclear/tags/items/anti_radiation_armor.json 2e4d08932c4a84863f0198eb2845f80d8fda1221 data/createnuclear/tags/items/cloth.json 8e6598f14a72a61cbe1e5ed2aaea229fb2dd74e6 data/createnuclear/tags/items/cooler.json -c5587bb72c54f59e9f9a4cd2c3e6bedb78ee198d data/createnuclear/tags/items/fuel.json +d534438c9314e8b014bf1796060dd801f4ef4d4e data/createnuclear/tags/items/fuel.json 1a438d724641b4899f18b4abeef0b0708c76ea70 data/createnuclear/tags/items/stone_types/autunite.json d8d6ad7a4fc31fd68a98b368207c359fb610f417 data/create/tags/blocks/safe_nbt.json 75f0600da4891d0f4a3329fb44cac6c4945a0b49 data/forge/tags/blocks/glass.json diff --git a/src/generated/resources/data/createnuclear/tags/items/fuel.json b/src/generated/resources/data/createnuclear/tags/items/fuel.json index 951757d9..9efea370 100644 --- a/src/generated/resources/data/createnuclear/tags/items/fuel.json +++ b/src/generated/resources/data/createnuclear/tags/items/fuel.json @@ -1,5 +1,6 @@ { "values": [ - "createnuclear:uranium_rod" + "createnuclear:uranium_rod", + "createnuclear:thorium_rod" ] } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 4dbc83f8..b271710c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -3,18 +3,11 @@ import com.tterrag.registrate.util.entry.ItemEntry; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.tterrag.registrate.providers.DataGenContext; -import com.tterrag.registrate.providers.RegistrateItemModelProvider; import com.tterrag.registrate.providers.RegistrateRecipeProvider; -import com.tterrag.registrate.util.nullness.NonNullBiConsumer; -import net.minecraftforge.client.model.generators.ItemModelBuilder; import net.minecraft.data.recipes.RecipeCategory; import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.Item; @@ -30,7 +23,6 @@ import net.nuclearteam.createnuclear.content.equipment.cloth.ClothItem.Cloths; import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintItem; import net.nuclearteam.createnuclear.foundation.utility.TextUtils; -import java.util.function.Supplier; import net.minecraft.world.item.Items; import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; @@ -225,7 +217,7 @@ public class CNItems { .dynamicRodTimer(() -> CNConfigs.server().rods.thoriumRodLifetime.get()) .dynamicHeatRatio(() -> CNConfigs.server().rods.thoriumHeatRatio.get()) .fuelRodType())) - .tag(CNTags.forgeItemTag("rods")) + .tag(CNTags.forgeItemTag("rods"), CNItemTags.FUEL.tag) .register() ; diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java index 1133180d..35eb11b5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java @@ -14,7 +14,6 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; @@ -301,20 +300,18 @@ public String getSerializedName() { public static final class TypeRodPredicate { public static final Predicate IS_NOT_NULL = Objects::nonNull; - public static final Predicate IS_FUEL = s -> { - TypeRod type = ItemRodTypesValue.getRodType(s.getItem()).type; - return IS_NOT_NULL.test(s) && (s.is(CNItemTags.FUEL.tag) || type == TypeRod.FUEL); - }; + public static boolean isFuel(ItemStack stack, Level level) { + return IS_NOT_NULL.test(stack) && RodType.resolveRodType(stack.getItem(), level).type == TypeRod.FUEL; + } - public static final Predicate IS_COOLED = s -> { - TypeRod type = ItemRodTypesValue.getRodType(s.getItem()).type; - return IS_NOT_NULL.test(s) && (s.is(CNItemTags.COOLER.tag) || type == TypeRod.COOLER); - }; + public static boolean isCooled(ItemStack stack, Level level) { + return IS_NOT_NULL.test(stack) && RodType.resolveRodType(stack.getItem(), level).type == TypeRod.COOLER; + } - public static String tooltipKey(ItemStack stack) { + public static String tooltipKey(ItemStack stack, Level level) { if (!IS_NOT_NULL.test(stack)) return "unknown"; - if (IS_FUEL.test(stack)) return "fuel"; - if (IS_COOLED.test(stack)) return "cooled"; + if (isFuel(stack, level)) return "fuel"; + if (isCooled(stack, level)) return "cooled"; return "unknown"; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java index 16b6435c..aa00b615 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java @@ -8,6 +8,7 @@ import net.createmod.catnip.lang.LangBuilder; import net.minecraft.ChatFormatting; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.nuclearteam.createnuclear.CNTags.CNItemTags; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; @@ -108,10 +109,10 @@ public static LangBuilder getFormattedHeatText(int heat, int reactorSize) { return builder; } - public static LangBuilder getFormattedItemText(ItemStack itemRod, Boolean isEmpty) { + public static LangBuilder getFormattedItemText(ItemStack itemRod, Boolean isEmpty, Level level) { LangBuilder builder = Lang.builder(CreateNuclear.MOD_ID); - String tooltip = TypeRodPredicate.tooltipKey(itemRod); + String tooltip = TypeRodPredicate.tooltipKey(itemRod, level); builder.translate("tooltip.item." + tooltip + ".rod") // when it's empty, we show the number minus one to display zero because we fake the item count as 1 @@ -122,8 +123,8 @@ public static LangBuilder getFormattedItemText(ItemStack itemRod, Boolean isEmpt return builder; } - public static LangBuilder getFormattedItemText(BigItemStack itemRod, Boolean isEmpty) { - return getFormattedItemText(new ItemStack(itemRod.stack.getItem(), itemRod.count), isEmpty); + public static LangBuilder getFormattedItemText(BigItemStack itemRod, Boolean isEmpty, Level level) { + return getFormattedItemText(new ItemStack(itemRod.stack.getItem(), itemRod.count), isEmpty, level); } public static LangBuilder getName(String name) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index 3b00a0e7..49da3884 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -127,10 +127,10 @@ protected void saveData(ItemStack contentHolder) { continue; } - RodType typeRod = ItemRodTypesValue.getRodType(stack.getItem()); + RodType typeRod = RodType.resolveRodType(stack.getItem(), playerInventory.player.level()); - boolean isFuel = stack.is(CNItemTags.FUEL.tag) || typeRod.type() == TypeRod.FUEL; - boolean isCooler = stack.is(CNItemTags.COOLER.tag) || typeRod.type() == TypeRod.COOLER; + boolean isFuel = typeRod.type() == TypeRod.FUEL; + boolean isCooler = typeRod.type() == TypeRod.COOLER; if (isCooler) { countCooledRod++; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java index 70677bc0..01a18c18 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorInputManager.java @@ -82,8 +82,8 @@ public VirtualReactorInputsItem getInventory(Level level) { for (int s = 0; s < slots; s++) { ItemStack st = h.getStackInSlot(s); - if (TypeRodPredicate.IS_FUEL.test(st)) totalFuel += st.getCount(); - else if (TypeRodPredicate.IS_COOLED.test(st)) totalCooler += st.getCount(); + if (TypeRodPredicate.isFuel(st, level)) totalFuel += st.getCount(); + else if (TypeRodPredicate.isCooled(st, level)) totalCooler += st.getCount(); } } @@ -106,11 +106,11 @@ public boolean extractItems(Level level, int fuelNeeded, int coolerNeeded) { if (stack.isEmpty()) continue; - if (fuelRemaining > 0 && TypeRodPredicate.IS_FUEL.test(stack)) { + if (fuelRemaining > 0 && TypeRodPredicate.isFuel(stack, level)) { int toExtract = Math.min(fuelRemaining, stack.getCount()); handler.extractItem(s, toExtract, false); fuelRemaining -= toExtract; - } else if (coolerRemaining > 0 && TypeRodPredicate.IS_COOLED.test(stack)) { + } else if (coolerRemaining > 0 && TypeRodPredicate.isCooled(stack, level)) { int toExtract = Math.min(coolerRemaining, stack.getCount()); handler.extractItem(s, toExtract, false); coolerRemaining -= toExtract; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java index 2edb0cad..ecc72da3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputInventory.java @@ -2,11 +2,9 @@ import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraftforge.items.ItemStackHandler; -import net.nuclearteam.createnuclear.CNTags; -import net.nuclearteam.createnuclear.api.ItemRodTypesValue; -import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; -import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRod; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; import org.jetbrains.annotations.NotNull; public class ReactorRodInputInventory extends ItemStackHandler { @@ -25,9 +23,9 @@ protected void onContentsChanged(int slot) { @Override public boolean isItemValid(int slot, @NotNull ItemStack stack) { - RodType rodType = ItemRodTypesValue.getRodType(stack.getItem()); + Level level = be.getLevel(); return switch (slot) { - case 0 -> CNTags.CNItemTags.FUEL.matches(stack) || rodType.type() == TypeRod.FUEL || CNTags.CNItemTags.COOLER.matches(stack) || rodType.type() == TypeRod.COOLER; + case 0 -> level != null && (TypeRodPredicate.isFuel(stack, level) || TypeRodPredicate.isCooled(stack, level)); default -> !super.isItemValid(slot, stack); }; } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index aaf4ba69..bd3ee4f3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -5,6 +5,7 @@ import net.minecraft.nbt.Tag; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; import net.nuclearteam.createnuclear.CNTags; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; @@ -32,7 +33,7 @@ public class DefaultHeatCalculator implements IHeatCalculator { private final int[][] offsets = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} }; @Override - public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat, ReactorDisplayState displayState) { + public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat, ReactorDisplayState displayState, Level level) { double heat = 0; ListTag list = inventory.getStackInSlot(0).getOrCreateTag().getCompound("pattern").getList("Items", Tag.TAG_COMPOUND); @@ -56,12 +57,12 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re for (Map.Entry entry : actualRods.entrySet()) { int slot = entry.getKey(); ItemStack currentStack = entry.getValue(); - RodType rod = ItemRodTypesValue.getRodType(currentStack.getItem()); + RodType rod = RodType.resolveRodType(currentStack.getItem(), level); String currentRod = ""; - if (currentStack.is(CNTags.CNItemTags.FUEL.tag) || (rod.items().size() > 0 && rod.type() == RodType.TypeRod.FUEL)) { + if (rod.items().size() > 0 && rod.type() == RodType.TypeRod.FUEL) { heat += rod.baseRodHeat(); currentRod = "fuel"; - } else if (currentStack.is(CNTags.CNItemTags.COOLER.tag) || (rod.items().size() > 0 && rod.type() == RodType.TypeRod.COOLER)) { + } else if (rod.items().size() > 0 && rod.type() == RodType.TypeRod.COOLER) { heat += rod.baseRodHeat(); currentRod = "cooler"; } @@ -82,9 +83,9 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re if ("fuel".equals(currentRod)) { ItemStack stack = actualRods.get(neighborSlot); RodType neighborRod = ItemRodTypesValue.getRodType(stack.getItem()); - if (stack.is(CNTags.CNItemTags.FUEL.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL)) { + if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL) { heat += rod.proximityRodHeat(); - } else if (stack.is(CNTags.CNItemTags.COOLER.tag) || (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER)) { + } else if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER) { heat += rod.baseRodHeat() / neighborRod.proximityRodHeat(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java index d47b1450..9ddccb58 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/HeatManager.java @@ -31,7 +31,7 @@ public double calculateHeat(BigFluidStack bigFluidStack, int totalHeatRatio, Rea ReactorFluidType type = bigFluidStack == null ? null : bigFluidStack.getFluidtype(level); overheatController.updateState(totalHeatRatio, bigFluidStack, type); - return calculator.computeHeat(bigFluidStack, type, inventory, overheatController.getOverHeat(), displayState); + return calculator.computeHeat(bigFluidStack, type, inventory, overheatController.getOverHeat(), displayState, level); } public int getLiquidTimer() { return overheatController.getLiquidTimer();} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java index ba200fe6..09dbba96 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/IHeatCalculator.java @@ -1,10 +1,11 @@ package net.nuclearteam.createnuclear.content.multiblock.reactorLogic; +import net.minecraft.world.level.Level; import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; public interface IHeatCalculator { - double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat, ReactorDisplayState displayState); + double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, ReactorControllerInventory inventory, double overHeat, ReactorDisplayState displayState, Level level); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java index 8c2844b6..687800b6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java @@ -32,7 +32,7 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget int cooler = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { for (Entry entry : controller.getDisplayState().items().entrySet()) { - if (TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { + if (TypeRodPredicate.isCooled(entry.getKey().getDefaultInstance(), context.level())) { cooler += entry.getValue(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java index 4a49ce45..76961ab7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java @@ -29,7 +29,7 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget int fuel = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { for (var entry : controller.getDisplayState().items().entrySet()) { - if (TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { + if (TypeRodPredicate.isFuel(entry.getKey().getDefaultInstance(), context.level())) { fuel += entry.getValue(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index 8cc4ca84..964c0284 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -123,9 +123,9 @@ private Stream> getComponents(DisplayLinkContext context, int cooler = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { for (var entry : controller.getDisplayState().items().entrySet()) { - if (TypeRodPredicate.IS_FUEL.test(entry.getKey().getDefaultInstance())) { + if (TypeRodPredicate.isFuel(entry.getKey().getDefaultInstance(), context.level())) { fuel += entry.getValue(); - } else if (TypeRodPredicate.IS_COOLED.test(entry.getKey().getDefaultInstance())) { + } else if (TypeRodPredicate.isCooled(entry.getKey().getDefaultInstance(), context.level())) { cooler += entry.getValue(); } } From 30de52a783ac5a20e441bfeb6d10708371579fde Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 17:21:14 +0200 Subject: [PATCH 123/171] fix: resolve rod type consistently in remaining call sites Two spots were missed in the previous fuel/cooler classification cleanup and still mixed the old tag-based check with ItemRodTypesValue.getRodType(...) instead of using RodType.resolveRodType(item, level): the second loop in ReactorBluePrintMenu (the one populating the ghost inventory preview) and the neighbor-rod lookup in DefaultHeatCalculator's proximity-heat loop. Both now resolve consistently through RodType.resolveRodType(...), matching the rest of the codebase after the earlier cleanup. --- .../multiblock/bluePrintItem/ReactorBluePrintMenu.java | 6 +++--- .../multiblock/reactorLogic/DefaultHeatCalculator.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index 49da3884..324cc8a2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -160,10 +160,10 @@ protected void saveData(ItemStack contentHolder) { continue; } - RodType typeRod = ItemRodTypesValue.getRodType(stack.getItem()); + RodType typeRod = RodType.resolveRodType(stack.getItem(), playerInventory.player.level()); - boolean isFuel = stack.is(CNItemTags.FUEL.tag) || typeRod.type() == TypeRod.FUEL; - boolean isCooler = stack.is(CNItemTags.COOLER.tag) || typeRod.type() == TypeRod.COOLER; + boolean isFuel = typeRod.type() == TypeRod.FUEL; + boolean isCooler = typeRod.type() == TypeRod.COOLER; if (!(isFuel || isCooler)) { ghostInventory.setStackInSlot(i, new ItemStack(Items.GLASS_PANE)); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index bd3ee4f3..35b743f8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -82,7 +82,7 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re if (actualRods.containsKey(neighborSlot)) { if ("fuel".equals(currentRod)) { ItemStack stack = actualRods.get(neighborSlot); - RodType neighborRod = ItemRodTypesValue.getRodType(stack.getItem()); + RodType neighborRod = RodType.resolveRodType(stack.getItem(), level); if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL) { heat += rod.proximityRodHeat(); } else if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER) { From f870362d04dd54a1396e34daad1e231c51c58566 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 28 Jun 2026 17:24:39 +0200 Subject: [PATCH 124/171] docs: mark fuel/cooler tag-desync item closed and renumber roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the consolidated audit to reflect three follow-up commits (2aaddb4d, 562ce99d, 30de52a7): the dead SimpleMultiBlockPattern.test() removal, and the two-part fuel/cooler classification migration (RodType.TypeRodPredicate.isFuel/isCooled now resolve purely via RodType.resolveRodType(stack, level), with Level threaded through IHeatCalculator/HeatManager/DefaultHeatCalculator) — close out the item previously assigned as a low-priority task, move it to the "fixed" section, and renumber the remaining roadmap items accordingly. Note that the migration's first commit missed two call sites (ReactorBluePrintMenu, DefaultHeatCalculator's neighbor lookup) later caught by manual review and fixed in the second commit, and use that as a concrete example for why test coverage on TypeRodPredicate would have caught the gap immediately. --- AUDIT_ACTUEL.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 4209c999..aa7709cb 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -1,6 +1,6 @@ # Audit consolidé — CreateNuclearForge (branche V2-CorrectifAudit) -**Dernière mise à jour : 2026-06-28.** Nouvel audit indépendant réalisé en repartant exclusivement du code actuel (`src/main/java`, **291 fichiers, ~25 070 lignes**, hors `src/generated` et `src/main/resources`). `AUDIT_V1.md` et l'historique de ce fichier (versions précédentes) n'ont servi qu'à comparer les résultats — chaque point a été **revérifié par lecture directe des fichiers cités** (et, pour les zones les plus actives, par `git show`/`git log` sur les commits du 2026-06-24 au 2026-06-28). +**Dernière mise à jour : 2026-06-28 (après commits `2aaddb4d`, `562ce99d`, `30de52a7`).** Nouvel audit indépendant réalisé en repartant exclusivement du code actuel (`src/main/java`, **291 fichiers, ~25 070 lignes**, hors `src/generated` et `src/main/resources`). `AUDIT_V1.md` et l'historique de ce fichier (versions précédentes) n'ont servi qu'à comparer les résultats — chaque point a été **revérifié par lecture directe des fichiers cités** (et, pour les zones les plus actives, par `git show`/`git log` sur les commits du 2026-06-24 au 2026-06-28). > Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §6 pour mémoire, puis ne sont plus repris. @@ -16,7 +16,9 @@ Aucun de ces changements ne casse les acquis des audits précédents : le point **Nouveauté la plus significative de cet audit** : en creusant le scan multiblock fusionné (déjà crédité « corrigé » au tour précédent), la boucle partagée `scanControllerCandidates` (`ReactorPattern.java:40-56`) ne court-circuite en réalité que via `findControllerPos` (utilisé par `MultiblockHelpers`, donc par `ReactorOutput`/`ReactorRodInput`/`ReactorFluidInput`/`ReactorAlarm`). La méthode `findController` — appelée **directement** par `ReactorCasing`, `ReactorCooler` et `ReactorFrame` — a un visiteur qui retourne toujours `false` et **ne s'arrête jamais avant d'avoir parcouru les ~3971 positions** de la zone de recherche, même après avoir trouvé et traité le contrôleur pertinent. Comme `ReactorCasing` constitue le gros de la coque d'un réacteur (le bloc le plus posé/cassé), c'est en réalité le chemin le plus coûteux des deux — voir §2 point 1. -La dette la plus structurelle reste **l'absence totale de tests** (`src/test` toujours vide, confirmé) — précisément là où des bugs silencieux (sur-extraction fluide, tautologie `IHeat`, scan non court-circuité) survivent à plusieurs passes d'audit. +**Depuis cette mise à jour**, trois commits supplémentaires : retrait de `SimpleMultiBlockPattern.test()` (`2aaddb4d`, quick win déjà acquis), puis l'exécution en deux temps du chantier « tags vs `RodType` » assigné à Gio — `562ce99d` migre l'essentiel (5 des 6 sites) et enfile enfin `Level` jusqu'à `DefaultHeatCalculator`, et `30de52a7` corrige les deux sites manqués par le premier commit (`ReactorBluePrintMenu`, lookup du voisin dans `DefaultHeatCalculator`). Le chantier est désormais **intégralement terminé et cohérent** (vérifié par grep : plus aucun site de classification ne lit `CNItemTags.FUEL`/`COOLER`, seules les déclarations de tag de craft dans `CNItems.java` subsistent) — voir §2 point 8, reclassé en §6. + +La dette la plus structurelle reste **l'absence totale de tests** (`src/test` toujours vide, confirmé) — précisément là où des bugs silencieux (sur-extraction fluide, tautologie `IHeat`, scan non court-circuité) survivent à plusieurs passes d'audit. Ce chantier de classification illustre d'ailleurs bien le risque : la première passe (`562ce99d`) a laissé passer deux sites incohérents, repérés seulement par relecture manuelle puis corrigés en quelques minutes (`30de52a7`) — un test unitaire sur `TypeRodPredicate.isFuel/isCooled` aurait détecté l'écart immédiatement. --- @@ -47,7 +49,7 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to 2. **`DefaultHeatCalculator.computeHeat` — partiellement amélioré, reste O(n×81) + asymétrie fuel/cooler** *(réévalué 2026-06-28, moins grave qu'estimé précédemment)* `DefaultHeatCalculator.java:35-97` a changé de forme depuis le dernier audit : les items du pattern sont désormais désérialisés **une seule fois** dans une `Map actualRods` (l.44-54), et la recherche du **voisin** se fait par lookup direct `actualRods.containsKey(neighborSlot)` (l.81) — **l'ancienne re-boucle O(n) sur tous les items à chaque voisin a disparu**, ce n'est donc plus un O(n²) sur les items. Reste cependant, pour chaque rod, une boucle complète sur la grille `formattedPattern` (9×9=81 cellules, l.70-73) pour retrouver sa propre position — non remplacée par une map slot→position précalculée (coût ~57×81 ≈ 4617 itérations/tick sur réacteur plein, contre le ~1 050 000 estimé par l'ancien audit, qui est donc à reclasser **🟡 mineur** plutôt que 🟠). - **Asymétrie toujours présente** (l.82) : l'examen des voisins ne se fait que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.88, **division**) côté fuel→cooler-voisin vs addition (l.86) côté fuel→fuel-voisin. **Ne pas toucher sans confirmation balance** (toujours valable). - - `IHeatCalculator.computeHeat` (`IHeatCalculator.java:9`) ne reçoit toujours **aucun `Level`** ; `HeatManager.calculateHeat` (`HeatManager.java:30`) en reçoit un mais ne le propage pas (`HeatManager.java:34`) — bloque toujours la migration `isFuel`/`isCooled` (voir point 8) sur ce fichier précis. + - ✅ **Corrigé le 2026-06-28** (`562ce99d`) — `IHeatCalculator.computeHeat` reçoit maintenant un `Level` (`IHeatCalculator.java:10`), propagé par `HeatManager.calculateHeat` (`HeatManager.java:34`) puis utilisé pour résoudre le rod courant **et**, depuis `30de52a7`, le rod voisin (`DefaultHeatCalculator.java:60` et `:85`) via `RodType.resolveRodType`. Plus aucun appel à l'ancienne `ItemRodTypesValue.getRodType` dans ce fichier. Voir §6 pour le détail du chantier. - *Recommandation* : précalculer une `Map` (ou inverser `formattedPattern` en `Map` statique au chargement de la classe) pour éliminer la boucle 81 cellules — gain mineur, risque nul, mais moins urgent qu'estimé avant. 3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** *(inchangé)* @@ -61,8 +63,7 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to 5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé)* 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. 7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. -8. **`CNItemTags.FUEL`/`COOLER` — double source de catégorisation avec `RodType.type()`, toujours désynchronisée** *(assigné Gio, priorité basse — inchangé, plan non encore exécuté)* — `RodType.java:301-320` (`TypeRodPredicate.IS_FUEL`/`IS_COOLED`) est **toujours** un `Predicate` basé sur `ItemRodTypesValue.getRodType` (sans `Level`), **pas migré** vers `isFuel(ItemStack, Level)`/`isCooled(ItemStack, Level)` basé sur `RodType.resolveRodType`. Tous les sites listés au tour précédent (`ReactorRodInputInventory.isItemValid`, `ReactorBluePrintMenu.saveData` ×2, `*DisplaySource`, `ReactorInputManager`, `DefaultHeatCalculator`) testent toujours le double critère `stack.is(TAG) || rod.type() == X`. **`THORIUM_ROD`** (`CNItems.java:220-228`) a toujours `RodType.fuelRodType()` enregistré mais **pas** le tag `CNItemTags.FUEL` (seul `CNTags.forgeItemTag("rods")`, l.228) — preuve de désync inchangée. Plan déjà documenté au tour précédent, toujours valide, **non commencé**. -9. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`. +8. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`. --- @@ -136,6 +137,8 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Corrigé le 2026-06-28** : garde `level.isClientSide` manquante sur la chaîne multiblock et double scan `playerDestroy`/`onRemove` (§2.1). Fix appliqué de façon centralisée plutôt que classe par classe : (1) `if (level.isClientSide) return;` ajouté en tête de `ReactorAssembler.assemble`/`disassemble` — point de convergence unique de toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler` ; (2) l'override `playerDestroy` a été supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput` et `ReactorFluidInput`, généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel de retrait, dans `onRemove`, qui se déclenche systématiquement y compris lors d'une casse joueur). Vérifié par lecture directe des 7 fichiers modifiés. Seul le court-circuit manquant de `findController` (perf pure) reste ouvert — voir §2.1 et §7. +**Corrigé le 2026-06-28** (`562ce99d` + `30de52a7`) : désynchronisation `CNItemTags.FUEL`/`COOLER` vs `RodType.type()` (ex-§2 point 8, assigné Gio). `RodType.TypeRodPredicate.IS_FUEL`/`IS_COOLED` (anciens `Predicate` basés sur `ItemRodTypesValue.getRodType`, sans `Level`) ont été remplacés par `isFuel(ItemStack, Level)`/`isCooled(ItemStack, Level)` basés uniquement sur `RodType.resolveRodType` (`RodType.java:303-309`). `Level` a été enfilé jusqu'à `IHeatCalculator.computeHeat`/`HeatManager.calculateHeat`/`DefaultHeatCalculator.computeHeat`. Premier commit (`562ce99d`) avait migré 5 des 6 sites mais laissé deux endroits sur l'ancien critère mixte `stack.is(TAG) || rod.type() == X` (`ReactorBluePrintMenu.java:165-166`) ou l'ancienne API sans `Level` (`DefaultHeatCalculator.java:85`, lookup du voisin) ; second commit (`30de52a7`) les a corrigés. Vérifié par grep sur tout `src/main/java` : plus aucun site de classification ne lit `CNItemTags.FUEL`/`COOLER` ou n'appelle `ItemRodTypesValue.getRodType` en dehors de l'implémentation interne de `RodType.resolveRodType` lui-même. Le tag `CNItemTags.FUEL` reste posé sur `THORIUM_ROD` (`CNItems.java:220`) à titre de tag de craft/recette, explicitement découplé de la classification — cohérent, pas un résidu de désync. + **Confirmé neutre** : le commit `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) ne fusionne rien dans le code de jeu — nettoyage cosmétique d'une scène Ponder uniquement. --- @@ -148,25 +151,22 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). 4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. 5. ~~`git rm --cached` sur les 6 fichiers de debug `run/` (§4).~~ ✅ **fait le 2026-06-28** -6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait** et retirer `IrradiatedBiomes.monsters()` (toujours à faire). +6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait le 2026-06-28** (commit `2aaddb4d`) et retirer `IrradiatedBiomes.monsters()` (toujours à faire). **Corrections ciblées (risque faible à moyen)** 7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). 8. `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle 81 cellules (gain mineur désormais, priorité baissée par rapport au tour précédent) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance. -9. Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques (§2.9). - -**Assigné Gio (priorité basse, à faire quand le temps le permet)** -10. Tags `CNItemTags.FUEL`/`COOLER` → créer `TypeRodPredicate.isFuel/isCooled(stack, level)` basés sur `RodType.resolveRodType`, migrer `ReactorRodInputInventory`, `ReactorBluePrintMenu`, les `*DisplaySource`, `ReactorInputManager` ; restreindre les tags au craft (§2.8). Le site `DefaultHeatCalculator` nécessite d'abord d'ajouter `Level` à `IHeatCalculator.computeHeat` — toujours en suspens, non commencé. +9. Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques (§2.8). **Décisions produit (choisir puis exécuter)** -11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). -12. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). +10. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). +11. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). **Chantier de fond (le plus rentable à long terme)** -13. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. +12. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. **À surveiller sans action immédiate** -14. `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (recalcul à chaque tick) — compromis assumé par le commit `9ded502c`, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. +13. `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (recalcul à chaque tick) — compromis assumé par le commit `9ded502c`, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. **Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** - Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos, croissance maîtrisée). @@ -175,3 +175,4 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B - Coordinateur dédié au verrouillage fluide (non justifié). - Spam de log `ReactorAssembler` (corrigé le 2026-06-26). - Anti-pattern try/catch `NuclearExplosionEntity` / B15 (corrigé). +- Tags `CNItemTags.FUEL`/`COOLER` désynchronisés de `RodType.type()` (assigné Gio, **terminé le 2026-06-28** via `562ce99d` + `30de52a7` — voir §6). From d87b0b088f813bce062b37fd5f0c441636267089 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 3 Jul 2026 20:00:50 +0200 Subject: [PATCH 125/171] chore: clean up unused imports and reorder entity registrations Remove unused imports (FriendlyByteBuf, CNItemTags, ItemRodTypesValue, CNConfigs, BigItemStack, CNTags, CreateNuclear) left over from previous refactors. Move NUCLEAR_EXPLOSION entity registration after IRRADIATED_COW to reflect logical grouping order. --- .../createnuclear/CNEntityType.java | 45 +++++++++---------- .../createnuclear/CNParticleTypes.java | 1 - .../bluePrintItem/ReactorBluePrintMenu.java | 3 -- .../reactorLogic/DefaultHeatCalculator.java | 4 -- 4 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java b/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java index 3eb556e1..524702ce 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java @@ -25,23 +25,6 @@ public class CNEntityType { - public static final EntityEntry NUCLEAR_EXPLOSION = - CreateNuclear.REGISTRATE - .entity( - "nuclear_explosion", - NuclearExplosionEntity::new, - MobCategory.MISC - ) - .properties(builder -> builder - .sized(0.2F, 0.2F) - .setTrackingRange(128) - .setUpdateInterval(1) - .setShouldReceiveVelocityUpdates(true) - ) - // Utilise le renderer vide par défaut de Minecraft - .renderer(() -> NoopRenderer::new) - .register(); - public static final EntityEntry IRRADIATED_CAT = CreateNuclear.REGISTRATE .entity("irradiated_cat", IrradiatedCat::new, MobCategory.CREATURE) .loot((tb, e) -> tb.add(e, LootTable.lootTable())) @@ -72,14 +55,26 @@ public class CNEntityType { .attributes(IrradiatedWolf::createAttributes) .register(); - public static final EntityEntry IRRADIATED_COW = CreateNuclear.REGISTRATE - .entity("irradiated_cow", IrradiatedCow::new, MobCategory.CREATURE) - .loot((tb, e) -> tb.add(e, LootTable.lootTable())) - .tag(CNEntityTags.IRRADIATED_IMMUNE.tag) - .properties(p -> p.sized(0.6f, 0.85f)) - .lang("Irradiated Cow") - .renderer(() -> IrradiatedCowRenderer::new) - .attributes(IrradiatedCow::createAttributes) + public static final EntityEntry IRRADIATED_COW = CreateNuclear.REGISTRATE + .entity("irradiated_cow", IrradiatedCow::new, MobCategory.CREATURE) + .loot((tb, e) -> tb.add(e, LootTable.lootTable())) + .tag(CNEntityTags.IRRADIATED_IMMUNE.tag) + .properties(p -> p.sized(0.6f, 0.85f)) + .lang("Irradiated Cow") + .renderer(() -> IrradiatedCowRenderer::new) + .attributes(IrradiatedCow::createAttributes) + .register(); + + public static final EntityEntry NUCLEAR_EXPLOSION = + CreateNuclear.REGISTRATE.entity("nuclear_explosion", NuclearExplosionEntity::new, MobCategory.MISC) + .properties(builder -> builder + .sized(0.2F, 0.2F) + .setTrackingRange(128) + .setUpdateInterval(1) + .setShouldReceiveVelocityUpdates(true) + ) + // Utilise le renderer vide par défaut de Minecraft + .renderer(() -> NoopRenderer::new) .register(); public static void registerModelLayer(EntityRenderersEvent.RegisterLayerDefinitions event) { diff --git a/src/main/java/net/nuclearteam/createnuclear/CNParticleTypes.java b/src/main/java/net/nuclearteam/createnuclear/CNParticleTypes.java index 344a565d..6a6be860 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNParticleTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNParticleTypes.java @@ -2,7 +2,6 @@ import com.simibubi.create.foundation.particle.ICustomParticleData; import net.createmod.catnip.lang.Lang; -import net.minecraft.network.FriendlyByteBuf; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.RegisterParticleProvidersEvent; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index 324cc8a2..bf1e84ee 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -14,11 +14,8 @@ import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.SlotItemHandler; import net.nuclearteam.createnuclear.CNMenus; -import net.nuclearteam.createnuclear.CNTags.CNItemTags; -import net.nuclearteam.createnuclear.api.ItemRodTypesValue; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRod; -import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import static net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintItem.getItemStorage; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index 35b743f8..c1a5beb3 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -1,14 +1,10 @@ package net.nuclearteam.createnuclear.content.multiblock.reactorLogic; -import com.simibubi.create.content.logistics.BigItemStack; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Item; import net.minecraft.world.level.Level; -import net.nuclearteam.createnuclear.CNTags; -import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.api.ItemRodTypesValue; import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; From f24904698a376ebdab0d68909918bf136d11aa4e Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 3 Jul 2026 20:36:09 +0200 Subject: [PATCH 126/171] fix: rename and clean up PlayerInteractReactorFluidInput dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename PlayerInteracteReactorFluidInput → PlayerInteractReactorFluidInput (remove stray 'e' from "Interacte"). Remove dead code in interact(): - ITEM_TO_TANK creative block (lines 56-61): unused variable fluidInItem and a reference to the non-existent ReactorLiquidInput class - TANK_TO_ITEM empty creative block (lines 69-71) - Redundant instanceof ReactorFluidInputEntity check (line 88): be is already cast and null-checked earlier, the guard was always true Update AUDIT_ACTUEL.md to reflect the rename and expand the dead code analysis with line-level detail and corrected line numbers for ReactorOutput.SPEED. --- AUDIT_ACTUEL.md | 12 +++- ...a => PlayerInteractReactorFluidInput.java} | 55 +++++++------------ .../input/fluid/ReactorFluidInput.java | 4 +- 3 files changed, 31 insertions(+), 40 deletions(-) rename src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/{PlayerInteracteReactorFluidInput.java => PlayerInteractReactorFluidInput.java} (70%) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index aa7709cb..fee7e460 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -92,8 +92,14 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to - **`IrradiatedBiomes.monsters()`** — corps toujours vide (`IrradiatedBiomes.java:17-18`), appelé avec des arguments (95, 5, 100) silencieusement ignorés (l.55). À retirer ou implémenter. **Code commencé puis abandonné (hygiène de fin de PR)** -- `content/multiblock/input/fluid/PlayerInteracteReactorFluidInput.java:57-61` — bloc d'interaction fluide toujours commenté/inachevé (non touché par le récent nettoyage de `ReactorOutput`). -- `content/multiblock/output/ReactorOutput.java:43,52,93` — propriété `SPEED` toujours entièrement commentée (pas supprimée). +- `content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java:57-61` *(fichier renommé — suppression du 'e' parasite dans "Interacte")* — quatre problèmes distincts, tous du dead code : + 1. **L.57** : `FluidStack fluidInItem = GenericItemEmptying.emptyItem(level, stack, true).getFirst()` — variable calculée uniquement pour les lignes commentées en-dessous ; jamais utilisée ailleurs. L'appel simule (`true`) donc pas de mutation, mais le calcul est inutile. + 2. **L.58-60** : bloc commenté qui référence `ReactorLiquidInput` — classe **inexistante** dans le projet (renommée en `ReactorFluidInputEntity`), avec une invocation tronquée `fluidInInput.set` jamais complétée. Code définitivement abandonné, non récupérable tel quel. + 3. **L.69-71** : bloc `if (player.isCreative() && !onClient) { }` entièrement vide sous `TANK_TO_ITEM` — dead code pur. + 4. **L.88** : `if (be instanceof ReactorFluidInputEntity)` — `be` est déjà casté en `ReactorFluidInputEntity` à la ligne 31 et null-checké à la ligne 32 ; ce `instanceof` est **toujours vrai**, branche morte. À simplifier en retirant la condition. + - Note de contexte : `ReactorFluidInput.use()` interdit déjà toute interaction non-creative avant d'appeler `interact()` → les gardes `player.isCreative()` à l'intérieur de `interact()` sont redondantes (toujours vraies). + - **Action** : supprimer les lignes 56-61 (bloc créatif ITEM_TO_TANK entier), supprimer les lignes 69-71 (bloc créatif TANK_TO_ITEM vide), simplifier la condition l.88. +- `content/multiblock/output/ReactorOutput.java:43,52,87` — propriété `SPEED` toujours entièrement commentée (pas supprimée). *(Numéros de lignes mis à jour : l.93 → l.87 après décalage.)* - `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. ~~**Reliquats Git (`run/`)** — confirmé via `git ls-files run/` : il reste **6 fichiers de debug/env trackés** malgré `.gitignore` : @@ -160,7 +166,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Décisions produit (choisir puis exécuter)** 10. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). -11. `PlayerInteracteReactorFluidInput` / `ReactorOutput.SPEED` : terminer ou retirer le code commenté (§4). +11. `PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK (l.56-61 : variable morte + référence à `ReactorLiquidInput` inexistant), le bloc créatif TANK_TO_ITEM (l.69-71 : vide), et simplifier l.88 (`instanceof` toujours vrai). `ReactorOutput.SPEED` : retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). **Chantier de fond (le plus rentable à long terme)** 12. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/PlayerInteracteReactorFluidInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java similarity index 70% rename from src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/PlayerInteracteReactorFluidInput.java rename to src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java index 1887c5e0..bcc02e74 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/PlayerInteracteReactorFluidInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java @@ -25,7 +25,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; -public class PlayerInteracteReactorFluidInput { +public class PlayerInteractReactorFluidInput { public static InteractionResult interact(Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, boolean onClient, BlockHitResult ray) { FluidExchange exchange = null; ReactorFluidInputEntity be = (ReactorFluidInputEntity) level.getBlockEntity(pos); @@ -53,23 +53,12 @@ public static InteractionResult interact(Level level, BlockPos pos, Player playe .orElse(FluidStack.EMPTY); if (exchange == FluidExchange.ITEM_TO_TANK) { - if (player.isCreative() && !onClient) { - FluidStack fluidInItem = GenericItemEmptying.emptyItem(level, stack, true).getFirst(); -// if (!fluidInItem.isEmpty() && fluidInInput instanceof ReactorLiquidInput) { -// fluidInInput.set -// } - } - Fluid fluid = fluidInInput.getFluid(); fluidState = fluid.defaultFluidState().createLegacyBlock(); soundEvent = FluidHelper.getEmptySound(fluidInInput); } if (exchange == FluidExchange.TANK_TO_ITEM) { - if ( player.isCreative() && !onClient) { - - } - Fluid fluid = prevFluidInInput.getFluid(); fluidState = fluid.defaultFluidState().createLegacyBlock(); soundEvent = FluidHelper.getFillSound(prevFluidInInput); @@ -85,28 +74,26 @@ public static InteractionResult interact(Level level, BlockPos pos, Player playe } if (!fluidInInput.isFluidStackIdentical(prevFluidInInput)) { - if (be instanceof ReactorFluidInputEntity) { - if (fluidState != null && onClient) { - BlockParticleOption blockParticleData = - new BlockParticleOption(ParticleTypes.BLOCK, fluidState); - float flevel = (float) fluidInInput.getAmount() / fluidInput.getTankCapacity(0); - - boolean reversed = fluidInInput.getFluid() - .getFluidType() - .isLighterThanAir(); - if (reversed) - flevel = 1 - flevel; - - Vec3 vec = ray.getLocation(); - vec = new Vec3(vec.x, be.getBlockPos() - .getY() + flevel * (1 - .5f) + .25f, vec.z); - Vec3 motion = player.position() - .subtract(vec) - .scale(1 / 20f); - vec = vec.add(motion); - level.addParticle(blockParticleData, vec.x, vec.y, vec.z, motion.x, motion.y, motion.z); - return InteractionResult.SUCCESS; - } + if (fluidState != null && onClient) { + BlockParticleOption blockParticleData = + new BlockParticleOption(ParticleTypes.BLOCK, fluidState); + float flevel = (float) fluidInInput.getAmount() / fluidInput.getTankCapacity(0); + + boolean reversed = fluidInInput.getFluid() + .getFluidType() + .isLighterThanAir(); + if (reversed) + flevel = 1 - flevel; + + Vec3 vec = ray.getLocation(); + vec = new Vec3(vec.x, be.getBlockPos() + .getY() + flevel * (1 - .5f) + .25f, vec.z); + Vec3 motion = player.position() + .subtract(vec) + .scale(1 / 20f); + vec = vec.add(motion); + level.addParticle(blockParticleData, vec.x, vec.y, vec.z, motion.x, motion.y, motion.z); + return InteractionResult.SUCCESS; } } return InteractionResult.SUCCESS; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java index 67f47120..6c406f76 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInput.java @@ -13,7 +13,6 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; @@ -25,7 +24,6 @@ import net.nuclearteam.createnuclear.CNShapes; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; -import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import net.nuclearteam.createnuclear.foundation.block.MultiDirectionalReactorBlock; import org.jetbrains.annotations.NotNull; @@ -87,7 +85,7 @@ public InteractionResult use(BlockState state, Level world, BlockPos pos, Player if (!player.isCreative()) return InteractionResult.PASS; - return PlayerInteracteReactorFluidInput.interact(world, pos, player, hand, heldItem, onClient, ray); + return PlayerInteractReactorFluidInput.interact(world, pos, player, hand, heldItem, onClient, ray); } @Override From ab29fee386eb2f60e55254e27bf704a1b6519ff7 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 3 Jul 2026 21:10:26 +0200 Subject: [PATCH 127/171] feat: add shaft placement helper to ReactorOutput block Implement IPlacementHelper on ReactorOutput so that right-clicking the block while holding a shaft item automatically places the shaft in the facing direction. Also annotate the class with @MethodsReturnNonnullByDefault and clean up unused imports (Vec3i, BlockEntity, ReactorPattern, etc.). --- .../multiblock/output/ReactorOutput.java | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java index 339c2bae..4ce2da50 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java @@ -1,24 +1,29 @@ package net.nuclearteam.createnuclear.content.multiblock.output; +import com.simibubi.create.AllBlocks; import com.simibubi.create.content.equipment.wrench.IWrenchable; import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; import com.simibubi.create.foundation.block.IBE; +import net.createmod.catnip.placement.IPlacementHelper; +import net.createmod.catnip.placement.PlacementHelpers; +import net.createmod.catnip.placement.PlacementOffset; +import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; -import net.minecraft.core.Vec3i; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; @@ -29,20 +34,19 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.nuclearteam.createnuclear.*; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; -import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; -import net.nuclearteam.createnuclear.content.multiblock.pattern.ReactorPattern; -import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancementBehaviour; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.function.Predicate; +@MethodsReturnNonnullByDefault public class ReactorOutput extends DirectionalKineticBlock implements IWrenchable, IBE { - //public static final IntegerProperty SPEED = IntegerProperty.create("speed", 0, 256); public static final IntegerProperty DIR = IntegerProperty.create("dir", 0, 2); + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + + public ReactorOutput(Properties properties) { super(properties); } @@ -87,6 +91,20 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { return defaultBlockState().setValue(FACING, preferred)/*.setValue(SPEED, 0)*/.setValue(DIR, 0); } + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) { + ItemStack heldItem = player.getItemInHand(hand); + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (!player.isShiftKeyDown() && player.mayBuild()) { + if (placementHelper.matchesItem(heldItem) && placementHelper.getOffset(player, level, state, pos, hitResult) + .placeInWorld(level, (BlockItem) heldItem.getItem(), player, hand, hitResult) + .consumesAction()) + return InteractionResult.SUCCESS; + } + + return super.use(state, level, pos, player, hand, hitResult); + } + // IRotate: @Override @@ -119,4 +137,28 @@ public Class getBlockEntityClass() { public BlockEntityType getBlockEntityType() { return CNBlockEntityTypes.REACTOR_OUTPUT.get(); } + + private static class PlacementHelper implements IPlacementHelper { + + @Override + public Predicate getItemPredicate() { + return AllBlocks.SHAFT::isIn; + } + + @Override + public Predicate getStatePredicate() { + return s -> s.getBlock() instanceof ReactorOutput; + } + + @Override + public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, BlockHitResult ray) { + Direction facing = state.getValue(FACING); + BlockPos target = pos.relative(facing); + + if (!world.getBlockState(target).canBeReplaced()) + return PlacementOffset.fail(); + + return PlacementOffset.success(target, s -> s.setValue(BlockStateProperties.AXIS, facing.getAxis())); + } + } } \ No newline at end of file From e51a72b94293bb66ab5aa9060f71ebed617d7f3b Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 5 Jul 2026 12:28:31 +0200 Subject: [PATCH 128/171] refactor: replace direct RADIATION effect with dose-based contagion in RadiationCapability - Add contagionDose/contagionTicks fields to IRadiationCapability and RadiationCapability, with a new applyContagion(entity, dose, ticks) helper and per-tick decay in tickRadiation() - Update all radiation sources (uranium fluid, enriching campfire, fan enriching processing, RadiationEffect vicinity contamination, pipe leak handler) to call RadiationCapability.applyContagion() instead of directly adding a MobEffectInstance(CNEffects.RADIATION) - Make VicinityEffect abstract with a new onContaminate(LivingEntity) hook, removing the Supplier[] varargs mechanism so subclasses control how contamination is actually applied - Remove now-unused imports (TickEvent, AntiRadiationArmorItem static import, MobEffectInstance) across affected files --- .../nuclearteam/createnuclear/CNFluids.java | 5 ++- .../content/effects/VicinityEffect.java | 19 ++++---- .../campfire/EnrichingCampfireBlock.java | 9 ++-- .../fan/processing/CNFanProcessingTypes.java | 5 ++- .../content/radiation/RadiationEffect.java | 12 +++-- .../radiation/RadiationEffectHandler.java | 8 ++-- .../capability/IRadiationCapability.java | 6 +++ .../capability/RadiationCapability.java | 44 +++++++++++++++---- 8 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java index aadf5b41..a7550e98 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java @@ -32,6 +32,7 @@ import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fluids.ForgeFlowingFluid; import net.nuclearteam.createnuclear.content.decoration.palettes.CNPaletteStoneTypes; +import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import net.nuclearteam.createnuclear.foundation.advancement.CNAdvancement; import net.nuclearteam.createnuclear.content.radiation.RadiationBucketItem; @@ -42,6 +43,8 @@ import java.util.function.Supplier; public class CNFluids { + private static final double URANIUM_FLUID_DOSE = 5.0D; + public static final FluidEntry URANIUM = CreateNuclear.REGISTRATE.standardFluid("uranium", SolidRenderedPlaceableFluidtype.create(0x38FF08, () -> 1f / 32f)) .lang("Liquid Uranium") @@ -127,7 +130,7 @@ public static void handleFluidEffect(LivingEvent.LivingTickEvent event) { // 1. EFFET DE L'URANIUM (Radiation) if (entity.isInFluidType(URANIUM.getType())) { if (entity.tickCount % 20 == 0) { - entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 100, 0)); + RadiationCapability.applyContagion(entity, URANIUM_FLUID_DOSE, 100); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java index 1ec4cac0..00de7508 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java @@ -12,21 +12,18 @@ import java.util.UUID; import java.util.function.*; -public class VicinityEffect extends MobEffect { +public abstract class VicinityEffect extends MobEffect { private final UnaryOperator areaSize; private final Predicate filter; - private final Supplier[] effects; // Stores the GameTime tick when the cooldown expires for each entity private final Map cooldowns = new HashMap<>(); - @SafeVarargs - protected VicinityEffect(MobEffectCategory category, int color, UnaryOperator areaSize, Predicate filter, Consumer timer, Supplier... effects) { + protected VicinityEffect(MobEffectCategory category, int color, UnaryOperator areaSize, Predicate filter, Consumer timer) { super(category, color); this.areaSize = areaSize; this.filter = filter; - this.effects = effects; } @Override @@ -45,10 +42,7 @@ public void applyEffectTick(LivingEntity entity, int amplifier) { // Check if the cooldown has expired if (currentTime >= cooldowns.getOrDefault(entityUuid, 0L)) { - - for (Supplier effect : effects) { - nearby.addEffect(effect.get()); - } + onContaminate(nearby); // Set a 100-tick (5 seconds) cooldown before refreshing the effect again cooldowns.put(entityUuid, currentTime + 100); @@ -56,6 +50,13 @@ public void applyEffectTick(LivingEntity entity, int amplifier) { } } + /** + * Called for each eligible nearby entity once its cooldown expires. Chaque sous-classe + * décide comment elle transmet réellement l'effet (ex: RadiationEffect alimente la dose + * de RadiationCapability plutôt que d'ajouter un MobEffect directement). + */ + protected abstract void onContaminate(LivingEntity nearby); + @Override public boolean isDurationEffectTick(int duration, int amplifier) { return duration % 5 == 0; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/enriching/campfire/EnrichingCampfireBlock.java b/src/main/java/net/nuclearteam/createnuclear/content/enriching/campfire/EnrichingCampfireBlock.java index 1b210938..a6499335 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/enriching/campfire/EnrichingCampfireBlock.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/enriching/campfire/EnrichingCampfireBlock.java @@ -10,7 +10,6 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -37,7 +36,7 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.nuclearteam.createnuclear.CNBlockEntityTypes; -import net.nuclearteam.createnuclear.CNEffects; +import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import org.jetbrains.annotations.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -46,6 +45,8 @@ @ParametersAreNonnullByDefault @SuppressWarnings({"deprecation", "unused"}) public class EnrichingCampfireBlock extends BaseEntityBlock implements SimpleWaterloggedBlock, IBE { + private static final double CAMPFIRE_DOSE = 5.0D; + protected static final VoxelShape SHAPE = Block.box(0.0, 0.0, 0.0, 16.0, 7.0, 16.0); public static final BooleanProperty LIT = BlockStateProperties.LIT; public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; @@ -65,8 +66,8 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player @Override public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { - if (state.getValue(LIT) && entity instanceof LivingEntity && !EnchantmentHelper.hasFrostWalker((LivingEntity)entity)) { - ((LivingEntity) entity).addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 100, 0)); + if (state.getValue(LIT) && entity instanceof LivingEntity livingEntity && !EnchantmentHelper.hasFrostWalker(livingEntity)) { + RadiationCapability.applyContagion(livingEntity, CAMPFIRE_DOSE, 100); } super.entityInside(state, level, pos, entity); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java b/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java index 702b68fc..9ed4d2e7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/kinetics/fan/processing/CNFanProcessingTypes.java @@ -22,6 +22,7 @@ import net.nuclearteam.createnuclear.content.enriching.campfire.EnrichingCampfireBlock; import net.nuclearteam.createnuclear.content.kinetics.fan.processing.EnrichedRecipe.EnrichedWrapper; import net.nuclearteam.createnuclear.content.kinetics.fan.processing.SnowPowderRecipe.SnowPowderWrapper; +import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import net.nuclearteam.createnuclear.foundation.damageTypes.CNDamageSources; import javax.annotation.Nullable; @@ -64,6 +65,8 @@ public static FanProcessingType parseLegacy(String str) { } public static class EnrichedType implements FanProcessingType { + private static final double FAN_ENRICHING_DOSE = 5.0D; + private static final EnrichedWrapper ENRICHED_WRAPPER = new EnrichedWrapper(); @Override @@ -118,7 +121,7 @@ public void morphAirFlow(AirFlowParticleAccess particleAccess, RandomSource rand @Override public void affectEntity(Entity entity, Level level) { if (entity instanceof LivingEntity livingEntity) { - livingEntity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 10, -1, true, true)); + RadiationCapability.applyContagion(livingEntity, FAN_ENRICHING_DOSE, 10); livingEntity.hurt(CNDamageSources.fanRadiation(level), 1); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java index af366613..56e318da 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffect.java @@ -1,7 +1,6 @@ package net.nuclearteam.createnuclear.content.radiation; import net.minecraft.world.effect.MobEffectCategory; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.nuclearteam.createnuclear.CNEffects; @@ -12,6 +11,7 @@ import net.nuclearteam.createnuclear.foundation.damageTypes.CNDamageSources; public class RadiationEffect extends VicinityEffect { + private static final int CONTAGION_DURATION_TICKS = 300; /** * Constructs the RadiationEffect with harmful category and color. @@ -20,9 +20,8 @@ public class RadiationEffect extends VicinityEffect { public RadiationEffect() { super(MobEffectCategory.HARMFUL, 15453236, amplifier -> 10, - e -> RadiationCapability.canBeIrradiated(e) && !e.hasEffect(CNEffects.RADIATION.get()), - timer -> {}, - () -> new MobEffectInstance(CNEffects.RADIATION.get(), 300)); // Custom color (hex value) + RadiationCapability::canBeIrradiated, + timer -> {}); // Custom color (hex value) // Reduces movement speed by 20% this.addAttributeModifier(Attributes.MOVEMENT_SPEED, @@ -50,6 +49,11 @@ public boolean isDurationEffectTick(int duration, int amplifier) { return true; } + @Override + protected void onContaminate(LivingEntity nearby) { + RadiationCapability.applyContagion(nearby, 15D, CONTAGION_DURATION_TICKS); + } + @Override public void applyEffectTick(LivingEntity entity, int amplifier) { super.applyEffectTick(entity, amplifier); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java index 53a72c3d..8a32a83f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/RadiationEffectHandler.java @@ -1,17 +1,17 @@ package net.nuclearteam.createnuclear.content.radiation; import com.simibubi.create.api.effect.OpenPipeEffectHandler; -import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; import net.minecraftforge.fluids.FluidStack; -import net.nuclearteam.createnuclear.CNEffects; import net.nuclearteam.createnuclear.content.radiation.capability.RadiationCapability; import java.util.List; public class RadiationEffectHandler implements OpenPipeEffectHandler { + private static final double PIPE_LEAK_DOSE = 40.0D; + @Override public void apply(Level level, AABB area, FluidStack fluid) { if (level.getGameTime() % 5 != 0) return; @@ -19,7 +19,7 @@ public void apply(Level level, AABB area, FluidStack fluid) { List entities = level.getEntitiesOfClass(LivingEntity.class, area, LivingEntity::isAffectedByPotions); for (LivingEntity entity : entities) { if (!RadiationCapability.canBeIrradiated(entity)) continue; - entity.addEffect(new MobEffectInstance(CNEffects.RADIATION.get(), 3, 2, false, false, false)); + RadiationCapability.applyContagion(entity, PIPE_LEAK_DOSE, 20); } } -} +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java index bd51ca2b..3b1f550d 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/IRadiationCapability.java @@ -11,4 +11,10 @@ public interface IRadiationCapability { ResourceLocation getLastBiomeLocation(); void setLastBiomeLocation(ResourceLocation location); + + double getContagionDose(); + void setContagionDose(double dose); + + int getContagionTicks(); + void setContagionTicks(int ticks); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java index bd2f2795..d57e3cc5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java @@ -15,8 +15,6 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.event.TickEvent.PlayerTickEvent; import net.minecraftforge.event.entity.living.LivingEvent.LivingTickEvent; import net.nuclearteam.createnuclear.CNAttributes; import net.nuclearteam.createnuclear.CNEffects; @@ -24,13 +22,10 @@ import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.api.radiation.IRadiationSource; import net.nuclearteam.createnuclear.api.radiation.RadiationRegistry; -import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; import net.nuclearteam.createnuclear.foundation.utility.ConfigValueResolver; import net.nuclearteam.createnuclear.foundation.utility.InventoryHashUtil; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; -import static net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem.RADIATION_VALUE; - import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -40,6 +35,8 @@ public class RadiationCapability implements IRadiationCapability { private double radiation; private long inventoryHash; private ResourceLocation lastBiomeLocation; + private double contagionDose; + private int contagionTicks; @Override public double getRadiation() { @@ -71,6 +68,26 @@ public void setLastBiomeLocation(ResourceLocation location) { this.lastBiomeLocation = location; } + @Override + public double getContagionDose() { + return this.contagionDose; + } + + @Override + public void setContagionDose(double dose) { + this.contagionDose = dose; + } + + @Override + public int getContagionTicks() { + return this.contagionTicks; + } + + @Override + public void setContagionTicks(int ticks) { + this.contagionTicks = ticks; + } + public static void attach(AttachCapabilitiesEvent event) { if (event.getObject() instanceof LivingEntity) { event.addCapability(CreateNuclear.asResource("irradiated_resistance"), new RadiationProvider()); @@ -81,11 +98,17 @@ public static void onLivingEntityTick(LivingTickEvent event) { tickRadiation(event.getEntity()); } + public static void applyContagion(LivingEntity entity, double doseValue, int durationTicks) { + entity.getCapability(RadiationProvider.CAP).ifPresent(cap -> { + cap.setContagionDose(doseValue); + cap.setContagionTicks(durationTicks); + }); + } + public static void tickRadiation(LivingEntity entity) { Level level = entity.level(); if (level.isClientSide) return; - entity.getCapability(RadiationProvider.CAP).ifPresent(cap -> { if (entity instanceof Player player) { long newHash = InventoryHashUtil.compute(player); @@ -97,7 +120,6 @@ public static void tickRadiation(LivingEntity entity) { cap.setRadiation(Math.max(0, computeItemRadiation(entity))); } - ResourceKey biomeKey = level.getBiome(entity.blockPosition()).unwrapKey().orElse(null); ResourceLocation biomeLoc = biomeKey != null ? biomeKey.location() : null; if (!Objects.equals(biomeLoc, cap.getLastBiomeLocation())) { @@ -106,7 +128,13 @@ public static void tickRadiation(LivingEntity entity) { if (!canBeIrradiated(entity)) return; - double totalRaw = cap.getRadiation() + getRawBiomeRadiation(biomeKey); + if (cap.getContagionTicks() > 0) { + cap.setContagionTicks(cap.getContagionTicks() - 1); + } + + double contagionDose = cap.getContagionTicks() > 0 ? cap.getContagionDose() : 0; + + double totalRaw = cap.getRadiation() + getRawBiomeRadiation(biomeKey) + contagionDose; double resistance = getRadiationResistance(entity); double totalRadiation = totalRaw * (1.0 - resistance); From fb0897d3bfa3ee65f37a4e29b37a2ac98f73fb26 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 5 Jul 2026 14:16:14 +0200 Subject: [PATCH 129/171] fix: correct isNotDanger logic and throttle output RPM updates IHeat.HeatLevel.isNotDanger() previously used a tautological OR condition (x != DANGER || x != NONE) that always returned true regardless of the heat level, masking the danger gate entirely. Replace it with a simple inequality (x != DANGER) so the method actually reflects whether the reactor is safe. ReactorControllerBlockEntity now caches the last heat value applied to outputs in lastAppliedOutputHeat and only triggers rotateOutputs() when the heat has changed by at least RPM_DIVIDER / 2, preventing unnecessary shaft network updates every tick when heat is stable. RPM_DIVIDER is promoted from private to public in ReactorOutputManager so the threshold expression in the controller can reference the canonical constant rather than a magic number. --- .../nuclearteam/createnuclear/content/multiblock/IHeat.java | 2 +- .../multiblock/controller/ReactorControllerBlockEntity.java | 4 ++++ .../multiblock/controller/manager/ReactorOutputManager.java | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java index aa00b615..c0c39327 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/IHeat.java @@ -87,7 +87,7 @@ public static HeatLevel of(int heat, int reactorSize) { } public static boolean isNotDanger(int heat, int reactorSize) { - return of(heat, reactorSize) != DANGER || of(heat, reactorSize) != NONE; + return of(heat, reactorSize) != DANGER; } public static LangBuilder getFormattedHeatText(int heat, int reactorSize) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index 924e39f4..e4710391 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -59,6 +59,7 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity private int countCoolerRod; private int totalHeatRatio; private int heat; + private int lastAppliedOutputHeat; private boolean isExploding = false; /** Client-only looping "running" sound instance; never accessed server-side. */ @@ -426,6 +427,9 @@ private void handleAssembledState() { cycleManager.update(configuredPattern, level, inputManager, level.getGameTime() % 20 == 0); if (IHeat.HeatLevel.isNotDanger(heat, getMultiblockSize()) && !outputManager.getBlocksPosition(level).isEmpty()) { + if (Math.abs(heat - lastAppliedOutputHeat) >= ReactorOutputManager.RPM_DIVIDER / 2) { + lastAppliedOutputHeat = heat; + } outputManager.rotateOutputs(getLevel(), getAssembled(), heat); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java index 6972e562..cb6616a5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorOutputManager.java @@ -17,7 +17,7 @@ */ public class ReactorOutputManager extends AbstractReactorIOManager implements ReactorOutputManagerI { private static final String NBT_KEY = "ReactorOutputs"; - private static final int RPM_DIVIDER = 32; + public static final int RPM_DIVIDER = 32; @Override public void write(CompoundTag compound) { From a18038db20d388d233cbd779c4d5d2c528e3e344 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 5 Jul 2026 14:21:04 +0200 Subject: [PATCH 130/171] fix: pass hysteresis-buffered heat to rotateOutputs and document output flicker root cause MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ReactorControllerBlockEntity was computing lastAppliedOutputHeat correctly but still forwarding the raw heat value to rotateOutputs(), making the throttle field entirely inert. Switch the call to pass lastAppliedOutputHeat so the shaft network only sees heat changes that exceed RPM_DIVIDER / 2, suppressing the per-tick RPM flicker caused by the overHeat oscillator straddling a multiple of 32. The audit is updated to reflect both this session's fixes: - isNotDanger tautology (IHeat.java:89) marked closed; behavioral note added (outputs now stop in DANGER — a real balance change to validate in-game) - New open item #10: overHeat self-oscillation (+1 / -2 each tick regardless of fuel stock) combined with integer division by RPM_DIVIDER can still cause output speed flicker when base heat sits near a multiple of 32; hystereris threshold itself still needs in-game validation - Roadmap items renumbered accordingly (10→11 … 13→14) --- AUDIT_ACTUEL.md | 15 +++++++++------ .../controller/ReactorControllerBlockEntity.java | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index fee7e460..f13c90ec 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -26,8 +26,8 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to | Réf. | Fichier:ligne | Gravité | Détail (vérifié 2026-06-28) | |---|---|---|---| -| **isNotDanger tautologie** | `content/multiblock/IHeat.java:88-90` | 🟠 | `return of(heat,size) != DANGER \|\| of(heat,size) != NONE;` — toujours `true`. Appelant unique confirmé `ReactorControllerBlockEntity.java:428` (la classe a grossi, la ligne a bougé). La garde « ne pas faire tourner les sorties en `DANGER` » reste **inopérante** : les sorties tournent même en surchauffe. Correctif d'1 ligne (`!= DANGER` seul), à confirmer côté balance. | | **ReactorInputFluidManager — sur-extraction** | `controller/manager/ReactorInputFluidManager.java:137-155` | 🟠 | `fluidNeeded` (paramètre de `extractFluids`) n'est **toujours jamais décrémenté** entre handlers (l.146-151) → chaque handler de la boucle tente d'extraire le besoin complet, sur-extraction possible avec plusieurs inputs. `if (toExtract > 1)` (l.147) ignore toujours les extractions de 1 unité. Toléré aujourd'hui (tank mono-slot), reste une violation de contrat latente. | +| **Flicker vitesse de sortie en fin de ressources (`overHeat` + division entière)** *(nouveau, trouvé 2026-07-05)* | `content/multiblock/reactorLogic/DefaultOverheatController.java:13-30` + `controller/manager/ReactorOutputManager.java:90` | 🟡 | `overHeat` s'incrémente de `+1` (fluide insuffisant) et se décrémente de `-2` (fluide suffisant) à un rythme régulier — un oscillateur auto-entretenu, **indépendant de tout réapprovisionnement**. Ce `overHeat` est additionné au heat des barres (`DefaultHeatCalculator.java:93`) puis divisé en entier par `RPM_DIVIDER=32` (`ReactorOutputManager.java:90`) pour obtenir le RPM des sorties. En fin de ressources, le heat de base est faible et peut se trouver juste à cheval sur un multiple de 32 : le va-et-vient de `overHeat` fait alors basculer la vitesse de sortie entre `0` et `X` en boucle, sans lien avec le stock de combustible. Hystérésis sur le heat appliqué à `rotateOutputs` dans `ReactorControllerBlockEntity.handleAssembledState` (nouveau champ `lastAppliedOutputHeat`, ne réactualiser que si `\|heat - lastAppliedOutputHeat\| >= RPM_DIVIDER/2`). Pas besoin de persister ce champ en NBT (comme `heat`/`totalHeatRatio`, recalculé chaque tick). | --- @@ -141,6 +141,8 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Corrigé le 2026-06-28** : `InventoryHashUtil.stackHash` n'inclut plus `getDamageValue()` (`InventoryHashUtil.java:90-91` retiré). Vérifié : aucune implémentation de `IRadiationSource`/`RadiationRegistry` (`UraniumOreItem`, `RadiationItem`, `RadiationBucketItem`, `RadiationEffect`) ne lit la durabilité, donc l'inclure dans le hash ne faisait que déclencher `RadiationCapability.computeItemRadiation` (`RadiationCapability.java:91-95`) sans raison à chaque variation de durabilité (minage, combat) — précisément sur les hot paths que le cache devait protéger. Pour mémoire, le terme « resync » des audits précédents désignait ce recalcul serveur, pas un trafic réseau (`RadiationProvider` ne fait que sérialiser en NBT, aucun `RadiationSyncPacket` impliqué). +**Corrigé le 2026-07-05** : `IHeat.HeatLevel.isNotDanger` (ex-§1, `IHeat.java:89-91`) — la tautologie `of(heat,size) != DANGER || of(heat,size) != NONE` (toujours `true`) a été remplacée par `of(heat,size) != DANGER`. La garde « ne pas faire tourner les sorties en `DANGER` » (appelant unique `ReactorControllerBlockEntity.java:428`) est désormais réellement opérante : les sorties s'arrêtent en surchauffe. ⚠️ **Changement de comportement de balance réel** (avant : les sorties tournaient toujours ; maintenant : elles s'arrêtent en `DANGER`) — à valider en jeu, un joueur peut désormais se retrouver sans écoulement de sortie tant que le réacteur reste en surchauffe. + **Corrigé le 2026-06-28** : garde `level.isClientSide` manquante sur la chaîne multiblock et double scan `playerDestroy`/`onRemove` (§2.1). Fix appliqué de façon centralisée plutôt que classe par classe : (1) `if (level.isClientSide) return;` ajouté en tête de `ReactorAssembler.assemble`/`disassemble` — point de convergence unique de toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler` ; (2) l'override `playerDestroy` a été supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput` et `ReactorFluidInput`, généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel de retrait, dans `onRemove`, qui se déclenche systématiquement y compris lors d'une casse joueur). Vérifié par lecture directe des 7 fichiers modifiés. Seul le court-circuit manquant de `findController` (perf pure) reste ouvert — voir §2.1 et §7. **Corrigé le 2026-06-28** (`562ce99d` + `30de52a7`) : désynchronisation `CNItemTags.FUEL`/`COOLER` vs `RodType.type()` (ex-§2 point 8, assigné Gio). `RodType.TypeRodPredicate.IS_FUEL`/`IS_COOLED` (anciens `Predicate` basés sur `ItemRodTypesValue.getRodType`, sans `Level`) ont été remplacés par `isFuel(ItemStack, Level)`/`isCooled(ItemStack, Level)` basés uniquement sur `RodType.resolveRodType` (`RodType.java:303-309`). `Level` a été enfilé jusqu'à `IHeatCalculator.computeHeat`/`HeatManager.calculateHeat`/`DefaultHeatCalculator.computeHeat`. Premier commit (`562ce99d`) avait migré 5 des 6 sites mais laissé deux endroits sur l'ancien critère mixte `stack.is(TAG) || rod.type() == X` (`ReactorBluePrintMenu.java:165-166`) ou l'ancienne API sans `Level` (`DefaultHeatCalculator.java:85`, lookup du voisin) ; second commit (`30de52a7`) les a corrigés. Vérifié par grep sur tout `src/main/java` : plus aucun site de classification ne lit `CNItemTags.FUEL`/`COOLER` ou n'appelle `ItemRodTypesValue.getRodType` en dehors de l'implémentation interne de `RodType.resolveRodType` lui-même. Le tag `CNItemTags.FUEL` reste posé sur `THORIUM_ROD` (`CNItems.java:220`) à titre de tag de craft/recette, explicitement découplé de la classification — cohérent, pas un résidu de désync. @@ -155,7 +157,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 1. **`ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur** (l.69), pour court-circuiter comme `findControllerPos` le fait déjà. **← dernier point ouvert de ce chantier, le plus rentable : c'est le chemin appelé par le bloc le plus posé/cassé (Casing).** 2. ~~Garde `level.isClientSide()` en tête de `findController`/`findControllerPos`/`ReactorAssembler.assemble/disassemble`.~~ ✅ **fait le 2026-06-28** (garde centralisée dans `ReactorAssembler.assemble`/`disassemble`). 3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). -4. `IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance. +4. ~~`IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance.~~ ✅ **fait le 2026-07-05** — voir §6 pour le changement de comportement associé à valider en jeu. 5. ~~`git rm --cached` sur les 6 fichiers de debug `run/` (§4).~~ ✅ **fait le 2026-06-28** 6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait le 2026-06-28** (commit `2aaddb4d`) et retirer `IrradiatedBiomes.monsters()` (toujours à faire). @@ -163,16 +165,17 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). 8. `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle 81 cellules (gain mineur désormais, priorité baissée par rapport au tour précédent) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance. 9. Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques (§2.8). +10. Flicker vitesse de sortie en fin de ressources (oscillateur `overHeat` × division entière `RPM_DIVIDER`) : ajouter une hystérésis sur le heat appliqué à `rotateOutputs`, seuil à valider (§1). **Décisions produit (choisir puis exécuter)** -10. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). -11. `PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK (l.56-61 : variable morte + référence à `ReactorLiquidInput` inexistant), le bloc créatif TANK_TO_ITEM (l.69-71 : vide), et simplifier l.88 (`instanceof` toujours vrai). `ReactorOutput.SPEED` : retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). +11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). +12. `PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK (l.56-61 : variable morte + référence à `ReactorLiquidInput` inexistant), le bloc créatif TANK_TO_ITEM (l.69-71 : vide), et simplifier l.88 (`instanceof` toujours vrai). `ReactorOutput.SPEED` : retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). **Chantier de fond (le plus rentable à long terme)** -12. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. +13. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. **À surveiller sans action immédiate** -13. `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (recalcul à chaque tick) — compromis assumé par le commit `9ded502c`, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. +14. `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (recalcul à chaque tick) — compromis assumé par le commit `9ded502c`, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. **Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** - Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos, croissance maîtrisée). diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java index e4710391..b0a26eb8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/ReactorControllerBlockEntity.java @@ -430,7 +430,7 @@ private void handleAssembledState() { if (Math.abs(heat - lastAppliedOutputHeat) >= ReactorOutputManager.RPM_DIVIDER / 2) { lastAppliedOutputHeat = heat; } - outputManager.rotateOutputs(getLevel(), getAssembled(), heat); + outputManager.rotateOutputs(getLevel(), getAssembled(), lastAppliedOutputHeat); } } From d6be5b84b03bd1749cc882143f940bdad8a98daf Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 19:24:55 +0200 Subject: [PATCH 131/171] refactor: collapse RodType static/dynamic dual-path into unified Supplier fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RodType previously stored every heat/timing value twice — once as a static primitive (baseRodHeatStatic, proximityRodHeatStatic, …) and once as an optional Supplier — and exposed wrapper accessors that picked between them at call time. The Builder mirrored this split with separate dynamic*() methods and boolean "set" flags. Replace the dual representation with a single Supplier per field in the record. Builder.baseRodHeat(int), proximityRodHeat(float), rodTimer(int), and heatRatio(int) now wrap their argument in a constant supplier; the corresponding Supplier overloads store directly. The dynamic* prefixed builder methods are removed — callers use the same names regardless of whether the value is static or config-backed. Consequences: - RodType record shrinks from 9 components to 5; the four *Static components and their accessor shim methods are gone. - Builder removes 4 boolean flags and merges 8 setter methods into 4 overloaded pairs; heatRatio defaults to () -> 1 and type defaults to TypeRod.NONE so neither needs to be set explicitly. - The CODEC serializes by calling .get() on each supplier; deserializing wraps the decoded primitives back in constant suppliers via the compact constructor. - Every call site (ReactorBluePrintMenu, ItemConsumable, ReactorHeatUpdateCoordinator, DefaultHeatCalculator, RodsStats) updated to call .get() on the accessor result. - CNItems rod registrations updated from dynamicBaseRodHeat/… to baseRodHeat/… (supplier overloads). --- .../nuclearteam/createnuclear/CNItems.java | 24 +- .../api/multiblock/rods/RodType.java | 228 ++++++++++-------- .../bluePrintItem/ReactorBluePrintMenu.java | 6 +- .../controller/consumable/ItemConsumable.java | 2 +- .../service/ReactorHeatUpdateCoordinator.java | 2 +- .../reactorLogic/DefaultHeatCalculator.java | 8 +- .../foundation/item/RodsStats.java | 8 +- 7 files changed, 155 insertions(+), 123 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index b271710c..992f06c1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -122,10 +122,10 @@ public class CNItems { GRAPHITE_ROD = CreateNuclear.REGISTRATE .item("graphite_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueGraphite.get()) - .dynamicProximityRodHeat(() -> CNConfigs.server().rods.graphiteProxyMalus.getF()) - .dynamicRodTimer(() -> CNConfigs.server().rods.graphiteRodLifetime.get()) - .dynamicHeatRatio(() -> CNConfigs.server().rods.graphiteHeatRatio.get()) + .baseRodHeat(() -> CNConfigs.server().rods.baseValueGraphite.get()) + .proximityRodHeat(() -> CNConfigs.server().rods.graphiteProxyMalus.getF()) + .rodTimer(() -> CNConfigs.server().rods.graphiteRodLifetime.get()) + .heatRatio(() -> CNConfigs.server().rods.graphiteHeatRatio.get()) .coolerRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.COOLER.tag) .register(), @@ -165,10 +165,10 @@ public class CNItems { URANIUM_ROD = CreateNuclear.REGISTRATE .item("uranium_rod", p -> new RadiationItem(p, 100)) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueUranium.get()) - .dynamicProximityRodHeat(() ->(float) CNConfigs.server().rods.uraniumProxyBonus.get()) - .dynamicRodTimer(() -> CNConfigs.server().rods.uraniumRodLifetime.get()) - .dynamicHeatRatio(() -> CNConfigs.server().rods.uraniumHeatRatio.get()) + .baseRodHeat(() -> CNConfigs.server().rods.baseValueUranium.get()) + .proximityRodHeat(() ->(float) CNConfigs.server().rods.uraniumProxyBonus.get()) + .rodTimer(() -> CNConfigs.server().rods.uraniumRodLifetime.get()) + .heatRatio(() -> CNConfigs.server().rods.uraniumHeatRatio.get()) .fuelRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.FUEL.tag) .register(), @@ -212,10 +212,10 @@ public class CNItems { THORIUM_ROD = CreateNuclear.REGISTRATE .item("thorium_rod", Item::new) .onRegister(ItemRodTypesValue.setRodTypeInfos(new RodType.Builder() - .dynamicBaseRodHeat(() -> CNConfigs.server().rods.baseValueThorium.get()) - .dynamicProximityRodHeat(() -> (float) CNConfigs.server().rods.thoriumProxyBonus.get()) - .dynamicRodTimer(() -> CNConfigs.server().rods.thoriumRodLifetime.get()) - .dynamicHeatRatio(() -> CNConfigs.server().rods.thoriumHeatRatio.get()) + .baseRodHeat(() -> CNConfigs.server().rods.baseValueThorium.get()) + .proximityRodHeat(() -> (float) CNConfigs.server().rods.thoriumProxyBonus.get()) + .rodTimer(() -> CNConfigs.server().rods.thoriumRodLifetime.get()) + .heatRatio(() -> CNConfigs.server().rods.thoriumHeatRatio.get()) .fuelRodType())) .tag(CNTags.forgeItemTag("rods"), CNItemTags.FUEL.tag) .register() diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java index 35eb11b5..5f430709 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java @@ -33,13 +33,11 @@ */ @MethodsReturnNonnullByDefault public record RodType(HolderSet items, - int baseRodHeatStatic, float proximityRodHeatStatic, - int rodTimerStatic, TypeRod type, - Supplier baseRodHeatSupplier, - Supplier proximityRodHeatSupplier, - Supplier rodTimerSupplier, - int heatRatioStatic, - Supplier heatRatioSupplier) { + Supplier baseRodHeat, + Supplier proximityRodHeat, + Supplier rodTimer, + Supplier heatRatio, + TypeRod type) { public RodType(HolderSet items, int baseRodHeat, float proximityRodHeat, @@ -50,20 +48,20 @@ public RodType(HolderSet items, public RodType(HolderSet items, int baseRodHeat, float proximityRodHeat, int rodTimer, TypeRod type, int heatRatio) { - this(items, baseRodHeat, proximityRodHeat, rodTimer, type, null, null, null, heatRatio, null); + this(items, () -> baseRodHeat, () -> proximityRodHeat, () -> rodTimer, () -> heatRatio, type); } /** * Serialization codec for saving/loading {@link RodType} instances. */ public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - RegistryCodecs.homogeneousList(Registries.ITEM).fieldOf("items").forGetter(RodType::items), - Codec.INT.fieldOf("baseRodHeat").forGetter(RodType::baseRodHeatStatic), - Codec.FLOAT.fieldOf("proximityRodHeat").forGetter(RodType::proximityRodHeatStatic), - Codec.INT.fieldOf("rodTimer").forGetter(RodType::rodTimerStatic), - StringRepresentable.fromEnum(TypeRod::values).fieldOf("type").forGetter(RodType::type), - Codec.INT.optionalFieldOf("heatRatio", 1).forGetter(RodType::heatRatioStatic) - ).apply(i, (items, baseHeat, proxHeat, timer, type, heatRatio) -> new RodType(items, baseHeat, proxHeat, timer, type, null, null, null, heatRatio, null))); + RegistryCodecs.homogeneousList(Registries.ITEM).fieldOf("items").forGetter(RodType::items), + Codec.INT.fieldOf("baseRodHeat").forGetter(rt -> rt.baseRodHeat().get()), + Codec.FLOAT.fieldOf("proximityRodHeat").forGetter(rt -> rt.proximityRodHeat().get()), + Codec.INT.fieldOf("rodTimer").forGetter(rt -> rt.rodTimer().get()), + StringRepresentable.fromEnum(TypeRod::values).fieldOf("type").forGetter(RodType::type), + Codec.INT.optionalFieldOf("heatRatio", 1).forGetter(rt -> rt.heatRatio().get()) + ).apply(i, RodType::new)); /** * Searches the {@code ROD_TYPE} registry for a {@link RodType} matching the @@ -116,88 +114,137 @@ public boolean isNotEmptyItem() { /** * Fluent builder for creating an immutable {@link RodType} instance. *

- * Use the configuration methods and call {@link #build()} to obtain the - * resulting instance. + * Every heat/timing value ({@code baseRodHeat}, {@code proximityRodHeat}, + * {@code rodTimer}, {@code heatRatio}) can be set either as a fixed + * primitive (evaluated once, at build time) or as a {@link Supplier} + * (re-evaluated on every call to the corresponding {@link RodType} + * accessor). The primitive overloads are pure convenience: they simply + * wrap the given value in a constant supplier, e.g. + * {@code baseRodHeat(5)} is equivalent to {@code baseRodHeat(() -> 5)}. + * Use the {@link Supplier} overloads to back a value with a live source + * such as a config option (see {@code CNItems} for examples), so that + * changes are picked up without rebuilding the {@code RodType}. + *

+ * {@code items}, {@code type}, {@code baseRodHeat}, {@code proximityRodHeat} + * and {@code rodTimer} are required; {@code heatRatio} defaults to a + * constant {@code 1} and never needs to be set explicitly. Call + * {@link #build()} once all required values are configured. */ public static class Builder { private final List> items = new ArrayList<>(); - private int baseRodHeat = 0; - private float proximityRodHeat = 0; - private int rodTimer = 0; - private int heatRatio = 1; - private TypeRod type = TypeRod.FUEL; - - private Supplier baseRodHeatSupplier = null; - private Supplier proximityRodHeatSupplier = null; - private Supplier rodTimerSupplier = null; - private Supplier heatRatioSupplier = null; - - private boolean itemsSet = false; - private boolean baseRodHeatSet = false; - private boolean proximityRodHeatSet = false; - private boolean rodTimerSet = false; - private boolean heatRatioSet = false; - private boolean typeSet = false; + private Supplier baseRodHeat = null; + private Supplier proximityRodHeat = null; + private Supplier rodTimer = null; + private Supplier heatRatio = () -> 1; + private TypeRod type = TypeRod.NONE; /** - * Sets the base heat for the rod. + * Sets a fixed base heat value, evaluated once at build time. + * Equivalent to {@code baseRodHeat(() -> baseRodHeat)}. * - * @param baseRodHeat base heat value + * @param baseRodHeat constant base heat value * @return this builder */ public Builder baseRodHeat(int baseRodHeat) { + return baseRodHeat(() -> baseRodHeat); + } + + /** + * Sets a dynamic base heat value, re-evaluated every time + * {@link RodType#baseRodHeat()} is called (e.g. to reflect a live + * config option instead of a value frozen at registration time). + * + * @param baseRodHeat supplier producing the base heat value on demand + * @return this builder + */ + public Builder baseRodHeat(Supplier baseRodHeat) { this.baseRodHeat = baseRodHeat; - this.baseRodHeatSet = true; return this; } /** - * Sets the heat contributed by nearby rods. + * Sets a fixed proximity heat value (heat contributed by nearby rods), + * evaluated once at build time. + * Equivalent to {@code proximityRodHeat(() -> proximityRodHeat)}. * - * @param proximityRodHeat proximity heat value + * @param proximityRodHeat constant proximity heat value * @return this builder */ public Builder proximityRodHeat(float proximityRodHeat) { - this.proximityRodHeat = proximityRodHeat; - this.proximityRodHeatSet = true; - return this; + return proximityRodHeat(() -> proximityRodHeat) ; } /** - * Sets the timer (duration) for the rod's behavior. + * Sets a dynamic proximity heat value, re-evaluated every time + * {@link RodType#proximityRodHeat()} is called. * - * @param rodTimer duration in ticks or mod-specific units + * @param proximityRodHeat supplier producing the proximity heat value on demand * @return this builder */ - public Builder rodTimer(int rodTimer) { - this.rodTimer = rodTimer; - this.rodTimerSet = true; + public Builder proximityRodHeat(Supplier proximityRodHeat) { + this.proximityRodHeat = proximityRodHeat; return this; } - public Builder heatRatio(int heatRatio) { - this.heatRatio = heatRatio; - this.heatRatioSet = true; - return this; + /** + * Sets a fixed timer (duration) for the rod's behavior, evaluated + * once at build time. Equivalent to {@code rodTimer(() -> rodTimer)}. + * + * @param rodTimer constant duration in ticks or mod-specific units + * @return this builder + */ + public Builder rodTimer(int rodTimer) { + return rodTimer(() -> rodTimer); } - public Builder dynamicBaseRodHeat(Supplier supplier) { - this.baseRodHeatSupplier = supplier; + /** + * Sets a dynamic timer (duration) for the rod's behavior, + * re-evaluated every time {@link RodType#rodTimer()} is called. + * + * @param rodTimer supplier producing the duration on demand + * @return this builder + */ + public Builder rodTimer(Supplier rodTimer) { + this.rodTimer = rodTimer; return this; } - public Builder dynamicProximityRodHeat(Supplier supplier) { - this.proximityRodHeatSupplier = supplier; - return this; + /** + * Sets a fixed heat ratio, evaluated once at build time. Optional: + * defaults to a constant {@code 1} if never called. + * Equivalent to {@code heatRatio(() -> heatRatio)}. + * + * @param heatRatio constant heat ratio value + * @return this builder + */ + public Builder heatRatio(int heatRatio) { + return heatRatio(() -> heatRatio); } - public Builder dynamicRodTimer(Supplier supplier) { - this.rodTimerSupplier = supplier; + /** + * Sets a dynamic heat ratio, re-evaluated every time + * {@link RodType#heatRatio()} is called. Optional: defaults to a + * constant {@code 1} if never called. + * + * @param heatRatio supplier producing the heat ratio on demand + * @return this builder + */ + public Builder heatRatio(Supplier heatRatio) { + this.heatRatio = heatRatio; return this; } - public Builder dynamicHeatRatio(Supplier supplier) { - this.heatRatioSupplier = supplier; + /** + * Sets the rod category directly. Prefer the {@link #coolerRodType()} + * and {@link #fuelRodType()} convenience methods for the common + * cases; use this overload only to set {@link TypeRod#NONE} + * explicitly (e.g. for a fallback/sentinel rod type). + * + * @param type the rod category to assign + * @return this builder + */ + public Builder type(TypeRod type) { + this.type = type; return this; } @@ -207,9 +254,7 @@ public Builder dynamicHeatRatio(Supplier supplier) { * @return this builder */ public Builder coolerRodType() { - this.type = TypeRod.COOLER; - this.typeSet = true; - return this; + return type(TypeRod.COOLER); } /** @@ -218,13 +263,13 @@ public Builder coolerRodType() { * @return this builder */ public Builder fuelRodType() { - this.type = TypeRod.FUEL; - this.typeSet = true; - return this; + return type(TypeRod.FUEL); } /** - * Adds one or more items that represent this rod type. + * Adds one or more items that represent this rod type. Can be called + * multiple times; items accumulate rather than replace one another. + * At least one item must be added before {@link #build()}. * * @param items array of {@link ItemLike} elements to associate * @return this builder @@ -232,50 +277,37 @@ public Builder fuelRodType() { public Builder addItems(ItemLike... items) { for (ItemLike provider : items) this.items.add(provider.asItem().builtInRegistryHolder()); - if (items.length > 0) this.itemsSet = true; return this; } /** * Builds the immutable {@link RodType} instance. + *

+ * Validates that {@code items} is non-empty and that {@code type}, + * {@code baseRodHeat}, {@code proximityRodHeat} and {@code rodTimer} + * have all been set (either as a fixed value or as a dynamic + * {@link Supplier}); {@code heatRatio} is exempt since it defaults + * to a constant {@code 1}. * - * @throws IllegalStateException if required fields are missing + * @throws IllegalStateException if one or more required fields are missing, + * naming every missing field in the exception message * @return the created instance */ public RodType build() { List missing = new ArrayList<>(); - if (!itemsSet || items.isEmpty()) missing.add("items"); - if (!typeSet) missing.add("type"); - - if (baseRodHeatSupplier == null && !baseRodHeatSet) missing.add("baseRodHeat"); - if (proximityRodHeatSupplier == null && !proximityRodHeatSet) missing.add("proximityRodHeat"); - if (rodTimerSupplier == null && !rodTimerSet) missing.add("rodTimer"); - if (heatRatioSupplier == null && !heatRatioSet) missing.add("heatRatio"); + if (items.isEmpty()) missing.add("items"); + if (type == null) missing.add("type"); + if (baseRodHeat == null) missing.add("baseRodHeat"); + if (proximityRodHeat == null) missing.add("proximityRodHeat"); + if (rodTimer == null) missing.add("rodTimer"); if (!missing.isEmpty()) throw new IllegalStateException("Missing required RodType fields: " + String.join(", ", missing)); - return new RodType(HolderSet.direct(items), baseRodHeat, proximityRodHeat, rodTimer, type, baseRodHeatSupplier, proximityRodHeatSupplier, rodTimerSupplier, heatRatio, heatRatioSupplier); + return new RodType(HolderSet.direct(items), baseRodHeat, proximityRodHeat, rodTimer, heatRatio, type); } } - public int baseRodHeat() { - return baseRodHeatSupplier != null ? baseRodHeatSupplier.get() : baseRodHeatStatic; - } - - public float proximityRodHeat() { - return proximityRodHeatSupplier != null ? proximityRodHeatSupplier.get() : proximityRodHeatStatic; - } - - public int rodTimer() { - return rodTimerSupplier != null ? rodTimerSupplier.get() : rodTimerStatic; - } - - public int heatRatio() { - return heatRatioSupplier != null ? heatRatioSupplier.get() : heatRatioStatic; - } - - public enum TypeRod implements StringRepresentable { /** * Fuel rod: generates heat via reaction. @@ -319,10 +351,10 @@ public static String tooltipKey(ItemStack stack, Level level) { @Override public String toString() { return "RodType [items: " + this.items() + - ", baseRodHeat: " + this.baseRodHeat() + - ", proximityRodHeat: " + this.proximityRodHeat() + - ", rodTimer: " + this.rodTimer() + - ", heatRatio: " + this.heatRatio() + + ", baseRodHeat: " + this.baseRodHeat().get() + + ", proximityRodHeat: " + this.proximityRodHeat().get() + + ", rodTimer: " + this.rodTimer().get() + + ", heatRatio: " + this.heatRatio().get() + ", type: " + this.type() + "]"; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java index bf1e84ee..b3862c63 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/bluePrintItem/ReactorBluePrintMenu.java @@ -131,15 +131,15 @@ protected void saveData(ItemStack contentHolder) { if (isCooler) { countCooledRod++; - totalCoolerTime += typeRod.rodTimer(); + totalCoolerTime += typeRod.rodTimer().get(); } if (isFuel) { countFuelRod++; - totalFuelTime += typeRod.rodTimer(); + totalFuelTime += typeRod.rodTimer().get(); } if (isCooler || isFuel) { - totalHeatRatio += typeRod.heatRatio(); + totalHeatRatio += typeRod.heatRatio().get(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ItemConsumable.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ItemConsumable.java index 8e5d7774..556b554f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ItemConsumable.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/consumable/ItemConsumable.java @@ -21,7 +21,7 @@ public String getId() { @Override public int computeTimer(int count) { - int base = Math.max(1, rodType.rodTimer()); + int base = Math.max(1, rodType.rodTimer().get()); return Math.max(1, (int) (base / Math.max(1, count))); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java index 4bb0f5ec..2734d264 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/service/ReactorHeatUpdateCoordinator.java @@ -40,7 +40,7 @@ public static int calculateActualTotalHeatRatio(ItemStack configuredPattern, Rea if (countToUse > 0) { RodType rodType = RodType.resolveRodType(item, level); if (rodType != null && rodType.isNotEmptyItem()) { - totalHeatRatio += rodType.heatRatio() * countToUse; + totalHeatRatio += rodType.heatRatio().get() * countToUse; } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index c1a5beb3..b6aa1f0a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -56,10 +56,10 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re RodType rod = RodType.resolveRodType(currentStack.getItem(), level); String currentRod = ""; if (rod.items().size() > 0 && rod.type() == RodType.TypeRod.FUEL) { - heat += rod.baseRodHeat(); + heat += rod.baseRodHeat().get(); currentRod = "fuel"; } else if (rod.items().size() > 0 && rod.type() == RodType.TypeRod.COOLER) { - heat += rod.baseRodHeat(); + heat += rod.baseRodHeat().get(); currentRod = "cooler"; } @@ -80,9 +80,9 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re ItemStack stack = actualRods.get(neighborSlot); RodType neighborRod = RodType.resolveRodType(stack.getItem(), level); if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL) { - heat += rod.proximityRodHeat(); + heat += rod.proximityRodHeat().get(); } else if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER) { - heat += rod.baseRodHeat() / neighborRod.proximityRodHeat(); + heat += rod.baseRodHeat().get() / neighborRod.proximityRodHeat().get(); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java b/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java index b42d36db..8b1f6f85 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/item/RodsStats.java @@ -44,16 +44,16 @@ private static List getRodTypeStats(Item item, Player player) { .addTo(components); CreateNuclearLang.builder() - .add(CreateNuclearLang.translate("tooltip.baseRodHeat", rodType.baseRodHeat())) + .add(CreateNuclearLang.translate("tooltip.baseRodHeat", rodType.baseRodHeat().get())) .addTo(components); CreateNuclearLang.builder() - .add(CreateNuclearLang.translate("tooltip.proximityRodHeat", rodType.proximityRodHeat())) + .add(CreateNuclearLang.translate("tooltip.proximityRodHeat", rodType.proximityRodHeat().get())) .addTo(components); CreateNuclearLang.builder() - .add(CreateNuclearLang.translate("tooltip.rodTimer", rodType.rodTimer())) + .add(CreateNuclearLang.translate("tooltip.rodTimer", rodType.rodTimer().get())) .addTo(components); CreateNuclearLang.builder() - .add(CreateNuclearLang.translate("tooltip.heatRatio", rodType.heatRatio())) + .add(CreateNuclearLang.translate("tooltip.heatRatio", rodType.heatRatio().get())) .addTo(components); CreateNuclearLang.builder() .add(CreateNuclearLang.translate("tooltip.typeRod", rodType.type().name())) From 381c7a5f38c0b1a787cb75a070e3dde93ad9dbcf Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 19:33:30 +0200 Subject: [PATCH 132/171] fix: guard frame column NBT write and remove spurious cast in LiquidLevelDisplaySource ReactorFrameDisplayManager.write() previously serialized frameColumnMinY and frameColumnMaxY unconditionally, persisting their uninitialized default values (0 / 0) for reactors that have no frame column set yet. Wrap the two putInt calls in hasFrameColumn() so NBT is only written when the column bounds are actually meaningful. LiquidLevelDisplaySource cast the raw fluid amount to int via (int) before assigning it to an int local variable; the explicit cast is redundant since FluidStack.amount is already an int. Remove it to eliminate the unnecessary narrowing-cast noise. --- .../controller/manager/ReactorFrameDisplayManager.java | 7 ++++--- .../displayLink/source/LiquidLevelDisplaySource.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java index 81b95e14..cc9f239b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/controller/manager/ReactorFrameDisplayManager.java @@ -21,7 +21,6 @@ public class ReactorFrameDisplayManager implements ReactorFrameDisplayManagerI { private long frameFluidCacheTick = -1; private float frameFluidFillRatioCache = 0f; - private FluidStack frameFluidCache = FluidStack.EMPTY; /** @@ -128,7 +127,9 @@ public void read(CompoundTag compound) { @Override public void write(CompoundTag compound) { - compound.putInt(COMPONENT_FRAME_COLUMN_MIN_Y, frameColumnMinY); - compound.putInt(COMPONENT_FRAME_COLUMN_MAX_Y, frameColumnMaxY); + if (hasFrameColumn()) { + compound.putInt(COMPONENT_FRAME_COLUMN_MIN_Y, frameColumnMinY); + compound.putInt(COMPONENT_FRAME_COLUMN_MAX_Y, frameColumnMaxY); + } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java index a65b1afd..1c65b8f0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java @@ -25,7 +25,7 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget int mode = context.sourceConfig().getInt("display_mode"); var fluidList = controller.getBigFluidStack(); - int fluid = (fluidList != null && !fluidList.isEmpty()) ? (int) fluidList.get(0).amount : 0; + int fluid = (fluidList != null && !fluidList.isEmpty()) ? fluidList.get(0).amount : 0; int maxFluid = 16000; return label.append(switch (mode) { From 8c4ef5dfadbc769cf039bd0f80ed50be445bf92a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 19:37:18 +0200 Subject: [PATCH 133/171] docs: mark ReactorFrameDisplayManager NBT sentinel write as resolved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the consolidated audit to record the fix applied in the previous commit: ReactorFrameDisplayManager.write() no longer persists COMPONENT_FRAME_COLUMN_MIN_Y / MAX_Y when hasFrameColumn() is false, eliminating the spurious sentinel pollution. Item §2-7 is struck through in the open-issues table and a resolution note is added to the §6 fix log with the relevant line references and a regression-safety rationale. --- AUDIT_ACTUEL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f13c90ec..81ebd044 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -62,7 +62,7 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to 5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé)* 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. -7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure. +~~7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure.~~ ✅ **Corrigé le 2026-07-11** — `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit plus `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse simplement les champs à leurs valeurs par défaut (identique à l'état pré-assignation). 8. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`. --- @@ -149,6 +149,8 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Confirmé neutre** : le commit `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) ne fusionne rien dans le code de jeu — nettoyage cosmétique d'une scène Ponder uniquement. +**Corrigé le 2026-07-11** : `ReactorFrameDisplayManager.write` (ex-§2 point 7) persistait systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` était faux. `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit désormais `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque de régression : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse les champs à leurs valeurs par défaut (identique à l'état pré-assignation). + --- ## 7. 🗺️ Feuille de route — priorités From 35e474e3fca1df80f41d62bab97a8c03fa1bef1a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 20:38:44 +0200 Subject: [PATCH 134/171] refactor: extract AbstractReactorStatDisplaySource and ReactorGaugeRenderer to eliminate display-source duplication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CoolerDisplaySource, HeatDisplaySource, LiquidLevelDisplaySource, and ReactorSummaryDisplaySource each contained an identical private drawGauge() method and repeated the same controller-lookup, label-build, mode-switch pattern. Extract the shared logic into two new types: - AbstractReactorStatDisplaySource — abstract base extending NumericSingleLineDisplaySource; centralises provideLine() (controller lookup, label, mode switch), initConfigurationWidgets(), and allowsLabeling(). Subclasses implement four lightweight hooks: getLabelKey(), getMax(), computeValue(), getColor(); an optional getUnitSuffix() covers sources that append a unit token in value mode. - ReactorGaugeRenderer — package-private utility holding the single canonical drawGauge() implementation (Mth.clamp → filled/empty block chars). ReactorSummaryDisplaySource delegates its two formatFluid/formatValue gauge branches to it and drops its own private copy. CoolerDisplaySource, HeatDisplaySource, and LiquidLevelDisplaySource are fully rewritten to extend AbstractReactorStatDisplaySource; each is now ~20 lines of hook implementations instead of ~50–65 lines of duplicated boilerplate. ReactorFluidInputEntity and ReactorRodInputEntity: getCapability() now returns LazyOptional.empty() for any side that does not match the block's FACING direction, preventing adjacent automation (hoppers, pipes) from accessing the inventory or fluid handler through the wrong face. --- .../input/fluid/ReactorFluidInputEntity.java | 7 +- .../input/item/ReactorRodInputEntity.java | 7 +- .../AbstractReactorStatDisplaySource.java | 54 +++++++++++++++ .../source/CoolerDisplaySource.java | 68 +++++++------------ .../displayLink/source/HeatDisplaySource.java | 64 +++++------------ .../source/LiquidLevelDisplaySource.java | 56 +++++++-------- .../source/ReactorGaugeRenderer.java | 15 ++++ .../source/ReactorSummaryDisplaySource.java | 14 ++-- 8 files changed, 151 insertions(+), 134 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/AbstractReactorStatDisplaySource.java create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorGaugeRenderer.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java index 1533b2b6..2e275cbf 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/fluid/ReactorFluidInputEntity.java @@ -22,6 +22,7 @@ import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; +import net.nuclearteam.createnuclear.foundation.block.MultiDirectionalReactorBlock; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -143,7 +144,11 @@ public void invalidate() { @Override public @NotNull LazyOptional getCapability(Capability cap, Direction side) { if (!capability.isPresent()) refreshCapability(); - if (cap == ForgeCapabilities.FLUID_HANDLER) return capability.cast(); + if (cap == ForgeCapabilities.FLUID_HANDLER) { + if (side != null && side != getBlockState().getValue(MultiDirectionalReactorBlock.FACING)) + return LazyOptional.empty(); + return capability.cast(); + } return super.getCapability(cap, side); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java index b20632fa..72cec9c9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java @@ -18,6 +18,7 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.IItemHandler; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlock; +import net.nuclearteam.createnuclear.foundation.block.MultiDirectionalReactorBlock; import javax.annotation.Nullable; import java.util.List; @@ -93,8 +94,12 @@ protected boolean isItemHandlerCap(Capability cap) { @Override public LazyOptional getCapability(Capability cap, Direction side) { - if (isItemHandlerCap(cap)) + if (isItemHandlerCap(cap)){ + if (side != null && side != getBlockState().getValue(MultiDirectionalReactorBlock.FACING)) + return LazyOptional.empty(); return inventoryProvider.cast(); + } + return super.getCapability(cap, side); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/AbstractReactorStatDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/AbstractReactorStatDisplaySource.java new file mode 100644 index 00000000..b33d9b4f --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/AbstractReactorStatDisplaySource.java @@ -0,0 +1,54 @@ +package net.nuclearteam.createnuclear.content.redstone.displayLink.source; + +import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; +import com.simibubi.create.content.redstone.displayLink.source.NumericSingleLineDisplaySource; +import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; +import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; +import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; + +public abstract class AbstractReactorStatDisplaySource extends NumericSingleLineDisplaySource { + protected abstract String getLabelKey(); + protected abstract int getMax(); + protected abstract int computeValue(ReactorControllerBlockEntity controller, DisplayLinkContext context); + protected abstract ChatFormatting getColor(int value, ReactorControllerBlockEntity controller); + protected MutableComponent getUnitSuffix() { return null; } + + @Override + protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { + ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); + if (controller == null || controller.isRemoved()) return ZERO.copy(); + + MutableComponent label = CreateNuclearLang.translateDirect(getLabelKey()).append(" "); + int mode = context.sourceConfig().getInt("display_mode"); + int value = computeValue(controller, context); + int max = getMax(); + ChatFormatting color = getColor(value, controller); + + return label.append(switch (mode) { + case 1 -> Component.literal((value * 100 / max) + "%").withStyle(color); + case 2 -> ReactorGaugeRenderer.drawGauge(value, max, color, 6); + default -> { + MutableComponent base = Component.literal(String.valueOf(value)); + MutableComponent unit = getUnitSuffix(); + yield (unit != null ? base.append(unit) : base).withStyle(color); + } + }); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, boolean isFirstLine) { + if (isFirstLine) return; + builder.addSelectionScrollInput(0, 100, (input, l) -> input + .forOptions(CreateNuclearLang.translatedOptions("display_source.reactor.mode", "value", "percent", "gauge")), "display_mode"); + } + + @Override protected boolean allowsLabeling(DisplayLinkContext context) { return true; } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java index 687800b6..f93e9e89 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java @@ -1,68 +1,46 @@ package net.nuclearteam.createnuclear.content.redstone.displayLink.source; import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; -import com.simibubi.create.content.redstone.displayLink.source.NumericSingleLineDisplaySource; -import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; -import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.util.Mth; import net.minecraft.world.item.Item; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; -import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; +import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; -import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; -import java.util.Map.Entry; +import java.util.Map; + +public class CoolerDisplaySource extends AbstractReactorStatDisplaySource { -public class CoolerDisplaySource extends NumericSingleLineDisplaySource { @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); - if (controller == null || controller.isRemoved()) return ZERO.copy(); + protected String getLabelKey() { + return "display_source.reactor.cooler"; + } - // Label + Espace - MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.cooler").append(" "); + @Override + protected int getMax() { + return 64; + } + + @Override + protected ChatFormatting getColor(int value, ReactorControllerBlockEntity controller) { + return ChatFormatting.AQUA; + } - int mode = context.sourceConfig().getInt("display_mode"); + @Override + protected int computeValue(ReactorControllerBlockEntity controller, DisplayLinkContext context) { int cooler = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { - for (Entry entry : controller.getDisplayState().items().entrySet()) { - if (TypeRodPredicate.isCooled(entry.getKey().getDefaultInstance(), context.level())) { + for (Map.Entry entry : controller.getDisplayState().items().entrySet()) { + if (RodType.TypeRodPredicate.isCooled(entry.getKey().getDefaultInstance(), context.level())) { cooler += entry.getValue(); } } } - int maxCooler = 64; - - return label.append(switch (mode) { - case 1 -> Component.literal((cooler * 100 / maxCooler) + "%").withStyle(ChatFormatting.AQUA); - case 2 -> { - int gaugeWidth = 6; - yield drawGauge(cooler, maxCooler, ChatFormatting.AQUA, gaugeWidth); - } - default -> Component.literal(String.valueOf(cooler)).withStyle(ChatFormatting.AQUA); - }); + return cooler; } - private MutableComponent drawGauge(int current, int max, ChatFormatting color, int width) { - int filled = (int) (Mth.clamp((float) current / max, 0, 1) * width); - return Component.literal("█".repeat(filled) + "▒".repeat(Math.max(0, width - filled))).withStyle(color); - } - - @Override protected String getTranslationKey() { return "cooler"; } - @Override - @OnlyIn(Dist.CLIENT) - public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, boolean isFirstLine) { - if (isFirstLine) return; - builder.addSelectionScrollInput(0, 100, (selectionScrollInput, l) -> selectionScrollInput - .forOptions(CreateNuclearLang.translatedOptions("display_source.reactor.mode", "value", "percent", "gauge")), "display_mode"); + protected String getTranslationKey() { + return "cooler"; } - - @Override protected boolean allowsLabeling(DisplayLinkContext context) { return true; } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java index aeb6c1f2..2f646df6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java @@ -1,64 +1,34 @@ package net.nuclearteam.createnuclear.content.redstone.displayLink.source; import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; -import com.simibubi.create.content.redstone.displayLink.source.NumericSingleLineDisplaySource; -import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; -import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.ChatFormatting; import net.nuclearteam.createnuclear.content.multiblock.IHeat; -import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; -import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; -public class HeatDisplaySource extends NumericSingleLineDisplaySource { +public class HeatDisplaySource extends AbstractReactorStatDisplaySource { @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); - if (controller == null || controller.isRemoved()) return ZERO.copy(); - - // Ajout du Label + Espace - MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.heat").append(" "); - - int mode = context.sourceConfig().getInt("display_mode"); - int heat = (int) controller.getConfiguredPattern().getOrCreateTag().getDouble("heat"); - int maxHeat = 1000; - - return label.append(switch (mode) { - case 1 -> Component.literal((heat * 100 / maxHeat) + "%") - .withStyle(IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor()); - - case 2 -> { - // Largeur réduite pour laisser de la place au label - int gaugeWidth = 6; - yield drawGauge(heat, maxHeat, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth); - } - - default -> Component.literal(String.valueOf(heat)) - .append(CreateNuclearLang.translateDirect("generic.unit.heat.value")) - .withStyle(IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor()); - }); + protected String getLabelKey() { + return "display_source.reactor.heat"; } - private MutableComponent drawGauge(int current, int max, net.minecraft.ChatFormatting color, int width) { - int filled = (int) (Mth.clamp((float) current / max, 0, 1) * width); - int empty = Math.max(0, width - filled); - return Component.literal("█".repeat(filled) + "▒".repeat(empty)).withStyle(color); + @Override + protected int getMax() { + return 1000; } - @Override protected String getTranslationKey() { return "heat"; } + @Override + protected ChatFormatting getColor(int value, ReactorControllerBlockEntity controller) { + return IHeat.HeatLevel.of(value, controller.getMultiblockSize()).getTextColor(); + } @Override - @OnlyIn(Dist.CLIENT) - public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, boolean isFirstLine) { - if (isFirstLine) return; - builder.addSelectionScrollInput(0, 100, (selectionScrollInput, l) -> selectionScrollInput - .forOptions(CreateNuclearLang.translatedOptions("display_source.reactor.mode", "value", "percent", "gauge")), "display_mode"); + protected int computeValue(ReactorControllerBlockEntity controller, DisplayLinkContext context) { + return (int) controller.getConfiguredPattern().getOrCreateTag().getDouble("heat"); } - @Override protected boolean allowsLabeling(DisplayLinkContext context) { return true; } + @Override + protected String getTranslationKey() { + return "heat"; + } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java index 1c65b8f0..abf3a8e2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java @@ -10,50 +10,42 @@ import net.minecraft.util.Mth; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; -public class LiquidLevelDisplaySource extends NumericSingleLineDisplaySource { +import java.util.List; +public class LiquidLevelDisplaySource extends AbstractReactorStatDisplaySource { @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); - if (controller == null || controller.isRemoved()) return ZERO.copy(); - - MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.fluid").append(" "); - - int mode = context.sourceConfig().getInt("display_mode"); - var fluidList = controller.getBigFluidStack(); - int fluid = (fluidList != null && !fluidList.isEmpty()) ? fluidList.get(0).amount : 0; - int maxFluid = 16000; - - return label.append(switch (mode) { - case 1 -> Component.literal((fluid * 100 / maxFluid) + "%").withStyle(ChatFormatting.BLUE); - case 2 -> { - int gaugeWidth = 6; - yield drawGauge(fluid, maxFluid, ChatFormatting.BLUE, gaugeWidth); - } - default -> Component.literal(String.valueOf(fluid)) - .append(CreateNuclearLang.translateDirect("generic.unit.fluid.value")) - .withStyle(ChatFormatting.BLUE); - }); + protected String getLabelKey() { + return "display_source.reactor.fluid"; } - private MutableComponent drawGauge(int current, int max, ChatFormatting color, int width) { - int filled = (int) (Mth.clamp((float) current / max, 0, 1) * width); - return Component.literal("█".repeat(filled) + "▒".repeat(Math.max(0, width - filled))).withStyle(color); + @Override + protected int getMax() { + return 16000; + } + + @Override + protected ChatFormatting getColor(int value, ReactorControllerBlockEntity controller) { + return ChatFormatting.BLUE; } - @Override protected String getTranslationKey() { return "liquid_level"; } + @Override + protected int computeValue(ReactorControllerBlockEntity controller, DisplayLinkContext context) { + List fluidList = controller.getBigFluidStack(); + return (fluidList != null && !fluidList.isEmpty()) ? fluidList.get(0).amount : 0; + } @Override - @OnlyIn(Dist.CLIENT) - public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, boolean isFirstLine) { - if (isFirstLine) return; - builder.addSelectionScrollInput(0, 100, (selectionScrollInput, l) -> selectionScrollInput - .forOptions(CreateNuclearLang.translatedOptions("display_source.reactor.mode", "value", "percent", "gauge")), "display_mode"); + protected MutableComponent getUnitSuffix() { + return CreateNuclearLang.translateDirect("generic.unit.fluid.value"); } - @Override protected boolean allowsLabeling(DisplayLinkContext context) { return true; } + @Override + protected String getTranslationKey() { + return "liquid_level"; + } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorGaugeRenderer.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorGaugeRenderer.java new file mode 100644 index 00000000..4b590b16 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorGaugeRenderer.java @@ -0,0 +1,15 @@ +package net.nuclearteam.createnuclear.content.redstone.displayLink.source; + +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.Mth; + +public final class ReactorGaugeRenderer { + private ReactorGaugeRenderer() {} + + static MutableComponent drawGauge(int current, int max, ChatFormatting color, int width) { + int filled = (int) (Mth.clamp((float) current / max, 0, 1) * width); + return Component.literal("█".repeat(filled) + "▒".repeat(Math.max(0, width - filled))).withStyle(color); + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index 964c0284..3dc0e33f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -164,22 +164,17 @@ private MutableComponent formatSize(int size) { } private MutableComponent formatFluid(int current, int max, int mode, ChatFormatting color, int width) { - if (mode == 0 || mode == 3) return drawGauge(current, max, color, width); + if (mode == 0 || mode == 3) return ReactorGaugeRenderer.drawGauge(current, max, color, width); if (mode == 2) return Component.literal((current * 100 / max) + "%").withStyle(color); return Component.literal(String.valueOf(current)).append(" ").append(CreateNuclearLang.translateDirect("generic.unit.fluid.value")).withStyle(color); } private MutableComponent formatValue(int current, int max, int mode, boolean gaugeOnNormal, ChatFormatting color, int width) { - if (mode == 3 || (mode == 0 && gaugeOnNormal)) return drawGauge(current, max, color, width); + if (mode == 3 || (mode == 0 && gaugeOnNormal)) return ReactorGaugeRenderer.drawGauge(current, max, color, width); if (mode == 2) return Component.literal((current * 100 / max) + "%").withStyle(color); return Component.literal(String.valueOf(current)).withStyle(color); } - private MutableComponent drawGauge(int current, int max, ChatFormatting color, int width) { - int filled = (int) (Mth.clamp((float) current / max, 0, 1) * width); - return Component.literal("█".repeat(filled) + "▒".repeat(Math.max(0, width - filled))).withStyle(color); - } - private int labelWidth() { return Stream.of("status", "size", "fuel", "cooler", "fluid", "heat").mapToInt(this::labelWidthOf).max().orElse(0); } @@ -200,5 +195,8 @@ public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineB .forOptions(CreateNuclearLang.translatedOptions("display_source.reactor.mode", "normal", "value", "percent", "gauge")), "display_mode"); } - @Override protected String getTranslationKey() { return "reactor_summary"; } + @Override + protected String getTranslationKey() { + return "reactor_summary"; + } } \ No newline at end of file From d0da13d14cef2638cc0853fd6dab66cfc2da4d46 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 21:00:13 +0200 Subject: [PATCH 135/171] chore: centralise display-source max constants and migrate FuelDisplaySource; bump version to 2.0.15-beta Extract the four magic-number cap values (64 / 64 / 16000 / 1000) that were scattered across display sources into a new package-private ReactorDisplayConstants class (MAX_FUEL, MAX_COOLER, MAX_FLUID, MAX_HEAT). Update CoolerDisplaySource, HeatDisplaySource, and LiquidLevelDisplaySource to reference the constants; all three already extended AbstractReactorStatDisplaySource. Migrate FuelDisplaySource from NumericSingleLineDisplaySource to AbstractReactorStatDisplaySource following the same pattern applied to the other three sources in the previous commit: boilerplate provideLine(), drawGauge(), and initConfigurationWidgets() replaced by getLabelKey(), getMax(), computeValue(), and getColor() hook implementations. gradle.properties: mod_version bumped from 2.0.14-beta to 2.0.15-beta. --- gradle.properties | 2 +- .../source/CoolerDisplaySource.java | 2 +- .../displayLink/source/FuelDisplaySource.java | 64 +++++++------------ .../displayLink/source/HeatDisplaySource.java | 2 +- .../source/LiquidLevelDisplaySource.java | 2 +- .../source/ReactorDisplayConstants.java | 9 +++ 6 files changed, 35 insertions(+), 46 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorDisplayConstants.java diff --git a/gradle.properties b/gradle.properties index 95fddd29..52685895 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.14-beta +mod_version=2.0.15-beta # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java index f93e9e89..ce7934b5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/CoolerDisplaySource.java @@ -18,7 +18,7 @@ protected String getLabelKey() { @Override protected int getMax() { - return 64; + return ReactorDisplayConstants.MAX_COOLER; } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java index 76961ab7..56a8dc27 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/FuelDisplaySource.java @@ -1,65 +1,45 @@ package net.nuclearteam.createnuclear.content.redstone.displayLink.source; import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext; -import com.simibubi.create.content.redstone.displayLink.source.NumericSingleLineDisplaySource; -import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats; -import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraft.world.item.Item; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; -import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; -import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; -public class FuelDisplaySource extends NumericSingleLineDisplaySource { +import java.util.Map; + +public class FuelDisplaySource extends AbstractReactorStatDisplaySource { @Override - protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) { - ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); - if (controller == null || controller.isRemoved()) return ZERO.copy(); + protected String getLabelKey() { + return "display_source.reactor.fuel"; + } - // Label + Espace - MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.fuel").append(" "); + @Override + protected int getMax() { + return ReactorDisplayConstants.MAX_FUEL; + } + + @Override + protected ChatFormatting getColor(int value, ReactorControllerBlockEntity controller) { + return ChatFormatting.GREEN; + } - int mode = context.sourceConfig().getInt("display_mode"); + @Override + protected int computeValue(ReactorControllerBlockEntity controller, DisplayLinkContext context) { int fuel = 0; if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { - for (var entry : controller.getDisplayState().items().entrySet()) { + for (Map.Entry entry : controller.getDisplayState().items().entrySet()) { if (TypeRodPredicate.isFuel(entry.getKey().getDefaultInstance(), context.level())) { fuel += entry.getValue(); } } } - int maxFuel = 64; - - return label.append(switch (mode) { - case 1 -> Component.literal((fuel * 100 / maxFuel) + "%").withStyle(ChatFormatting.GREEN); - case 2 -> { - int gaugeWidth = 6; - yield drawGauge(fuel, maxFuel, ChatFormatting.GREEN, gaugeWidth); - } - default -> Component.literal(String.valueOf(fuel)).withStyle(ChatFormatting.GREEN); - }); + return fuel; } - private MutableComponent drawGauge(int current, int max, ChatFormatting color, int width) { - int filled = (int) (Mth.clamp((float) current / max, 0, 1) * width); - return Component.literal("█".repeat(filled) + "▒".repeat(Math.max(0, width - filled))).withStyle(color); - } - - @Override protected String getTranslationKey() { return "fuel"; } - @Override - @OnlyIn(Dist.CLIENT) - public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder, boolean isFirstLine) { - if (isFirstLine) return; - builder.addSelectionScrollInput(0, 100, (selectionScrollInput, l) -> selectionScrollInput - .forOptions(CreateNuclearLang.translatedOptions("display_source.reactor.mode", "value", "percent", "gauge")), "display_mode"); + protected String getTranslationKey() { + return "fuel"; } - - @Override protected boolean allowsLabeling(DisplayLinkContext context) { return true; } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java index 2f646df6..98f05262 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/HeatDisplaySource.java @@ -14,7 +14,7 @@ protected String getLabelKey() { @Override protected int getMax() { - return 1000; + return ReactorDisplayConstants.MAX_HEAT; } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java index abf3a8e2..6acaab84 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/LiquidLevelDisplaySource.java @@ -25,7 +25,7 @@ protected String getLabelKey() { @Override protected int getMax() { - return 16000; + return ReactorDisplayConstants.MAX_FLUID; } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorDisplayConstants.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorDisplayConstants.java new file mode 100644 index 00000000..28360ff2 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorDisplayConstants.java @@ -0,0 +1,9 @@ +package net.nuclearteam.createnuclear.content.redstone.displayLink.source; + +final class ReactorDisplayConstants { + static final int MAX_FUEL = 64; + static final int MAX_COOLER = 64; + static final int MAX_FLUID = 16000; + static final int MAX_HEAT = 1000; + private ReactorDisplayConstants() {} +} From a8b6b23fbd5392569a69cbe46b4e300183c08128 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 21:04:53 +0200 Subject: [PATCH 136/171] refactor: replace magic-number max values in ReactorSummaryDisplaySource with ReactorDisplayConstants --- .../displayLink/source/ReactorSummaryDisplaySource.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index 3dc0e33f..411d3888 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -147,10 +147,10 @@ private Stream> getComponents(DisplayLinkContext context, CreateNuclearLang.translateDirect("display_source.reactor.active").withStyle(ChatFormatting.GOLD) : CreateNuclearLang.translateDirect("display_source.reactor.idle").withStyle(ChatFormatting.GRAY)), List.of(lSize, formatSize(size)), - List.of(lFuel, formatValue(fuel, 64, mode, false, ChatFormatting.GREEN, gaugeWidth)), - List.of(lCooler, formatValue(cooler, 64, mode, false, ChatFormatting.AQUA, gaugeWidth)), - List.of(lFluid, formatFluid(fluid, 16000, mode, ChatFormatting.BLUE, gaugeWidth)), - List.of(lHeat, formatValue(heat, 1000, mode, true, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth)) + List.of(lFuel, formatValue(fuel, ReactorDisplayConstants.MAX_FUEL, mode, false, ChatFormatting.GREEN, gaugeWidth)), + List.of(lCooler, formatValue(cooler, ReactorDisplayConstants.MAX_COOLER, mode, false, ChatFormatting.AQUA, gaugeWidth)), + List.of(lFluid, formatFluid(fluid, ReactorDisplayConstants.MAX_FLUID, mode, ChatFormatting.BLUE, gaugeWidth)), + List.of(lHeat, formatValue(heat, ReactorDisplayConstants.MAX_HEAT, mode, true, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth)) ); } From e34adcc5715469ae439cfcface7e35a267154190 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 21:08:29 +0200 Subject: [PATCH 137/171] docs: mark drawGauge deduplication closed and update roadmap item #9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record the resolution of audit item §2.8 (drawGauge duplication across five display-source classes): AbstractReactorStatDisplaySource, ReactorGaugeRenderer, and ReactorDisplayConstants are summarised in the §6 fix log with the full rationale — which classes migrated, why ReactorSummaryDisplaySource stays on DisplaySource, and why ReactorSizeDisplaySource was intentionally excluded. Strike through item #8 in the open-issues table and strike through roadmap item #9, marking both as done on 2026-07-11. --- AUDIT_ACTUEL.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 81ebd044..d44d48af 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -63,7 +63,7 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to 5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé)* 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. ~~7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure.~~ ✅ **Corrigé le 2026-07-11** — `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit plus `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse simplement les champs à leurs valeurs par défaut (identique à l'état pré-assignation). -8. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`. +~~8. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`.~~ ✅ **Corrigé le 2026-07-11** — `ReactorGaugeRenderer.drawGauge` (nouvelle classe utilitaire) centralise le rendu, appelé par les 4 sous-classes via le nouveau template `AbstractReactorStatDisplaySource` (`FuelDisplaySource`, `CoolerDisplaySource`, `HeatDisplaySource`, `LiquidLevelDisplaySource` héritent désormais de cette classe abstraite au lieu de dupliquer `provideLine`/`drawGauge`) et directement par `ReactorSummaryDisplaySource` (qui reste sur `DisplaySource`, structure multi-lignes incompatible avec le template). Les magic numbers des 4 sous-classes sont centralisés dans `ReactorDisplayConstants` (`MAX_FUEL`, `MAX_COOLER`, `MAX_FLUID`, `MAX_HEAT`). `ReactorSizeDisplaySource` reste volontairement en dehors (sémantique différente : jauge à 3 segments discrets par tier, pas un ratio `current/max` continu — n'avait de toute façon pas de duplication de `drawGauge`). `ReactorSummaryDisplaySource.getComponents()` (l.150-153) référence désormais aussi `ReactorDisplayConstants.MAX_FUEL/MAX_COOLER/MAX_FLUID/MAX_HEAT` au lieu de magic numbers en dur — déduplication complète sur les 5 classes. --- @@ -151,6 +151,8 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Corrigé le 2026-07-11** : `ReactorFrameDisplayManager.write` (ex-§2 point 7) persistait systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` était faux. `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit désormais `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque de régression : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse les champs à leurs valeurs par défaut (identique à l'état pré-assignation). +**Corrigé le 2026-07-11** : duplication `drawGauge` (ex-§2 point 8). Nouvelle classe `ReactorGaugeRenderer.drawGauge` centralise le rendu de jauge, jusque-là copié à l'identique dans 5 classes. `FuelDisplaySource`, `CoolerDisplaySource`, `HeatDisplaySource` et `LiquidLevelDisplaySource` héritent désormais d'un nouveau template `AbstractReactorStatDisplaySource extends NumericSingleLineDisplaySource` (`provideLine`, `initConfigurationWidgets`, `allowsLabeling` mutualisés ; chaque sous-classe ne fournit plus que `getLabelKey`, `getMax`, `computeValue`, `getColor`, et optionnellement `getUnitSuffix`). `ReactorSummaryDisplaySource` reste sur `DisplaySource` (structure multi-lignes non compatible avec le template single-line) mais appelle désormais `ReactorGaugeRenderer.drawGauge` au lieu de sa propre copie. Les magic numbers des 5 classes (les 4 sous-classes migrées **et** `ReactorSummaryDisplaySource`, l.150-153) sont désormais tous nommés dans `ReactorDisplayConstants`. Vérifié par lecture directe des 8 fichiers concernés et par `Grep` confirmant l'usage de `ReactorDisplayConstants.MAX_*` partout où figuraient auparavant `64`/`16000`/`1000` en dur. `ReactorSizeDisplaySource` a été délibérément exclue du template (jauge à 3 segments discrets par tier, sémantique incompatible avec un ratio `current/max`) — elle n'avait de toute façon pas de `drawGauge` dupliqué. Déduplication complète, aucun point résiduel. + --- ## 7. 🗺️ Feuille de route — priorités @@ -166,7 +168,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Corrections ciblées (risque faible à moyen)** 7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). 8. `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle 81 cellules (gain mineur désormais, priorité baissée par rapport au tour précédent) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance. -9. Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques (§2.8). +9. ~~Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques.~~ ✅ **fait le 2026-07-11** (§2.8). 10. Flicker vitesse de sortie en fin de ressources (oscillateur `overHeat` × division entière `RPM_DIVIDER`) : ajouter une hystérésis sur le heat appliqué à `rotateOutputs`, seuil à valider (§1). **Décisions produit (choisir puis exécuter)** From 17b29aa38dc2431b6aef349e1ae772afe24874d5 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 21:20:13 +0200 Subject: [PATCH 138/171] chore: remove incomplete dyeable-collar mechanic from IrradiatedCat and IrradiatedWolf Delete IrradiatedCatCollarLayer and IrradiatedWoldCollarLayer, which were never wired into any renderer (addLayer call was missing) and had no reachable code path to trigger a color change (DyeItem interaction on IrradiatedWolf was also absent). Strip the corresponding dead code from IrradiatedCat: DATA_COLLAR_COLOR EntityDataAccessor, getCollarColor()/setCollarColor() accessors, its registration in defineSynchedData(), and the CollarColor NBT read/write in addAdditionalSaveData()/readAdditionalSaveData(). --- .../irradiated/cat/IrradiatedCat.java | 17 ---------- .../cat/IrradiatedCatCollarLayer.java | 32 ------------------- .../wolf/IrradiatedWoldCollarLayer.java | 23 ------------- 3 files changed, 72 deletions(-) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCatCollarLayer.java delete mode 100644 src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWoldCollarLayer.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java index 668ecc53..576a4fa7 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCat.java @@ -57,7 +57,6 @@ public class IrradiatedCat extends TamableAnimal { private static final Ingredient TEMPT_INGREDIENT; private static final EntityDataAccessor IS_LYING; private static final EntityDataAccessor RELAX_STATE_ONE; - private static final EntityDataAccessor DATA_COLLAR_COLOR; private CatAvoidEntityGoal avoidPlayersGoal; @Nullable private TemptGoal temptGoal; @@ -108,33 +107,18 @@ public boolean isRelaxStateOne() { return this.entityData.get(RELAX_STATE_ONE); } - public DyeColor getCollarColor() { - return DyeColor.byId(this.entityData.get(DATA_COLLAR_COLOR)); - } - - public void setCollarColor(DyeColor color) { - this.entityData.set(DATA_COLLAR_COLOR, color.getId()); - } - protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(IS_LYING, false); this.entityData.define(RELAX_STATE_ONE, false); - this.entityData.define(DATA_COLLAR_COLOR, DyeColor.RED.getId()); } public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); - compound.putByte("CollarColor", (byte)this.getCollarColor().getId()); } public void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); - - if (compound.contains("CollarColor", 99)) { - this.setCollarColor(DyeColor.byId(compound.getInt("CollarColor"))); - } - } public void customServerAiStep() { @@ -397,7 +381,6 @@ public boolean isSteppingCarefully() { TEMPT_INGREDIENT = Ingredient.of(new ItemLike[]{Items.COD, Items.SALMON, CNItems.YELLOWCAKE}); IS_LYING = SynchedEntityData.defineId(IrradiatedCat.class, EntityDataSerializers.BOOLEAN); RELAX_STATE_ONE = SynchedEntityData.defineId(IrradiatedCat.class, EntityDataSerializers.BOOLEAN); - DATA_COLLAR_COLOR = SynchedEntityData.defineId(IrradiatedCat.class, EntityDataSerializers.INT); } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCatCollarLayer.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCatCollarLayer.java deleted file mode 100644 index 83d842f8..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/cat/IrradiatedCatCollarLayer.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.nuclearteam.createnuclear.content.contraptions.irradiated.cat; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.model.geom.EntityModelSet; -import net.minecraft.client.model.geom.ModelLayers; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.entity.RenderLayerParent; -import net.minecraft.client.renderer.entity.layers.RenderLayer; -import net.minecraft.resources.ResourceLocation; - -import javax.annotation.ParametersAreNonnullByDefault; - -@SuppressWarnings("unused") -@ParametersAreNonnullByDefault -public class IrradiatedCatCollarLayer extends RenderLayer> { - private static final ResourceLocation CAT_COLLAR_LOCATION = new ResourceLocation("textures/entity/cat/cat_collar.png"); - private final IrradiatedCatModel irrigatedCatCollarModel; - - public IrradiatedCatCollarLayer(RenderLayerParent> render, EntityModelSet modelSet) { - super(render); - this.irrigatedCatCollarModel = new IrradiatedCatModel<>(modelSet.bakeLayer(ModelLayers.CAT_COLLAR)); - } - - - @Override - public void render(PoseStack matrixStack, MultiBufferSource buffer, int packedLight, IrradiatedCat livingEntity, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch) { - if (livingEntity.isTame()) { - float[] fs = livingEntity.getCollarColor().getTextureDiffuseColors(); - coloredCutoutModelCopyLayerRender(this.getParentModel(), this.irrigatedCatCollarModel, CAT_COLLAR_LOCATION, matrixStack, buffer, packedLight, livingEntity, limbSwing, limbSwingAmount, partialTick, ageInTicks, netHeadYaw, headPitch, fs[0], fs[1], fs[2]); - } - } -} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWoldCollarLayer.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWoldCollarLayer.java deleted file mode 100644 index 78e3f599..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/wolf/IrradiatedWoldCollarLayer.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.nuclearteam.createnuclear.content.contraptions.irradiated.wolf; - -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.entity.RenderLayerParent; -import net.minecraft.client.renderer.entity.layers.RenderLayer; -import net.minecraft.resources.ResourceLocation; - -import javax.annotation.ParametersAreNonnullByDefault; - -@ParametersAreNonnullByDefault -@SuppressWarnings("unused") -public class IrradiatedWoldCollarLayer extends RenderLayer> { - private static final ResourceLocation WOLF_COLLAR_LOCATION = new ResourceLocation("textures/entity/wolf/wolf_collar.png"); - - public IrradiatedWoldCollarLayer(RenderLayerParent> renderer) { - super(renderer); - } - - @Override - public void render(PoseStack matrixStack, MultiBufferSource buffer, int packedLight, IrradiatedWolf livingEntity, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch) { - } -} From 261b26d8c2ce9b118012a1473eb7af48ca13c9c9 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 11 Jul 2026 21:49:28 +0200 Subject: [PATCH 139/171] feat: block taming of irradiated mobs with a WIP player message Irradiated cat and wolf taming was either broken (cat: consumed food items and triggered the vanilla taming path but lacked a functional collar/layer; wolf: had no taming path at all) or silently inconsistent. Replace both with an explicit "not yet tameable" gate: - AnimalUtil.blockTamingWip(Player, Level): new shared helper that sends the translatable "irradiated.taming.wip" system message server-side and returns sidedSuccess to consume the interaction. - IrradiatedCat.mobInteract: untamed path now delegates to blockTamingWip when the player uses YELLOWCAKE; the entire DyeItem collar-color branch is removed from the tamed-owner path; the vanilla collar-color inheritance in getBreedOffspring is removed. - IrradiatedWolf.mobInteract: adds an else-if on isFood to call blockTamingWip for untamed wolves; client-side hint predicate updated from is(Items.BONE) to isFood to match the new logic. - irradiated.json: new default lang file providing the "irradiated.taming.wip" key; wired into CreateNuclearDatagen alongside the existing category files; en_us/en_ud generated outputs regenerated. - AUDIT_ACTUEL.md: dyeable-collar decision item and roadmap entry #11 marked resolved. --- AUDIT_ACTUEL.md | 6 +-- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 +-- .../assets/createnuclear/lang/en_ud.json | 1 + .../assets/createnuclear/lang/en_us.json | 1 + .../contraptions/irradiated/AnimalUtil.java | 17 +++++++ .../irradiated/cat/IrradiatedCat.java | 51 +++++-------------- .../irradiated/wolf/IrradiatedWolf.java | 5 +- .../data/CreateNuclearDatagen.java | 1 + .../lang/default/irradiated.json | 3 ++ 9 files changed, 43 insertions(+), 48 deletions(-) create mode 100644 src/main/resources/assets/createnuclear/lang/default/irradiated.json diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index d44d48af..e502228b 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -106,9 +106,7 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to `run/hs_err_pid21100.log`, `run/hs_err_pid27848.log`, `run/imgui.ini`, `run/servers.dat`, `run/servers.dat_old`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`.~~ ⚠️ **Conserver** les 10 `run/schematics/*.nbt` (assets de gameplay légitimes). -**Décisions produit (pas du pur dead code — choisir puis exécuter)** - -- **Collier teignable chat/loup non câblé** *(inchangé)* : `IrradiatedWoldCollarLayer.render()` reste un corps vide ; `IrradiatedCatCollarLayer` n'est toujours pas enregistré via `addLayer(...)` dans `CNEntityType.java`. `IrradiatedWolf` ne câble toujours pas l'interaction `DyeItem`/`setCollarColor` (`mobInteract` sans logique dye), alors qu'`IrradiatedCat` câble entièrement `DyeItem → setCollarColor/getCollarColor`. Un joueur peut toujours teindre le collier d'un chat irradié sans effet visible. *Décision* : enregistrer le layer + implémenter `render`, ou retirer toute la mécanique `DyeItem`/`setCollarColor`. +~~**Collier teignable chat/loup non câblé**~~ ✅ **Résolu le 2026-07-11** — décision prise : retrait complet de la mécanique plutôt que câblage. `IrradiatedCatCollarLayer.java` et `IrradiatedWoldCollarLayer.java` ont été supprimés (aucun appelant ne les référençait, confirmé par grep). Dans `IrradiatedCat.java`, le champ `DATA_COLLAR_COLOR`, les accesseurs `getCollarColor()`/`setCollarColor()` et le bloc `readAdditionalSaveData`/`addAdditionalSaveData` associé ont été retirés ; l'interaction `DyeItem` dans `mobInteract` a été retirée (le fix a complété une suppression partielle laissée par l'édition en cours, qui laissait `mobInteract` appeler des méthodes déjà supprimées — code non compilable en l'état intermédiaire). `IrradiatedWolf` n'avait de toute façon jamais câblé cette mécanique (`DATA_COLLAR_COLOR` déjà en commentaire). Note : `getBreedOffspring` (`IrradiatedCat.java:248-260`) appelle toujours `cat.setCollarColor(...)`/`cat2.getCollarColor()`, mais sur des `Cat` vanilla (API native Minecraft), sans rapport avec la mécanique retirée — laissé tel quel. **Worldgen « irradié » — template non terminé** *(inchangé)* - `IrradiatedBiomes.addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent toujours du contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`). @@ -172,7 +170,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 10. Flicker vitesse de sortie en fin de ressources (oscillateur `overHeat` × division entière `RPM_DIVIDER`) : ajouter une hystérésis sur le heat appliqué à `rotateOutputs`, seuil à valider (§1). **Décisions produit (choisir puis exécuter)** -11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4). +~~11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4).~~ ✅ **fait le 2026-07-11** — mécanique retirée entièrement (§4). 12. `PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK (l.56-61 : variable morte + référence à `ReactorLiquidInput` inexistant), le bloc créatif TANK_TO_ITEM (l.69-71 : vide), et simplifier l.88 (`instanceof` toujours vrai). `ReactorOutput.SPEED` : retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). **Chantier de fond (le plus rentable à long terme)** diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 423cf4ff..62a8f9f6 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-28T17:14:06.741002 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-07-11T21:44:40.1947842 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -dc54adf8c8c1b59d29350e21b25cff0944a33559 assets/createnuclear/lang/en_ud.json -599851e1479c4ce135a120f7ab850b3043897965 assets/createnuclear/lang/en_us.json +6fc3f1ba9893df163bc9dc3208342eaf271b7cb7 assets/createnuclear/lang/en_ud.json +c411e7160186d59d54c2c499ce6af3163b0653f9 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 4b5bae1d..5cc37c4a 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -327,6 +327,7 @@ "fluid.createnuclear.uranium": "ɯnıuɐɹ∩ pınbıꞀ", "gui.createnuclear.reactor_controller.title": "ɹǝןןoɹʇuoƆ ɹoʇɔɐǝᴚ", "gui.createnuclear.reactor_input.title": "ǝbɐɹoʇS ʇnduI ɹoʇɔɐǝᴚ", + "irradiated.taming.wip": "ssǝɹboɹd uı ʞɹoʍ ɐ ןןıʇs ǝɹɐ sqoɯ pǝʇɐıpɐɹɹı - ʇǝʎ pǝɯɐʇ ǝq ʇouuɐɔ ǝɹnʇɐǝɹɔ sıɥ⟘", "item.createnuclear.biome_restore_cell": "ןןǝƆ ǝɹoʇsǝᴚ ǝɯoıᗺ", "item.createnuclear.black_cloth": "ɥʇoןƆ ʞɔɐןᗺ", "item.createnuclear.blue_cloth": "ɥʇoןƆ ǝnןᗺ", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 174c4cec..06a2ca67 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -327,6 +327,7 @@ "fluid.createnuclear.uranium": "Liquid Uranium", "gui.createnuclear.reactor_controller.title": "Reactor Controller", "gui.createnuclear.reactor_input.title": "Reactor Input Storage", + "irradiated.taming.wip": "This creature cannot be tamed yet - irradiated mobs are still a work in progress", "item.createnuclear.biome_restore_cell": "Biome Restore Cell", "item.createnuclear.black_cloth": "Black Cloth", "item.createnuclear.blue_cloth": "Blue Cloth", diff --git a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java index eff9865a..1ac5958b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/contraptions/irradiated/AnimalUtil.java @@ -1,8 +1,13 @@ package net.nuclearteam.createnuclear.content.contraptions.irradiated; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.Level; import net.nuclearteam.createnuclear.CNItems; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import java.util.function.Predicate; @@ -20,4 +25,16 @@ public static boolean isFood(ItemStack stack, Ingredient foodItems, Predicate Date: Sun, 12 Jul 2026 13:00:54 +0200 Subject: [PATCH 140/171] refactor: remove unused monsters() stub from IrradiatedBiomes The monsters() method was an empty no-op stub (body was blank) and its only call site, inside the irradiated() biome builder, passed hardcoded weights that had no effect. Both the method declaration and the call are removed; mob-spawn settings for the irradiated biome are now controlled solely by the MobSpawnSettings.Builder directly, without a dead forwarding layer. --- .../infrastructure/worldgen/biome/IrradiatedBiomes.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 7216d955..5732706b 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -14,9 +14,6 @@ public static Biome createPlain(HolderGetter featureLookup, Holde return IrradiatedBiomes.irradiated(featureLookup, carverLookup, new BiomeGenerationSettings.Builder(featureLookup, carverLookup)); } - public static void monsters(MobSpawnSettings.Builder builder, int zombieWeight, int zombieVillagerWeight, int skeletonWeight) { - } - public static void addDefaultIrradiatedOres(BiomeGenerationSettings.Builder builder) { builder.addFeature(GenerationStep.Decoration.UNDERGROUND_STRUCTURES, MiscOverworldPlacements.BLUE_ICE); builder.addCarver(GenerationStep.Carving.AIR, Carvers.NETHER_CAVE); @@ -52,7 +49,6 @@ public static Biome irradiated(HolderGetter featureGetter, Holder IrradiatedBiomes.addDefaultIrradiatedOres(generation); IrradiatedBiomes.addDefaultSoftDisks(generation); - IrradiatedBiomes.monsters(spawnBuilder, 95, 5, 100); return new Biome.BiomeBuilder() .mobSpawnSettings(spawnBuilder.build()) From b70bb7fa4269ae235971980d57975335b07ffe96 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 13:30:14 +0200 Subject: [PATCH 141/171] docs: update AUDIT_ACTUEL.md to reflect IrradiatedBiomes.monsters() removal and surface stale PlayerInteractReactorFluidInput entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump last-updated date to 2026-07-12 (through commit 8b0428e3). - §4 dead-code section: strike through IrradiatedBiomes.monsters() as resolved (commit 8b0428e3, 2026-07-12); strike through the PlayerInteractReactorFluidInput dead-code block and annotate it as already fixed on 2026-07-03 (f2490469) — the four problems (dead variable fluidInItem, dangling reference to non-existent ReactorLiquidInput, empty TANK_TO_ITEM creative block, always-true instanceof) were suppressed in that commit but the audit entry had incorrectly been expanded rather than closed. - §6 fix log: add two new entries documenting both corrections with context and commit references. - Roadmap item #6: mark IrradiatedBiomes.monsters() removal as done (8b0428e3). - Roadmap item #12: strike through the PlayerInteractReactorFluidInput sub-task; leave ReactorOutput.SPEED open as the only remaining item under that point. --- AUDIT_ACTUEL.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index e502228b..aa3e7caf 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -1,6 +1,6 @@ # Audit consolidé — CreateNuclearForge (branche V2-CorrectifAudit) -**Dernière mise à jour : 2026-06-28 (après commits `2aaddb4d`, `562ce99d`, `30de52a7`).** Nouvel audit indépendant réalisé en repartant exclusivement du code actuel (`src/main/java`, **291 fichiers, ~25 070 lignes**, hors `src/generated` et `src/main/resources`). `AUDIT_V1.md` et l'historique de ce fichier (versions précédentes) n'ont servi qu'à comparer les résultats — chaque point a été **revérifié par lecture directe des fichiers cités** (et, pour les zones les plus actives, par `git show`/`git log` sur les commits du 2026-06-24 au 2026-06-28). +**Dernière mise à jour : 2026-07-12 (après commits jusqu'à `8b0428e3` inclus).** Nouvel audit indépendant réalisé en repartant exclusivement du code actuel (`src/main/java`, **291 fichiers, ~25 070 lignes**, hors `src/generated` et `src/main/resources`). `AUDIT_V1.md` et l'historique de ce fichier (versions précédentes) n'ont servi qu'à comparer les résultats — chaque point a été **revérifié par lecture directe des fichiers cités** (et, pour les zones les plus actives, par `git show`/`git log` sur les commits du 2026-06-24 au 2026-06-28). > Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §6 pour mémoire, puis ne sont plus repris. @@ -89,16 +89,10 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to **Pur dead code (retrait sûr)** - ~~**`lib/multiblock/SimpleMultiBlockPattern.java` méthode `test()`**~~ ✅ **Retiré** — confirmé par `git diff` : la méthode a disparu du fichier de travail, aucun appelant n'était présent. -- **`IrradiatedBiomes.monsters()`** — corps toujours vide (`IrradiatedBiomes.java:17-18`), appelé avec des arguments (95, 5, 100) silencieusement ignorés (l.55). À retirer ou implémenter. +- ~~**`IrradiatedBiomes.monsters()`**~~ ✅ **Retiré le 2026-07-12** (`8b0428e3`) — la méthode (corps vide) et son unique site d'appel dans le builder du biome irradié ont été supprimés ; les réglages de spawn du biome irradié passent désormais uniquement par `MobSpawnSettings.Builder`. **Code commencé puis abandonné (hygiène de fin de PR)** -- `content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java:57-61` *(fichier renommé — suppression du 'e' parasite dans "Interacte")* — quatre problèmes distincts, tous du dead code : - 1. **L.57** : `FluidStack fluidInItem = GenericItemEmptying.emptyItem(level, stack, true).getFirst()` — variable calculée uniquement pour les lignes commentées en-dessous ; jamais utilisée ailleurs. L'appel simule (`true`) donc pas de mutation, mais le calcul est inutile. - 2. **L.58-60** : bloc commenté qui référence `ReactorLiquidInput` — classe **inexistante** dans le projet (renommée en `ReactorFluidInputEntity`), avec une invocation tronquée `fluidInInput.set` jamais complétée. Code définitivement abandonné, non récupérable tel quel. - 3. **L.69-71** : bloc `if (player.isCreative() && !onClient) { }` entièrement vide sous `TANK_TO_ITEM` — dead code pur. - 4. **L.88** : `if (be instanceof ReactorFluidInputEntity)` — `be` est déjà casté en `ReactorFluidInputEntity` à la ligne 31 et null-checké à la ligne 32 ; ce `instanceof` est **toujours vrai**, branche morte. À simplifier en retirant la condition. - - Note de contexte : `ReactorFluidInput.use()` interdit déjà toute interaction non-creative avant d'appeler `interact()` → les gardes `player.isCreative()` à l'intérieur de `interact()` sont redondantes (toujours vraies). - - **Action** : supprimer les lignes 56-61 (bloc créatif ITEM_TO_TANK entier), supprimer les lignes 69-71 (bloc créatif TANK_TO_ITEM vide), simplifier la condition l.88. +- ~~`content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java:57-61` — quatre problèmes de dead code~~ ✅ **Déjà corrigé le 2026-07-03** (`f2490469`) — **stale depuis la mise à jour précédente de ce document** : ce commit avait renommé le fichier (suppression du 'e' parasite dans "Interacte") et **supprimé** les 4 problèmes (variable morte `fluidInItem`, bloc commenté référençant `ReactorLiquidInput` inexistant, bloc vide `TANK_TO_ITEM`, `instanceof` toujours vrai) directement dans le `.java`, mais la description ci-dessus n'avait, par erreur, pas été retirée de l'audit — elle avait au contraire été détaillée davantage dans ce même commit. Vérifié par lecture directe du fichier actuel (`PlayerInteractReactorFluidInput.java`) : plus aucun des 4 problèmes n'est présent. - `content/multiblock/output/ReactorOutput.java:43,52,87` — propriété `SPEED` toujours entièrement commentée (pas supprimée). *(Numéros de lignes mis à jour : l.93 → l.87 après décalage.)* - `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. @@ -149,6 +143,10 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Corrigé le 2026-07-11** : `ReactorFrameDisplayManager.write` (ex-§2 point 7) persistait systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` était faux. `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit désormais `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque de régression : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse les champs à leurs valeurs par défaut (identique à l'état pré-assignation). +**Corrigé le 2026-07-03** : `PlayerInteractReactorFluidInput` (ex-§4, renommage + 4 problèmes de dead code). Fichier renommé (`PlayerInteracteReactorFluidInput` → `PlayerInteractReactorFluidInput`, suppression du 'e' parasite) et nettoyé (`f2490469`) : variable morte `fluidInItem`, bloc commenté référençant la classe inexistante `ReactorLiquidInput`, bloc vide `TANK_TO_ITEM`, et `instanceof ReactorFluidInputEntity` toujours vrai (branche morte) — tous supprimés. *(Correction bien réelle dans le code depuis le 2026-07-03, mais était restée décrite comme non résolue dans ce document jusqu'au 2026-07-12 — staleness de documentation repérée et corrigée à cette date.)* + +**Corrigé le 2026-07-12** : `IrradiatedBiomes.monsters()` (ex-§4, `8b0428e3`) — méthode au corps vide et son unique site d'appel (arguments 95/5/100 silencieusement ignorés) supprimés ; les réglages de spawn du biome irradié passent désormais uniquement par `MobSpawnSettings.Builder`, sans couche de délégation morte. + **Corrigé le 2026-07-11** : duplication `drawGauge` (ex-§2 point 8). Nouvelle classe `ReactorGaugeRenderer.drawGauge` centralise le rendu de jauge, jusque-là copié à l'identique dans 5 classes. `FuelDisplaySource`, `CoolerDisplaySource`, `HeatDisplaySource` et `LiquidLevelDisplaySource` héritent désormais d'un nouveau template `AbstractReactorStatDisplaySource extends NumericSingleLineDisplaySource` (`provideLine`, `initConfigurationWidgets`, `allowsLabeling` mutualisés ; chaque sous-classe ne fournit plus que `getLabelKey`, `getMax`, `computeValue`, `getColor`, et optionnellement `getUnitSuffix`). `ReactorSummaryDisplaySource` reste sur `DisplaySource` (structure multi-lignes non compatible avec le template single-line) mais appelle désormais `ReactorGaugeRenderer.drawGauge` au lieu de sa propre copie. Les magic numbers des 5 classes (les 4 sous-classes migrées **et** `ReactorSummaryDisplaySource`, l.150-153) sont désormais tous nommés dans `ReactorDisplayConstants`. Vérifié par lecture directe des 8 fichiers concernés et par `Grep` confirmant l'usage de `ReactorDisplayConstants.MAX_*` partout où figuraient auparavant `64`/`16000`/`1000` en dur. `ReactorSizeDisplaySource` a été délibérément exclue du template (jauge à 3 segments discrets par tier, sémantique incompatible avec un ratio `current/max`) — elle n'avait de toute façon pas de `drawGauge` dupliqué. Déduplication complète, aucun point résiduel. --- @@ -161,7 +159,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B 3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). 4. ~~`IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance.~~ ✅ **fait le 2026-07-05** — voir §6 pour le changement de comportement associé à valider en jeu. 5. ~~`git rm --cached` sur les 6 fichiers de debug `run/` (§4).~~ ✅ **fait le 2026-06-28** -6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait le 2026-06-28** (commit `2aaddb4d`) et retirer `IrradiatedBiomes.monsters()` (toujours à faire). +6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait le 2026-06-28** (commit `2aaddb4d`) et ~~retirer `IrradiatedBiomes.monsters()`~~ ✅ **fait le 2026-07-12** (commit `8b0428e3`). **Corrections ciblées (risque faible à moyen)** 7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). @@ -171,7 +169,7 @@ Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B **Décisions produit (choisir puis exécuter)** ~~11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4).~~ ✅ **fait le 2026-07-11** — mécanique retirée entièrement (§4). -12. `PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK (l.56-61 : variable morte + référence à `ReactorLiquidInput` inexistant), le bloc créatif TANK_TO_ITEM (l.69-71 : vide), et simplifier l.88 (`instanceof` toujours vrai). `ReactorOutput.SPEED` : retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). +12. ~~`PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK...~~ ✅ **fait le 2026-07-03** (`f2490469`, staleness de documentation corrigée le 2026-07-12 — voir §6). *Reste ouvert* : `ReactorOutput.SPEED` — retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). **Chantier de fond (le plus rentable à long terme)** 13. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. From 3a809987853b5862d5da5c73169d33d07fa9c116 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 14:25:11 +0200 Subject: [PATCH 142/171] feat: add ambient Geiger-counter sounds to the irradiated biome MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire two CNSoundEvents entries into the irradiated_land biome definition so players hear a persistent audio cue when inside the biome: - IrradiatedBiomes: createPlain() and irradiated() now accept a HolderGetter parameter; the effectBuilder is extended with ambientLoopSound (GEIGER_LOW) and ambientAdditionsSound (GEIGER_MEDIUM, tick_chance 0.0111). - CNBiomes.bootstrapRegistries: resolves a SoundEvent HolderGetter from the registry context and forwards it to IrradiatedBiomes.createPlain(). - irradiated_land.json: regenerated — ambient_sound and additions_sound entries now present in the biome JSON. Also removes ReactorRodInputEntity.readInventory(), an unused public method that duplicated inventory.deserializeNBT() without callers. --- .../fed443662143001aeb5341375f6f5ef31d10baea | 4 ++-- .../worldgen/biome/irradiated_land.json | 5 +++++ .../input/item/ReactorRodInputEntity.java | 5 ----- .../worldgen/biome/CNBiomes.java | 5 +++-- .../worldgen/biome/IrradiatedBiomes.java | 18 ++++++++++++++---- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 3e1f0c7a..4d8d75f6 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-06-24T11:36:24.8723899 CreateNuclear Generated Registry Entries +// 1.20.1 2026-07-12T14:09:29.2536256 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -10,7 +10,7 @@ afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids 72173023e6a31748692e750db0f5fa8c555d1009 data/createnuclear/forge/biome_modifier/striated_ores_overworld.json 1d15657126bab7c0b4355d0dcb9addc2d417ed01 data/createnuclear/forge/biome_modifier/thorium_ore.json fa32145101dc12ec914684fec8c5cbb995d2c051 data/createnuclear/forge/biome_modifier/uranium_ore.json -738687a49c3cd8473d1c511f55e274637fe44478 data/createnuclear/worldgen/biome/irradiated_land.json +291523426e13be57633005f545b13a3d6c52f752 data/createnuclear/worldgen/biome/irradiated_land.json 211d1391981d173b8bc490e5af1471441e1df37f data/createnuclear/worldgen/configured_feature/lead_ore.json c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_feature/nitrate_ore.json 4f11c0a518c0de7857919983fc638ba551c6630a data/createnuclear/worldgen/configured_feature/striated_ores_overworld.json diff --git a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json index 7570a5c4..adbd57b2 100644 --- a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json +++ b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json @@ -4,6 +4,11 @@ }, "downfall": 0.0, "effects": { + "additions_sound": { + "sound": "createnuclear:geiger/medium", + "tick_chance": 0.0111 + }, + "ambient_sound": "createnuclear:geiger/low", "fog_color": 4742718, "foliage_color": 5660222, "grass_color": 9211739, diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java index 72cec9c9..6fb2089c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/input/item/ReactorRodInputEntity.java @@ -61,11 +61,6 @@ protected void read(CompoundTag tag, boolean clientPacket) { } } - public void readInventory(CompoundTag compound) { - inventory.deserializeNBT(compound); - } - - @Nullable @Override public Level getLevel() { diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java index c8b562e8..ead5d665 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/CNBiomes.java @@ -4,6 +4,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.BootstapContext; import net.minecraft.resources.ResourceKey; +import net.minecraft.sounds.SoundEvent; import net.minecraft.world.level.biome.*; import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; import net.minecraft.world.level.levelgen.placement.PlacedFeature; @@ -18,8 +19,8 @@ public static final class Irradiated { public static void bootstrapRegistries(BootstapContext context) { HolderGetter featureLookup = context.lookup(Registries.PLACED_FEATURE); HolderGetter> carverLookup = context.lookup(Registries.CONFIGURED_CARVER); - - context.register(Irradiated.PLAIN, IrradiatedBiomes.createPlain(featureLookup, carverLookup)); + HolderGetter soundLookup = context.lookup(Registries.SOUND_EVENT); + context.register(Irradiated.PLAIN, IrradiatedBiomes.createPlain(featureLookup, carverLookup, soundLookup)); } public static @NotNull ResourceKey key(String id) { diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 5732706b..91c52244 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -1,17 +1,21 @@ package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; import net.minecraft.core.HolderGetter; +import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.Carvers; import net.minecraft.data.worldgen.placement.MiscOverworldPlacements; +import net.minecraft.resources.ResourceKey; +import net.minecraft.sounds.SoundEvent; import net.minecraft.world.level.biome.*; import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.nuclearteam.createnuclear.CNSoundEvents; import net.nuclearteam.createnuclear.content.particles.IrradiatedParticlesData; public class IrradiatedBiomes { - public static Biome createPlain(HolderGetter featureLookup, HolderGetter> carverLookup) { - return IrradiatedBiomes.irradiated(featureLookup, carverLookup, new BiomeGenerationSettings.Builder(featureLookup, carverLookup)); + public static Biome createPlain(HolderGetter featureLookup, HolderGetter> carverLookup, HolderGetter soundLookup) { + return IrradiatedBiomes.irradiated(featureLookup, carverLookup, soundLookup, new BiomeGenerationSettings.Builder(featureLookup, carverLookup)); } public static void addDefaultIrradiatedOres(BiomeGenerationSettings.Builder builder) { @@ -23,7 +27,7 @@ public static void addDefaultSoftDisks(BiomeGenerationSettings.Builder builder) builder.addFeature(GenerationStep.Decoration.SURFACE_STRUCTURES, MiscOverworldPlacements.VOID_START_PLATFORM); } - public static Biome irradiated(HolderGetter featureGetter, HolderGetter> carverGetter, BiomeGenerationSettings.Builder generation) { + public static Biome irradiated(HolderGetter featureGetter, HolderGetter> carverGetter, HolderGetter soundLookup, BiomeGenerationSettings.Builder generation) { MobSpawnSettings.Builder spawnBuilder = new MobSpawnSettings.Builder(); BiomeSpecialEffects.Builder effectBuilder = new BiomeSpecialEffects.Builder(); @@ -45,7 +49,13 @@ public static Biome irradiated(HolderGetter featureGetter, Holder .foliageColorOverride(0x565E3E) .ambientParticle(new AmbientParticleSettings(new IrradiatedParticlesData(), 0.025F)) - .ambientMoodSound(AmbientMoodSettings.LEGACY_CAVE_SETTINGS); + .ambientMoodSound(AmbientMoodSettings.LEGACY_CAVE_SETTINGS) + .ambientLoopSound(soundLookup.getOrThrow(ResourceKey.create(Registries.SOUND_EVENT, CNSoundEvents.GEIGER_LOW.getId()))) + .ambientAdditionsSound(new AmbientAdditionsSettings( + soundLookup.getOrThrow(ResourceKey.create(Registries.SOUND_EVENT, CNSoundEvents.GEIGER_MEDIUM.getId())), + 0.0111 + )) + ; IrradiatedBiomes.addDefaultIrradiatedOres(generation); IrradiatedBiomes.addDefaultSoftDisks(generation); From c85695c739445805a5541cdfb394133418701b53 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 14:48:44 +0200 Subject: [PATCH 143/171] =?UTF-8?q?docs:=20restructure=20AUDIT=5FACTUEL.md?= =?UTF-8?q?=20=E2=80=94=20keep=20only=20open=20issues=20in=20=C2=A71?= =?UTF-8?q?=E2=80=93=C2=A77,=20archive=20resolved=20items=20in=20new=20?= =?UTF-8?q?=C2=A78?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The document had grown unwieldy: resolved items were interleaved as strikethroughs among open issues across every section, making it increasingly difficult to read the current action list without navigating resolved context. This reorganisation applies a strict separation: - §1–§7 now contain **only open or unvalidated items**; each section header updated accordingly. - New §8 "Mémoire" (four subsections): - §8.1 — all confirmed corrections, each with commit hash, date, and a one-line summary; 16 entries covering everything from `8b0428e3` (IrradiatedBiomes.monsters()) back to `b309f231` (LOGGER spam). Commit hashes researched via `git log -S` where possible; canditate-only or unresolved cases annotated explicitly. - §8.2 — architecture affirmations from AUDIT_V1 that were refuted (no hash applicable — the alleged problems never existed or are the result of many accumulated commits). - §8.3 — product decisions that were executed (collar mechanic removal, WIP taming block). - §8.4 — AUDIT_V1 historical corrections for which no confident commit hash was found; scope and methodology documented for any future archaeology. Other changes in this reorganisation: - §0 updated: notes the stale "flicker" entry discovered during review (was documented as fully open, code correction already applied by `a18038db`); item reclassified in §1 as "partially resolved, in-game validation remaining." - New §6: code documentation audit — 14 files (~5 %) with French-only comments on non-trivial logic; worst cases listed (VicinityEffect.java, CNPonderReactorScenes.java Javadoc), priority set to cosmetic/progressive. - §7 roadmap fully rewritten: 9 numbered categories ordered by impact rather than the old quick-wins / targeted-fixes / product-decisions split. - ReactorOutput.SPEED stale line numbers corrected (l.43/52/87 → l.56/91). - §4 worldgen section: file/line references made explicit; dead-code pure items removed (now in §8.1). - §5 priority table trimmed to the two remaining open points. --- AUDIT_ACTUEL.md | 254 ++++++++++++++++++++++++++++-------------------- 1 file changed, 151 insertions(+), 103 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index aa3e7caf..7438a71f 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -1,56 +1,48 @@ # Audit consolidé — CreateNuclearForge (branche V2-CorrectifAudit) -**Dernière mise à jour : 2026-07-12 (après commits jusqu'à `8b0428e3` inclus).** Nouvel audit indépendant réalisé en repartant exclusivement du code actuel (`src/main/java`, **291 fichiers, ~25 070 lignes**, hors `src/generated` et `src/main/resources`). `AUDIT_V1.md` et l'historique de ce fichier (versions précédentes) n'ont servi qu'à comparer les résultats — chaque point a été **revérifié par lecture directe des fichiers cités** (et, pour les zones les plus actives, par `git show`/`git log` sur les commits du 2026-06-24 au 2026-06-28). +**Réorganisation du 2026-07-12 (HEAD `8b0428e3`).** Ce document a été restructuré pour ne conserver dans ses sections principales (§1 à §7) **que les problèmes encore ouverts**. Tout ce qui est corrigé, réfuté ou décidé (produit) a été déplacé en **§8 Mémoire**, avec le hash du commit correspondant quand il a pu être déterminé avec certitude par archéologie Git (`git log -S`, `git show`, `git blame`) — sinon c'est indiqué explicitement, sans hash inventé. -> Ce document ne liste que **ce qui reste à corriger ou à décider**. Les bugs résolus sont récapitulés en §6 pour mémoire, puis ne sont plus repris. +**Méthodologie de cette réorganisation** : nouvelle relecture complète du code actuel (`src/main/java`, **292 fichiers**, hors `src/generated`/`src/main/resources`), croisée avec `AUDIT_V1.md`, les versions précédentes de ce fichier, et l'historique Git (`git log`, 1437 commits au total sur le dépôt) — aucun des deux audits n'a été pris comme vérité absolue : plusieurs points ont été revérifiés directement dans le code et un point s'est avéré **périmé** (voir §0). -**Limite de couverture honnête** : les bugs mineurs/robustesse listés au §1 de l'historique (`B7, B10, B17, B18` et la liste « mineurs » non numérotée d'`AUDIT_V1.md`) n'ont pas été re-vérifiés ici faute de signal de changement — ni confirmés ni infirmés, à re-vérifier ponctuellement avant traitement. +**Limite de couverture honnête** : les bugs mineurs/robustesse listés au §1 de l'historique (`B7, B10, B17, B18` et la liste « mineurs » non numérotée d'`AUDIT_V1.md`) n'ont pas été re-vérifiés faute de signal de changement — ni confirmés ni infirmés, à re-vérifier ponctuellement avant traitement. Beaucoup de corrections d'`AUDIT_V1.md` (B1, B2, B4, B5, B9, B13, B18, et l'essentiel des listes de dead code) sont antérieures à la fenêtre de commits explorée en détail (avant le 2026-06-24) ; l'archéologie Git ciblée sur ces items n'a pas abouti à un hash certain dans la majorité des cas — voir §8.4. --- ## 0. Constat global -Depuis le dernier audit (2026-06-24), le projet a continué d'évoluer activement (16 commits en 4 jours) : extraction de `CNBuilderTransformers` (SRP propre, 97 lignes, 3 builders isolés), ajout de l'item **Biome Restore Cell** (code neuf, propre, bien isolé dans `BiomeRestoreCellItem`/`BiomeIrradiationService`), refonte du système de radiation pour couvrir **toutes les `LivingEntity`** et non plus seulement les joueurs (`9ded502c`), centralisation de l'attribution des advancements de pose via le contrôleur plutôt que la pièce posée (`19617118`), et suppression du `LOGGER.warn` redondant dans `ReactorAssembler` (`b309f231`, **quick win déjà traité**). +Depuis la dernière consolidation (2026-06-28), le projet a continué d'évoluer : retrait de `IrradiatedBiomes.monsters()` (`8b0428e3`), blocage explicite (message "WIP") de l'apprivoisement des mobs irradiés (`261b26d8`), retrait complet de la mécanique de collier teignable jamais câblée (`17b29aa3`), correction de la tautologie `IHeat.isNotDanger` et ajout d'une hystérésis sur le heat appliqué aux sorties (`fb0897d3`, `a18038db`), guard NBT sur `ReactorFrameDisplayManager.write` (`381c7a5f`), et déduplication complète de `drawGauge` via `ReactorGaugeRenderer`/`AbstractReactorStatDisplaySource` (`35e474e3`, `d0da13d1`, `a8b6b23f`). Détail de chaque correction en §8.1. -Aucun de ces changements ne casse les acquis des audits précédents : le point de vérité unique radiation (`canBeIrradiated`) tient toujours, l'extension aux mobs ne boucle pas sur le monde (elle s'appuie sur `LivingTickEvent`, déclenché nativement par tick et par entité), et la centralisation des advancements est un vrai gain (élimine un risque de double-attribution). Un commit au message trompeur (`20c1df0b`, *"IO blocks are now natively Casings"*) ne change **rien** à l'architecture : il ne fait que nettoyer 22 lignes d'une scène Ponder ; les blocs I/O (`ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`) restent des classes `Block` séparées de `ReactorCasing`. +**Point périmé trouvé lors de cette réorganisation** : l'item « Flicker vitesse de sortie en fin de ressources » était encore documenté en §1 comme un bug entièrement ouvert, proposant comme correction l'ajout d'un champ `lastAppliedOutputHeat` avec hystérésis sur `RPM_DIVIDER/2. **Cette correction a en réalité déjà été appliquée** par le commit `a18038db` (2026-07-05) — vérifié par lecture directe : `ReactorControllerBlockEntity.java:62` (champ `lastAppliedOutputHeat`), `:430-433` (comparaison au seuil et appel à `rotateOutputs` avec la valeur bufferisée). Le commit lui-même documente que le point reste partiellement ouvert : l'oscillateur `overHeat` sous-jacent (+1/-2 par tick) n'est pas supprimé, seul son symptôme visible (flicker RPM) est amorti, et le seuil de l'hystérésis n'a pas été validé en jeu. L'item est donc reclassé en §1 comme **partiellement résolu, validation en jeu restante** plutôt que comme bug non traité — voir §1. -**Nouveauté la plus significative de cet audit** : en creusant le scan multiblock fusionné (déjà crédité « corrigé » au tour précédent), la boucle partagée `scanControllerCandidates` (`ReactorPattern.java:40-56`) ne court-circuite en réalité que via `findControllerPos` (utilisé par `MultiblockHelpers`, donc par `ReactorOutput`/`ReactorRodInput`/`ReactorFluidInput`/`ReactorAlarm`). La méthode `findController` — appelée **directement** par `ReactorCasing`, `ReactorCooler` et `ReactorFrame` — a un visiteur qui retourne toujours `false` et **ne s'arrête jamais avant d'avoir parcouru les ~3971 positions** de la zone de recherche, même après avoir trouvé et traité le contrôleur pertinent. Comme `ReactorCasing` constitue le gros de la coque d'un réacteur (le bloc le plus posé/cassé), c'est en réalité le chemin le plus coûteux des deux — voir §2 point 1. +**Nouveau point d'audit ajouté** : qualité et langue de la documentation du code (Javadoc, commentaires, noms de symboles) — voir §6. Un premier signal existait déjà dans `AUDIT_V1.md` §5 (« commentaires FR/EN mêlés ») mais n'avait jamais été centralisé ni suivi comme item d'audit à part entière. -**Depuis cette mise à jour**, trois commits supplémentaires : retrait de `SimpleMultiBlockPattern.test()` (`2aaddb4d`, quick win déjà acquis), puis l'exécution en deux temps du chantier « tags vs `RodType` » assigné à Gio — `562ce99d` migre l'essentiel (5 des 6 sites) et enfile enfin `Level` jusqu'à `DefaultHeatCalculator`, et `30de52a7` corrige les deux sites manqués par le premier commit (`ReactorBluePrintMenu`, lookup du voisin dans `DefaultHeatCalculator`). Le chantier est désormais **intégralement terminé et cohérent** (vérifié par grep : plus aucun site de classification ne lit `CNItemTags.FUEL`/`COOLER`, seules les déclarations de tag de craft dans `CNItems.java` subsistent) — voir §2 point 8, reclassé en §6. - -La dette la plus structurelle reste **l'absence totale de tests** (`src/test` toujours vide, confirmé) — précisément là où des bugs silencieux (sur-extraction fluide, tautologie `IHeat`, scan non court-circuité) survivent à plusieurs passes d'audit. Ce chantier de classification illustre d'ailleurs bien le risque : la première passe (`562ce99d`) a laissé passer deux sites incohérents, repérés seulement par relecture manuelle puis corrigés en quelques minutes (`30de52a7`) — un test unitaire sur `TypeRodPredicate.isFuel/isCooled` aurait détecté l'écart immédiatement. +La dette la plus structurelle reste **l'absence totale de tests** (`src/test` toujours vide, reconfirmé — 0 fichier `.java`) — précisément là où des bugs/incohérences silencieux (sur-extraction fluide, ex-tautologie `IHeat`, scan non court-circuité, doc devenue obsolète sans que personne ne le remarque) survivent à plusieurs passes d'audit. Voir §3 et §7. --- -## 1. 🐛 Bugs confirmés toujours présents (revérifiés) +## 1. 🐛 Bugs confirmés ouverts -| Réf. | Fichier:ligne | Gravité | Détail (vérifié 2026-06-28) | +| Réf. | Fichier:ligne | Gravité | Détail (revérifié 2026-07-12) | |---|---|---|---| -| **ReactorInputFluidManager — sur-extraction** | `controller/manager/ReactorInputFluidManager.java:137-155` | 🟠 | `fluidNeeded` (paramètre de `extractFluids`) n'est **toujours jamais décrémenté** entre handlers (l.146-151) → chaque handler de la boucle tente d'extraire le besoin complet, sur-extraction possible avec plusieurs inputs. `if (toExtract > 1)` (l.147) ignore toujours les extractions de 1 unité. Toléré aujourd'hui (tank mono-slot), reste une violation de contrat latente. | -| **Flicker vitesse de sortie en fin de ressources (`overHeat` + division entière)** *(nouveau, trouvé 2026-07-05)* | `content/multiblock/reactorLogic/DefaultOverheatController.java:13-30` + `controller/manager/ReactorOutputManager.java:90` | 🟡 | `overHeat` s'incrémente de `+1` (fluide insuffisant) et se décrémente de `-2` (fluide suffisant) à un rythme régulier — un oscillateur auto-entretenu, **indépendant de tout réapprovisionnement**. Ce `overHeat` est additionné au heat des barres (`DefaultHeatCalculator.java:93`) puis divisé en entier par `RPM_DIVIDER=32` (`ReactorOutputManager.java:90`) pour obtenir le RPM des sorties. En fin de ressources, le heat de base est faible et peut se trouver juste à cheval sur un multiple de 32 : le va-et-vient de `overHeat` fait alors basculer la vitesse de sortie entre `0` et `X` en boucle, sans lien avec le stock de combustible. Hystérésis sur le heat appliqué à `rotateOutputs` dans `ReactorControllerBlockEntity.handleAssembledState` (nouveau champ `lastAppliedOutputHeat`, ne réactualiser que si `\|heat - lastAppliedOutputHeat\| >= RPM_DIVIDER/2`). Pas besoin de persister ce champ en NBT (comme `heat`/`totalHeatRatio`, recalculé chaque tick). | +| **ReactorInputFluidManager — sur-extraction** | `controller/manager/ReactorInputFluidManager.java:137-155` | 🟠 | `fluidNeeded` (paramètre de `extractFluids`) n'est **toujours jamais décrémenté** entre handlers (l.146-151) → chaque handler de la boucle tente d'extraire le besoin complet, sur-extraction possible avec plusieurs inputs. `if (toExtract > 1)` (l.147) ignore toujours les extractions de 1 unité. **Détail supplémentaire trouvé cette revue** : la garde `if (fluidNeeded <= 0) break;` (l.151) est **du code mort** — `fluidNeeded` n'étant jamais réassigné dans la boucle, cette condition ne peut être vraie que si le paramètre est déjà ≤ 0 en entrée. Toléré aujourd'hui (tank mono-slot en pratique), reste une violation de contrat latente. | +| **Flicker vitesse de sortie en fin de ressources — partiellement corrigé, validation en jeu restante** *(reclassé le 2026-07-12, code de correction déjà présent depuis `a18038db`, 2026-07-05)* | `content/multiblock/reactorLogic/DefaultOverheatController.java:13-30` + `controller/ReactorControllerBlockEntity.java:430-433` | 🟡 | `overHeat` continue de s'incrémenter de `+1`/`-2` à un rythme régulier, indépendamment du réapprovisionnement — l'oscillateur de base n'a **pas** été supprimé. Mais son symptôme (bascule de vitesse de sortie entre `0` et `X`) est désormais amorti : `ReactorControllerBlockEntity` ne réapplique `rotateOutputs` que si `\|heat - lastAppliedOutputHeat\| >= RPM_DIVIDER/2` (code vérifié présent). **Reste ouvert** : (1) valider en jeu que ce seuil élimine réellement la perception du flicker en fin de ressources (le commit d'origine le signale lui-même comme non validé) ; (2) décider si l'oscillateur `overHeat` doit être revu à la racine ou si l'hystérésis en aval suffit durablement. | --- -## 2. 🆕 Autres problèmes (hors radiation) +## 2. 🆕 Autres problèmes ouverts (hors radiation, hors documentation) -### 🟠 Important — performance résiduelle du scan multiblock (était 🔴, deux des trois sous-points corrigés le 2026-06-28) +### 🟠 Important — performance résiduelle du scan multiblock -1. **Scan géométrique du contrôleur : court-circuit incomplet (findController)** *(garde client et double scan corrigés 2026-06-28, vérifié par lecture directe du code modifié)* - - ✅ **Toujours acquis** — `ReactorPattern` n'a qu'**une seule** boucle de scan partagée (`scanControllerCandidates`, `ReactorPattern.java:40-56`) sur ~3971 positions (`y∈[-5,+5]`, `x,z∈[-9,+9]`), filtrée par `isInReactorRange` (l.111-113). - - ❌ **Toujours non corrigé** — le court-circuit (`return true` dans le visiteur dès qu'un contrôleur pertinent est trouvé) n'existe que dans **`findControllerPos`** (`ReactorPattern.java:73-94`, utilisé via `MultiblockHelpers.handleOnPlace/handleRemoval/getControllerForPart` → donc par `ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`). **`findController`** (`ReactorPattern.java:58-71`), appelé **directement** par `ReactorCasing.java:49,61`, `ReactorCooler.java:28,40` et `ReactorFrame.java:113,129`, a un visiteur qui **retourne toujours `false`** (l.69) : il continue de parcourir les ~3971 positions restantes même après avoir traité le contrôleur pertinent. `ReactorCasing` étant le bloc le plus posé/cassé (coque du réacteur), c'est le chemin le plus chaud des deux et il n'est **toujours pas** optimisé. Fix trivial inchangé : faire retourner `inRange` au lieu de `false` dans le visiteur de `findController`, comme c'est déjà fait dans `findControllerPos`. - - ✅ **Corrigé le 2026-06-28** — garde `level.isClientSide` ajoutée en tête de `ReactorAssembler.assemble` (`ReactorAssembler.java:34`) et `ReactorAssembler.disassemble` (l.58), plutôt que dans `findController`/`findControllerPos` comme envisagé initialement : ces deux méthodes sont le point de convergence unique de toute la chaîne (`findController` direct sur Casing/Cooler/Frame, et `findControllerPos` via `MultiblockHelpers` sur Alarm/Output/FluidInput/RodInput), donc une garde centralisée ici couvre l'intégralité du chemin `onPlace/onRemove/playerDestroy → ... → assemble/disassemble` sans dupliquer le test dans 7 classes de blocs. - - ✅ **Corrigé le 2026-06-28** — double scan à la casse résolu en généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel dans `onRemove`, pas de `playerDestroy`) : `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` n'ont plus d'override `playerDestroy` (vérifié par lecture directe des 6 fichiers — l'override a été supprimé, pas seulement vidé). Comme `onRemove` se déclenche déjà systématiquement lors d'une casse joueur (avant l'appel `playerDestroy` du `PlayerInteractionManager`), retirer l'appel redondant dans `playerDestroy` élimine le double scan sans changer de comportement observable. `ReactorAlarm`/`ReactorFrame` conservent en plus leur garde `!state.is(newState.getBlock())` dans `onRemove` (utile pour leurs propriétés mutables `POWERED`/`PART`). - - **Point résiduel mineur, non corrigé** — `ReactorOutput` (propriété `DIR`) et `ReactorFluidInput` (propriété `FACING`) ont une propriété mutable mais leur `onRemove` (`ReactorOutput.java:71-74`, `ReactorFluidInput.java:93-97`) n'a **pas** la garde `!state.is(newState.getBlock())`. Pas un bug confirmé (aucun chemin connu ne change `DIR`/`FACING` via `setBlock` sans remplacer le bloc) mais à surveiller si une interaction clé/wrench s'avère un jour déclencher un retrait/réenregistrement non désiré. - - ✅ **Corrigé et confirmé stable** — `ReactorAssembler.assemble` ne logue plus rien en succès (`ReactorAssembler.java`, vérifié : aucun `LOGGER.warn`/`LOGGER.info` dans `assemble`/`disassemble`). *(Quick win traité par le commit `b309f231`.)* - - *Reste à faire* : `findController` doit court-circuiter comme `findControllerPos` (1 ligne, gain net immédiat sur le chemin le plus chaud — Casing). Risque très faible, **reste la priorité n°1 du projet** (perf uniquement désormais, plus une question de correction). +1. **Scan géométrique du contrôleur : court-circuit incomplet (`findController`)** — **seul sous-point encore ouvert de ce chantier** (garde client-side et double scan à la casse : corrigés, voir §8.1). + `ReactorPattern` n'a qu'**une seule** boucle de scan partagée (`scanControllerCandidates`, `ReactorPattern.java:40-56`) sur ~3971 positions (`y∈[-5,+5]`, `x,z∈[-9,+9]`), filtrée par `isInReactorRange`. Le court-circuit (`return true` dans le visiteur dès qu'un contrôleur pertinent est trouvé) n'existe que dans **`findControllerPos`** (`ReactorPattern.java:73-94`, utilisé par `MultiblockHelpers` → `ReactorOutput`/`ReactorRodInput`/`ReactorFluidInput`/`ReactorAlarm`). **`findController`** (`ReactorPattern.java:58-71`, revérifié 2026-07-12 : le visiteur retourne toujours `false` l.69), appelé **directement** par `ReactorCasing.java`, `ReactorCooler.java` et `ReactorFrame.java`, continue de parcourir les ~3971 positions restantes même après avoir traité le contrôleur pertinent. `ReactorCasing` étant le bloc le plus posé/cassé (coque du réacteur), c'est le chemin le plus chaud du projet et il n'est **toujours pas** optimisé. + Fix trivial inchangé : faire retourner `inRange` au lieu de `false` dans le visiteur de `findController`, comme c'est déjà fait dans `findControllerPos`. **Reste la priorité n°1 du projet** (perf uniquement désormais, plus une question de correction — voir §7). + - **Point résiduel mineur, non corrigé, non confirmé comme bug** : `ReactorOutput` (propriété `DIR`) et `ReactorFluidInput` (propriété `FACING`) ont une propriété mutable mais leur `onRemove` n'a pas la garde `!state.is(newState.getBlock())` présente sur `ReactorAlarm`/`ReactorFrame`. Aucun chemin connu ne change `DIR`/`FACING` via `setBlock` sans remplacer le bloc, mais à surveiller si une interaction clé/wrench déclenche un jour un retrait/réenregistrement non désiré. ### 🟠 Importants -2. **`DefaultHeatCalculator.computeHeat` — partiellement amélioré, reste O(n×81) + asymétrie fuel/cooler** *(réévalué 2026-06-28, moins grave qu'estimé précédemment)* - `DefaultHeatCalculator.java:35-97` a changé de forme depuis le dernier audit : les items du pattern sont désormais désérialisés **une seule fois** dans une `Map actualRods` (l.44-54), et la recherche du **voisin** se fait par lookup direct `actualRods.containsKey(neighborSlot)` (l.81) — **l'ancienne re-boucle O(n) sur tous les items à chaque voisin a disparu**, ce n'est donc plus un O(n²) sur les items. Reste cependant, pour chaque rod, une boucle complète sur la grille `formattedPattern` (9×9=81 cellules, l.70-73) pour retrouver sa propre position — non remplacée par une map slot→position précalculée (coût ~57×81 ≈ 4617 itérations/tick sur réacteur plein, contre le ~1 050 000 estimé par l'ancien audit, qui est donc à reclasser **🟡 mineur** plutôt que 🟠). - - **Asymétrie toujours présente** (l.82) : l'examen des voisins ne se fait que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins. `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (l.88, **division**) côté fuel→cooler-voisin vs addition (l.86) côté fuel→fuel-voisin. **Ne pas toucher sans confirmation balance** (toujours valable). - - ✅ **Corrigé le 2026-06-28** (`562ce99d`) — `IHeatCalculator.computeHeat` reçoit maintenant un `Level` (`IHeatCalculator.java:10`), propagé par `HeatManager.calculateHeat` (`HeatManager.java:34`) puis utilisé pour résoudre le rod courant **et**, depuis `30de52a7`, le rod voisin (`DefaultHeatCalculator.java:60` et `:85`) via `RodType.resolveRodType`. Plus aucun appel à l'ancienne `ItemRodTypesValue.getRodType` dans ce fichier. Voir §6 pour le détail du chantier. - - *Recommandation* : précalculer une `Map` (ou inverser `formattedPattern` en `Map` statique au chargement de la classe) pour éliminer la boucle 81 cellules — gain mineur, risque nul, mais moins urgent qu'estimé avant. +2. **`DefaultHeatCalculator.computeHeat` — reste O(n×81) + asymétrie fuel/cooler** *(gravité réévaluée à la baisse lors d'un tour précédent, toujours d'actualité)* + Le neighbor lookup est passé de O(n) à O(1) (map `actualRods`, déjà corrigé — voir §8.1), mais chaque rod continue de boucler sur toute la grille `formattedPattern` (9×9=81 cellules) pour retrouver sa propre position — non remplacée par une map slot→position précalculée (coût ~57×81 ≈ 4617 itérations/tick sur réacteur plein). **Recommandation** : précalculer une `Map` — gain mineur, risque nul, priorité basse. + - **Asymétrie toujours présente** : l'examen des voisins ne se fait que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins, et `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (division) côté fuel→cooler-voisin vs addition côté fuel→fuel-voisin. **Ne pas toucher sans confirmation balance** — c'est potentiellement voulu. 3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** *(inchangé)* `getComponents()` retourne toujours une liste de taille 1 (pas de contrôleur) ou 6 (normal) ; les appelants gardent `if (components.size() < 6)` avant un accès positionnel `components.get(2).get(1)` (ligne « fuel »). Toujours fragile à tout réordonnancement de ligne. @@ -60,26 +52,19 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to ### 🟡 Mineurs -5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé)* +5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé depuis plusieurs audits)* 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. -~~7. **`ReactorFrameDisplayManager.write`** — persiste systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` est faux — pollution NBT mineure.~~ ✅ **Corrigé le 2026-07-11** — `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit plus `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse simplement les champs à leurs valeurs par défaut (identique à l'état pré-assignation). -~~8. **Duplication `drawGauge`** *(nouveau point, déjà signalé dans `AUDIT_V1` mais jamais repris dans ce document — confirmé toujours présent)* — la méthode `drawGauge(...)` est copiée à l'identique dans `FuelDisplaySource.java:49-51`, `CoolerDisplaySource.java:52-54`, `HeatDisplaySource.java:47-50`, `LiquidLevelDisplaySource.java:43-45` et `ReactorSummaryDisplaySource.java:178-180`, avec des magic numbers (`maxFuel=64`, `maxCooler=64`, `maxFluid=16000`, `maxHeat=1000`) éparpillés dans chaque classe. Aucune classe abstraite commune. Risque faible, mais 5 points de maintenance pour 1 seule logique de rendu — extraire une `AbstractReactorStatDisplaySource`.~~ ✅ **Corrigé le 2026-07-11** — `ReactorGaugeRenderer.drawGauge` (nouvelle classe utilitaire) centralise le rendu, appelé par les 4 sous-classes via le nouveau template `AbstractReactorStatDisplaySource` (`FuelDisplaySource`, `CoolerDisplaySource`, `HeatDisplaySource`, `LiquidLevelDisplaySource` héritent désormais de cette classe abstraite au lieu de dupliquer `provideLine`/`drawGauge`) et directement par `ReactorSummaryDisplaySource` (qui reste sur `DisplaySource`, structure multi-lignes incompatible avec le template). Les magic numbers des 4 sous-classes sont centralisés dans `ReactorDisplayConstants` (`MAX_FUEL`, `MAX_COOLER`, `MAX_FLUID`, `MAX_HEAT`). `ReactorSizeDisplaySource` reste volontairement en dehors (sémantique différente : jauge à 3 segments discrets par tier, pas un ratio `current/max` continu — n'avait de toute façon pas de duplication de `drawGauge`). `ReactorSummaryDisplaySource.getComponents()` (l.150-153) référence désormais aussi `ReactorDisplayConstants.MAX_FUEL/MAX_COOLER/MAX_FLUID/MAX_HEAT` au lieu de magic numbers en dur — déduplication complète sur les 5 classes. --- -## 3. 🏗️ Architecture — état réévalué +## 3. 🏗️ Architecture — points encore ouverts -| Affirmation historique | Verdict actuel (revérifié 2026-06-28) | +| Point | État (revérifié 2026-07-12) | |---|---| -| **Inversion `api/`** | ❌ **Toujours réfuté** — `MultiBlockManagerBeta`, `api/multiblock/rods/RodType`, `api/multiblock/fluid/ReactorFluidType` n'importent toujours aucun `content.*` (imports vérifiés ligne par ligne). Aucune action. | -| **Deux/trois frameworks multiblock concurrents** | ❌ **Toujours réfutté** — `lib/multiblock/manager/*` et `IBetterPattern` n'existent toujours pas (8 fichiers restants dans `lib/multiblock/`, tous utilisés). Le commit `20c1df0b` (*"IO blocks are now natively Casings"*) ne change rien à l'architecture : il nettoie 22 lignes d'une scène Ponder, les blocs I/O restent des `Block` séparés. | -| **God class `ReactorControllerBlockEntity`** | ✅ **Chantier toujours clos, classe en légère croissance maîtrisée** — **529 lignes** (492 au dernier audit), délégation à **34 fichiers** de support : `service/` (14, était 8), `manager/` (12, était 5), `consumable/` (6), `display/` (2). La croissance suit l'ajout de fonctionnalités (gestion de la frame, alarmes, etc.), pas une régression de la délégation — le constructeur injecte toujours les dépendances via interfaces (`IHeatService`, `IPersistenceService`, etc.). Pas d'action. | -| **Coordinateur de verrou fluide** | ✅ **Toujours non justifié** — `PersistentFluidLocks` reste le seul système ; pas de `FluidLockManager` concurrent retrouvé. `clearLockIfAllInputsEmpty` utilise toujours `inputFluidManager.getFuildHandlers(level)` (pas de scan 3D), avec une double itération mineure (boucle sur handlers puis sur `getTanks()`) sans gravité. | -| **`src/test`** | ❌ **Toujours vide** — confirmé, 0 fichier `.java` sous `src/test`. Le point structurel le plus important du projet reste entier. | -| **Radiation étendue à `LivingEntity` (nouveau, `9ded502c`)** | ✅ **Extension propre** — le point de vérité unique `canBeIrradiated(LivingEntity)` est toujours respecté (un seul appel, `RadiationCapability.java:107`), le hook passe par `LivingTickEvent` (pas de boucle manuelle sur les entités du monde). ⚠️ **Point à surveiller, pas un bug** : pour les non-joueurs, `tickRadiation` recalcule `computeItemRadiation` à **chaque tick sans dirty-check** (le hash d'inventaire existant ne couvre que le joueur, l.90-95 vs l.96-98) — assumé dans le commit (« no equivalent inventory to diff against »), mais à reconsidérer si la densité de mobs équipés en zone irradiée augmente. | -| **Advancements de pose centralisés sur le contrôleur (nouveau, `19617118`)** | ✅ **Amélioration confirmée** — `MultiblockHelpers.handleAdvancedPlacedBy` (l.58-66) redirige `setPlacedBy` vers le contrôleur via `getControllerForPart`, et `CNAdvancementBehaviour.java:106` vérifie maintenant `!advancement.isAlreadyAwardedTo(player)` (état Minecraft natif) au lieu d'une liste interne. Élimine un risque de double-attribution. Limite résiduelle (pas une régression) : si le contrôleur n'est pas encore résolu au moment de la pose, l'advancement de pose est silencieusement sauté pour cette pièce. | +| **`src/test`** | ❌ **Toujours vide** — confirmé, 0 fichier `.java` sous `src/test`. Le point structurel le plus important du projet reste entier ; c'est le terrain commun à la quasi-totalité des bugs silencieux relevés depuis le premier audit (chaleur, pattern matching, verrouillage fluide, double-scan multiblock, et maintenant la doc obsolète repérée en §0). | +| **`RadiationCapability.tickRadiation` pour `LivingEntity` non-joueurs** | ⚠️ **Point à surveiller, pas un bug** — recalcule `computeItemRadiation` à chaque tick sans dirty-check (le hash d'inventaire existant, `InventoryHashUtil`, ne couvre que le joueur). Compromis assumé explicitement dans le commit `9ded502c` (« no equivalent inventory to diff against ») — à reconsidérer seulement si la densité de mobs équipés en zone irradiée augmente et qu'un problème de perf est mesuré. | -**Vrai writ-large structurel : l'absence de tests**, inchangé — c'est toujours là (chaleur, pattern matching, verrouillage fluide, et maintenant le double-scan multiblock) que les bugs silencieux survivent aux audits successifs. +*(Les autres affirmations historiques de cette table — inversion `api/`, deux frameworks multiblock concurrents, god class `ReactorControllerBlockEntity`, coordinateur de verrou fluide dédié — ont toutes été réfutées ou closes ; voir §8.2.)* --- @@ -87,24 +72,15 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to > **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé par `NuclearMushroomCloudModel`). -**Pur dead code (retrait sûr)** -- ~~**`lib/multiblock/SimpleMultiBlockPattern.java` méthode `test()`**~~ ✅ **Retiré** — confirmé par `git diff` : la méthode a disparu du fichier de travail, aucun appelant n'était présent. -- ~~**`IrradiatedBiomes.monsters()`**~~ ✅ **Retiré le 2026-07-12** (`8b0428e3`) — la méthode (corps vide) et son unique site d'appel dans le builder du biome irradié ont été supprimés ; les réglages de spawn du biome irradié passent désormais uniquement par `MobSpawnSettings.Builder`. - **Code commencé puis abandonné (hygiène de fin de PR)** -- ~~`content/multiblock/input/fluid/PlayerInteractReactorFluidInput.java:57-61` — quatre problèmes de dead code~~ ✅ **Déjà corrigé le 2026-07-03** (`f2490469`) — **stale depuis la mise à jour précédente de ce document** : ce commit avait renommé le fichier (suppression du 'e' parasite dans "Interacte") et **supprimé** les 4 problèmes (variable morte `fluidInItem`, bloc commenté référençant `ReactorLiquidInput` inexistant, bloc vide `TANK_TO_ITEM`, `instanceof` toujours vrai) directement dans le `.java`, mais la description ci-dessus n'avait, par erreur, pas été retirée de l'audit — elle avait au contraire été détaillée davantage dans ce même commit. Vérifié par lecture directe du fichier actuel (`PlayerInteractReactorFluidInput.java`) : plus aucun des 4 problèmes n'est présent. -- `content/multiblock/output/ReactorOutput.java:43,52,87` — propriété `SPEED` toujours entièrement commentée (pas supprimée). *(Numéros de lignes mis à jour : l.93 → l.87 après décalage.)* +- `content/multiblock/output/ReactorOutput.java:56,91` — propriété `SPEED` toujours entièrement commentée (pas supprimée). *(Lignes revérifiées 2026-07-12 : `//builder.add(SPEED);` l.56, `/*.setValue(SPEED, 0)*/` l.91 — décalage mineur par rapport aux anciens numéros de ligne l.43/52/87.)* - `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. -~~**Reliquats Git (`run/`)** — confirmé via `git ls-files run/` : il reste **6 fichiers de debug/env trackés** malgré `.gitignore` : -`run/hs_err_pid21100.log`, `run/hs_err_pid27848.log`, `run/imgui.ini`, `run/servers.dat`, `run/servers.dat_old`, `run/mods/Jade-1.20.1-Forge-11.12.2.jar.disabled`.~~ -⚠️ **Conserver** les 10 `run/schematics/*.nbt` (assets de gameplay légitimes). +**Worldgen « irradié » — template non terminé** *(revérifié 2026-07-12, inchangé)* +- `IrradiatedBiomes.java:22-27` ajoute toujours du contenu vanilla sans rapport avec le biome irradié (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`). +- `CNNoiseGeneratorSettings.java:25` utilise toujours `STEEL_BLOCK` comme bloc de remplissage par défaut du biome irradié. -~~**Collier teignable chat/loup non câblé**~~ ✅ **Résolu le 2026-07-11** — décision prise : retrait complet de la mécanique plutôt que câblage. `IrradiatedCatCollarLayer.java` et `IrradiatedWoldCollarLayer.java` ont été supprimés (aucun appelant ne les référençait, confirmé par grep). Dans `IrradiatedCat.java`, le champ `DATA_COLLAR_COLOR`, les accesseurs `getCollarColor()`/`setCollarColor()` et le bloc `readAdditionalSaveData`/`addAdditionalSaveData` associé ont été retirés ; l'interaction `DyeItem` dans `mobInteract` a été retirée (le fix a complété une suppression partielle laissée par l'édition en cours, qui laissait `mobInteract` appeler des méthodes déjà supprimées — code non compilable en l'état intermédiaire). `IrradiatedWolf` n'avait de toute façon jamais câblé cette mécanique (`DATA_COLLAR_COLOR` déjà en commentaire). Note : `getBreedOffspring` (`IrradiatedCat.java:248-260`) appelle toujours `cat.setCollarColor(...)`/`cat2.getCollarColor()`, mais sur des `Cat` vanilla (API native Minecraft), sans rapport avec la mécanique retirée — laissé tel quel. - -**Worldgen « irradié » — template non terminé** *(inchangé)* -- `IrradiatedBiomes.addDefaultIrradiatedOres`/`addDefaultSoftDisks` ajoutent toujours du contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`). -- `CNNoiseGeneratorSettings.IRRADIATED` utilise toujours `STEEL_BLOCK` comme bloc de remplissage par défaut. +*(Le dead code pur déjà retiré — `SimpleMultiBlockPattern.test()`, `IrradiatedBiomes.monsters()`, le nettoyage de `PlayerInteractReactorFluidInput`, les fichiers de debug `run/`, la mécanique de collier teignable — est en §8.1/§8.3 avec ses hash.)* --- @@ -112,76 +88,148 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to | Point | État | Réf. | |---|---|---| -| `ReactorPattern.findController` (Casing/Cooler/Frame) : **ne court-circuite jamais**, scanne ~3971 positions à chaque pose/casse même après avoir trouvé le contrôleur | ❌ **non corrigé** — chemin le plus chaud, dernier point ouvert | §2.1 | -| `ReactorPattern.findControllerPos` (Output/RodInput/FluidInput/Alarm via `MultiblockHelpers`) : court-circuite bien | ✅ déjà correct | §2.1 | -| Aucune garde `level.isClientSide()` sur toute la chaîne de scan | ✅ **corrigé le 2026-06-28** — garde centralisée dans `ReactorAssembler.assemble`/`disassemble` | §2.1 | -| Double scan à la casse (`playerDestroy` + `onRemove`) sur Casing/Cooler/Output/FluidInput (sans garde) et Alarm/Frame (garde partielle) | ✅ **corrigé le 2026-06-28** — modèle `ReactorRodInput` généralisé aux 6 autres blocs (override `playerDestroy` supprimé) | §2.1 | -| `DefaultHeatCalculator.computeHeat` : neighbor lookup passé de O(n) à O(1) (map), reste une boucle O(81) de recherche de position par rod | 🟡 **partiellement corrigé, gravité réévaluée à la baisse** | §2.2 | -| `clearLockIfAllInputsEmpty` : pas de scan cubique O(n³), double itération mineure | ✅ acceptable | §3 | +| `ReactorPattern.findController` (Casing/Cooler/Frame) : **ne court-circuite jamais**, scanne ~3971 positions à chaque pose/casse même après avoir trouvé le contrôleur | ❌ **non corrigé** — chemin le plus chaud, dernier point ouvert du chantier scan multiblock | §2.1 | +| `DefaultHeatCalculator.computeHeat` : neighbor lookup en O(1) (déjà corrigé), reste une boucle O(81) de recherche de position par rod | 🟡 **partiellement corrigé, priorité basse** | §2.2 | + +*(`findControllerPos`, la garde `isClientSide`, le double scan à la casse, et `clearLockIfAllInputsEmpty` sont déjà sains/corrigés — voir §8.1/§8.2.)* --- -## 6. ✅ Pour mémoire — déjà corrigé (ne plus reprendre) +## 6. 📝 Documentation — langue et clarté du code (nouveau point d'audit, 2026-07-12) -Vérifiés résolus dans le code actuel (cumul des tours précédents) : **B2, B3/B4/B5/B6/B8/B9/B11/B13/B16/B19, B12, B14**, off-by-one `getFluidInTank`, icône d'item de l'armure anti-radiation teinte, tous les problèmes radiation historiques (point de vérité unique `canBeIrradiated`). +**Périmètre** : `src/main/java` (292 fichiers), recherche des commentaires/Javadoc non rédigés en anglais et des cas ambigus/incomplets indépendamment de la langue. Méthodologie : recherche par caractères accentués + vocabulaire français typique des commentaires, puis lecture manuelle des occurrences trouvées. -**Confirmé corrigé le 2026-06-26** : **spam de log `ReactorAssembler.assemble`** — plus aucun `LOGGER.warn`/`info` dans le chemin de succès (commit `b309f231`). *(Quick win n°3 de la feuille de route précédente, traité.)* +**Décompte global** : **14 fichiers sur 292** (~5 %) contiennent du français détectable, pour environ **40 lignes** de commentaires/Javadoc concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires et Javadoc**, pas à l'API elle-même. Le mélange est quasi systématique FR/EN **dans le même fichier**, parfois la même méthode — jamais un fichier intégralement en français. -**Confirmé corrigé (NuclearExplosionEntity, ex-B15)** : l'ancien anti-pattern `try { onBlockExploded } catch(Exception){ destroyBlock(...,true) }` a disparu. Le code actuel (`NuclearExplosionEntity.java:224-232`) fait une vérification explicite (`if (level().getBlockState(immutablePos).is(state.getBlock())) level().destroyBlock(...)`) au lieu d'avaler une exception. Plus d'anti-pattern de contrôle par exception. +**Cas les plus significatifs** : -**Confirmé sain, nouveau code 2026-06-25/27** : `CNBuilderTransformers` (extraction propre des builders de modèles d'item/spawn-egg hors de `CNItems`, 97 lignes, SRP respectée) et l'item **Biome Restore Cell** (`BiomeRestoreCellItem`, 75 lignes, logique métier déléguée à `BiomeIrradiationService`, gardes serveur/client correctes) — aucun problème structurel à signaler, rien à ajouter au plan d'action. +*Javadoc public sur API/points d'extension — le plus grave car visible par tout futur contributeur :* +1. `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)`, point d'extension abstrait clé (`RadiationEffect` en dépend) : première phrase en anglais, puis bascule en français dans la même doc. Pire cas relevé : Javadoc public, méthode non triviale, bilingue au sein d'un seul bloc. +2. `infrastructure/ponder/scenes/CNPonderReactorScenes.java:32` — Javadoc de la classe interne `Positions` entièrement en français, documentant une convention critique non répétée ailleurs (« Les BlockPos ici doivent être EN COORDONNÉES SCÈNE »). +3. `infrastructure/ponder/scenes/CNPonderReactorScenes.java:50` — Javadoc de `STATIC_POS` rédigé comme une note à soi-même plutôt qu'une documentation (« adapte ces valeurs exactement comme dans ton NBT »). +4. `infrastructure/ponder/scenes/CNPonderReactorScenes.java:85` — Javadoc de `positionsFor` en français ; bloque la lecture pour un contributeur non francophone d'une scène Ponder (bibliothèque Create, publique par nature). -**Corrigé le 2026-06-28** : `InventoryHashUtil.stackHash` n'inclut plus `getDamageValue()` (`InventoryHashUtil.java:90-91` retiré). Vérifié : aucune implémentation de `IRadiationSource`/`RadiationRegistry` (`UraniumOreItem`, `RadiationItem`, `RadiationBucketItem`, `RadiationEffect`) ne lit la durabilité, donc l'inclure dans le hash ne faisait que déclencher `RadiationCapability.computeItemRadiation` (`RadiationCapability.java:91-95`) sans raison à chaque variation de durabilité (minage, combat) — précisément sur les hot paths que le cache devait protéger. Pour mémoire, le terme « resync » des audits précédents désignait ce recalcul serveur, pas un trafic réseau (`RadiationProvider` ne fait que sérialiser en NBT, aucun `RadiationSyncPacket` impliqué). +*Commentaires sur logique métier non triviale :* +5. `CNFluids.java:139,153,156,159` — bloc de commentaires français documentant une correction fine de désynchronisation client/serveur des ticks de gel/dégel (compensation d'offset). Logique fragile, documentée uniquement en français. +6. `ClientEvents.java:24,60-78` — logique de tremblement de caméra liée à l'explosion nucléaire, entièrement commentée en français, y compris la formule de puissance ; non documentée en anglais du tout. +7. `foundation/mixin/RadiationHeartMixin.java:13,21,32` — mixin overridant le rendu du cœur HUD vanilla, commentaires français expliquant le ciblage. Les mixins sont le code le plus fragile aux montées de version MC/Forge — mérite une documentation claire et bilingue a minima. +8. `foundation/mixin/CameraAccessor.java:9` — accessor mixin, commentaire français isolé sur le pattern « invoker » Mixin. +9. `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:51,75,114` — trois commentaires français de garde défensive (« Sécurité Triple-Check ») sur le chemin d'affichage, seule trace de documentation de cette logique de garde. +10. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. +11. `content/decoration/palettes/PalettesVariantEntry.java:54` — commentaire français sur un changement d'architecture de rendu déjà effectué ailleurs, utile pour éviter une régression, en français uniquement. +12. `infrastructure/worldgen/biome/IrradiatedBiomes.java:39-48` — 4 commentaires français sur des choix esthétiques de biome ; mineur, mais dans un fichier déjà pointé par §4 comme « template non terminé ». +13. `content/equipment/armor/AntiRadiationArmorItem.java:48` — commentaire français sur `getArmorTexture` (override d'API Forge publique) ; trivial sur le fond, à harmoniser en anglais par cohérence. +14. `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:33` — commentaire français isolé, sur une classe explicitement exclue du refactor de mutualisation `drawGauge` (§8.1) — bon candidat à documenter proprement au prochain passage sur ce fichier. +15. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. -**Corrigé le 2026-07-05** : `IHeat.HeatLevel.isNotDanger` (ex-§1, `IHeat.java:89-91`) — la tautologie `of(heat,size) != DANGER || of(heat,size) != NONE` (toujours `true`) a été remplacée par `of(heat,size) != DANGER`. La garde « ne pas faire tourner les sorties en `DANGER` » (appelant unique `ReactorControllerBlockEntity.java:428`) est désormais réellement opérante : les sorties s'arrêtent en surchauffe. ⚠️ **Changement de comportement de balance réel** (avant : les sorties tournaient toujours ; maintenant : elles s'arrêtent en `DANGER`) — à valider en jeu, un joueur peut désormais se retrouver sans écoulement de sortie tant que le réacteur reste en surchauffe. +**Ambiguïtés/incomplétudes indépendantes de la langue relevées au passage** : +- `CNPonderReactorScenes.java:50,90` — formulations en forme de note de dev figée dans le code (« adapte ces valeurs... comme dans ton NBT », « si tu veux éviter un NPE ») plutôt qu'une documentation stable, à reformuler indépendamment de la traduction. +- `ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée — ambiguïté fonctionnelle non résolue. +- `CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers. -**Corrigé le 2026-06-28** : garde `level.isClientSide` manquante sur la chaîne multiblock et double scan `playerDestroy`/`onRemove` (§2.1). Fix appliqué de façon centralisée plutôt que classe par classe : (1) `if (level.isClientSide) return;` ajouté en tête de `ReactorAssembler.assemble`/`disassemble` — point de convergence unique de toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler` ; (2) l'override `playerDestroy` a été supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput` et `ReactorFluidInput`, généralisant le modèle déjà correct de `ReactorRodInput` (un seul appel de retrait, dans `onRemove`, qui se déclenche systématiquement y compris lors d'une casse joueur). Vérifié par lecture directe des 7 fichiers modifiés. Seul le court-circuit manquant de `findController` (perf pure) reste ouvert — voir §2.1 et §7. +**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité** et se concentre sur un noyau stable de fichiers : les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSummaryDisplaySource`, `ReactorSizeDisplaySource`), les scènes Ponder (`CNPonderReactorScenes`), et `CNFluids`/`ClientEvents`. Aucun de ces fichiers n'a été assaini depuis. Point positif : le sous-ensemble concerné est petit et stable (14/292 fichiers, ~5 %) et n'a pas grossi récemment — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger) n'ont pas introduit de nouveau commentaire français. -**Corrigé le 2026-06-28** (`562ce99d` + `30de52a7`) : désynchronisation `CNItemTags.FUEL`/`COOLER` vs `RodType.type()` (ex-§2 point 8, assigné Gio). `RodType.TypeRodPredicate.IS_FUEL`/`IS_COOLED` (anciens `Predicate` basés sur `ItemRodTypesValue.getRodType`, sans `Level`) ont été remplacés par `isFuel(ItemStack, Level)`/`isCooled(ItemStack, Level)` basés uniquement sur `RodType.resolveRodType` (`RodType.java:303-309`). `Level` a été enfilé jusqu'à `IHeatCalculator.computeHeat`/`HeatManager.calculateHeat`/`DefaultHeatCalculator.computeHeat`. Premier commit (`562ce99d`) avait migré 5 des 6 sites mais laissé deux endroits sur l'ancien critère mixte `stack.is(TAG) || rod.type() == X` (`ReactorBluePrintMenu.java:165-166`) ou l'ancienne API sans `Level` (`DefaultHeatCalculator.java:85`, lookup du voisin) ; second commit (`30de52a7`) les a corrigés. Vérifié par grep sur tout `src/main/java` : plus aucun site de classification ne lit `CNItemTags.FUEL`/`COOLER` ou n'appelle `ItemRodTypesValue.getRodType` en dehors de l'implémentation interne de `RodType.resolveRodType` lui-même. Le tag `CNItemTags.FUEL` reste posé sur `THORIUM_ROD` (`CNItems.java:220`) à titre de tag de craft/recette, explicitement découplé de la classification — cohérent, pas un résidu de désync. +**Pourquoi ça doit être suivi** : ces commentaires portent presque toujours l'explication du *pourquoi* d'un choix non trivial (compat cross-mod, compensation de désync réseau, convention de coordonnées Ponder, garde défensive) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). -**Confirmé neutre** : le commit `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) ne fusionne rien dans le code de jeu — nettoyage cosmétique d'une scène Ponder uniquement. +**Priorité recommandée** : 🟢 **cosmétique, à faire au fil de l'eau — pas bloquant.** Aucun symbole d'API n'est en français, donc pas d'impact sur la lisibilité des signatures pour un contributeur externe. Traiter en priorité les 4 cas de Javadoc public (items 1-4 ci-dessus, notamment `VicinityEffect.java` et `CNPonderReactorScenes.java`, seuls vrais cas de Javadoc public bilingue) lors du prochain passage sur ces fichiers, plutôt que d'ouvrir un chantier de traduction dédié — le volume (~40 lignes) ne le justifie pas. Chaque futur commit touchant l'un des 14 fichiers devrait normaliser en anglais les commentaires qu'il modifie. **Suivi** : cet item reste en §6 jusqu'à ce que les 4 cas de Javadoc public soient traduits ; à re-scanner périodiquement (le pattern n'a pas grossi depuis le dernier audit, mais rien ne garantit que ça dure). -**Corrigé le 2026-07-11** : `ReactorFrameDisplayManager.write` (ex-§2 point 7) persistait systématiquement les sentinelles `Integer.MAX_VALUE`/`MIN_VALUE` même quand `hasFrameColumn()` était faux. `write()` (`ReactorFrameDisplayManager.java:129-134`) n'écrit désormais `COMPONENT_FRAME_COLUMN_MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai. Sans risque de régression : `read()` (l.118-126) protège déjà chaque champ par `compound.contains(...)`, donc l'absence de clé laisse les champs à leurs valeurs par défaut (identique à l'état pré-assignation). +--- -**Corrigé le 2026-07-03** : `PlayerInteractReactorFluidInput` (ex-§4, renommage + 4 problèmes de dead code). Fichier renommé (`PlayerInteracteReactorFluidInput` → `PlayerInteractReactorFluidInput`, suppression du 'e' parasite) et nettoyé (`f2490469`) : variable morte `fluidInItem`, bloc commenté référençant la classe inexistante `ReactorLiquidInput`, bloc vide `TANK_TO_ITEM`, et `instanceof ReactorFluidInputEntity` toujours vrai (branche morte) — tous supprimés. *(Correction bien réelle dans le code depuis le 2026-07-03, mais était restée décrite comme non résolue dans ce document jusqu'au 2026-07-12 — staleness de documentation repérée et corrigée à cette date.)* +## 7. 🗺️ Feuille de route — priorités justifiées -**Corrigé le 2026-07-12** : `IrradiatedBiomes.monsters()` (ex-§4, `8b0428e3`) — méthode au corps vide et son unique site d'appel (arguments 95/5/100 silencieusement ignorés) supprimés ; les réglages de spawn du biome irradié passent désormais uniquement par `MobSpawnSettings.Builder`, sans couche de délégation morte. +Classement par catégorie et impact, du plus important au plus cosmétique. Chaque item renvoie à sa section de détail. -**Corrigé le 2026-07-11** : duplication `drawGauge` (ex-§2 point 8). Nouvelle classe `ReactorGaugeRenderer.drawGauge` centralise le rendu de jauge, jusque-là copié à l'identique dans 5 classes. `FuelDisplaySource`, `CoolerDisplaySource`, `HeatDisplaySource` et `LiquidLevelDisplaySource` héritent désormais d'un nouveau template `AbstractReactorStatDisplaySource extends NumericSingleLineDisplaySource` (`provideLine`, `initConfigurationWidgets`, `allowsLabeling` mutualisés ; chaque sous-classe ne fournit plus que `getLabelKey`, `getMax`, `computeValue`, `getColor`, et optionnellement `getUnitSuffix`). `ReactorSummaryDisplaySource` reste sur `DisplaySource` (structure multi-lignes non compatible avec le template single-line) mais appelle désormais `ReactorGaugeRenderer.drawGauge` au lieu de sa propre copie. Les magic numbers des 5 classes (les 4 sous-classes migrées **et** `ReactorSummaryDisplaySource`, l.150-153) sont désormais tous nommés dans `ReactorDisplayConstants`. Vérifié par lecture directe des 8 fichiers concernés et par `Grep` confirmant l'usage de `ReactorDisplayConstants.MAX_*` partout où figuraient auparavant `64`/`16000`/`1000` en dur. `ReactorSizeDisplaySource` a été délibérément exclue du template (jauge à 3 segments discrets par tier, sémantique incompatible avec un ratio `current/max`) — elle n'avait de toute façon pas de `drawGauge` dupliqué. Déduplication complète, aucun point résiduel. +**1. Dette technique structurelle (racine des bugs silencieux récurrents)** +- Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` (§3). **Justification** : c'est la cause profonde identifiée à travers *tous* les tours d'audit successifs — sur-extraction fluide, tautologie `IHeat`, scan non court-circuité, et maintenant une section d'audit devenue obsolète sans que personne ne s'en aperçoive (§0) sont tous des symptômes du même problème : rien ne vérifie automatiquement le comportement. C'est l'investissement qui a le plus gros effet de levier sur la fiabilité future, mais c'est aussi le plus long — d'où la priorité 1 malgré l'absence d'urgence immédiate. ---- +**2. Optimisation — chemin le plus chaud du projet** +- `ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur, pour court-circuiter comme `findControllerPos` le fait déjà (§2.1, §5). **Justification** : fix d'une ligne, risque quasi nul, et c'est le chemin appelé par le bloc le plus posé/cassé du jeu (`ReactorCasing`). Rapport gain/effort le plus élevé du projet — reste la priorité n°1 « quick win » malgré son classement en position 2 ici (juste après la dette de tests, qui est stratégiquement plus importante mais bien plus longue à traiter). + +**3. Bug fonctionnel latent — robustesse d'un contrat interne** +- `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers, gérer `toExtract == 1`, retirer la garde morte `fluidNeeded <= 0` (§1). **Justification** : viole silencieusement le contrat d'extraction ; toléré aujourd'hui uniquement parce que la configuration actuelle (tank mono-slot) masque le symptôme — un futur ajout de multi-input fluide le ferait resurgir sans avertissement. -## 7. 🗺️ Feuille de route — priorités +**4. Validation en jeu — correction déjà codée** +- Flicker de vitesse de sortie : valider en jeu que le seuil d'hystérésis (`RPM_DIVIDER/2`, déjà implémenté par `a18038db`) supprime bien la perception du flicker en fin de ressources (§1). **Justification** : le code est déjà en place, il ne reste qu'une validation de gameplay — priorité basse en effort mais à ne pas oublier, sinon le point restera indéfiniment « à moitié fait » dans la mémoire du projet. -**Quick wins (risque quasi nul, gain immédiat)** -1. **`ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur** (l.69), pour court-circuiter comme `findControllerPos` le fait déjà. **← dernier point ouvert de ce chantier, le plus rentable : c'est le chemin appelé par le bloc le plus posé/cassé (Casing).** -2. ~~Garde `level.isClientSide()` en tête de `findController`/`findControllerPos`/`ReactorAssembler.assemble/disassemble`.~~ ✅ **fait le 2026-06-28** (garde centralisée dans `ReactorAssembler.assemble`/`disassemble`). -3. ~~Généraliser le modèle `ReactorRodInput`...~~ ✅ **fait le 2026-06-28** — `playerDestroy` supprimé de `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` ; la logique de retrait vit désormais uniquement dans `onRemove` pour ces 6 classes (comme `ReactorRodInput`). Point résiduel mineur non traité : `ReactorOutput`/`ReactorFluidInput` n'ont pas la garde `!state.is(newState.getBlock())` dans `onRemove` malgré leurs propriétés mutables `DIR`/`FACING` (cf. §2.1). -4. ~~`IHeat.HeatLevel.isNotDanger` : corriger la tautologie (`!= DANGER` seul), après confirmation balance.~~ ✅ **fait le 2026-07-05** — voir §6 pour le changement de comportement associé à valider en jeu. -5. ~~`git rm --cached` sur les 6 fichiers de debug `run/` (§4).~~ ✅ **fait le 2026-06-28** -6. ~~Retirer `SimpleMultiBlockPattern.test()`~~ ✅ **fait le 2026-06-28** (commit `2aaddb4d`) et ~~retirer `IrradiatedBiomes.monsters()`~~ ✅ **fait le 2026-07-12** (commit `8b0428e3`). +**5. Amélioration de conception / cohérence UX** +- `ReactorSummaryDisplaySource.formatValue` : harmoniser le mode d'affichage du heat avec `HeatDisplaySource` (§2.4). **Justification** : incohérence visible par le joueur, mais purement cosmétique, aucun risque fonctionnel. +- `ReactorSummaryDisplaySource` : remplacer l'accès positionnel fragile (`components.get(2).get(1)`) par un accès nommé/typé (§2.3). **Justification** : dette de conception qui ne casse rien aujourd'hui mais rendra toute évolution de l'ordre des lignes affichées dangereuse sans le vouloir. -**Corrections ciblées (risque faible à moyen)** -7. `ReactorInputFluidManager` : décrémenter `fluidNeeded` entre handlers + gérer `toExtract == 1` (§1). -8. `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle 81 cellules (gain mineur désormais, priorité baissée par rapport au tour précédent) ; **ne pas** toucher l'asymétrie fuel/cooler sans validation balance. -9. ~~Extraire `AbstractReactorStatDisplaySource.drawGauge` pour dédupliquer les 5 copies identiques.~~ ✅ **fait le 2026-07-11** (§2.8). -10. Flicker vitesse de sortie en fin de ressources (oscillateur `overHeat` × division entière `RPM_DIVIDER`) : ajouter une hystérésis sur le heat appliqué à `rotateOutputs`, seuil à valider (§1). +**6. Optimisation mineure (gain faible, risque nul)** +- `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle O(81) restante (§2.2, §5). **Ne pas** toucher à l'asymétrie fuel/cooler sans validation balance. +- `CNPonderReactorScenes.showReactorStructure` : remplacer la boucle triple par une map précalculée (§2.6). Coût ponctuel (ouverture d'un ponder), gain marginal. -**Décisions produit (choisir puis exécuter)** -~~11. Collier teignable chat/loup : finir le câblage (`addLayer` + `render` + interaction `DyeItem` sur `IrradiatedWolf`) ou retirer toute la mécanique (§4).~~ ✅ **fait le 2026-07-11** — mécanique retirée entièrement (§4). -12. ~~`PlayerInteractReactorFluidInput` *(renommé)* : retirer le bloc créatif ITEM_TO_TANK...~~ ✅ **fait le 2026-07-03** (`f2490469`, staleness de documentation corrigée le 2026-07-12 — voir §6). *Reste ouvert* : `ReactorOutput.SPEED` — retirer les 3 commentaires (l.43, 52, 87) ou décider si la propriété doit être réactivée (§4). +**7. Nettoyage / décisions produit à trancher** +- `ReactorOutput.SPEED` : retirer les commentaires ou décider de réactiver la propriété (§4). +- `CNStandardRecipeGen.java:226` : trancher le `FIXME` sur les catégories de recette (§4). +- Worldgen « irradié » : retirer le contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`) et choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. -**Chantier de fond (le plus rentable à long terme)** -13. Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` — les trois zones où des bugs/inefficacités silencieuses ont survécu à plusieurs audits successifs. +**8. Documentation (nouveau, §6)** +- Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3) en priorité, puis les commentaires métier non triviaux listés en §6, au fil des prochains passages sur ces fichiers. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais ce sont typiquement des commentaires qui expliquent un « pourquoi » non trivial (compat, désync réseau, convention Ponder) — les laisser en français limite l'audit/onboarding futur. -**À surveiller sans action immédiate** -14. `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (recalcul à chaque tick) — compromis assumé par le commit `9ded502c`, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. +**9. À surveiller sans action immédiate** +- `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. +- `ReactorOutput`/`ReactorFluidInput` : garde `!state.is(newState.getBlock())` absente dans `onRemove` malgré des propriétés mutables (§2.1). Pas un bug confirmé, à surveiller. +- `CreateNuclearJEI` : champ statique mutable `Categories`, non revérifié récemment (§2.5). -**Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** +**Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** — détail et justification en §8.2/§8.3 : - Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos, croissance maîtrisée). -- « Correction » de l'inversion de dépendance `api/` (n'existe pas). -- Fusion/suppression du pipeline multiblock (sain). -- Coordinateur dédié au verrouillage fluide (non justifié). -- Spam de log `ReactorAssembler` (corrigé le 2026-06-26). -- Anti-pattern try/catch `NuclearExplosionEntity` / B15 (corrigé). -- Tags `CNItemTags.FUEL`/`COOLER` désynchronisés de `RodType.type()` (assigné Gio, **terminé le 2026-06-28** via `562ce99d` + `30de52a7` — voir §6). +- « Correction » de l'inversion de dépendance `api/` (n'a jamais existé dans le code observé). +- Fusion/suppression du pipeline multiblock (sain, un seul framework vivant). +- Coordinateur dédié au verrouillage fluide (non justifié, `PersistentFluidLocks` suffit). +- Tags `CNItemTags.FUEL`/`COOLER` désynchronisés de `RodType.type()` (terminé). + +--- + +## 8. ✅ Mémoire — corrections, réfutations et décisions déjà actées + +### 8.1 Corrections appliquées, avec commit identifié + +| Correction | Hash(es) | Date | Détail | +|---|---|---|---| +| Retrait de `IrradiatedBiomes.monsters()` (corps vide, arguments ignorés) | `8b0428e3` | 2026-07-12 | Méthode et son unique site d'appel supprimés ; les réglages de spawn passent désormais uniquement par `MobSpawnSettings.Builder`. | +| Blocage explicite (message "WIP") de l'apprivoisement des mobs irradiés (`AnimalUtil.blockTamingWip`) | `261b26d8` | 2026-07-11 | Remplace un apprivoisement cassé/incohérent (chat : collier non fonctionnel ; loup : aucun chemin d'apprivoisement) par un message explicite "pas encore implémenté". Ce même commit a aussi retiré la mécanique de collier (§8.3). | +| Retrait de la mécanique de collier teignable jamais câblée (`IrradiatedCatCollarLayer`, `IrradiatedWoldCollarLayer`, `DATA_COLLAR_COLOR`) | `17b29aa3` | 2026-07-11 | Décision produit exécutée — voir §8.3 pour le contexte de la décision. | +| Guard NBT : `ReactorFrameDisplayManager.write()` n'écrit les sentinelles `MIN_Y`/`MAX_Y` que si `hasFrameColumn()` est vrai | `381c7a5f` | 2026-07-11 | Élimine une pollution NBT mineure ; `read()` protégeait déjà chaque champ par `compound.contains(...)`, donc sans risque de régression. | +| Déduplication `drawGauge` : nouvelle classe `ReactorGaugeRenderer` + template `AbstractReactorStatDisplaySource`, constantes centralisées dans `ReactorDisplayConstants` | `35e474e3` → `d0da13d1` → `a8b6b23f` → `e34adcc5` | 2026-07-11 (20:38 → 21:08, ordre chronologique confirmé) | 5 copies identiques de `drawGauge` (Fuel/Cooler/Heat/LiquidLevel/Summary) ramenées à une seule implémentation ; `ReactorSizeDisplaySource` volontairement exclue (jauge à segments discrets, sémantique différente). | +| `IHeat.HeatLevel.isNotDanger` : tautologie `!= DANGER \|\| != NONE` (toujours vraie) remplacée par `!= DANGER` | `fb0897d3` | 2026-07-05 | ⚠️ **Changement de comportement de balance réel** : avant, les sorties tournaient toujours ; désormais elles s'arrêtent en `DANGER`. À valider en jeu (un joueur peut se retrouver sans écoulement de sortie tant que le réacteur reste en surchauffe). | +| Hystérésis sur le heat appliqué à `rotateOutputs` (champ `lastAppliedOutputHeat`, seuil `RPM_DIVIDER/2`) | `a18038db` | 2026-07-05 | Corrige le flicker RPM en fin de ressources — voir §1 pour le statut résiduel (validation en jeu du seuil encore ouverte). | +| `PlayerInteractReactorFluidInput` : renommage (`PlayerInteracteReactorFluidInput` → sans le 'e' parasite) + retrait de 4 blocs de dead code (variable morte, bloc commenté référençant `ReactorLiquidInput` inexistant, bloc vide `TANK_TO_ITEM`, `instanceof` toujours vrai) | `f2490469` | 2026-07-03 | **Note de fiabilité documentaire** : ce commit avait, par erreur, laissé l'ancienne description du problème dans `AUDIT_ACTUEL.md` (et même l'avait détaillée davantage) au lieu de la marquer résolue — staleness corrigée le 2026-07-12. Exemple concret de pourquoi §3 recommande des tests plutôt qu'une documentation manuelle comme seul filet de sécurité. | +| Tags `CNItemTags.FUEL`/`COOLER` désynchronisés de `RodType.type()` : classification unifiée sur `RodType.resolveRodType(Level)` | `562ce99d` (5 des 6 sites) + `30de52a7` (2 sites manqués : `ReactorBluePrintMenu`, lookup voisin `DefaultHeatCalculator`) | 2026-06-28 | `Level` enfilé jusqu'à `IHeatCalculator.computeHeat`. Vérifié par grep : plus aucun site de classification ne lit `CNItemTags.FUEL`/`COOLER`. `CNItemTags.FUEL` reste sur `THORIUM_ROD` comme tag de craft, explicitement découplé de la classification. | +| Retrait de `SimpleMultiBlockPattern.test()` | `2aaddb4d` | 2026-06-28 | Aucun appelant, retrait sûr. | +| `InventoryHashUtil.stackHash` n'inclut plus `getDamageValue()` | `575a8ab8` | 2026-06-28 | Aucune implémentation `IRadiationSource`/`RadiationRegistry` ne lit la durabilité ; l'inclure ne faisait que déclencher un recalcul serveur (`RadiationCapability.computeItemRadiation`) à chaque variation de durabilité (minage, combat) sur le hot path que le cache devait protéger. | +| Garde `level.isClientSide` centralisée dans `ReactorAssembler.assemble`/`disassemble` + suppression des overrides `playerDestroy` redondants (généralisation du modèle `ReactorRodInput`) sur `ReactorCasing`, `ReactorCooler`, `ReactorFrame`, `ReactorAlarm`, `ReactorOutput`, `ReactorFluidInput` | `34d5706f` | 2026-06-28 | Point de convergence unique de toute la chaîne `onPlace/onRemove/playerDestroy → findController/findControllerPos → ReactorAssembler` ; `onRemove` se déclenche déjà systématiquement lors d'une casse joueur, donc retirer l'appel redondant dans `playerDestroy` élimine le double scan sans changer de comportement observable. | +| Retrait des 6 fichiers de debug/env trackés dans `run/` (`hs_err_pid*.log`, `imgui.ini`, `servers.dat*`, `Jade*.jar.disabled`) + `.gitignore` élargi | `9ddb5a2a` | 2026-06-28 | Les 10 `run/schematics/*.nbt` conservés (assets de gameplay légitimes). | +| Extension de la radiation à toutes les `LivingEntity` (pas seulement le joueur) | `9ded502c` | 2026-06-28 | Point de vérité unique `canBeIrradiated(LivingEntity)` respecté, hook via `LivingTickEvent` (pas de boucle manuelle sur les entités du monde). Compromis assumé : pas de dirty-check pour les non-joueurs — voir §3 (point à surveiller). | +| Centralisation de l'attribution des advancements de pose sur le contrôleur (au lieu de la pièce posée) | `19617118` | 2026-06-26 | `MultiblockHelpers.handleAdvancedPlacedBy` redirige vers le contrôleur ; `CNAdvancementBehaviour` vérifie l'état Minecraft natif (`isAlreadyAwardedTo`) au lieu d'une liste interne. Élimine un risque de double-attribution. | +| Retrait du `LOGGER.warn` redondant dans `ReactorAssembler.assemble` (spam de log) | `b309f231` | 2026-06-26 | Plus aucun `LOGGER.warn`/`info` dans le chemin de succès. | +| `NuclearExplosionEntity` : anti-pattern `try { onBlockExploded } catch(Exception) { destroyBlock(...) }` remplacé par une vérification explicite (`getBlockState(immutablePos).is(state.getBlock())`) | `11b1108a` | 2026-06-22 | Introduit par `5acde3db` (2026-03-04, compat Alex's Caves), corrigé par `11b1108a`. Antérieur à la fenêtre de commits habituellement explorée en détail par ce document, mais retrouvé avec certitude par `git log -S "immutablePos"`. | + +**Commit à mention neutre (ni bug ni fix, clarification)** : `20c1df0b` (*"IO blocks are now natively Casings in NBT"*) — message trompeur, ne change **rien** à l'architecture : nettoyage cosmétique de 22 lignes d'une scène Ponder. Les blocs I/O (`ReactorOutput`, `ReactorRodInput`, `ReactorFluidInput`, `ReactorAlarm`) restent des classes `Block` séparées de `ReactorCasing`. + +### 8.2 Réfutations / non-problèmes confirmés (architecture) + +Ces affirmations historiques ont été vérifiées comme **fausses ou déjà closes** dans le code actuel — elles ne correspondent à aucun commit de correction isolé (soit rien n'a jamais été cassé, soit la résolution est le résultat cumulatif de nombreux commits non attribuables individuellement) : + +- **Inversion de dépendance `api/`** — ❌ toujours réfuté : `MultiBlockManagerBeta`, `api/multiblock/rods/RodType`, `api/multiblock/fluid/ReactorFluidType` n'importent aucun `content.*` (revérifié par grep sur tout `api/`, 2026-07-12 : zéro résultat). *Pas de hash applicable — l'inversion alléguée par `AUDIT_V1.md` n'existe pas dans l'historique observé.* +- **Deux/trois frameworks multiblock concurrents** — ❌ toujours réfuté : `lib/multiblock/manager/*` et `IBetterPattern` n'existent pas (8 fichiers restants dans `lib/multiblock/`, tous utilisés). *Pas de hash applicable.* +- **God class `ReactorControllerBlockEntity`** — ✅ chantier clos, croissance maîtrisée : **533 lignes** (886 dans `AUDIT_V1.md`, 492 puis 529 aux tours intermédiaires), délégation à 34 fichiers de support (`service/` 14, `manager/` 12, `consumable/` 6, `display/` 2). *Pas de hash unique — résultat cumulatif de dizaines de commits d'extraction progressive vers `manager/service/consumable`, non attribuable avec certitude à un commit isolé.* +- **Coordinateur de verrou fluide dédié** — ✅ toujours non justifié : `PersistentFluidLocks` reste le seul système ; pas de `FluidLockManager` concurrent retrouvé (celui décrit en `AUDIT_V1.md` B14 a disparu, hash non déterminé — voir §8.4). `clearLockIfAllInputsEmpty` utilise `getFuildHandlers(level)` (pas de scan 3D), double itération mineure sans gravité. +- **`clearLockIfAllInputsEmpty` : pas de scan cubique O(n³)** — ✅ acceptable, confirmé sain. + +### 8.3 Décisions produit exécutées + +- **Collier teignable chat/loup** — décision prise : retrait complet de la mécanique plutôt que finir le câblage. `IrradiatedCatCollarLayer.java`/`IrradiatedWoldCollarLayer.java` supprimés (aucun appelant, confirmé par grep) ; `DATA_COLLAR_COLOR`, `getCollarColor()`/`setCollarColor()`, et le NBT associé retirés d'`IrradiatedCat.java` ; interaction `DyeItem` retirée de `mobInteract` (complète une suppression partielle laissée par une édition en cours qui rendait le code non compilable en état intermédiaire). `IrradiatedWolf` n'avait de toute façon jamais câblé cette mécanique. Note : `getBreedOffspring` (`IrradiatedCat.java:248-260`) appelle toujours `setCollarColor`/`getCollarColor`, mais sur des `Cat` **vanilla** (API Minecraft native), sans rapport avec la mécanique retirée — laissé tel quel à raison. Hash : `17b29aa3` (2026-07-11). +- **Apprivoisement des mobs irradiés bloqué avec message "WIP"** plutôt que laissé cassé/incohérent — décision produit exécutée en même temps que le retrait du collier. Hash : `261b26d8` (2026-07-11). + +### 8.4 Corrections historiques d'`AUDIT_V1.md` — hash non déterminé avec certitude pour la majorité + +L'audit courant indique depuis plusieurs tours que les bugs suivants d'`AUDIT_V1.md` sont **vérifiés résolus dans le code actuel** : **B2, B3, B4, B5, B6, B8, B9, B11, B13, B16, B19, B12, B14**, l'off-by-one `getFluidInTank`, l'icône d'item de l'armure anti-radiation teintée, et l'ensemble des problèmes radiation historiques (point de vérité unique `canBeIrradiated`). Cette réorganisation a tenté de retrouver un hash de commit pour chacun via `git log -S` sur des chaînes distinctives ; résultat : + +- **B15 (anti-pattern try/catch `NuclearExplosionEntity`)** — ✅ hash déterminé avec certitude : `11b1108a` (voir §8.1). +- **B9 (palier radiation `amplifierLevel0` dupliqué)** — candidat trouvé mais **non confirmé avec certitude** : `3b84bac4` ("refactor: update IrradiatedSurfaceRules and RadiationCapability for improved biome handling and radiation amplification logic") est thématiquement plausible mais le diff n'a pas été vérifié en détail. À valider manuellement avant de le citer comme preuve. +- **B13 (bras invisibles de l'armure anti-radiation)** — candidat trouvé mais **non confirmé avec certitude** : `d9ba3956` (2026-06-26, "fix: adjust arm dimensions and positions in AntiRadiationArmor model for better alignment") correspond thématiquement mais ne mentionne pas explicitement le bug des bras invisibles dans son message. À valider manuellement. +- **B1, B2, B4, B5, B18** — **non déterminé**. Recherches `git log -S` ciblées effectuées sur les chaînes distinctives de chaque bug (`&& false`, `RadiationSyncPacket`, valeur de drop `THORIUM_BLOCK`, `BiomeTagRule`/`return null`, clé config `screenShaking`) sans résultat concluant. Ces corrections sont probablement antérieures à la fenêtre de commits explorée en détail par ce document (avant le 2026-06-24) ; les retrouver demanderait une revue manuelle complète de l'historique pré-fenêtre, disproportionnée par rapport au gain (le code actuel confirme déjà que le bug n'est plus présent, seule la traçabilité du commit manque). +- **Reste de la liste** (B3, B6, B8, B11, B12, B16, B19, off-by-one `getFluidInTank`, icône armure, historique radiation complet) — recherche non retentée par souci de proportionnalité : chaque item nécessiterait sa propre requête `git log -S` sur une chaîne distinctive extraite manuellement du code originel décrit par `AUDIT_V1.md`, pour un ensemble de plus de 10 items mineurs déjà revérifiés comme absents du code actuel à plusieurs tours d'audit successifs. **Si la traçabilité individuelle de ces corrections devient nécessaire (audit externe, obligation de conformité), prévoir une session dédiée à l'archéologie Git plutôt que de l'inclure au fil de l'eau d'un audit de code.** + +**Dead code massif d'`AUDIT_V1.md`** (§3 de ce document historique : `lib.multiblock.manager.*`, framework d'animation keyframe, `CreateNuclearDamageSources`, `CommentEventClients`, fichier `possible code`, `CNShapelessRecipeGen`, `RadiationOverlay`/`EasingHudOverlay`, `IrradiatedSurfaceRules` v1, `VerifyPattern7x7`/`9x9`, `saveData2`, et la longue liste de membres/méthodes/imports morts §3) — non revérifié individuellement dans cette réorganisation (hors périmètre de la demande, qui portait sur la réorganisation d'`AUDIT_ACTUEL.md` et non sur un nouveau balayage complet du dead code d'`AUDIT_V1.md`). Signal indirect : `lib/multiblock/` ne contient plus que 8 fichiers, tous utilisés (revérifié §8.2), ce qui suggère que le plus gros bloc (`lib.multiblock.manager.*` + `IBetterPattern`) a bien été supprimé à un moment de l'historique — mais aucun hash précis n'a été recherché pour cette réorganisation. From 3be6252a61ac4e2ffa451303c2091eed5f0bf78a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 15:18:21 +0200 Subject: [PATCH 144/171] style: translate French comments and Javadoc to English in VicinityEffect and CNPonderReactorScenes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the two highest-priority cases from the §6 documentation audit: - VicinityEffect.java: Javadoc of the abstract extension point onContaminate(LivingEntity) was bilingual (English opening sentence, then French body). Fully rewritten in English; meaning preserved verbatim. - CNPonderReactorScenes.java: seven comments and three Javadoc blocks translated to English — - Positions class Javadoc: scene-coordinate convention now readable by any contributor. - STATIC_POS field Javadoc: dev-note phrasing ("adapte ces valeurs...") replaced with stable documentation. - Three "Exemple pour Tx" block comments → "Example for Tx". - positionsFor() Javadoc and its NPE-avoidance fallback comment. - Inline positional labels: "devant", "derrière", "à droite" → "front", "back", "right". - PEDESTAL_Y inline comment: "couche de piedestal" → "pedestal layer". No logic or behaviour changed. --- .../content/effects/VicinityEffect.java | 6 ++--- .../ponder/scenes/CNPonderReactorScenes.java | 24 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java index 00de7508..9b5590b0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/effects/VicinityEffect.java @@ -51,9 +51,9 @@ public void applyEffectTick(LivingEntity entity, int amplifier) { } /** - * Called for each eligible nearby entity once its cooldown expires. Chaque sous-classe - * décide comment elle transmet réellement l'effet (ex: RadiationEffect alimente la dose - * de RadiationCapability plutôt que d'ajouter un MobEffect directement). + * Called for each eligible nearby entity once its cooldown expires. Each subclass + * decides how it actually delivers the effect (e.g. RadiationEffect feeds the dose + * into RadiationCapability rather than adding a MobEffect directly). */ protected abstract void onContaminate(LivingEntity nearby); diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 0be3884e..5e3fe1f6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -24,12 +24,12 @@ public class CNPonderReactorScenes { private static final int S_T3 = 9; private static final int H_T3 = 11; - private static final int PEDESTAL_Y = 0; // couche de piedestal (snow/concrete) + private static final int PEDESTAL_Y = 0; // pedestal layer (snow/concrete) private static final int MULTIBLOCK_BASE_Y = 1; // multiblock starts at y=1 private static final int MARGIN = 2; // Create margin private static int plateSizeFor(int multiblockSize) { return multiblockSize + MARGIN * 2; } - /** * Conteneur simple pour stocker toutes les positions d'intérêt d'un multiblock. * Les BlockPos ici doivent être EN COORDONNÉES SCÈNE (0..plate-1 pour X/Z, 1..H pour Y). */ + /** * Simple container for storing all positions of interest for a multiblock. * The BlockPos values here must be in SCENE COORDINATES (0..plate-1 for X/Z, 1..H for Y). */ private static class Positions { final BlockPos controller, input1, input2, liquidInput, alarm, output; Positions(BlockPos controller, BlockPos input1, BlockPos input2, BlockPos liquidInput, BlockPos alarm, BlockPos output) { @@ -47,11 +47,11 @@ BlockPos[] specials() { } } - /** * Map statique – remplis/ajuste les coordonnées ici pour chaque taille (multiblockSize). * Exemple : clef = 5 pour S_T1 (5x5), 7 pour S_T2, 9 pour S_T3. * * Règle : x/z en 0..plate-1, y en 1..H ; adapte ces valeurs exactement comme dans ton NBT. */ + /** * Static map of positions per multiblock size. * Key = multiblockSize (5 for S_T1, 7 for S_T2, 9 for S_T3). * * Rule: x/z in 0..plate-1, y in 1..H; these values must match the structure's actual NBT layout. */ private static final Map STATIC_POS = new HashMap<>(); static { - // Exemple pour T1 (multiblockSize = 5) - // plate = 5 + 4 = 9 => x/z valides : 0..8 ; multiblock intérieur : 2..6 + // Example for T1 (multiblockSize = 5) + // plate = 5 + 4 = 9 => valid x/z: 0..8; inner multiblock: 2..6 STATIC_POS.put(5, new Positions( new BlockPos(4, 4, 6), // controller new BlockPos(3, 2, 6), // input1 @@ -61,7 +61,7 @@ BlockPos[] specials() { new BlockPos(5, 2, 6) // output )); - // Exemple pour T2 (multiblockSize = 7) + // Example for T2 (multiblockSize = 7) STATIC_POS.put(7, new Positions( new BlockPos(5, 5, 8), // controller new BlockPos(3, 3, 8), // input1 @@ -71,7 +71,7 @@ BlockPos[] specials() { new BlockPos(7, 3, 8) // output )); - // Exemple pour T3 (multiblockSize = 9) + // Example for T3 (multiblockSize = 9) STATIC_POS.put(9, new Positions( new BlockPos(6, 6, 10), // controller new BlockPos(5, 4, 10), // input1 @@ -82,12 +82,12 @@ BlockPos[] specials() { )); } - /** * Retourne les positions statiques pour la taille donnée. * Si aucune entrée statique n'existe, retourne des positions calculées "raisonnables". */ + /** * Returns the static positions for the given size. * If no static entry exists, returns "reasonable" computed positions instead. */ private static Positions positionsFor(int multiblockSize, int height) { Positions p = STATIC_POS.get(multiblockSize); if (p != null) return p; - // fallback : calcul simple centré (si tu veux éviter un NPE) + // fallback: simple centered calculation (avoids an NPE) int plate = plateSizeFor(multiblockSize); int offset = MARGIN; int cx = offset + (multiblockSize / 2); @@ -95,11 +95,11 @@ private static Positions positionsFor(int multiblockSize, int height) { int cy = MULTIBLOCK_BASE_Y + (height / 2); return new Positions( new BlockPos(cx, cy, cz), // controller - new BlockPos(cx, MULTIBLOCK_BASE_Y+1, offset + multiblockSize - 1), // input1 devant + new BlockPos(cx, MULTIBLOCK_BASE_Y+1, offset + multiblockSize - 1), // input1 front new BlockPos(cx, Math.min(MULTIBLOCK_BASE_Y+height-1, MULTIBLOCK_BASE_Y+2), offset + multiblockSize - 1), // input2 - new BlockPos(cx, cy, offset), // liquidInput derrière + new BlockPos(cx, cy, offset), // liquidInput back new BlockPos(Math.max(offset, cx-1), cy, cz), // alarm - new BlockPos(offset + multiblockSize - 1, cy, cz) // output à droite + new BlockPos(offset + multiblockSize - 1, cy, cz) // output right ); } From 2d82f13a82f13ee4675d0f530633c2e2f4560439 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 15:23:51 +0200 Subject: [PATCH 145/171] =?UTF-8?q?docs:=20update=20AUDIT=5FACTUEL.md=20to?= =?UTF-8?q?=20record=20French-comment=20translation=20and=20close=20=C2=A7?= =?UTF-8?q?6=20Javadoc=20priority=20item?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §6 global count updated from 14/40 to 12 files/~25 lines following commit 3be6252a (VicinityEffect.java + CNPonderReactorScenes.java fully translated). - §6 top of section: four resolved Javadoc cases moved out of the "most significant" list and replaced with an explicit "Résolu" summary block; CNPonderReactorScenes removed from the recurring-pattern file list. - §6 ambiguities: CNPonderReactorScenes.java:50,90 entry struck through and marked resolved (reformulated to stable documentation in the same commit). - §6 priority recommendation updated: 4 public-Javadoc cases now committed and closed; remaining ~25 lines deferred to incremental cleanup. - §7 roadmap item #8: Javadoc translation sub-task struck through as done; remaining scope (items 5-15, ~25 lines, 12 files) stated explicitly. - §8.1 fix-log table: new entry for commit 3be6252a with affected files and updated file/line counts. --- AUDIT_ACTUEL.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 7438a71f..3e770a31 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -99,15 +99,15 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to **Périmètre** : `src/main/java` (292 fichiers), recherche des commentaires/Javadoc non rédigés en anglais et des cas ambigus/incomplets indépendamment de la langue. Méthodologie : recherche par caractères accentués + vocabulaire français typique des commentaires, puis lecture manuelle des occurrences trouvées. -**Décompte global** : **14 fichiers sur 292** (~5 %) contiennent du français détectable, pour environ **40 lignes** de commentaires/Javadoc concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires et Javadoc**, pas à l'API elle-même. Le mélange est quasi systématique FR/EN **dans le même fichier**, parfois la même méthode — jamais un fichier intégralement en français. +**Décompte global** *(mis à jour 2026-07-12, commit `3be6252a`)* : **12 fichiers sur 292** (~4 %) contiennent encore du français détectable, pour environ **25 lignes** de commentaires/Javadoc concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires et Javadoc**, pas à l'API elle-même. -**Cas les plus significatifs** : +**Résolu** — les 4 cas de Javadoc public bilingue, seul sous-item classé 🟢 prioritaire au tour précédent, ont été traduits en intégralité (commit `3be6252a`, *"style: translate French comments and Javadoc to English in VicinityEffect and CNPonderReactorScenes"*) : +- `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)` entièrement repassée en anglais. +- `infrastructure/ponder/scenes/CNPonderReactorScenes.java` — fichier intégralement traduit : Javadoc de `Positions` (l.32), de `STATIC_POS` (l.50, reformulée en documentation stable plutôt qu'en note à soi-même) et de `positionsFor` (l.85), plus tous les commentaires inline restants (pedestal, exemples T1/T2/T3, fallback, positions devant/derrière/droite). Ce fichier ne contient plus aucun français. -*Javadoc public sur API/points d'extension — le plus grave car visible par tout futur contributeur :* -1. `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)`, point d'extension abstrait clé (`RadiationEffect` en dépend) : première phrase en anglais, puis bascule en français dans la même doc. Pire cas relevé : Javadoc public, méthode non triviale, bilingue au sein d'un seul bloc. -2. `infrastructure/ponder/scenes/CNPonderReactorScenes.java:32` — Javadoc de la classe interne `Positions` entièrement en français, documentant une convention critique non répétée ailleurs (« Les BlockPos ici doivent être EN COORDONNÉES SCÈNE »). -3. `infrastructure/ponder/scenes/CNPonderReactorScenes.java:50` — Javadoc de `STATIC_POS` rédigé comme une note à soi-même plutôt qu'une documentation (« adapte ces valeurs exactement comme dans ton NBT »). -4. `infrastructure/ponder/scenes/CNPonderReactorScenes.java:85` — Javadoc de `positionsFor` en français ; bloque la lecture pour un contributeur non francophone d'une scène Ponder (bibliothèque Create, publique par nature). +Ces deux fichiers sortent donc de la liste ci-dessous et sont déplacés dans la table de §8.1. + +**Cas les plus significatifs restants** : *Commentaires sur logique métier non triviale :* 5. `CNFluids.java:139,153,156,159` — bloc de commentaires français documentant une correction fine de désynchronisation client/serveur des ticks de gel/dégel (compensation d'offset). Logique fragile, documentée uniquement en français. @@ -123,15 +123,15 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to 15. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. **Ambiguïtés/incomplétudes indépendantes de la langue relevées au passage** : -- `CNPonderReactorScenes.java:50,90` — formulations en forme de note de dev figée dans le code (« adapte ces valeurs... comme dans ton NBT », « si tu veux éviter un NPE ») plutôt qu'une documentation stable, à reformuler indépendamment de la traduction. +- ~~`CNPonderReactorScenes.java:50,90`~~ — **résolu** (`3be6252a`) : les deux Javadoc ont été reformulées en documentation stable en même temps que leur traduction (voir ci-dessus). - `ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée — ambiguïté fonctionnelle non résolue. - `CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers. -**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité** et se concentre sur un noyau stable de fichiers : les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSummaryDisplaySource`, `ReactorSizeDisplaySource`), les scènes Ponder (`CNPonderReactorScenes`), et `CNFluids`/`ClientEvents`. Aucun de ces fichiers n'a été assaini depuis. Point positif : le sous-ensemble concerné est petit et stable (14/292 fichiers, ~5 %) et n'a pas grossi récemment — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger) n'ont pas introduit de nouveau commentaire français. +**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité mais se réduit** : il se concentre désormais sur les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSummaryDisplaySource`, `ReactorSizeDisplaySource`), et `CNFluids`/`ClientEvents`. Les scènes Ponder (`CNPonderReactorScenes`) sortent de cette liste, assainies cette session. Point positif : le sous-ensemble concerné continue de rétrécir (12/292 fichiers désormais, ~4 %) — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger) n'ont pas introduit de nouveau commentaire français. -**Pourquoi ça doit être suivi** : ces commentaires portent presque toujours l'explication du *pourquoi* d'un choix non trivial (compat cross-mod, compensation de désync réseau, convention de coordonnées Ponder, garde défensive) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). +**Pourquoi ça doit être suivi** : ces commentaires portent presque toujours l'explication du *pourquoi* d'un choix non trivial (compat cross-mod, compensation de désync réseau, garde défensive) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). -**Priorité recommandée** : 🟢 **cosmétique, à faire au fil de l'eau — pas bloquant.** Aucun symbole d'API n'est en français, donc pas d'impact sur la lisibilité des signatures pour un contributeur externe. Traiter en priorité les 4 cas de Javadoc public (items 1-4 ci-dessus, notamment `VicinityEffect.java` et `CNPonderReactorScenes.java`, seuls vrais cas de Javadoc public bilingue) lors du prochain passage sur ces fichiers, plutôt que d'ouvrir un chantier de traduction dédié — le volume (~40 lignes) ne le justifie pas. Chaque futur commit touchant l'un des 14 fichiers devrait normaliser en anglais les commentaires qu'il modifie. **Suivi** : cet item reste en §6 jusqu'à ce que les 4 cas de Javadoc public soient traduits ; à re-scanner périodiquement (le pattern n'a pas grossi depuis le dernier audit, mais rien ne garantit que ça dure). +**Priorité recommandée** : 🟢 **cosmétique, à faire au fil de l'eau — pas bloquant.** Aucun symbole d'API n'est en français, donc pas d'impact sur la lisibilité des signatures pour un contributeur externe. Les 4 cas de Javadoc public (`VicinityEffect.java` et `CNPonderReactorScenes.java` ×3, seuls vrais cas de Javadoc public bilingue) sont traduits et committés (`3be6252a`). Pas de chantier de traduction dédié à ouvrir pour le reste (~25 lignes restantes) : chaque futur commit touchant l'un des 12 fichiers restants devrait normaliser en anglais les commentaires qu'il modifie. **Suivi** : cet item reste en §6, à re-scanner périodiquement. --- @@ -165,7 +165,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq - Worldgen « irradié » : retirer le contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`) et choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. **8. Documentation (nouveau, §6)** -- Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3) en priorité, puis les commentaires métier non triviaux listés en §6, au fil des prochains passages sur ces fichiers. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais ce sont typiquement des commentaires qui expliquent un « pourquoi » non trivial (compat, désync réseau, convention Ponder) — les laisser en français limite l'audit/onboarding futur. +- ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait cette session** (working tree, à committer). Reste : les commentaires métier non triviaux listés en §6 (items 5-15, ~25 lignes sur 12 fichiers), au fil des prochains passages sur ces fichiers. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais ce sont typiquement des commentaires qui expliquent un « pourquoi » non trivial (compat, désync réseau) — les laisser en français limite l'audit/onboarding futur. **9. À surveiller sans action immédiate** - `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. @@ -187,6 +187,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| Traduction en anglais des 4 cas de Javadoc public bilingue relevés en §6 (`VicinityEffect.onContaminate`, `CNPonderReactorScenes.Positions`/`STATIC_POS`/`positionsFor`), plus l'intégralité des commentaires inline restants de `CNPonderReactorScenes.java` | `3be6252a` | 2026-07-12 | `VicinityEffect.java` et `CNPonderReactorScenes.java` ne contiennent plus aucun français ; sortis de la liste §6 (14→12 fichiers concernés, ~40→~25 lignes). | | Retrait de `IrradiatedBiomes.monsters()` (corps vide, arguments ignorés) | `8b0428e3` | 2026-07-12 | Méthode et son unique site d'appel supprimés ; les réglages de spawn passent désormais uniquement par `MobSpawnSettings.Builder`. | | Blocage explicite (message "WIP") de l'apprivoisement des mobs irradiés (`AnimalUtil.blockTamingWip`) | `261b26d8` | 2026-07-11 | Remplace un apprivoisement cassé/incohérent (chat : collier non fonctionnel ; loup : aucun chemin d'apprivoisement) par un message explicite "pas encore implémenté". Ce même commit a aussi retiré la mécanique de collier (§8.3). | | Retrait de la mécanique de collier teignable jamais câblée (`IrradiatedCatCollarLayer`, `IrradiatedWoldCollarLayer`, `DATA_COLLAR_COLOR`) | `17b29aa3` | 2026-07-11 | Décision produit exécutée — voir §8.3 pour le contexte de la décision. | From 200df62fb853634b9d30dd1847cefa2cbb60c99e Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 16:10:11 +0200 Subject: [PATCH 146/171] test: add GameTest suite for ReactorInputFluidManager covering the audited over-extraction bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces the first automated tests in the project (src/test was empty until now). ReactorInputFluidManagerGameTest.java — 23 GameTests running against a real ServerLevel and real ReactorFluidInputEntity blocks (no mocks): - NBT round-trip (read/write): absent key, clear-on-read, single and multiple entries, order preservation, write-then-read symmetry. - clearInvalid: missing block entity, block entity without fluid capability, valid fluid input, mixed set. - getBlocksPosition(Level): filters non-matching entity types. - getFuildHandlers: capability present, insertion-order preservation. - getInventory: empty case, aggregation across multiple handlers. - extractFluids (core of the audited bug, AUDIT_ACTUEL.md §1): - null level, no handlers, single handler with enough/insufficient stock, need-zero guard, empty-handler graceful skip. - *_currentBehavior / *_characterization tests: document and pin what the code does today (toExtract > 1 guard silently ignores unit-1 requests; fluidNeeded never decremented causes both handlers to drain in full). - *_expectedContract tests: assert the intended contract and are EXPECTED TO FAIL against the current implementation — they act as regression markers for the upcoming fix. - Javadoc-mismatch characterization: return value semantics diverge from the method's own Javadoc (true on partial extraction). empty_platform.nbt — 5×3×5 stone-floor structure used as the shared test template; placed under data/createnuclear/structures/ per Forge's GameTest auto-discovery convention. --- .../ReactorInputFluidManagerGameTest.java | 494 ++++++++++++++++++ .../structures/empty_platform.nbt | Bin 0 -> 208 bytes 2 files changed, 494 insertions(+) create mode 100644 src/main/java/net/nuclearteam/createnuclear/gametest/ReactorInputFluidManagerGameTest.java create mode 100644 src/main/resources/data/createnuclear/structures/empty_platform.nbt diff --git a/src/main/java/net/nuclearteam/createnuclear/gametest/ReactorInputFluidManagerGameTest.java b/src/main/java/net/nuclearteam/createnuclear/gametest/ReactorInputFluidManagerGameTest.java new file mode 100644 index 00000000..b645f3b0 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/gametest/ReactorInputFluidManagerGameTest.java @@ -0,0 +1,494 @@ +package net.nuclearteam.createnuclear.gametest; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.gametest.PrefixGameTestTemplate; +import net.minecraftforge.registries.ForgeRegistries; +import net.nuclearteam.createnuclear.CNBlocks; +import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.content.multiblock.controller.manager.ReactorInputFluidManager; +import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity; +import net.nuclearteam.createnuclear.content.multiblock.input.fluid.VirtualReactorInputFluid; +import net.nuclearteam.createnuclear.foundation.block.MultiDirectionalReactorBlock; + +import java.util.List; + +/** + * GameTest coverage for {@link ReactorInputFluidManager}, run against a real + * {@code ServerLevel} and real {@link ReactorFluidInputEntity} blocks (no mocks). + *

+ * All tests share the "empty_platform" structure + * (data/createnuclear/structures/empty_platform.nbt): a 5x3x5 area with a + * stone floor at y=0, leaving y=1..2 free to place fluid input blocks. The structure + * is a real compressed structure-block export (a hand-authored .snbt cannot be loaded + * directly here: Forge only auto-discovers packaged ".nbt" structures under + * data/<namespace>/structures/, not loose ".snbt" text unless it also sits on disk + * relative to the run's working directory). + *

+ * Tests named "*_expectedContract" assert the documented/intended behavior of + * extractFluids and are EXPECTED TO FAIL against the current implementation + * (AUDIT_ACTUEL.md, ReactorInputFluidManager.java:137-155). They act as regression + * markers for the future fix. Tests named "*_currentBehavior"/"*_characterization" + * assert what the code does today and should keep passing until that fix lands. + */ +@GameTestHolder(CreateNuclear.MOD_ID) +@PrefixGameTestTemplate(false) +public class ReactorInputFluidManagerGameTest { + + private static final String STRUCTURE = "empty_platform"; + + // ---------- test fixtures ---------- + + private static void place(GameTestHelper helper, BlockPos rel, Direction facing) { + helper.setBlock(rel, CNBlocks.REACTOR_FLUID_INPUT.get().defaultBlockState() + .setValue(MultiDirectionalReactorBlock.FACING, facing)); + } + + private static ReactorFluidInputEntity entity(GameTestHelper helper, BlockPos rel) { + return (ReactorFluidInputEntity) helper.getBlockEntity(rel); + } + + private static void fill(GameTestHelper helper, BlockPos rel, FluidStack stack) { + entity(helper, rel).getCapability(ForgeCapabilities.FLUID_HANDLER) + .ifPresent(h -> h.fill(stack, FluidAction.EXECUTE)); + } + + private static int tankAmount(GameTestHelper helper, BlockPos rel) { + return entity(helper, rel).getCapability(ForgeCapabilities.FLUID_HANDLER) + .map(h -> h.getFluidInTank(0).getAmount()) + .orElse(-1); + } + + private static ReactorInputFluidManager manager(GameTestHelper helper, BlockPos... relPositions) { + ReactorInputFluidManager manager = new ReactorInputFluidManager(); + for (BlockPos rel : relPositions) manager.addBlock(helper.absolutePos(rel)); + return manager; + } + + // ================================================================ + // read / write (pure NBT, no world interaction required) + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void read_absentKey_leavesEmpty(GameTestHelper helper) { + ReactorInputFluidManager manager = new ReactorInputFluidManager(); + manager.read(new CompoundTag()); + + helper.assertTrue(manager.size() == 0, "expected no tracked positions when NBT key is absent"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void read_clearsPreviousPositions(GameTestHelper helper) { + ReactorInputFluidManager manager = new ReactorInputFluidManager(); + manager.addBlock(new BlockPos(1, 2, 3)); + + manager.read(new CompoundTag()); + + helper.assertTrue(manager.size() == 0, "read() must clear previously tracked positions before loading"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void read_singleEntry_roundTrips(GameTestHelper helper) { + CompoundTag entry = new CompoundTag(); + entry.putInt("x", 5); + entry.putInt("y", 64); + entry.putInt("z", -3); + ListTag list = new ListTag(); + list.add(entry); + CompoundTag root = new CompoundTag(); + root.put("ReactorInputFluid", list); + + ReactorInputFluidManager manager = new ReactorInputFluidManager(); + manager.read(root); + + helper.assertTrue(manager.size() == 1, "expected exactly one entry after read"); + helper.assertTrue(manager.contains(new BlockPos(5, 64, -3)), "expected BlockPos(5,64,-3) to be present"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void read_multipleEntries_preservesOrder(GameTestHelper helper) { + BlockPos a = new BlockPos(0, 0, 0); + BlockPos b = new BlockPos(1, 1, 1); + BlockPos c = new BlockPos(2, 2, 2); + + ListTag list = new ListTag(); + for (BlockPos p : List.of(a, b, c)) { + CompoundTag entry = new CompoundTag(); + entry.putInt("x", p.getX()); + entry.putInt("y", p.getY()); + entry.putInt("z", p.getZ()); + list.add(entry); + } + CompoundTag root = new CompoundTag(); + root.put("ReactorInputFluid", list); + + ReactorInputFluidManager manager = new ReactorInputFluidManager(); + manager.read(root); + + helper.assertTrue(manager.getBlocksPosition().equals(List.of(a, b, c)), + "expected insertion order to be preserved, found " + manager.getBlocksPosition()); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void write_emptyPositions_stillWritesKey(GameTestHelper helper) { + CompoundTag tag = new CompoundTag(); + new ReactorInputFluidManager().write(tag); + + helper.assertTrue(tag.contains("ReactorInputFluid"), "write() should always write the NBT key, even when empty"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void write_then_read_roundTrip(GameTestHelper helper) { + BlockPos a = new BlockPos(1, 2, 3); + BlockPos b = new BlockPos(-5, 64, 100); + + ReactorInputFluidManager original = new ReactorInputFluidManager(); + original.addBlock(a); + original.addBlock(b); + + CompoundTag tag = new CompoundTag(); + original.write(tag); + + ReactorInputFluidManager restored = new ReactorInputFluidManager(); + restored.read(tag); + + helper.assertTrue(restored.getBlocksPosition().equals(List.of(a, b)), + "round-trip through NBT should preserve exact positions and order"); + helper.succeed(); + } + + // ================================================================ + // clearInvalid + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void clearInvalid_missingBlockEntity_removesPosition(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); // never placed: air, no block entity + ReactorInputFluidManager manager = manager(helper, rel); + + manager.clearInvalid(helper.getLevel()); + + helper.assertTrue(manager.size() == 0, "a position without a block entity should be removed"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void clearInvalid_noCapability_removesPosition(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + helper.setBlock(rel, Blocks.CHEST.defaultBlockState()); // real BE, no fluid capability + ReactorInputFluidManager manager = manager(helper, rel); + + manager.clearInvalid(helper.getLevel()); + + helper.assertTrue(manager.size() == 0, "a block entity without a fluid capability should be removed"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void clearInvalid_validCapability_keepsPosition(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + ReactorInputFluidManager manager = manager(helper, rel); + + manager.clearInvalid(helper.getLevel()); + + helper.assertTrue(manager.size() == 1, "a valid ReactorFluidInputEntity should be kept"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void clearInvalid_mixedSet_onlyInvalidRemoved(GameTestHelper helper) { + BlockPos valid = new BlockPos(1, 1, 1); + BlockPos chest = new BlockPos(3, 1, 1); + BlockPos missing = new BlockPos(1, 1, 3); + + place(helper, valid, Direction.NORTH); + helper.setBlock(chest, Blocks.CHEST.defaultBlockState()); + + ReactorInputFluidManager manager = manager(helper, valid, chest, missing); + manager.clearInvalid(helper.getLevel()); + + helper.assertTrue(manager.getBlocksPosition().equals(List.of(helper.absolutePos(valid))), + "only the valid fluid input position should remain, found " + manager.getBlocksPosition()); + helper.succeed(); + } + + // ================================================================ + // getBlocksPosition(Level) + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void getBlocksPosition_filtersNonMatchingEntityType(GameTestHelper helper) { + BlockPos validRel = new BlockPos(1, 1, 1); + BlockPos otherRel = new BlockPos(3, 1, 1); + place(helper, validRel, Direction.NORTH); + helper.setBlock(otherRel, Blocks.CHEST.defaultBlockState()); + + ReactorInputFluidManager manager = manager(helper, validRel, otherRel); + + List result = manager.getBlocksPosition(helper.getLevel()); + + helper.assertTrue(result.equals(List.of(helper.absolutePos(validRel))), + "only the ReactorFluidInputEntity position should be returned, found " + result); + helper.succeed(); + } + + // ================================================================ + // getFuildHandlers + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void getFuildHandlers_capabilityPresent_included(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + fill(helper, rel, new FluidStack(Fluids.WATER, 500)); + + List handlers = manager(helper, rel).getFuildHandlers(helper.getLevel()); + + helper.assertTrue(handlers.size() == 1, "expected exactly one handler"); + helper.assertTrue(handlers.get(0).getFluidInTank(0).getAmount() == 500, + "handler should expose the filled tank content"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void getFuildHandlers_preservesTrackingOrder(GameTestHelper helper) { + BlockPos rel1 = new BlockPos(1, 1, 1); + BlockPos rel2 = new BlockPos(3, 1, 1); + place(helper, rel1, Direction.NORTH); + place(helper, rel2, Direction.NORTH); + fill(helper, rel1, new FluidStack(Fluids.WATER, 100)); + fill(helper, rel2, new FluidStack(Fluids.LAVA, 200)); + + List handlers = manager(helper, rel1, rel2).getFuildHandlers(helper.getLevel()); + + helper.assertTrue(handlers.size() == 2, "expected two handlers"); + helper.assertTrue(handlers.get(0).getFluidInTank(0).getFluid() == Fluids.WATER, + "first handler should be the water tank (matches insertion order)"); + helper.assertTrue(handlers.get(1).getFluidInTank(0).getFluid() == Fluids.LAVA, + "second handler should be the lava tank (matches insertion order)"); + helper.succeed(); + } + + // ================================================================ + // getInventory + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void getInventory_noHandlers_returnsEmpty(GameTestHelper helper) { + VirtualReactorInputFluid inventory = new ReactorInputFluidManager().getInventory(helper.getLevel()); + + helper.assertTrue(inventory.fluids().isEmpty(), "expected an empty inventory with no tracked handlers"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void getInventory_aggregatesAcrossHandlers(GameTestHelper helper) { + BlockPos rel1 = new BlockPos(1, 1, 1); + BlockPos rel2 = new BlockPos(3, 1, 1); + place(helper, rel1, Direction.NORTH); + place(helper, rel2, Direction.NORTH); + fill(helper, rel1, new FluidStack(Fluids.WATER, 300)); + fill(helper, rel2, new FluidStack(Fluids.WATER, 250)); + + VirtualReactorInputFluid inventory = manager(helper, rel1, rel2).getInventory(helper.getLevel()); + + ResourceLocation waterId = ForgeRegistries.FLUIDS.getKey(Fluids.WATER); + long total = inventory.getAmount(waterId); + helper.assertTrue(total == 550, "expected aggregated total of 550, found " + total); + helper.succeed(); + } + + // ================================================================ + // extractFluids — core of the audited bug + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void extractFluids_nullLevel_returnsFalse(GameTestHelper helper) { + boolean result = new ReactorInputFluidManager().extractFluids(null, 10); + helper.assertTrue(!result, "extractFluids should return false for a null level"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void extractFluids_noHandlers_returnsFalse(GameTestHelper helper) { + boolean result = new ReactorInputFluidManager().extractFluids(helper.getLevel(), 10); + helper.assertTrue(!result, "extractFluids should return false when there are no handlers"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void extractFluids_singleHandlerEnoughStock_drainsExactAmount(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + fill(helper, rel, new FluidStack(Fluids.WATER, 1000)); + + boolean result = manager(helper, rel).extractFluids(helper.getLevel(), 400); + + helper.assertTrue(result, "extraction should succeed when enough fluid is available"); + helper.assertTrue(tankAmount(helper, rel) == 600, "expected 600 remaining, found " + tankAmount(helper, rel)); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void extractFluids_singleHandlerInsufficientStock_drainsAvailable(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + fill(helper, rel, new FluidStack(Fluids.WATER, 30)); + + boolean result = manager(helper, rel).extractFluids(helper.getLevel(), 100); + + helper.assertTrue(result, "extraction should be reported successful even for a partial drain"); + helper.assertTrue(tankAmount(helper, rel) == 0, "all 30 available units should have been drained"); + helper.succeed(); + } + + /** + * Characterizes the CURRENT (buggy) behavior: "if (toExtract > 1)" silently ignores + * a request for exactly 1 unit. This test PASSES today. + */ + @GameTest(template = STRUCTURE) + public static void extractFluids_needOfOne_isSilentlyIgnored_currentBehavior(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + fill(helper, rel, new FluidStack(Fluids.WATER, 5)); + + boolean result = manager(helper, rel).extractFluids(helper.getLevel(), 1); + + helper.assertTrue(!result, "current implementation ignores single-unit extraction requests"); + helper.assertTrue(tankAmount(helper, rel) == 5, "tank should be untouched: the toExtract>1 guard blocks the drain"); + helper.succeed(); + } + + /** + * Asserts the intended contract: a request for exactly 1 unit with stock available + * should succeed. FAILS TODAY against ReactorInputFluidManager.java:147 + * ("if (toExtract > 1)") — acts as a regression marker for the fix. + */ + @GameTest(template = STRUCTURE) + public static void extractFluids_needOfOne_shouldSucceed_expectedContract(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + fill(helper, rel, new FluidStack(Fluids.WATER, 5)); + + boolean result = manager(helper, rel).extractFluids(helper.getLevel(), 1); + + helper.assertTrue(result, "a request for exactly 1 unit with stock available should succeed"); + helper.assertTrue(tankAmount(helper, rel) == 4, "expected exactly 1 unit to be drained"); + helper.succeed(); + } + + /** + * Characterizes the CURRENT (buggy) over-extraction: fluidNeeded is never + * decremented between handlers, so both handlers get drained in full. + * This test PASSES today. + */ + @GameTest(template = STRUCTURE) + public static void extractFluids_twoHandlers_currentBuggyBehavior_characterization(GameTestHelper helper) { + BlockPos rel1 = new BlockPos(1, 1, 1); + BlockPos rel2 = new BlockPos(3, 1, 1); + place(helper, rel1, Direction.NORTH); + place(helper, rel2, Direction.NORTH); + fill(helper, rel1, new FluidStack(Fluids.WATER, 10)); + fill(helper, rel2, new FluidStack(Fluids.WATER, 10)); + + manager(helper, rel1, rel2).extractFluids(helper.getLevel(), 10); + + helper.assertTrue(tankAmount(helper, rel1) == 0, "handler1 fully drained"); + helper.assertTrue(tankAmount(helper, rel2) == 0, + "handler2 is ALSO fully drained: over-extraction bug removes 20 units for a request of 10"); + helper.succeed(); + } + + /** + * Asserts the intended contract: extracting 10 units from a 20-unit pool spread + * across two handlers should leave 10 total remaining. FAILS TODAY against + * ReactorInputFluidManager.java:137-155 (fluidNeeded never decremented) — this is + * the flagship regression marker for the ticket's main bug. + */ + @GameTest(template = STRUCTURE) + public static void extractFluids_twoHandlers_shouldNotOverExtract_expectedContract(GameTestHelper helper) { + BlockPos rel1 = new BlockPos(1, 1, 1); + BlockPos rel2 = new BlockPos(3, 1, 1); + place(helper, rel1, Direction.NORTH); + place(helper, rel2, Direction.NORTH); + fill(helper, rel1, new FluidStack(Fluids.WATER, 10)); + fill(helper, rel2, new FluidStack(Fluids.WATER, 10)); + + manager(helper, rel1, rel2).extractFluids(helper.getLevel(), 10); + + int totalRemaining = tankAmount(helper, rel1) + tankAmount(helper, rel2); + helper.assertTrue(totalRemaining == 10, + "extracting 10 out of a 20-unit pool should leave 10 total remaining, found " + totalRemaining); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void extractFluids_needZero_leavesTanksUntouched(GameTestHelper helper) { + BlockPos rel1 = new BlockPos(1, 1, 1); + BlockPos rel2 = new BlockPos(3, 1, 1); + place(helper, rel1, Direction.NORTH); + place(helper, rel2, Direction.NORTH); + fill(helper, rel1, new FluidStack(Fluids.WATER, 10)); + fill(helper, rel2, new FluidStack(Fluids.WATER, 10)); + + boolean result = manager(helper, rel1, rel2).extractFluids(helper.getLevel(), 0); + + helper.assertTrue(!result, "a non-positive fluidNeeded should never extract anything"); + helper.assertTrue(tankAmount(helper, rel1) == 10 && tankAmount(helper, rel2) == 10, + "no tank should be touched when fluidNeeded <= 0"); + helper.succeed(); + } + + @GameTest(template = STRUCTURE) + public static void extractFluids_emptyStackHandler_skippedGracefully(GameTestHelper helper) { + BlockPos rel1 = new BlockPos(1, 1, 1); + BlockPos rel2 = new BlockPos(3, 1, 1); + place(helper, rel1, Direction.NORTH); // left empty + place(helper, rel2, Direction.NORTH); + fill(helper, rel2, new FluidStack(Fluids.WATER, 20)); + + boolean result = manager(helper, rel1, rel2).extractFluids(helper.getLevel(), 15); + + helper.assertTrue(result, "the second, non-empty handler should still be usable"); + helper.assertTrue(tankAmount(helper, rel1) == 0, "empty handler should stay untouched"); + helper.assertTrue(tankAmount(helper, rel2) == 5, "expected 15 drained out of 20, 5 remaining"); + helper.succeed(); + } + + /** + * Documents a related contract mismatch found while designing this suite (not the + * ticket's main bug): the Javadoc promises "true if the full amount was extracted", + * but the implementation returns true after any partial extraction. This test + * asserts the CURRENT behavior and passes today; it is not a fix marker. + */ + @GameTest(template = STRUCTURE) + public static void extractFluids_returnsTrueEvenWhenNotFullyExtracted_javadocMismatch(GameTestHelper helper) { + BlockPos rel = new BlockPos(1, 1, 1); + place(helper, rel, Direction.NORTH); + fill(helper, rel, new FluidStack(Fluids.WATER, 30)); + + boolean result = manager(helper, rel).extractFluids(helper.getLevel(), 100); + + helper.assertTrue(result, "current implementation returns true even for a partial extraction (Javadoc mismatch)"); + helper.assertTrue(tankAmount(helper, rel) == 0, "all available fluid should have been drained"); + helper.succeed(); + } +} diff --git a/src/main/resources/data/createnuclear/structures/empty_platform.nbt b/src/main/resources/data/createnuclear/structures/empty_platform.nbt new file mode 100644 index 0000000000000000000000000000000000000000..1181be11bb64b26864f427848012e182ef456394 GIT binary patch literal 208 zcmb2|=3oGW|Gk$Txegf!uwJ Date: Sun, 12 Jul 2026 16:50:44 +0200 Subject: [PATCH 147/171] refactor(ponder): convert Positions to a record and precompute callout lookups - Turn the Positions inner class into a record, removing the boilerplate constructor. - Extract per-position callout data into a new CalloutInfo record and a buildCallouts() map, replacing the single hardcoded controller-only callout in tryShowCallout(). - Replace the linear scan over pos.specials() with an O(1) HashMap lookup per (x, y, z) cell in showReactorStructure(), removing the now-unused tryShowCallout() in favor of a generic showCallout(). - Drop unused local `H` variables in t1(), t2(), t3(), and ioPlacement(), passing H_T1/H_T2/H_T3 directly instead. - Reformat Javadoc comments to standard multi-line block style. --- .../ponder/scenes/CNPonderReactorScenes.java | 97 ++++++++++++------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java index 5e3fe1f6..f5e43efa 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/ponder/scenes/CNPonderReactorScenes.java @@ -29,25 +29,28 @@ public class CNPonderReactorScenes { private static final int MARGIN = 2; // Create margin private static int plateSizeFor(int multiblockSize) { return multiblockSize + MARGIN * 2; } - /** * Simple container for storing all positions of interest for a multiblock. * The BlockPos values here must be in SCENE COORDINATES (0..plate-1 for X/Z, 1..H for Y). */ - private static class Positions { - final BlockPos controller, input1, input2, liquidInput, alarm, output; - Positions(BlockPos controller, BlockPos input1, BlockPos input2, BlockPos liquidInput, BlockPos alarm, BlockPos output) { - this.controller = controller; - this.input1 = input1; - this.input2 = input2; - this.liquidInput = liquidInput; - this.alarm = alarm; - this.output = output; - } + /** + * Simple container for storing all positions of interest for a multiblock. * The BlockPos values here must be in SCENE COORDINATES (0..plate-1 for X/Z, 1..H for Y). + */ + private record Positions(BlockPos controller, BlockPos input1, BlockPos input2, BlockPos liquidInput, + BlockPos alarm, BlockPos output) { - /** All blocks that carry an explanatory callout, so a section-based reveal can show them per layer. */ + /** + * All blocks that carry an explanatory callout, so a section-based reveal can show them per layer. + */ BlockPos[] specials() { - return new BlockPos[] { controller, input1, input2, liquidInput, alarm, output }; + return new BlockPos[]{controller, input1, input2, liquidInput, alarm, output}; } } - /** * Static map of positions per multiblock size. * Key = multiblockSize (5 for S_T1, 7 for S_T2, 9 for S_T3). * * Rule: x/z in 0..plate-1, y in 1..H; these values must match the structure's actual NBT layout. */ + /** Describes a single callout: its text and the direction to point at. */ + private record CalloutInfo(String text, Direction pointDirection, int fullDuration, int reducedDuration, int fullIdle, int reducedIdle) {} + + /** + * Static map of positions per multiblock size. + * Key = multiblockSize (5 for S_T1, 7 for S_T2, 9 for S_T3). + * Rule: x/z in 0..plate-1, y in 1..H; these values must match the structure's actual NBT layout. + */ private static final Map STATIC_POS = new HashMap<>(); static { // Example for T1 (multiblockSize = 5) @@ -82,6 +85,25 @@ BlockPos[] specials() { )); } + /** + * Precomputes a BlockPos -> CalloutInfo map for O(1) lookup per cell instead of + * iterating pos.specials() and comparing coordinates for every (x, y, z) visited. + */ + private static Map buildCallouts(Positions pos) { + Map callouts = new HashMap<>(); + callouts.put(pos.controller, new CalloutInfo( + "Controller: brain of the reactor, and the place where the blueprint goes to start it", + Direction.DOWN, + 130, 110, + 140, 120 + )); + + // Extend here if input1/input2/liquidInput/alarm/output ever need a callout + // during structure reveal (they currently don't have one — see ioPlacement() + // for their dedicated explanations). + return callouts; + } + /** * Returns the static positions for the given size. * If no static entry exists, returns "reasonable" computed positions instead. */ private static Positions positionsFor(int multiblockSize, int height) { Positions p = STATIC_POS.get(multiblockSize); @@ -115,6 +137,7 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u */ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil util, int S, int H, int plate, boolean bySections) { Positions pos = positionsFor(S, H); + Map callouts = buildCallouts(pos); int minX = MARGIN; int maxX = MARGIN + S - 1; @@ -138,17 +161,21 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u // section per floor we must idle explicitly, otherwise callout-free floors flash // by instantly and their "Floor N" labels overlap each other. scene.idle(50); - for (BlockPos sp : pos.specials()) { - if (sp.getY() == y) { - tryShowCallout(scene, util, pos, sp.getX(), sp.getY(), sp.getZ(), bySections); + for (Map.Entry entry : callouts.entrySet()) { + if (entry.getKey().getY() == y) { + showCallout(scene, util, entry.getKey(), entry.getValue(), bySections); } } } else { for (int x = 0; x < plate; x++) { for (int z = 0; z < plate; z++) { + BlockPos cell = new BlockPos(x, y, z); scene.world().showSection(util.select().position(x, y, z), Direction.NORTH); scene.idle(4); - tryShowCallout(scene, util, pos, x, y, z, bySections); + CalloutInfo info = callouts.get(cell); + if (info != null) { + showCallout(scene, util, cell, info, bySections); + } } } } @@ -174,21 +201,17 @@ private static void showReactorStructure(SceneBuilder scene, SceneBuildingUtil u scene.idle(130); } - private static void tryShowCallout(SceneBuilder scene, SceneBuildingUtil util, Positions pos, int x, int y, int z, boolean reduced) { - BlockPos controller = pos.controller; - - if (x == controller.getX() && y == controller.getY() && z == controller.getZ()) { - scene.overlay().showText(reduced ? 110 : 130) - .text("Controller: brain of the reactor, and the place where the blueprint goes to start it") - .pointAt(util.vector().blockSurface(controller, Direction.DOWN)) - .attachKeyFrame() - .placeNearTarget(); - scene.idle(reduced ? 120 : 140); - } + private static void showCallout(SceneBuilder scene, SceneBuildingUtil util, BlockPos at, CalloutInfo info, boolean reduced) { + scene.overlay().showText(reduced ? info.reducedDuration() : info.fullDuration()) + .text(info.text()) + .pointAt(util.vector().blockSurface(at, info.pointDirection())) + .attachKeyFrame() + .placeNearTarget(); + scene.idle(reduced ? info.reducedIdle() : info.fullIdle()); } public static void t1(SceneBuilder scene, SceneBuildingUtil util) { - int S = S_T1, H = H_T1; + int S = S_T1; int plate = plateSizeFor(S); scene.title("reactor_t1","Reactor T1"); scene.configureBasePlate(0, 0, plate); @@ -196,11 +219,11 @@ public static void t1(SceneBuilder scene, SceneBuildingUtil util) { scene.showBasePlate(); scene.rotateCameraY(180); scene.scaleSceneView(0.55f); - showReactorStructure(scene, util, S, H, plate, true); + showReactorStructure(scene, util, S, H_T1, plate, true); } public static void t2(SceneBuilder scene, SceneBuildingUtil util) { - int S = S_T2, H = H_T2; + int S = S_T2; int plate = plateSizeFor(S); scene.title("reactor_t2","Reactor T2"); scene.configureBasePlate(0, 0, plate); @@ -208,11 +231,11 @@ public static void t2(SceneBuilder scene, SceneBuildingUtil util) { scene.showBasePlate(); scene.rotateCameraY(180); scene.scaleSceneView(0.45f); - showReactorStructure(scene, util, S, H, plate, true); + showReactorStructure(scene, util, S, H_T2, plate, true); } public static void t3(SceneBuilder scene, SceneBuildingUtil util) { - int S = S_T3, H = H_T3; + int S = S_T3; int plate = plateSizeFor(S); scene.title("reactor_t3","Reactor T3"); scene.configureBasePlate(0, 0, plate); @@ -221,13 +244,13 @@ public static void t3(SceneBuilder scene, SceneBuildingUtil util) { scene.rotateCameraY(180); scene.scaleSceneView(0.35f); // T3 reveals floor-by-floor (section-based) so the largest tier doesn't lag; T1/T2 stay block-by-block. - showReactorStructure(scene, util, S, H, plate, true); + showReactorStructure(scene, util, S, H_T3, plate, true); } public static void ioPlacement(SceneBuilder scene, SceneBuildingUtil util) { - int S = S_T1, H = H_T1; + int S = S_T1; int plate = plateSizeFor(S); - Positions pos = positionsFor(S, H); + Positions pos = positionsFor(S, H_T1); scene.title("reactor_io_placement", "Reactor I/O: Function & Placement"); scene.configureBasePlate(0, 0, plate); From cc532f83af11d46c46393e592a4613db7e87ceae Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 21:04:25 +0200 Subject: [PATCH 148/171] refactor(display): replace positional row list with typed ReactorSummary record - Add ReactorSummary.java: a new immutable record (status, size, fuel, cooler, fluid, heat) with a nested ReactorSummaryRow(label, value) and a Builder that fails fast via IllegalStateException listing any missing fields, plus a toRows() method that is now the single place where the positional List> ordering matters. - Rework ReactorSummaryDisplaySource to build and consume a ReactorSummary instead of a raw Stream>: - Replace getComponents() with getReactorSummary(), returning Optional so "no controller" is modeled explicitly instead of via a sentinel 1-element list. - Update provideText() and provideFlapDisplayText() to branch on Optional emptiness and call summary.toRows() instead of relying on components.size() < 6 and fragile positional access like components.get(2).get(1) for the fuel value. - Replace joptsimple's Strings.repeat(' ', n) with String.repeat(n). - Add explicit Map.Entry and List types in place of var, and drop the now-unnecessary Mth import. - Add Javadoc to the class and its public/private methods documenting the new Optional-based control flow. --- .../displayLink/source/ReactorSummary.java | 106 ++++++++++++++++++ .../source/ReactorSummaryDisplaySource.java | 101 +++++++++++------ 2 files changed, 175 insertions(+), 32 deletions(-) create mode 100644 src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummary.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummary.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummary.java new file mode 100644 index 00000000..80795208 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummary.java @@ -0,0 +1,106 @@ +package net.nuclearteam.createnuclear.content.redstone.displayLink.source; + +import net.minecraft.network.chat.MutableComponent; + +import java.util.ArrayList; +import java.util.List; + +/** + * Typed, immutable snapshot of a reactor controller's summary stats (status, size, + * fuel, cooler, fluid, heat), one named {@link ReactorSummaryRow} per stat. + *

+ * Replaces the previous {@code List>} representation, which + * relied on a size-based sentinel (1 element = no controller, 6 elements = full + * summary) and on fragile positional access (e.g. {@code components.get(2).get(1)} + * for the fuel value) that silently broke if the row order ever changed. + *

+ * Callers should build instances via {@link Builder}, and only call {@link #toRows()} + * at the point where Create's {@code DisplaySource} API actually requires the + * positional list format. + */ +public record ReactorSummary(ReactorSummaryRow status, + ReactorSummaryRow size, + ReactorSummaryRow fuel, + ReactorSummaryRow cooler, + ReactorSummaryRow fluid, + ReactorSummaryRow heat) { + + /** A single display row: a label component and its associated value component. */ + public record ReactorSummaryRow(MutableComponent label, MutableComponent value) { + List toPair() { + return List.of(label(), value()); + } + } + + /** + * Converts this summary to the positional {@code List>} + * format required by Create's {@code DisplaySource} API. This is the single place + * where row order matters; every other consumer should access fields by name + * (e.g. {@link #fuel()}) instead of relying on this order. + */ + public List> toRows() { + return List.of( + status().toPair(), size().toPair(), fuel().toPair(), + cooler().toPair(), fluid().toPair(), heat().toPair() + ); + } + + /** + * Fluent builder for {@link ReactorSummary}. All six rows are required; + * {@link #build()} throws {@link IllegalStateException} naming any missing row + * instead of allowing a partially-populated summary to be constructed silently. + */ + public static class Builder { + private ReactorSummaryRow status; + private ReactorSummaryRow size; + private ReactorSummaryRow fuel; + private ReactorSummaryRow cooler; + private ReactorSummaryRow fluid; + private ReactorSummaryRow heat; + + public Builder status(MutableComponent label, MutableComponent value) { + this.status = new ReactorSummaryRow(label, value); + return this; + } + + public Builder size(MutableComponent label, MutableComponent value) { + this.size = new ReactorSummaryRow(label, value); + return this; + } + + public Builder fuel(MutableComponent label, MutableComponent value) { + this.fuel = new ReactorSummaryRow(label, value); + return this; + } + + public Builder cooler(MutableComponent label, MutableComponent value) { + this.cooler = new ReactorSummaryRow(label, value); + return this; + } + + public Builder fluid(MutableComponent label, MutableComponent value) { + this.fluid = new ReactorSummaryRow(label, value); + return this; + } + + public Builder heat(MutableComponent label, MutableComponent value) { + this.heat = new ReactorSummaryRow(label, value); + return this; + } + + public ReactorSummary build() { + List missing = new ArrayList<>(); + if (status == null) missing.add("status"); + if (size == null) missing.add("size"); + if (fuel == null) missing.add("fuel"); + if (cooler == null) missing.add("cooler"); + if (fluid == null) missing.add("fluid"); + if (heat == null) missing.add("heat"); + + if (!missing.isEmpty()) + throw new IllegalStateException("Missing required ReactorSummary fields: " + String.join(", ", missing)); + + return new ReactorSummary(status, size, fuel, cooler, fluid, heat); + } + } +} diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java index 411d3888..57e2e4a0 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSummaryDisplaySource.java @@ -1,6 +1,8 @@ package net.nuclearteam.createnuclear.content.redstone.displayLink.source; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.stream.Stream; import com.simibubi.create.api.behaviour.display.DisplaySource; @@ -14,31 +16,50 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.util.Mth; +import net.minecraft.world.item.Item; import net.minecraft.world.level.block.entity.LecternBlockEntity; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRodPredicate; +import net.nuclearteam.createnuclear.content.logistics.BigFluidStack; import net.nuclearteam.createnuclear.content.multiblock.IHeat; import net.nuclearteam.createnuclear.content.multiblock.MultiblockHelpers; import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; -import joptsimple.internal.Strings; +/** + * Display source rendering a reactor controller's summary (status, size, fuel, + * cooler, fluid, heat) as one line per stat, for both regular displays and + * flap displays. + *

    qJ-=les#JlK!JsV1D}I@{#RM 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 -cVod&PzNc8#T2Y)QEPf^{^RNc@B}y3xBb+ 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]z*4;h(q6l%| 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 z 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 z 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 z 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 AUB5HK`m|!)y`B$4E9VEuGX<1`@&e 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 Dm*-Iw literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/sounds/reacteur/assemble_deassemble/motor_disassemble.ogg b/src/main/resources/assets/createnuclear/sounds/reacteur/assemble_deassemble/motor_disassemble.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8e1db4ca714b2f26420794a6d1bba8005886355e GIT binary patch literal 21913 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 Date: Mon, 13 Jul 2026 14:03:12 +0200 Subject: [PATCH 151/171] test: add GameTest coverage for DefaultHeatCalculator.computeHeat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add DefaultHeatCalculatorGameTest, a new GameTestHolder-based suite that exercises DefaultHeatCalculator.computeHeat against a real ServerLevel, a real ReactorControllerBlockEntity, and real registered rod items instead of mocks — plain JUnit cannot resolve Item/ItemStack/ RodType, which depend on bootstrapped Minecraft/Forge registries (AUDIT_ACTUEL.md §3). - Add shared test fixtures: placeController() to spawn a REACTOR_CONTROLLER on the "empty_platform" template and loadPattern() to write a slot->Item map into the blueprint item's "pattern" NBT tag, mirroring how ReactorBluePrintItem.getItemStorage reads it back. - Cover three cases: an isolated fuel rod contributing only its own baseRodHeat (+ overHeat), an isolated cooler rod behaving identically when isolated, and a three-rod fuel/cooler adjacency mix that documents the existing fuel<->cooler proximity-heat asymmetry (fuel-side addition vs. division, cooler scans never contributing) noted in AUDIT_ACTUEL.md §2.2. Expected values are derived from live CNConfigs.server().rods settings rather than hardcoded, so the tests stay correct if default balance changes. --- .../DefaultHeatCalculatorGameTest.java | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/main/java/net/nuclearteam/createnuclear/gametest/DefaultHeatCalculatorGameTest.java diff --git a/src/main/java/net/nuclearteam/createnuclear/gametest/DefaultHeatCalculatorGameTest.java b/src/main/java/net/nuclearteam/createnuclear/gametest/DefaultHeatCalculatorGameTest.java new file mode 100644 index 00000000..4f0ea062 --- /dev/null +++ b/src/main/java/net/nuclearteam/createnuclear/gametest/DefaultHeatCalculatorGameTest.java @@ -0,0 +1,164 @@ +package net.nuclearteam.createnuclear.gametest; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.gametest.PrefixGameTestTemplate; +import net.minecraftforge.items.ItemStackHandler; +import net.nuclearteam.createnuclear.CNBlocks; +import net.nuclearteam.createnuclear.CNItems; +import net.nuclearteam.createnuclear.CreateNuclear; +import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; +import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerInventory; +import net.nuclearteam.createnuclear.content.multiblock.controller.display.ReactorDisplayState; +import net.nuclearteam.createnuclear.content.multiblock.reactorLogic.DefaultHeatCalculator; +import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; + +import java.util.List; +import java.util.Map; + +/** + * GameTest coverage for {@link DefaultHeatCalculator#computeHeat}, run against a real + * {@code ServerLevel}, a real {@link ReactorControllerBlockEntity} and real registered + * rod items (no mocks) — plain JUnit cannot exercise this method at all: {@code Item}, + * {@code ItemStack} and {@code RodType} resolution all depend on Minecraft/Forge registries + * that only exist once the game has bootstrapped (see AUDIT_ACTUEL.md §3). + *

    + * All tests share the "empty_platform" structure and place a single + * {@code CNBlocks.REACTOR_CONTROLLER} to obtain a real {@link ReactorControllerInventory}. + * The reactor "pattern" (57-slot {@link ItemStackHandler}, slots per + * {@code DefaultHeatCalculator.formattedPattern}) is written directly into the blueprint + * item's {@code pattern} NBT tag and set into inventory slot 0, exactly as + * {@code ReactorBluePrintItem.getItemStorage} reads it back. + *

    + * Expected heat values are computed from the live {@code CNConfigs.server().rods} values + * rather than hardcoded, so these tests stay correct if the mod's default balance changes. + */ +@GameTestHolder(CreateNuclear.MOD_ID) +@PrefixGameTestTemplate(false) +public class DefaultHeatCalculatorGameTest { + + private static final String STRUCTURE = "empty_platform"; + private static final double DELTA = 1e-9; + + // ---------- test fixtures ---------- + + private static ReactorControllerInventory placeController(GameTestHelper helper, BlockPos rel) { + helper.setBlock(rel, CNBlocks.REACTOR_CONTROLLER.get().defaultBlockState()); + ReactorControllerBlockEntity be = (ReactorControllerBlockEntity) helper.getBlockEntity(rel); + return be.getInventoryObject(); + } + + /** Writes {@code rodsBySlot} into the blueprint item's "pattern" NBT and loads it into slot 0. */ + private static void loadPattern(ReactorControllerInventory inventory, Map rodsBySlot) { + ItemStackHandler patternHandler = new ItemStackHandler(57); + rodsBySlot.forEach((slot, item) -> patternHandler.setStackInSlot(slot, new ItemStack(item))); + + ItemStack blueprint = new ItemStack(CNItems.REACTOR_BLUEPRINT.get()); + blueprint.getOrCreateTag().put("pattern", patternHandler.serializeNBT()); + inventory.setStackInSlot(0, blueprint); + } + + private static final DefaultHeatCalculator CALCULATOR = new DefaultHeatCalculator(); + + // ================================================================ + // 1. single fuel rod, no neighbors + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void singleFuelRod_noNeighbors_addsOnlyItsOwnBaseRodHeat(GameTestHelper helper) { + Item thorium = CNItems.THORIUM_ROD.get(); + int baseRodHeat = CNConfigs.server().rods.baseValueThorium.get(); + + ReactorControllerInventory inventory = placeController(helper, new BlockPos(1, 1, 1)); + // slot 18: middle row, no adjacent slot populated -> no neighbor bonus possible + loadPattern(inventory, Map.of(18, thorium)); + + ReactorDisplayState displayState = new ReactorDisplayState(Map.of(thorium, 1), List.of(), 0); + double overHeat = 10.0; + + double heat = CALCULATOR.computeHeat(null, null, inventory, overHeat, displayState, helper.getLevel()); + + helper.assertTrue(Math.abs(heat - (baseRodHeat + overHeat)) < DELTA, + "an isolated fuel rod should only contribute its own baseRodHeat, plus overHeat: expected " + + (baseRodHeat + overHeat) + ", got " + heat); + helper.succeed(); + } + + // ================================================================ + // 2. single cooler rod, no neighbors + // ================================================================ + + @GameTest(template = STRUCTURE) + public static void singleCoolerRod_noNeighbors_addsOnlyItsOwnBaseRodHeat(GameTestHelper helper) { + Item graphite = CNItems.GRAPHITE_ROD.get(); + int baseRodHeat = CNConfigs.server().rods.baseValueGraphite.get(); + + ReactorControllerInventory inventory = placeController(helper, new BlockPos(1, 1, 1)); + loadPattern(inventory, Map.of(18, graphite)); + + ReactorDisplayState displayState = new ReactorDisplayState(Map.of(graphite, 1), List.of(), 0); + + double heat = CALCULATOR.computeHeat(null, null, inventory, /*overHeat*/ 0.0, displayState, helper.getLevel()); + + helper.assertTrue(Math.abs(heat - baseRodHeat) < DELTA, + "a cooler contributes its own baseRodHeat exactly like a fuel rod would, when isolated: expected " + + baseRodHeat + ", got " + heat); + helper.succeed(); + } + + // ================================================================ + // 3. fuel/cooler mix adjacency: documents the fuel<->cooler asymmetry (AUDIT_ACTUEL.md §2.2) + // ================================================================ + + /** + * Layout (row 3 of {@code formattedPattern}, three consecutive slots): + * uranium A (18) - thorium B (19) - graphite C (20). + *

    + * Expected total = sum of each rod's own baseRodHeat, PLUS proximity contributions that only + * ever originate from a FUEL rod's own neighbor scan (a cooler's scan never contributes, + * even though its neighbor is a fuel rod): + *

      + *
    • A's scan (fuel, neighbor B is fuel) -> + A.proximityRodHeat()
    • + *
    • B's scan (fuel, neighbor A is fuel) -> + B.proximityRodHeat()
    • + *
    • B's scan (fuel, neighbor C is cooler) -> + B.baseRodHeat() / C.proximityRodHeat()
    • + *
    • C's scan (cooler) -> nothing at all, regardless of its fuel neighbor B
    • + *
    + */ + @GameTest(template = STRUCTURE) + public static void fuelCoolerMix_onlyFuelScansContributeProximityHeat_coolerAdjacencyIsAsymmetric(GameTestHelper helper) { + Item uranium = CNItems.URANIUM_ROD.get(); + Item thorium = CNItems.THORIUM_ROD.get(); + Item graphite = CNItems.GRAPHITE_ROD.get(); + + int uraniumBase = CNConfigs.server().rods.baseValueUranium.get(); + float uraniumProxy = CNConfigs.server().rods.uraniumProxyBonus.get(); + int thoriumBase = CNConfigs.server().rods.baseValueThorium.get(); + float thoriumProxy = CNConfigs.server().rods.thoriumProxyBonus.get(); + int graphiteBase = CNConfigs.server().rods.baseValueGraphite.get(); + float graphiteProxy = CNConfigs.server().rods.graphiteProxyMalus.getF(); + + ReactorControllerInventory inventory = placeController(helper, new BlockPos(1, 1, 1)); + loadPattern(inventory, Map.of(18, uranium, 19, thorium, 20, graphite)); + + ReactorDisplayState displayState = new ReactorDisplayState( + Map.of(uranium, 1, thorium, 1, graphite, 1), List.of(), 0); + + double heat = CALCULATOR.computeHeat(null, null, inventory, /*overHeat*/ 0.0, displayState, helper.getLevel()); + + double expected = (uraniumBase + thoriumBase + graphiteBase) // each rod's own baseRodHeat + + uraniumProxy // A's scan: fuel neighbor B (thorium) -> addition + + thoriumProxy // B's scan: fuel neighbor A (uranium) -> addition + + (thoriumBase / graphiteProxy); + // B's scan: cooler neighbor C -> division (fuel.base / cooler.proximity) + // C's scan contributes 0: a cooler never examines its own neighbors + + helper.assertTrue(Math.abs(heat - expected) < DELTA, + "cooler-side proximity must not contribute anything, even though C is adjacent to fuel rod B: expected " + + expected + ", got " + heat); + helper.succeed(); + } +} From 4b96989fb0b371408c68cc1ccc2dbdd567896417 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 14:09:29 +0200 Subject: [PATCH 152/171] docs: update AUDIT_ACTUEL.md to record GameTest coverage for heat calculator and fluid manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-13 update noting the first concrete progress on the §7 priority-1 test debt: DefaultHeatCalculatorGameTest (`498f9dc6`) and the previously undocumented ReactorInputFluidManagerGameTest (`200df62f`), plus the JUnit+Mockito attempt that was rejected because mocking Item/ItemStack/Level fails outside a running game (confirms GameTest is the only viable approach for Minecraft/Forge types). - §0/§3: soften "l'absence totale de tests" to "l'absence de tests sur la majorité du code", since two components now have GameTest coverage; note the pattern matcher (ReactorPattern/CNMultiblock) and PersistentFluidLocks remain entirely uncovered. - §3: update the `src/test` row to explain why it stays empty (Minecraft/Forge types can't initialize outside a bootstrapped game) and add a new "Couverture GameTest" row tracking 2/4 components covered. - §7 priority 1: mark the DefaultHeatCalculator test item as done, referencing both new commits, and narrow the "reste" scope to the pattern matcher and PersistentFluidLocks. - §8.1: add two new changelog rows documenting DefaultHeatCalculatorGameTest (`498f9dc6`) and ReactorInputFluidManagerGameTest (`200df62f`), including the regression-marker `*_expectedContract` tests for the §1 over-extraction bug. --- AUDIT_ACTUEL.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index fff15eea..89b43602 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -16,7 +16,9 @@ Depuis la dernière consolidation (2026-06-28), le projet a continué d'évoluer **Nouveau point d'audit ajouté** : qualité et langue de la documentation du code (Javadoc, commentaires, noms de symboles) — voir §6. Un premier signal existait déjà dans `AUDIT_V1.md` §5 (« commentaires FR/EN mêlés ») mais n'avait jamais été centralisé ni suivi comme item d'audit à part entière. -La dette la plus structurelle reste **l'absence totale de tests** (`src/test` toujours vide, reconfirmé — 0 fichier `.java`) — précisément là où des bugs/incohérences silencieux (sur-extraction fluide, ex-tautologie `IHeat`, scan non court-circuité, doc devenue obsolète sans que personne ne le remarque) survivent à plusieurs passes d'audit. Voir §3 et §7. +**Mise à jour post-réorganisation (2026-07-13)** : première entame concrète de la dette de tests recommandée en priorité 1 du §7. Deux suites `GameTest` (sous `src/main/java/.../gametest/`, pas `src/test`) ont été ajoutées : `ReactorInputFluidManagerGameTest` (`200df62f`, antérieur à cette réorganisation mais jamais documenté ici — omission corrigée maintenant) et `DefaultHeatCalculatorGameTest` (`498f9dc6`). Cette dernière a été écrite après un aller-retour méthodologique instructif : une première tentative en JUnit pur + Mockito (mocker `Item`/`ItemStack`/`Level`) a été rejetée — Mockito doit exécuter le vrai bloc d'initialisation statique de ces classes Minecraft pour construire le proxy, et celui-ci échoue hors d'un jeu réellement démarré (`MockitoException: Cannot instrument class net.minecraft.world.item.Item ... could not be initialized`), ce qui **confirme empiriquement** pourquoi ce projet doit s'appuyer sur `GameTest` plutôt que sur du JUnit isolé pour tout ce qui touche aux types Minecraft/Forge. Détail en §8.1. + +La dette la plus structurelle reste **l'absence de tests sur la majorité du code** (`src/test` toujours vide — la mécanique JUnit classique n'est pas utilisable ici, voir ci-dessus — et seuls deux composants ont une suite `GameTest`) — précisément là où des bugs/incohérences silencieux (sur-extraction fluide, ex-tautologie `IHeat`, scan non court-circuité, doc devenue obsolète sans que personne ne le remarque) survivent à plusieurs passes d'audit. Le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` restent entièrement sans couverture. Voir §3 et §7. --- @@ -58,9 +60,10 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to ## 3. 🏗️ Architecture — points encore ouverts -| Point | État (revérifié 2026-07-12) | +| Point | État (revérifié 2026-07-13) | |---|---| -| **`src/test`** | ❌ **Toujours vide** — confirmé, 0 fichier `.java` sous `src/test`. Le point structurel le plus important du projet reste entier ; c'est le terrain commun à la quasi-totalité des bugs silencieux relevés depuis le premier audit (chaleur, pattern matching, verrouillage fluide, double-scan multiblock, et maintenant la doc obsolète repérée en §0). | +| **`src/test`** | ❌ **Toujours vide** — confirmé, 0 fichier `.java` sous `src/test`. Sans objet ici : les types Minecraft/Forge (`Item`, `ItemStack`, `Level`, registres du mod) ne s'initialisent pas hors d'un jeu démarré (confirmé empiriquement en tentant de les mocker via Mockito, voir §0/§8.1), donc la couverture de ce projet passe nécessairement par `GameTest`, pas par du JUnit isolé sous `src/test`. | +| **Couverture `GameTest` (`src/main/java/.../gametest/`)** | 🟡 **Partielle, 2 composants sur 4 couverts** — `ReactorInputFluidManager` (`200df62f`) et `DefaultHeatCalculator.computeHeat` (`498f9dc6`, 3 cas : fuel isolé, cooler isolé, asymétrie de voisinage fuel/cooler documentée en §2.2) ont une suite dédiée. Le pattern matcher (`ReactorPattern`/`CNMultiblock`, §2.1) et `PersistentFluidLocks` (§8.2) restent **entièrement sans test** — ce sont les deux items restants de la priorité 1 du §7. | | **`RadiationCapability.tickRadiation` pour `LivingEntity` non-joueurs** | ⚠️ **Point à surveiller, pas un bug** — recalcule `computeItemRadiation` à chaque tick sans dirty-check (le hash d'inventaire existant, `InventoryHashUtil`, ne couvre que le joueur). Compromis assumé explicitement dans le commit `9ded502c` (« no equivalent inventory to diff against ») — à reconsidérer seulement si la densité de mobs équipés en zone irradiée augmente et qu'un problème de perf est mesuré. | *(Les autres affirmations historiques de cette table — inversion `api/`, deux frameworks multiblock concurrents, god class `ReactorControllerBlockEntity`, coordinateur de verrou fluide dédié — ont toutes été réfutées ou closes ; voir §8.2.)* @@ -140,7 +143,7 @@ Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la tabl Classement par catégorie et impact, du plus important au plus cosmétique. Chaque item renvoie à sa section de détail. **1. Dette technique structurelle (racine des bugs silencieux récurrents)** -- Démarrer une couverture de tests sur `DefaultHeatCalculator`, le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` (§3). **Justification** : c'est la cause profonde identifiée à travers *tous* les tours d'audit successifs — sur-extraction fluide, tautologie `IHeat`, scan non court-circuité, et maintenant une section d'audit devenue obsolète sans que personne ne s'en aperçoive (§0) sont tous des symptômes du même problème : rien ne vérifie automatiquement le comportement. C'est l'investissement qui a le plus gros effet de levier sur la fiabilité future, mais c'est aussi le plus long — d'où la priorité 1 malgré l'absence d'urgence immédiate. +- ~~`DefaultHeatCalculator`~~ — **fait**, `GameTest` ajoutée (`498f9dc6`, voir §3/§8.1). `ReactorInputFluidManager` avait déjà sa suite (`200df62f`, jusqu'ici non documentée dans cet audit). **Reste** : le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` (§3). **Justification** : c'est la cause profonde identifiée à travers *tous* les tours d'audit successifs — sur-extraction fluide, tautologie `IHeat`, scan non court-circuité, et une section d'audit devenue obsolète sans que personne ne s'en aperçoive (§0) sont tous des symptômes du même problème : rien ne vérifie automatiquement le comportement. C'est l'investissement qui a le plus gros effet de levier sur la fiabilité future, mais c'est aussi le plus long — d'où la priorité 1 malgré l'absence d'urgence immédiate. Deux composants sur quatre sont maintenant couverts. **2. Optimisation — chemin le plus chaud du projet** - `ReactorPattern.findController` : faire retourner `inRange` au lieu de `false` dans le visiteur, pour court-circuiter comme `findControllerPos` le fait déjà (§2.1, §5). **Justification** : fix d'une ligne, risque quasi nul, et c'est le chemin appelé par le bloc le plus posé/cassé du jeu (`ReactorCasing`). Rapport gain/effort le plus élevé du projet — reste la priorité n°1 « quick win » malgré son classement en position 2 ici (juste après la dette de tests, qui est stratégiquement plus importante mais bien plus longue à traiter). @@ -189,6 +192,8 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| Ajout de `DefaultHeatCalculatorGameTest` (3 cas : fuel isolé, cooler isolé, asymétrie de voisinage fuel/cooler) — première couverture de test pour `DefaultHeatCalculator.computeHeat` (§3/§7 priorité 1) | `498f9dc6` | 2026-07-13 | Écrit en `GameTest` (real `ServerLevel`/`ReactorControllerBlockEntity`/items enregistrés) après rejet d'une première tentative JUnit+Mockito : mocker `Item`/`ItemStack`/`Level` échoue hors jeu démarré (static init Minecraft), ce qui confirme empiriquement le choix `GameTest` déjà fait pour `ReactorInputFluidManagerGameTest`. Valeurs attendues dérivées de `CNConfigs.server().rods.*` en direct (pas de valeurs codées en dur), donc robuste à un changement de balance. | +| Ajout de `ReactorInputFluidManagerGameTest` (couvre `read`/`write`/`clearInvalid`/`getBlocksPosition`/`getFuildHandlers`/`getInventory`/`extractFluids`, dont des marqueurs de régression `*_expectedContract` pour le bug de sur-extraction du §1) — **jamais documenté dans cet audit jusqu'ici**, omission corrigée à l'occasion de la mise à jour ci-dessus | `200df62f` | 2026-07-12 (avant la réorganisation issue de ce même jour, retrouvé par `git log`) | Deux tests `*_expectedContract` échouent intentionnellement aujourd'hui (documentent le comportement souhaité, pas encore implémenté) ; le reste passe et caractérise le comportement actuel. | | `ReactorSummaryDisplaySource` — remplacement de la sentinelle de taille (liste 1/6 éléments) et des accès positionnels fragiles (`components.get(2).get(1)`) par un `record ReactorSummary` typé (`ReactorSummaryRow` + `Builder` validant les 6 champs requis) ; `getComponents()` → `getReactorSummary()` retournant `Optional` ; remplacement de `joptsimple.internal.Strings.repeat` (dépendance transitive non déclarée) par `String.repeat` natif ; Javadoc anglais ajouté sur la classe et ses méthodes, retirant au passage les 3 commentaires français "Sécurité Triple-Check" (§6) | `cc532f83` | 2026-07-12 | Nouveau fichier `ReactorSummary.java` (§2.3 et §6, item ex-9, tous deux clos). `toRows()` reste le seul point de conversion vers le format positionnel `List>` exigé par l'API `DisplaySource` de Create. | | Traduction en anglais des 4 cas de Javadoc public bilingue relevés en §6 (`VicinityEffect.onContaminate`, `CNPonderReactorScenes.Positions`/`STATIC_POS`/`positionsFor`), plus l'intégralité des commentaires inline restants de `CNPonderReactorScenes.java` | `3be6252a` | 2026-07-12 | `VicinityEffect.java` et `CNPonderReactorScenes.java` ne contiennent plus aucun français ; sortis de la liste §6 (14→12 fichiers concernés, ~40→~25 lignes). | | Retrait de `IrradiatedBiomes.monsters()` (corps vide, arguments ignorés) | `8b0428e3` | 2026-07-12 | Méthode et son unique site d'appel supprimés ; les réglages de spawn passent désormais uniquement par `MobSpawnSettings.Builder`. | From ae1e394d425618843e081579e2752446719b004e Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 14:17:10 +0200 Subject: [PATCH 153/171] refactor: remove unused biome/nullability code and dead SPEED artifacts in ReactorOutput MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete OriginalBiomeLookup.java: the class was unused dead code (a ServerLevel/BlockPos biome resolver that fell back to sampling the chunk generator's noise biome inside irradiated zones). - IrradiatedBiomes: remove the unrelated vanilla worldgen leftovers flagged by AUDIT_ACTUEL.md §4 — BLUE_ICE feature and the addDefaultSoftDisks()/VOID_START_PLATFORM helper (and its only call site) — keeping only the NETHER_CAVE air carver in addDefaultIrradiatedOres. - ReactorOutput: add @ParametersAreNonnullByDefault alongside the existing @MethodsReturnNonnullByDefault, drop the redundant @NotNull on getShape() now covered by the class-level annotation, and remove the commented-out SPEED property references (createBlockStateDefinition, getStateForPlacement) along with a stray blank line. --- .../multiblock/output/ReactorOutput.java | 9 ++++--- .../worldgen/biome/IrradiatedBiomes.java | 6 ----- .../worldgen/biome/OriginalBiomeLookup.java | 24 ------------------- 3 files changed, 4 insertions(+), 35 deletions(-) delete mode 100644 src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java index 4ce2da50..84364f67 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/output/ReactorOutput.java @@ -37,23 +37,22 @@ import net.nuclearteam.createnuclear.content.multiblock.controller.ReactorControllerBlockEntity; import org.jetbrains.annotations.NotNull; +import javax.annotation.ParametersAreNonnullByDefault; import java.util.function.Predicate; - +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault public class ReactorOutput extends DirectionalKineticBlock implements IWrenchable, IBE { public static final IntegerProperty DIR = IntegerProperty.create("dir", 0, 2); private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); - public ReactorOutput(Properties properties) { super(properties); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { - //builder.add(SPEED); builder.add(DIR); super.createBlockStateDefinition(builder); } @@ -78,7 +77,7 @@ public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState } @Override - public @NotNull VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) { return CNShapes.REACTOR_OUTPUT.get(state.getValue(FACING)); } @@ -88,7 +87,7 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { if ((context.getPlayer() != null && context.getPlayer() .isShiftKeyDown()) || preferred == null) return super.getStateForPlacement(context); - return defaultBlockState().setValue(FACING, preferred)/*.setValue(SPEED, 0)*/.setValue(DIR, 0); + return defaultBlockState().setValue(FACING, preferred).setValue(DIR, 0); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 0120f40c..6a53cb34 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -19,14 +19,9 @@ public static Biome createPlain(HolderGetter featureLookup, Holde } public static void addDefaultIrradiatedOres(BiomeGenerationSettings.Builder builder) { - builder.addFeature(GenerationStep.Decoration.UNDERGROUND_STRUCTURES, MiscOverworldPlacements.BLUE_ICE); builder.addCarver(GenerationStep.Carving.AIR, Carvers.NETHER_CAVE); } - public static void addDefaultSoftDisks(BiomeGenerationSettings.Builder builder) { - builder.addFeature(GenerationStep.Decoration.SURFACE_STRUCTURES, MiscOverworldPlacements.VOID_START_PLATFORM); - } - public static Biome irradiated(HolderGetter featureGetter, HolderGetter> carverGetter, HolderGetter soundLookup, BiomeGenerationSettings.Builder generation) { MobSpawnSettings.Builder spawnBuilder = new MobSpawnSettings.Builder(); BiomeSpecialEffects.Builder effectBuilder = new BiomeSpecialEffects.Builder(); @@ -54,7 +49,6 @@ public static Biome irradiated(HolderGetter featureGetter, Holder ; IrradiatedBiomes.addDefaultIrradiatedOres(generation); - IrradiatedBiomes.addDefaultSoftDisks(generation); return new Biome.BiomeBuilder() .mobSpawnSettings(spawnBuilder.build()) diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java deleted file mode 100644 index d3e43b39..00000000 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/OriginalBiomeLookup.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.nuclearteam.createnuclear.infrastructure.worldgen.biome; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.QuartPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.biome.Biome; - -public class OriginalBiomeLookup { - private OriginalBiomeLookup() {} - - public static Holder resolve(ServerLevel level, BlockPos pos) { - if (!PersistentIrradiatedZones.get(level).isInsideAnyZone(pos)) { - return level.getBiome(pos); - } - - return level.getChunkSource().getGenerator().getBiomeSource().getNoiseBiome( - QuartPos.fromBlock(pos.getX()), - QuartPos.fromBlock(pos.getY()), - QuartPos.fromBlock(pos.getZ()), - level.getChunkSource().randomState().sampler() - ); - } -} From 77dfef284f6715b88fb24a2ce919c66eca13fa0f Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 14:23:02 +0200 Subject: [PATCH 154/171] docs: update AUDIT_ACTUEL.md to record SPEED/worldgen cleanup and OriginalBiomeLookup removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-13 update summarizing commit `ae1e394d`, which closes the ReactorOutput.SPEED cleanup item, partially resolves the "worldgen irradié" item (BLUE_ICE and addDefaultSoftDisks()/ VOID_START_PLATFORM removed, NETHER_CAVE kept without documented justification), and removes the never-called OriginalBiomeLookup.java (a class this audit hadn't previously flagged). - §4: mark the ReactorOutput.SPEED "code commencé puis abandonné" item as resolved, and update the "worldgen irradié" entry to reflect the partial fix (BLUE_ICE/VOID_START_PLATFORM gone, NETHER_CAVE's fate still undecided); add OriginalBiomeLookup.java to the list of already- removed dead code. - §6: adjust IrradiatedBiomes.java's line numbers (30-44, was 39-48) for item 11, shifted by the §4 code removal — content unchanged. - §7: mark the SPEED cleanup item as done and the worldgen item as partially done, narrowing the remaining scope to the NETHER_CAVE decision and the STEEL_BLOCK fill-block choice. - §8.1: add a changelog row for `ae1e394d` detailing the SPEED reference removal, the BLUE_ICE/addDefaultSoftDisks()/ VOID_START_PLATFORM removal, the OriginalBiomeLookup.java deletion, and the added @ParametersAreNonnullByDefault / removed redundant @NotNull on ReactorOutput.getShape(). - Regenerate irradiated_land.json and its datagen .cache file to drop the now-removed blue_ice/void_start_platform features. --- AUDIT_ACTUEL.md | 17 ++++++++++------- .../fed443662143001aeb5341375f6f5ef31d10baea | 4 ++-- .../worldgen/biome/irradiated_land.json | 12 +----------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 89b43602..f4338c5d 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -20,6 +20,8 @@ Depuis la dernière consolidation (2026-06-28), le projet a continué d'évoluer La dette la plus structurelle reste **l'absence de tests sur la majorité du code** (`src/test` toujours vide — la mécanique JUnit classique n'est pas utilisable ici, voir ci-dessus — et seuls deux composants ont une suite `GameTest`) — précisément là où des bugs/incohérences silencieux (sur-extraction fluide, ex-tautologie `IHeat`, scan non court-circuité, doc devenue obsolète sans que personne ne le remarque) survivent à plusieurs passes d'audit. Le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` restent entièrement sans couverture. Voir §3 et §7. +**Mise à jour (`ae1e394d`, 2026-07-13)** : nettoyage de trois points du §4/§7 en une seule fois — retrait complet des références commentées à la propriété `SPEED` de `ReactorOutput` (§4/§7 item 7, désormais clos), retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` d'`IrradiatedBiomes` (§4 « worldgen irradié », **partiellement clos** — `NETHER_CAVE` reste volontairement conservé, sans justification documentée dans le commit), et suppression de `OriginalBiomeLookup.java`, une classe de résolution de biome jamais appelée qui n'avait encore jamais été repérée par cet audit. Détail en §8.1. + --- ## 1. 🐛 Bugs confirmés ouverts @@ -75,14 +77,14 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod > **⚠️ Faux positifs à NE PAS supprimer** : `CNTabulaModelRenderUtils` (rendu vivant du champignon atomique) ; `ReactorOutputEntity.outputPos` (lu/écrit en NBT) ; `setRotateAngle` (appelé par `NuclearMushroomCloudModel`). **Code commencé puis abandonné (hygiène de fin de PR)** -- `content/multiblock/output/ReactorOutput.java:56,91` — propriété `SPEED` toujours entièrement commentée (pas supprimée). *(Lignes revérifiées 2026-07-12 : `//builder.add(SPEED);` l.56, `/*.setValue(SPEED, 0)*/` l.91 — décalage mineur par rapport aux anciens numéros de ligne l.43/52/87.)* +- ~~`content/multiblock/output/ReactorOutput.java` — propriété `SPEED` toujours entièrement commentée~~ — **résolu** (`ae1e394d`, 2026-07-13) : les références commentées (`//builder.add(SPEED);`, `/*.setValue(SPEED, 0)*/`) ont été retirées, voir §8.1. - `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. -**Worldgen « irradié » — template non terminé** *(revérifié 2026-07-12, inchangé)* -- `IrradiatedBiomes.java:22-27` ajoute toujours du contenu vanilla sans rapport avec le biome irradié (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`). +**Worldgen « irradié » — template non terminé** *(mis à jour 2026-07-13, `ae1e394d`)* +- `IrradiatedBiomes.java:22` — **partiellement résolu** : `BLUE_ICE` et l'aide `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (plus son unique site d'appel) ont été retirés. `NETHER_CAVE` reste présent (`addDefaultIrradiatedOres`, l.22) — le commit ne documente pas si ce choix est volontaire (carver de grottes potentiellement pertinent thématiquement) ou un oubli ; à trancher explicitement au prochain passage sur ce fichier. - `CNNoiseGeneratorSettings.java:25` utilise toujours `STEEL_BLOCK` comme bloc de remplissage par défaut du biome irradié. -*(Le dead code pur déjà retiré — `SimpleMultiBlockPattern.test()`, `IrradiatedBiomes.monsters()`, le nettoyage de `PlayerInteractReactorFluidInput`, les fichiers de debug `run/`, la mécanique de collier teignable — est en §8.1/§8.3 avec ses hash.)* +*(Le dead code pur déjà retiré — `SimpleMultiBlockPattern.test()`, `IrradiatedBiomes.monsters()`, le nettoyage de `PlayerInteractReactorFluidInput`, les fichiers de debug `run/`, la mécanique de collier teignable, `OriginalBiomeLookup.java` — est en §8.1/§8.3 avec ses hash.)* --- @@ -120,7 +122,7 @@ Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la tabl 8. `foundation/mixin/CameraAccessor.java:9` — accessor mixin, commentaire français isolé sur le pattern « invoker » Mixin. 9. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. 10. `content/decoration/palettes/PalettesVariantEntry.java:54` — commentaire français sur un changement d'architecture de rendu déjà effectué ailleurs, utile pour éviter une régression, en français uniquement. -11. `infrastructure/worldgen/biome/IrradiatedBiomes.java:39-48` — 4 commentaires français sur des choix esthétiques de biome ; mineur, mais dans un fichier déjà pointé par §4 comme « template non terminé ». +11. `infrastructure/worldgen/biome/IrradiatedBiomes.java:30-44` — 5 commentaires français sur des choix esthétiques de biome (numéros de ligne décalés par le retrait de code du §4 dans `ae1e394d`, contenu inchangé) ; mineur, mais dans un fichier déjà pointé par §4 comme « template non terminé ». 12. `content/equipment/armor/AntiRadiationArmorItem.java:48` — commentaire français sur `getArmorTexture` (override d'API Forge publique) ; trivial sur le fond, à harmoniser en anglais par cohérence. 13. `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:33` — commentaire français isolé, sur une classe explicitement exclue du refactor de mutualisation `drawGauge` (§8.1) — bon candidat à documenter proprement au prochain passage sur ce fichier. 14. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. @@ -163,9 +165,9 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq - `CNPonderReactorScenes.showReactorStructure` : remplacer la boucle triple par une map précalculée (§2.6). Coût ponctuel (ouverture d'un ponder), gain marginal. **7. Nettoyage / décisions produit à trancher** -- `ReactorOutput.SPEED` : retirer les commentaires ou décider de réactiver la propriété (§4). +- ~~`ReactorOutput.SPEED` : retirer les commentaires ou décider de réactiver la propriété~~ — **fait**, commit `ae1e394d` (§4/§8.1). - `CNStandardRecipeGen.java:226` : trancher le `FIXME` sur les catégories de recette (§4). -- Worldgen « irradié » : retirer le contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`) et choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. +- Worldgen « irradié » : **partiellement fait** (`ae1e394d`) — `BLUE_ICE` et `VOID_START_PLATFORM` retirés ; reste à trancher si `NETHER_CAVE` doit rester, et à choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. **8. Documentation (nouveau, §6)** - ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait**, commit `3be6252a`. @@ -192,6 +194,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| Retrait des références commentées à `SPEED` dans `ReactorOutput` (`createBlockStateDefinition`, `getStateForPlacement`) ; retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (+ son unique site d'appel) dans `IrradiatedBiomes` ; suppression de `OriginalBiomeLookup.java` (classe de résolution de biome jamais appelée, non repérée jusqu'ici par cet audit) ; ajout de `@ParametersAreNonnullByDefault` sur `ReactorOutput` et retrait du `@NotNull` désormais redondant sur `getShape()` | `ae1e394d` | 2026-07-13 | Clôt le premier bullet de §4/§7 item 7 (`SPEED`). Résout partiellement le second (« worldgen irradié ») : `NETHER_CAVE` est explicitement conservé dans `addDefaultIrradiatedOres`, sans justification documentée — reste à trancher. `OriginalBiomeLookup` est un bonus hors-périmètre de l'audit courant (jamais listé en §4). | | Ajout de `DefaultHeatCalculatorGameTest` (3 cas : fuel isolé, cooler isolé, asymétrie de voisinage fuel/cooler) — première couverture de test pour `DefaultHeatCalculator.computeHeat` (§3/§7 priorité 1) | `498f9dc6` | 2026-07-13 | Écrit en `GameTest` (real `ServerLevel`/`ReactorControllerBlockEntity`/items enregistrés) après rejet d'une première tentative JUnit+Mockito : mocker `Item`/`ItemStack`/`Level` échoue hors jeu démarré (static init Minecraft), ce qui confirme empiriquement le choix `GameTest` déjà fait pour `ReactorInputFluidManagerGameTest`. Valeurs attendues dérivées de `CNConfigs.server().rods.*` en direct (pas de valeurs codées en dur), donc robuste à un changement de balance. | | Ajout de `ReactorInputFluidManagerGameTest` (couvre `read`/`write`/`clearInvalid`/`getBlocksPosition`/`getFuildHandlers`/`getInventory`/`extractFluids`, dont des marqueurs de régression `*_expectedContract` pour le bug de sur-extraction du §1) — **jamais documenté dans cet audit jusqu'ici**, omission corrigée à l'occasion de la mise à jour ci-dessus | `200df62f` | 2026-07-12 (avant la réorganisation issue de ce même jour, retrouvé par `git log`) | Deux tests `*_expectedContract` échouent intentionnellement aujourd'hui (documentent le comportement souhaité, pas encore implémenté) ; le reste passe et caractérise le comportement actuel. | | `ReactorSummaryDisplaySource` — remplacement de la sentinelle de taille (liste 1/6 éléments) et des accès positionnels fragiles (`components.get(2).get(1)`) par un `record ReactorSummary` typé (`ReactorSummaryRow` + `Builder` validant les 6 champs requis) ; `getComponents()` → `getReactorSummary()` retournant `Optional` ; remplacement de `joptsimple.internal.Strings.repeat` (dépendance transitive non déclarée) par `String.repeat` natif ; Javadoc anglais ajouté sur la classe et ses méthodes, retirant au passage les 3 commentaires français "Sécurité Triple-Check" (§6) | `cc532f83` | 2026-07-12 | Nouveau fichier `ReactorSummary.java` (§2.3 et §6, item ex-9, tous deux clos). `toRows()` reste le seul point de conversion vers le format positionnel `List>` exigé par l'API `DisplaySource` de Create. | diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 8d559aee..6d390664 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-07-13T12:22:03.9183298 CreateNuclear Generated Registry Entries +// 1.20.1 2026-07-13T14:20:22.3751014 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -10,7 +10,7 @@ afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids 72173023e6a31748692e750db0f5fa8c555d1009 data/createnuclear/forge/biome_modifier/striated_ores_overworld.json 1d15657126bab7c0b4355d0dcb9addc2d417ed01 data/createnuclear/forge/biome_modifier/thorium_ore.json fa32145101dc12ec914684fec8c5cbb995d2c051 data/createnuclear/forge/biome_modifier/uranium_ore.json -6abf282b710f320cc2fbfe150cca1d08bfc28954 data/createnuclear/worldgen/biome/irradiated_land.json +34be7473e0eaccfd6f44d1cab3b7650ff5f3e37e data/createnuclear/worldgen/biome/irradiated_land.json 211d1391981d173b8bc490e5af1471441e1df37f data/createnuclear/worldgen/configured_feature/lead_ore.json c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_feature/nitrate_ore.json 4f11c0a518c0de7857919983fc638ba551c6630a data/createnuclear/worldgen/configured_feature/striated_ores_overworld.json diff --git a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json index 442b9cfc..67d93784 100644 --- a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json +++ b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json @@ -25,17 +25,7 @@ "water_color": 3887411, "water_fog_color": 658954 }, - "features": [ - [], - [], - [], - [ - "minecraft:blue_ice" - ], - [ - "minecraft:void_start_platform" - ] - ], + "features": [], "has_precipitation": false, "spawn_costs": {}, "spawners": { From 6bc20956c4ac6a9718c946c35007f13a7bf87040 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 15:36:31 +0200 Subject: [PATCH 155/171] refactor: remove NETHER_CAVE carver from IrradiatedBiomes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete addDefaultIrradiatedOres() (its only remaining content was the NETHER_CAVE air carver) and its only call site in irradiated(), finishing the "worldgen irradié" cleanup left open in AUDIT_ACTUEL.md §4/§7 — the irradiated biome no longer carves any unrelated vanilla content. - Regenerate irradiated_land.json and its datagen .cache file: the biome's "carvers" block is now empty. --- .../.cache/fed443662143001aeb5341375f6f5ef31d10baea | 4 ++-- .../createnuclear/worldgen/biome/irradiated_land.json | 4 +--- .../infrastructure/worldgen/biome/IrradiatedBiomes.java | 8 +------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 6d390664..69cb7ea4 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-07-13T14:20:22.3751014 CreateNuclear Generated Registry Entries +// 1.20.1 2026-07-13T15:35:50.3841285 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -10,7 +10,7 @@ afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids 72173023e6a31748692e750db0f5fa8c555d1009 data/createnuclear/forge/biome_modifier/striated_ores_overworld.json 1d15657126bab7c0b4355d0dcb9addc2d417ed01 data/createnuclear/forge/biome_modifier/thorium_ore.json fa32145101dc12ec914684fec8c5cbb995d2c051 data/createnuclear/forge/biome_modifier/uranium_ore.json -34be7473e0eaccfd6f44d1cab3b7650ff5f3e37e data/createnuclear/worldgen/biome/irradiated_land.json +a3399faccac4549c2c7d41a5863883ecea074e99 data/createnuclear/worldgen/biome/irradiated_land.json 211d1391981d173b8bc490e5af1471441e1df37f data/createnuclear/worldgen/configured_feature/lead_ore.json c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_feature/nitrate_ore.json 4f11c0a518c0de7857919983fc638ba551c6630a data/createnuclear/worldgen/configured_feature/striated_ores_overworld.json diff --git a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json index 67d93784..c69706c5 100644 --- a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json +++ b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json @@ -1,7 +1,5 @@ { - "carvers": { - "air": "minecraft:nether_cave" - }, + "carvers": {}, "downfall": 0.0, "effects": { "ambient_sound": "createnuclear:biomes/wasteland", diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 6a53cb34..963bd3ad 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -17,11 +17,7 @@ public class IrradiatedBiomes { public static Biome createPlain(HolderGetter featureLookup, HolderGetter> carverLookup, HolderGetter soundLookup) { return IrradiatedBiomes.irradiated(featureLookup, carverLookup, soundLookup, new BiomeGenerationSettings.Builder(featureLookup, carverLookup)); } - - public static void addDefaultIrradiatedOres(BiomeGenerationSettings.Builder builder) { - builder.addCarver(GenerationStep.Carving.AIR, Carvers.NETHER_CAVE); - } - + public static Biome irradiated(HolderGetter featureGetter, HolderGetter> carverGetter, HolderGetter soundLookup, BiomeGenerationSettings.Builder generation) { MobSpawnSettings.Builder spawnBuilder = new MobSpawnSettings.Builder(); BiomeSpecialEffects.Builder effectBuilder = new BiomeSpecialEffects.Builder(); @@ -48,8 +44,6 @@ public static Biome irradiated(HolderGetter featureGetter, Holder .ambientLoopSound(soundLookup.getOrThrow(ResourceKey.create(Registries.SOUND_EVENT, CNSoundEvents.BIOME_WASTELAND.getId()))) ; - IrradiatedBiomes.addDefaultIrradiatedOres(generation); - return new Biome.BiomeBuilder() .mobSpawnSettings(spawnBuilder.build()) .hasPrecipitation(false) From b0874bb1c755749592a39999293e0993f77397bc Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 15:40:34 +0200 Subject: [PATCH 156/171] docs: update AUDIT_ACTUEL.md to record NETHER_CAVE removal and close the worldgen cleanup item MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-13 update for commit `6bc20956`, noting the removal of NETHER_CAVE (via addDefaultIrradiatedOres() and its call site) and the regenerated irradiated_land.json with an empty carvers block; also amend the prior `ae1e394d` update to drop the now-outdated "partiellement clos" wording. - §4: mark the "worldgen irradié" item as fully resolved across `ae1e394d`/`6bc20956` (BLUE_ICE, NETHER_CAVE, VOID_START_PLATFORM all gone), leaving only the CNNoiseGeneratorSettings.java STEEL_BLOCK fill-block choice open; flag a newly found, not-yet-fixed issue: the Carvers/MiscOverworldPlacements/GenerationStep imports in IrradiatedBiomes.java are now dead following `6bc20956`. - §6: update IrradiatedBiomes.java's line numbers for item 11 (26-40, re-shifted by `ae1e394d`/`6bc20956`) and note that the parent §4 "template non terminé" item is now closed, only the comment-line tracking remains. - §7: mark the worldgen cleanup bullet as fully done across both commits, narrowing the remaining scope to the STEEL_BLOCK choice. - §8.1: add a changelog row for `6bc20956` (removal of addDefaultIrradiatedOres()/NETHER_CAVE and regenerated irradiated_land.json) and amend the `ae1e394d` row to reflect that it only started the worldgen cleanup, completed by `6bc20956`. --- AUDIT_ACTUEL.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f4338c5d..b1aa9283 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -20,7 +20,9 @@ Depuis la dernière consolidation (2026-06-28), le projet a continué d'évoluer La dette la plus structurelle reste **l'absence de tests sur la majorité du code** (`src/test` toujours vide — la mécanique JUnit classique n'est pas utilisable ici, voir ci-dessus — et seuls deux composants ont une suite `GameTest`) — précisément là où des bugs/incohérences silencieux (sur-extraction fluide, ex-tautologie `IHeat`, scan non court-circuité, doc devenue obsolète sans que personne ne le remarque) survivent à plusieurs passes d'audit. Le pattern matcher (`ReactorPattern`/`CNMultiblock`) et `PersistentFluidLocks` restent entièrement sans couverture. Voir §3 et §7. -**Mise à jour (`ae1e394d`, 2026-07-13)** : nettoyage de trois points du §4/§7 en une seule fois — retrait complet des références commentées à la propriété `SPEED` de `ReactorOutput` (§4/§7 item 7, désormais clos), retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` d'`IrradiatedBiomes` (§4 « worldgen irradié », **partiellement clos** — `NETHER_CAVE` reste volontairement conservé, sans justification documentée dans le commit), et suppression de `OriginalBiomeLookup.java`, une classe de résolution de biome jamais appelée qui n'avait encore jamais été repérée par cet audit. Détail en §8.1. +**Mise à jour (`ae1e394d`, 2026-07-13)** : nettoyage de trois points du §4/§7 en une seule fois — retrait complet des références commentées à la propriété `SPEED` de `ReactorOutput` (§4/§7 item 7, désormais clos), retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` d'`IrradiatedBiomes` (§4 « worldgen irradié », alors partiellement clos), et suppression de `OriginalBiomeLookup.java`, une classe de résolution de biome jamais appelée qui n'avait encore jamais été repérée par cet audit. Détail en §8.1. + +**Mise à jour (`6bc20956`, 2026-07-13)** : suite immédiate de la précédente — retrait de `NETHER_CAVE` (dernier contenu vanilla sans rapport identifié dans `IrradiatedBiomes`, via la suppression de `addDefaultIrradiatedOres()` et de son unique site d'appel), régénération de `irradiated_land.json` (bloc `carvers` désormais vide). **L'item « worldgen irradié » du §4/§7 est donc maintenant entièrement clos** ; seul reste `CNNoiseGeneratorSettings.java:25` (bloc de remplissage `STEEL_BLOCK`) côté §4. Détail en §8.1. --- @@ -80,9 +82,10 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod - ~~`content/multiblock/output/ReactorOutput.java` — propriété `SPEED` toujours entièrement commentée~~ — **résolu** (`ae1e394d`, 2026-07-13) : les références commentées (`//builder.add(SPEED);`, `/*.setValue(SPEED, 0)*/`) ont été retirées, voir §8.1. - `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. -**Worldgen « irradié » — template non terminé** *(mis à jour 2026-07-13, `ae1e394d`)* -- `IrradiatedBiomes.java:22` — **partiellement résolu** : `BLUE_ICE` et l'aide `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (plus son unique site d'appel) ont été retirés. `NETHER_CAVE` reste présent (`addDefaultIrradiatedOres`, l.22) — le commit ne documente pas si ce choix est volontaire (carver de grottes potentiellement pertinent thématiquement) ou un oubli ; à trancher explicitement au prochain passage sur ce fichier. -- `CNNoiseGeneratorSettings.java:25` utilise toujours `STEEL_BLOCK` comme bloc de remplissage par défaut du biome irradié. +**Worldgen « irradié » — template non terminé** +- ~~`IrradiatedBiomes.java` ajoutait du contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`)~~ — **résolu** (`ae1e394d` puis `6bc20956`, 2026-07-13) : les trois ont été retirés (dont `addDefaultIrradiatedOres()`/`addDefaultSoftDisks()` et leurs sites d'appel), `irradiated_land.json` régénéré avec un bloc `carvers` vide. Le fichier ne référence plus que ses propres effets de biome (couleurs, sons, particules). Voir §8.1. +- `CNNoiseGeneratorSettings.java:25` utilise toujours `STEEL_BLOCK` comme bloc de remplissage par défaut du biome irradié — seul point restant de cet item. +- **Point trouvé lors de cette mise à jour, non corrigé** : `IrradiatedBiomes.java:5,6,10` — les imports `Carvers`, `MiscOverworldPlacements` et `GenerationStep` sont devenus morts suite au retrait de leurs derniers usages par `6bc20956` (confirmé par grep : plus aucune référence dans le fichier). Trivial, à nettoyer au prochain passage. *(Le dead code pur déjà retiré — `SimpleMultiBlockPattern.test()`, `IrradiatedBiomes.monsters()`, le nettoyage de `PlayerInteractReactorFluidInput`, les fichiers de debug `run/`, la mécanique de collier teignable, `OriginalBiomeLookup.java` — est en §8.1/§8.3 avec ses hash.)* @@ -122,7 +125,7 @@ Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la tabl 8. `foundation/mixin/CameraAccessor.java:9` — accessor mixin, commentaire français isolé sur le pattern « invoker » Mixin. 9. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. 10. `content/decoration/palettes/PalettesVariantEntry.java:54` — commentaire français sur un changement d'architecture de rendu déjà effectué ailleurs, utile pour éviter une régression, en français uniquement. -11. `infrastructure/worldgen/biome/IrradiatedBiomes.java:30-44` — 5 commentaires français sur des choix esthétiques de biome (numéros de ligne décalés par le retrait de code du §4 dans `ae1e394d`, contenu inchangé) ; mineur, mais dans un fichier déjà pointé par §4 comme « template non terminé ». +11. `infrastructure/worldgen/biome/IrradiatedBiomes.java:26-40` — 5 commentaires français sur des choix esthétiques de biome (numéros de ligne re-décalés par `ae1e394d`/`6bc20956`, contenu inchangé) ; mineur. L'item §4 « template non terminé » lui-même est désormais clos (voir §4), seul le décalage de ces commentaires reste à suivre ici. 12. `content/equipment/armor/AntiRadiationArmorItem.java:48` — commentaire français sur `getArmorTexture` (override d'API Forge publique) ; trivial sur le fond, à harmoniser en anglais par cohérence. 13. `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:33` — commentaire français isolé, sur une classe explicitement exclue du refactor de mutualisation `drawGauge` (§8.1) — bon candidat à documenter proprement au prochain passage sur ce fichier. 14. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. @@ -167,7 +170,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq **7. Nettoyage / décisions produit à trancher** - ~~`ReactorOutput.SPEED` : retirer les commentaires ou décider de réactiver la propriété~~ — **fait**, commit `ae1e394d` (§4/§8.1). - `CNStandardRecipeGen.java:226` : trancher le `FIXME` sur les catégories de recette (§4). -- Worldgen « irradié » : **partiellement fait** (`ae1e394d`) — `BLUE_ICE` et `VOID_START_PLATFORM` retirés ; reste à trancher si `NETHER_CAVE` doit rester, et à choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. +- ~~Worldgen « irradié » : retirer le contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`)~~ — **fait**, commits `ae1e394d` puis `6bc20956` (§4/§8.1). Reste : choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` dans `CNNoiseGeneratorSettings.java:25` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. **8. Documentation (nouveau, §6)** - ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait**, commit `3be6252a`. @@ -194,7 +197,8 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| -| Retrait des références commentées à `SPEED` dans `ReactorOutput` (`createBlockStateDefinition`, `getStateForPlacement`) ; retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (+ son unique site d'appel) dans `IrradiatedBiomes` ; suppression de `OriginalBiomeLookup.java` (classe de résolution de biome jamais appelée, non repérée jusqu'ici par cet audit) ; ajout de `@ParametersAreNonnullByDefault` sur `ReactorOutput` et retrait du `@NotNull` désormais redondant sur `getShape()` | `ae1e394d` | 2026-07-13 | Clôt le premier bullet de §4/§7 item 7 (`SPEED`). Résout partiellement le second (« worldgen irradié ») : `NETHER_CAVE` est explicitement conservé dans `addDefaultIrradiatedOres`, sans justification documentée — reste à trancher. `OriginalBiomeLookup` est un bonus hors-périmètre de l'audit courant (jamais listé en §4). | +| Retrait de `addDefaultIrradiatedOres()` (dernier contenu : le carver `NETHER_CAVE`) et de son unique site d'appel dans `IrradiatedBiomes.irradiated()` ; régénération de `irradiated_land.json`/`.cache` (bloc `carvers` désormais vide) | `6bc20956` | 2026-07-13 | **Clôt entièrement** l'item « worldgen irradié » du §4/§7 (`BLUE_ICE`/`VOID_START_PLATFORM` déjà retirés par `ae1e394d` juste avant). Seul point restant sur ce sujet : `CNNoiseGeneratorSettings.java:25` (`STEEL_BLOCK`), sans rapport avec ce commit. | +| Retrait des références commentées à `SPEED` dans `ReactorOutput` (`createBlockStateDefinition`, `getStateForPlacement`) ; retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (+ son unique site d'appel) dans `IrradiatedBiomes` ; suppression de `OriginalBiomeLookup.java` (classe de résolution de biome jamais appelée, non repérée jusqu'ici par cet audit) ; ajout de `@ParametersAreNonnullByDefault` sur `ReactorOutput` et retrait du `@NotNull` désormais redondant sur `getShape()` | `ae1e394d` | 2026-07-13 | Clôt le premier bullet de §4/§7 item 7 (`SPEED`). Entame le second (« worldgen irradié »), achevé juste après par `6bc20956` (ci-dessus). `OriginalBiomeLookup` est un bonus hors-périmètre de l'audit courant (jamais listé en §4). | | Ajout de `DefaultHeatCalculatorGameTest` (3 cas : fuel isolé, cooler isolé, asymétrie de voisinage fuel/cooler) — première couverture de test pour `DefaultHeatCalculator.computeHeat` (§3/§7 priorité 1) | `498f9dc6` | 2026-07-13 | Écrit en `GameTest` (real `ServerLevel`/`ReactorControllerBlockEntity`/items enregistrés) après rejet d'une première tentative JUnit+Mockito : mocker `Item`/`ItemStack`/`Level` échoue hors jeu démarré (static init Minecraft), ce qui confirme empiriquement le choix `GameTest` déjà fait pour `ReactorInputFluidManagerGameTest`. Valeurs attendues dérivées de `CNConfigs.server().rods.*` en direct (pas de valeurs codées en dur), donc robuste à un changement de balance. | | Ajout de `ReactorInputFluidManagerGameTest` (couvre `read`/`write`/`clearInvalid`/`getBlocksPosition`/`getFuildHandlers`/`getInventory`/`extractFluids`, dont des marqueurs de régression `*_expectedContract` pour le bug de sur-extraction du §1) — **jamais documenté dans cet audit jusqu'ici**, omission corrigée à l'occasion de la mise à jour ci-dessus | `200df62f` | 2026-07-12 (avant la réorganisation issue de ce même jour, retrouvé par `git log`) | Deux tests `*_expectedContract` échouent intentionnellement aujourd'hui (documentent le comportement souhaité, pas encore implémenté) ; le reste passe et caractérise le comportement actuel. | | `ReactorSummaryDisplaySource` — remplacement de la sentinelle de taille (liste 1/6 éléments) et des accès positionnels fragiles (`components.get(2).get(1)`) par un `record ReactorSummary` typé (`ReactorSummaryRow` + `Builder` validant les 6 champs requis) ; `getComponents()` → `getReactorSummary()` retournant `Optional` ; remplacement de `joptsimple.internal.Strings.repeat` (dépendance transitive non déclarée) par `String.repeat` natif ; Javadoc anglais ajouté sur la classe et ses méthodes, retirant au passage les 3 commentaires français "Sécurité Triple-Check" (§6) | `cc532f83` | 2026-07-12 | Nouveau fichier `ReactorSummary.java` (§2.3 et §6, item ex-9, tous deux clos). `toRows()` reste le seul point de conversion vers le format positionnel `List>` exigé par l'API `DisplaySource` de Create. | From e79009593a70deda4cf1d294372153f109adc773 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 15:53:17 +0200 Subject: [PATCH 157/171] feat(jei): expose JEI runtime and decide the recipe-category FIXME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CreateNuclearJEI: store the IJeiRuntime made available via the new onRuntimeAvailable(IJeiRuntime) callback in a static `runtime` field, so other classes can access it once JEI has finished loading. - Rename the static `Categories` field to an instance field `allCategories`, and thread it explicitly through CategoryBuilder (new constructor parameter `targetCategories`) instead of closing over a static list — CategoryBuilder.add() now appends to the instance-owned list. - Reorder IModPlugin overrides (getPluginUid moved after field declarations, builder() moved next to loadCategories()) for a more logical top-to-bottom reading order; no behavioral change. - CNStandardRecipeGen: remove the `// FIXME 5.1 refactor - recipe categories as markers instead of sections?` comment on viaShaped(), resolving the open item tracked in AUDIT_ACTUEL.md §4/§7 — recipe categories stay markers, not sections. - IrradiatedBiomes: drop a trailing-whitespace-only blank line between createPlain() and irradiated(). --- .../compat/jei/CreateNuclearJEI.java | 45 ++++++++++++------- .../data/recipe/CNStandardRecipeGen.java | 1 - .../worldgen/biome/IrradiatedBiomes.java | 2 +- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/compat/jei/CreateNuclearJEI.java b/src/main/java/net/nuclearteam/createnuclear/compat/jei/CreateNuclearJEI.java index 9addda1c..0f29cc81 100644 --- a/src/main/java/net/nuclearteam/createnuclear/compat/jei/CreateNuclearJEI.java +++ b/src/main/java/net/nuclearteam/createnuclear/compat/jei/CreateNuclearJEI.java @@ -18,6 +18,7 @@ import mezz.jei.api.registration.IRecipeRegistration; import mezz.jei.api.registration.IRecipeTransferRegistration; import mezz.jei.api.runtime.IIngredientManager; +import mezz.jei.api.runtime.IJeiRuntime; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; @@ -50,16 +51,14 @@ @MethodsReturnNonnullByDefault public class CreateNuclearJEI implements IModPlugin { private static final ResourceLocation MOD_ID = CreateNuclear.asResource("jei_plugin"); - @Override - public ResourceLocation getPluginUid() { - return MOD_ID; - } + private final List> allCategories = new ArrayList<>(); public IIngredientManager ingredientManager; - private static final List> Categories = new ArrayList<>(); + + public static IJeiRuntime runtime; private void loadCategories() { - Categories.clear(); + allCategories.clear(); CreateRecipeCategory enriched = builder(EnrichedRecipe.class) .addTypedRecipes(CNRecipeTypes.ENRICHED::getType) @@ -76,21 +75,30 @@ private void loadCategories() { ; } + private > CategoryBuilder builder(Class recipeClass) { + return new CategoryBuilder<>(recipeClass, allCategories); + } + @Override - public void registerRecipes(IRecipeRegistration registration) { - ingredientManager = registration.getIngredientManager(); - Categories.forEach(c -> c.registerRecipes(registration)); + public ResourceLocation getPluginUid() { + return MOD_ID; } @Override public void registerCategories(IRecipeCategoryRegistration registration) { loadCategories(); - registration.addRecipeCategories(Categories.toArray(IRecipeCategory[]::new)); + registration.addRecipeCategories(allCategories.toArray(IRecipeCategory[]::new)); + } + + @Override + public void registerRecipes(IRecipeRegistration registration) { + ingredientManager = registration.getIngredientManager(); + allCategories.forEach(c -> c.registerRecipes(registration)); } @Override public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) { - Categories.forEach(c -> c.registerCatalysts(registration)); + allCategories.forEach(c -> c.registerCatalysts(registration)); } @Override @@ -98,12 +106,9 @@ public void registerRecipeTransferHandlers(IRecipeTransferRegistration registrat registration.addRecipeTransferHandler(new BlueprintTransferHandler(), RecipeTypes.CRAFTING); } - private > CategoryBuilder builder(Class recipeClass) { - return new CategoryBuilder<>(recipeClass); - } - private static class CategoryBuilder> { private final Class recipeClass; + private final List> targetCategories; private Predicate predicate = cRecipes -> true; private IDrawable background; @@ -112,8 +117,9 @@ private static class CategoryBuilder> { private final List>> recipeListConsumers = new ArrayList<>(); private final List> catalysts = new ArrayList<>(); - public CategoryBuilder(Class recipeClass) { + public CategoryBuilder(Class recipeClass, List> targetCategories) { this.recipeClass = recipeClass; + this.targetCategories = targetCategories; } public CategoryBuilder enableIf(Predicate predicate) { @@ -284,7 +290,7 @@ public CreateRecipeCategory build(String name, CreateRecipeCategory.Factory(CreateNuclear.asResource(name), recipeClass), CreateNuclearLang.translateDirect("recipe." + name), background, icon, recipesSupplier, catalysts); CreateRecipeCategory category = factory.create(info); - Categories.add(category); + targetCategories.add(category); return category; } } @@ -296,6 +302,11 @@ public static void consumeAllRecipes(Consumer> consumer) { .getRecipes() .forEach(consumer); } + + @Override + public void onRuntimeAvailable(IJeiRuntime runtime) { + CreateNuclearJEI.runtime = runtime; + } } diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java index a63835cf..48809231 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/recipe/CNStandardRecipeGen.java @@ -223,7 +223,6 @@ GeneratedRecipeBuilder withCategory(RecipeCategory category) { return this; } - // FIXME 5.1 refactor - recipe categories as markers instead of sections? GeneratedRecipe viaShaped(UnaryOperator builder) { return register(consumer -> { ShapedRecipeBuilder b = builder.apply(ShapedRecipeBuilder.shaped(category, result.get(), amount)); diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 963bd3ad..47fddc13 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -17,7 +17,7 @@ public class IrradiatedBiomes { public static Biome createPlain(HolderGetter featureLookup, HolderGetter> carverLookup, HolderGetter soundLookup) { return IrradiatedBiomes.irradiated(featureLookup, carverLookup, soundLookup, new BiomeGenerationSettings.Builder(featureLookup, carverLookup)); } - + public static Biome irradiated(HolderGetter featureGetter, HolderGetter> carverGetter, HolderGetter soundLookup, BiomeGenerationSettings.Builder generation) { MobSpawnSettings.Builder spawnBuilder = new MobSpawnSettings.Builder(); BiomeSpecialEffects.Builder effectBuilder = new BiomeSpecialEffects.Builder(); From 6c3bf9702415acc90b4243310ab1b589df3d7440 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 15:57:46 +0200 Subject: [PATCH 158/171] docs: update AUDIT_ACTUEL.md to record CreateNuclearJEI static-field fix and recipe-category FIXME resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-13 update for commit `e7900959`, summarizing both changes it makes: converting CreateNuclearJEI's static `Categories` field to an instance field `allCategories` (with IJeiRuntime now exposed via onRuntimeAvailable), and removing the CNStandardRecipeGen.java:226 FIXME with the decision that recipe categories stay markers, not sections. - §2 (mineurs item 5): mark the CreateNuclearJEI static mutable field issue as resolved. - §4 "Code commencé puis abandonné": mark the CNStandardRecipeGen FIXME as resolved with the decision rationale. - §6: mark the CNStandardRecipeGen.java:226 language-independent ambiguity note as resolved. - §7 (item 9 "cleanup à trancher"): mark the FIXME item as done. - §7 (item 9 "à surveiller"): mark the CreateNuclearJEI static-field watch item as done. - §8.1: add a changelog row documenting `e7900959` in detail (instance field conversion, CategoryBuilder's new targetCategories parameter, IJeiRuntime exposure, FIXME removal) and its closed audit items. --- AUDIT_ACTUEL.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index b1aa9283..a6b591e4 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -24,6 +24,8 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Mise à jour (`6bc20956`, 2026-07-13)** : suite immédiate de la précédente — retrait de `NETHER_CAVE` (dernier contenu vanilla sans rapport identifié dans `IrradiatedBiomes`, via la suppression de `addDefaultIrradiatedOres()` et de son unique site d'appel), régénération de `irradiated_land.json` (bloc `carvers` désormais vide). **L'item « worldgen irradié » du §4/§7 est donc maintenant entièrement clos** ; seul reste `CNNoiseGeneratorSettings.java:25` (bloc de remplissage `STEEL_BLOCK`) côté §4. Détail en §8.1. +**Mise à jour (`e7900959`, 2026-07-13)** : deux items de plus tranchés. (1) `CreateNuclearJEI` : le champ statique mutable `Categories` (§2 mineurs item 5) devient un champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder` — le risque de contamination entre instances lors d'un reload JEI est éliminé ; au passage, `IJeiRuntime` est désormais exposé via `onRuntimeAvailable`. (2) Le `FIXME` de `CNStandardRecipeGen.java:226` (§4/§6/§7) est tranché : retiré, décision actée que les catégories de recette restent des marqueurs plutôt que des sections. Détail en §8.1. + --- ## 1. 🐛 Bugs confirmés ouverts @@ -57,7 +59,7 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod ### 🟡 Mineurs -5. **`CreateNuclearJEI`** — champ statique mutable `Categories`, vidé/reconstruit à chaque `registerCategories` ; risque si JEI ré-appelle le cycle (reload ressources). *(non revérifié ce tour, signal inchangé depuis plusieurs audits)* +5. ~~**`CreateNuclearJEI`** — champ statique mutable `Categories`~~ — **résolu** (`e7900959`, 2026-07-13) : converti en champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder`. Voir §8.1. 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. --- @@ -80,7 +82,7 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Code commencé puis abandonné (hygiène de fin de PR)** - ~~`content/multiblock/output/ReactorOutput.java` — propriété `SPEED` toujours entièrement commentée~~ — **résolu** (`ae1e394d`, 2026-07-13) : les références commentées (`//builder.add(SPEED);`, `/*.setValue(SPEED, 0)*/`) ont été retirées, voir §8.1. -- `foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...` toujours présent, à trancher. +- ~~`foundation/data/recipe/CNStandardRecipeGen.java:226` — `// FIXME 5.1 refactor - recipe categories as markers...`~~ — **résolu** (`e7900959`, 2026-07-13) : commentaire retiré, décision actée que les catégories de recette restent des marqueurs plutôt que des sections. Voir §8.1. **Worldgen « irradié » — template non terminé** - ~~`IrradiatedBiomes.java` ajoutait du contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`)~~ — **résolu** (`ae1e394d` puis `6bc20956`, 2026-07-13) : les trois ont été retirés (dont `addDefaultIrradiatedOres()`/`addDefaultSoftDisks()` et leurs sites d'appel), `irradiated_land.json` régénéré avec un bloc `carvers` vide. Le fichier ne référence plus que ses propres effets de biome (couleurs, sons, particules). Voir §8.1. @@ -133,7 +135,7 @@ Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la tabl **Ambiguïtés/incomplétudes indépendantes de la langue relevées au passage** : - ~~`CNPonderReactorScenes.java:50,90`~~ — **résolu** (`3be6252a`) : les deux Javadoc ont été reformulées en documentation stable en même temps que leur traduction (voir ci-dessus). - `ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée — ambiguïté fonctionnelle non résolue. -- `CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers. +- ~~`CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers~~ — **résolu** (`e7900959`, 2026-07-13), voir §4/§8.1. **Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité mais se réduit** : il se concentre désormais sur les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSizeDisplaySource` uniquement désormais), et `CNFluids`/`ClientEvents`. Les scènes Ponder (`CNPonderReactorScenes`) et `ReactorSummaryDisplaySource` sortent de cette liste, assainies respectivement par `3be6252a` et `cc532f83`. Point positif : le sous-ensemble concerné continue de rétrécir (11/292 fichiers désormais, ~3,8 %) — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger, refactor `ReactorSummary`) n'ont pas introduit de nouveau commentaire français. @@ -169,7 +171,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq **7. Nettoyage / décisions produit à trancher** - ~~`ReactorOutput.SPEED` : retirer les commentaires ou décider de réactiver la propriété~~ — **fait**, commit `ae1e394d` (§4/§8.1). -- `CNStandardRecipeGen.java:226` : trancher le `FIXME` sur les catégories de recette (§4). +- ~~`CNStandardRecipeGen.java:226` : trancher le `FIXME` sur les catégories de recette~~ — **fait**, commit `e7900959` (§4/§8.1). - ~~Worldgen « irradié » : retirer le contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`)~~ — **fait**, commits `ae1e394d` puis `6bc20956` (§4/§8.1). Reste : choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` dans `CNNoiseGeneratorSettings.java:25` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. **8. Documentation (nouveau, §6)** @@ -180,7 +182,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq **9. À surveiller sans action immédiate** - `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. - `ReactorOutput`/`ReactorFluidInput` : garde `!state.is(newState.getBlock())` absente dans `onRemove` malgré des propriétés mutables (§2.1). Pas un bug confirmé, à surveiller. -- `CreateNuclearJEI` : champ statique mutable `Categories`, non revérifié récemment (§2.5). +- ~~`CreateNuclearJEI` : champ statique mutable `Categories`~~ — **fait**, commit `e7900959` (§2.5/§8.1). **Explicitement retiré du plan (ne plus y revenir sans nouvel élément)** — détail et justification en §8.2/§8.3 : - Découpage supplémentaire de `ReactorControllerBlockEntity` (chantier clos, croissance maîtrisée). @@ -197,6 +199,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| `CreateNuclearJEI` : champ statique mutable `Categories` converti en champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder` (nouveau paramètre `targetCategories`) ; exposition d'`IJeiRuntime` via `onRuntimeAvailable` ; retrait du `FIXME` de `CNStandardRecipeGen.java:226` (décision actée : catégories de recette = marqueurs, pas des sections) | `e7900959` | 2026-07-13 | Clôt §2 mineurs item 5, §4/§6/§7 (`CNStandardRecipeGen` FIXME) et §7 item 9 (surveillance `CreateNuclearJEI`). Aucun changement de comportement observable pour le FIXME (retrait de commentaire + décision documentée dans le message de commit) ; pour `CreateNuclearJEI`, chaque instance du plugin a désormais sa propre liste, éliminant le risque de contamination inter-instances en cas de reload JEI. | | Retrait de `addDefaultIrradiatedOres()` (dernier contenu : le carver `NETHER_CAVE`) et de son unique site d'appel dans `IrradiatedBiomes.irradiated()` ; régénération de `irradiated_land.json`/`.cache` (bloc `carvers` désormais vide) | `6bc20956` | 2026-07-13 | **Clôt entièrement** l'item « worldgen irradié » du §4/§7 (`BLUE_ICE`/`VOID_START_PLATFORM` déjà retirés par `ae1e394d` juste avant). Seul point restant sur ce sujet : `CNNoiseGeneratorSettings.java:25` (`STEEL_BLOCK`), sans rapport avec ce commit. | | Retrait des références commentées à `SPEED` dans `ReactorOutput` (`createBlockStateDefinition`, `getStateForPlacement`) ; retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (+ son unique site d'appel) dans `IrradiatedBiomes` ; suppression de `OriginalBiomeLookup.java` (classe de résolution de biome jamais appelée, non repérée jusqu'ici par cet audit) ; ajout de `@ParametersAreNonnullByDefault` sur `ReactorOutput` et retrait du `@NotNull` désormais redondant sur `getShape()` | `ae1e394d` | 2026-07-13 | Clôt le premier bullet de §4/§7 item 7 (`SPEED`). Entame le second (« worldgen irradié »), achevé juste après par `6bc20956` (ci-dessus). `OriginalBiomeLookup` est un bonus hors-périmètre de l'audit courant (jamais listé en §4). | | Ajout de `DefaultHeatCalculatorGameTest` (3 cas : fuel isolé, cooler isolé, asymétrie de voisinage fuel/cooler) — première couverture de test pour `DefaultHeatCalculator.computeHeat` (§3/§7 priorité 1) | `498f9dc6` | 2026-07-13 | Écrit en `GameTest` (real `ServerLevel`/`ReactorControllerBlockEntity`/items enregistrés) après rejet d'une première tentative JUnit+Mockito : mocker `Item`/`ItemStack`/`Level` échoue hors jeu démarré (static init Minecraft), ce qui confirme empiriquement le choix `GameTest` déjà fait pour `ReactorInputFluidManagerGameTest`. Valeurs attendues dérivées de `CNConfigs.server().rods.*` en direct (pas de valeurs codées en dur), donc robuste à un changement de balance. | From 43aa5723a3604d083c9b3ba9208cdbbdf2a8e532 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 18:59:42 +0200 Subject: [PATCH 159/171] chore: bump mod version to 2.0.16-beta --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 52685895..a678e3f8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,7 +64,7 @@ mod_name=Create Nuclear # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=MIT # The mod version. See https://semver.org/ -mod_version=2.0.15-beta +mod_version=2.0.16-beta # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html From 1841242e4b4bd4c8b584f66720d4bcb77905061a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Tue, 14 Jul 2026 12:15:10 +0200 Subject: [PATCH 160/171] style: replace var with explicit types in AntiRadiationArmorClientExtensions Replace `var entityModelSet`/`var root` with explicit EntityModelSet/ModelPart types in getHumanoidArmorModel(), for consistency with the project's preference for explicit typing over var (see e.g. ReactorSummaryDisplaySource's Map.Entry and List in commit e7900959's predecessor). --- .../equipment/armor/AntiRadiationArmorClientExtensions.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java index 0e2ddf57..765ba8b2 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorClientExtensions.java @@ -2,6 +2,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.EntityModelSet; +import net.minecraft.client.model.geom.ModelPart; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; @@ -15,8 +17,8 @@ public final class AntiRadiationArmorClientExtensions implements IClientItemExte @Override public @NotNull HumanoidModel getHumanoidArmorModel(LivingEntity livingEntity, ItemStack itemStack, EquipmentSlot equipmentSlot, HumanoidModel original) { if (this.model == null) { - var entityModelSet = Minecraft.getInstance().getEntityModels(); - var root = entityModelSet.bakeLayer(CNModelLayers.ANTI_IRRADIATION_ARMOR); + EntityModelSet entityModelSet = Minecraft.getInstance().getEntityModels(); + ModelPart root = entityModelSet.bakeLayer(CNModelLayers.ANTI_IRRADIATION_ARMOR); this.model = new AntiRadiationArmorModel(root); } From 9e8abe922cb9fe5e86ecc56c4bac5c4efec6a915 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Tue, 14 Jul 2026 12:31:47 +0200 Subject: [PATCH 161/171] style: translate remaining French comments to English across the codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete the §6 French-comment cleanup tracked in AUDIT_ACTUEL.md (items 6-14, minus the already-resolved ReactorSummaryDisplaySource guard clauses): translate every remaining French inline comment and Javadoc to English, with no functional or logic changes: - CNFluids.java: translate the uranium/liquid-nitrogen/thorium fluid effect comments, including the freeze-tick compensation notes. - ClientEvents.java: translate the tick-handling and camera-shake Javadoc/comments, and drop a redundant inline comment duplicating the method doc. - PalettesVariantEntry.java: remove a dead, comment-only `if` block that only held a French note about render-type handling moving elsewhere. - AntiRadiationArmorItem.java: translate the getArmorTexture comment. - ReactorSizeDisplaySource.java: translate the label/gauge comments. - CameraAccessor.java: translate/remove the package and Invoker comments (mixin invoker for Camera#move). - GameRendererMixin.java: translate the sky-darkening and white-flash injection comments. - RadiationHeartMixin.java: translate the Gui.class targeting comment and the renderHeart/heart-texture-swap comments. - IrradiatedBiomes.java: translate the biome color comments (water, fog, sky, grass, foliage). No file in this diff contains any remaining French text. --- .../nuclearteam/createnuclear/CNFluids.java | 14 ++++++------ .../createnuclear/ClientEvents.java | 22 ++++++++----------- .../palettes/PalettesVariantEntry.java | 3 --- .../armor/AntiRadiationArmorItem.java | 2 +- .../source/ReactorSizeDisplaySource.java | 4 ++-- .../foundation/mixin/CameraAccessor.java | 4 ++-- .../foundation/mixin/GameRendererMixin.java | 4 ++-- .../foundation/mixin/RadiationHeartMixin.java | 6 ++--- .../worldgen/biome/IrradiatedBiomes.java | 10 ++++----- 9 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java index a7550e98..abffe7d1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNFluids.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNFluids.java @@ -127,16 +127,16 @@ public static void handleFluidEffect(LivingEvent.LivingTickEvent event) { Level level = entity.level(); - // 1. EFFET DE L'URANIUM (Radiation) + // 1. Uranium: applies radiation contagion if (entity.isInFluidType(URANIUM.getType())) { if (entity.tickCount % 20 == 0) { RadiationCapability.applyContagion(entity, URANIUM_FLUID_DOSE, 100); } } - // 2. EFFET DE L'AZOTE LIQUIDE (Gel type Neige Poudreuse) + // 2. Liquid nitrogen: freezes the entity like powder snow else if (entity.isInFluidType(LIQUID_NITROGEN.getType())) { - // PROBLÈME 1 RÉSOLU : Si l'entité est en feu, on l'éteint immédiatement + // Extinguish fire immediately on contact if (entity.isOnFire()) { entity.clearFire(); } @@ -150,13 +150,13 @@ else if (entity.isInFluidType(LIQUID_NITROGEN.getType())) { int freezeSpeed = 3; if (level.isClientSide) { - // On vise maxTicks + 1 pour que la baisse de -1 du client ramène pile à maxTicks + // Target maxTicks + 1 so vanilla's client-side -1 decay settles exactly at maxTicks entity.setTicksFrozen(Math.min(maxTicks + 1, currentTicks + freezeSpeed + 1)); } else { - // On vise maxTicks + 2 pour que la baisse de -2 du serveur ramène pile à maxTicks + // Target maxTicks + 2 so vanilla's server-side -2 decay settles exactly at maxTicks entity.setTicksFrozen(Math.min(maxTicks + 2, currentTicks + freezeSpeed + 2)); - // PROBLÈME 2 RÉSOLU : On vérifie le gel APRÈS modification ou avec la compensation + // Check the freeze state after applying the compensation above if (entity.getTicksFrozen() >= maxTicks && entity.tickCount % 10 == 0) { entity.hurt(entity.damageSources().freeze(), 2.0F); } @@ -165,7 +165,7 @@ else if (entity.isInFluidType(LIQUID_NITROGEN.getType())) { } } - // 3. EFFET DU THORIUM (Brûlure) + // 3. Thorium: burns the entity like lava else if (entity.isInFluidType(THORIUM.getType())) { entity.lavaHurt(); } diff --git a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java b/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java index 226f2f3a..40b0128c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java @@ -20,50 +20,46 @@ public class ClientEvents { /** - * GESTION DU TICK (LOGIQUE) - * Ce code s'exécute 20 fois par seconde pour faire descendre les compteurs. + * Ticks down the nuke flash/darken timers, once per client tick. */ @SubscribeEvent public static void onClientTick(TickEvent.ClientTickEvent event) { if (event.phase == TickEvent.Phase.END) { - // On enregistre l'ancienne valeur pour l'interpolation fluide (Flash) + // Store the previous value for smooth interpolation of the flash CNClientProxy.prevNukeFlashAmount = CNClientProxy.nukeFlashAmount; - // Gestion du décompte de l'obscurité du ciel + // Count down the sky-darkening timer if (CNClientProxy.renderNukeSkyDarkFor > 0) { CNClientProxy.renderNukeSkyDarkFor--; } - // Gestion de la puissance du Flash blanc + // Ramp the white flash up while active, then fade it back out if (CNClientProxy.renderNukeFlashFor > 0) { if (CNClientProxy.nukeFlashAmount < 1F) { CNClientProxy.nukeFlashAmount = Math.min(CNClientProxy.nukeFlashAmount + 0.4F, 1F); } CNClientProxy.renderNukeFlashFor--; } else if (CNClientProxy.nukeFlashAmount > 0F) { - // Le flash s'estompe progressivement CNClientProxy.nukeFlashAmount = Math.max(CNClientProxy.nukeFlashAmount - 0.05F, 0F); } } } /** - * GESTION DU SCREEN SHAKE (TREMBLEMENT DE CAMÉRA) - * Ce code fait vibrer la vue du joueur pendant l'explosion. + * Shakes the player's camera while a nuke explosion is active. */ @SubscribeEvent public static void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) { Entity player = Minecraft.getInstance().getCameraEntity(); float partialTick = Minecraft.getInstance().getPartialTick(); - // On définit la puissance du tremblement. - // Si le ciel est sombre (nuke active), on fait trembler à 1.5F. + // Shake at 1.5F while the sky is darkened (nuke active), otherwise no shake float tremorAmount = CNClientProxy.renderNukeSkyDarkFor > 0 ? 1.5F : 0F; if (player != null && CNConfigs.client().screenShaking.get()) { if (tremorAmount > 0) { - // On génère des offsets aléatoires pour la vibration + // Generate random offsets for the shake, once per tick if (CNClientProxy.lastTremorTick != player.tickCount) { RandomSource rng = player.level().random; CNClientProxy.randomTremorOffsets[0] = rng.nextFloat(); @@ -72,10 +68,10 @@ public static void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) CNClientProxy.lastTremorTick = player.tickCount; } - // Intensité basée sur les réglages d'accessibilité de Minecraft + // Scale by Minecraft's screen-effect accessibility setting double intensity = tremorAmount * Minecraft.getInstance().options.screenEffectScale().get(); - // On déplace physiquement la caméra + // Physically offset the camera ((CameraAccessor) event.getCamera()).callMove( CNClientProxy.randomTremorOffsets[0] * 0.2F * intensity, CNClientProxy.randomTremorOffsets[1] * 0.2F * intensity, diff --git a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java index 8a4dcaed..2db86abb 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/decoration/palettes/PalettesVariantEntry.java @@ -50,9 +50,6 @@ public PalettesVariantEntry(String name, CNPaletteStoneTypes paletteStoneVariant itemBuilder.tag(paletteStoneVariants.materialTag); - if (pattern.isTranslucent()) { - // Le RenderType est maintenant géré directement dans la génération du modèle json (via PaletteBlockPattern) - } pattern.createCTBehaviour(name) .ifPresent(b -> builder.onRegister(CreateRegistrate.connectedTextures(b))); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java index 72e27518..6b823824 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/equipment/armor/AntiRadiationArmorItem.java @@ -45,7 +45,7 @@ private static Multimap irradiatedArmorAttribute(M return builder.build(); } - // Cette méthode indique au jeu où trouver la texture PNG de l'armure + // Tells the game where to find the armor's PNG texture @Override public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlot slot, String type) { return ClothTagHelper.getArmorTexturePath(stack, "anti_radiation_suit.png"); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSizeDisplaySource.java b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSizeDisplaySource.java index a8e11e87..53bbfca1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSizeDisplaySource.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/redstone/displayLink/source/ReactorSizeDisplaySource.java @@ -20,7 +20,7 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); if (controller == null || controller.isRemoved()) return ZERO.copy(); - // Label + Espace + // Label + trailing space MutableComponent label = CreateNuclearLang.translateDirect("display_source.reactor.size").append(" "); int mode = context.sourceConfig().getInt("display_mode"); @@ -30,7 +30,7 @@ protected MutableComponent provideLine(DisplayLinkContext context, DisplayTarget return label.append(switch (mode) { case 1 -> Component.literal((tier * 100 / 3) + "%").withStyle(ChatFormatting.BLUE); case 2 -> { - // Jauge courte de 3 segments représentant les Tiers + // Short 3-segment gauge representing the tier yield Component.literal("█".repeat(tier) + "▒".repeat(3 - tier)).withStyle(ChatFormatting.BLUE); } default -> { diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java index fddb0e38..e49cb8b8 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.mixin; // Ton package mixin +package net.nuclearteam.createnuclear.foundation.mixin; import net.minecraft.client.Camera; import org.spongepowered.asm.mixin.Mixin; @@ -6,7 +6,7 @@ @Mixin(Camera.class) public interface CameraAccessor { - // L'invoker permet de "débloquer" l'accès à la méthode move + // Exposes the private Camera#move so it can be called from outside the class @Invoker("move") void callMove(double distanceOffset, double verticalOffset, double horizontalOffset); } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java index 0cb33618..51b7751a 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java @@ -14,7 +14,7 @@ public abstract class GameRendererMixin { @Shadow private float darkenWorldAmount; - // Cette partie gère l'assombrissement du ciel/monde lors de l'explosion + // Handles darkening the sky/world during a nuclear explosion @Inject( method = {"Lnet/minecraft/client/renderer/GameRenderer;tick()V"}, remap = true, @@ -26,7 +26,7 @@ public void cn_tick(CallbackInfo ci) { } } - // Cette partie appelle le rendu du flash blanc (preScreenRender) + // Triggers the white flash render (preScreenRender) @Inject( method = {"Lnet/minecraft/client/renderer/GameRenderer;render(FJZ)V"}, remap = true, diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java index 3ee3afcb..f4779a93 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; -// On cible Gui.class car c'est là que se trouve renderHeart +// Gui.class is the target because that's where renderHeart is defined @Mixin(Gui.class) public class RadiationHeartMixin { @@ -18,7 +18,7 @@ public class RadiationHeartMixin { private static final ResourceLocation VANILLA_ICONS = new ResourceLocation("minecraft", "textures/gui/icons.png"); @ModifyArg( - method = "renderHeart", // La méthode singulière qui dessine VRAIMENT le coeur + method = "renderHeart", // The single-heart method that actually draws each heart icon at = @At( value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blit(Lnet/minecraft/resources/ResourceLocation;IIIIII)V" @@ -29,7 +29,7 @@ public class RadiationHeartMixin { if (originalTexture.equals(VANILLA_ICONS)) { Player player = Minecraft.getInstance().player; - // Si le joueur est irradié, on balance votre image ! + // Swap to the radiation heart texture while the player has the radiation effect if (player != null && player.hasEffect(CNEffects.RADIATION.get())) { return RADIATION_ICONS; } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 47fddc13..4a3a99ec 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -23,20 +23,20 @@ public static Biome irradiated(HolderGetter featureGetter, Holder BiomeSpecialEffects.Builder effectBuilder = new BiomeSpecialEffects.Builder(); effectBuilder - // Eau : Verte croupie + // Water: murky green .waterColor(0x3B5133) .waterFogColor(0x0A0E0A) - // BROUILLARD : Vert radioactif maladif (plus vif pour être visible) + // Fog: sickly radioactive green (kept bright so it stays visible) .fogColor(0x485E3E) - // CIEL : Gris-vert délavé (permet de voir le soleil/lune et le cycle jour/nuit) + // Sky: washed-out grey-green (still lets the sun/moon and day-night cycle show through) .skyColor(0x324132) - // HERBE : Jaune "soufre" / Brûlée + // Grass: sulfur yellow / scorched .grassColorOverride(0x8C8F5B) - // FEUILLES : Olive desséché + // Foliage: withered olive .foliageColorOverride(0x565E3E) .ambientParticle(new AmbientParticleSettings(new IrradiatedParticlesData(), 0.025F)) From eeffe4fef9aa3280bdfdc37e9544e1f80dcab01f Mon Sep 17 00:00:00 2001 From: Giovanni Date: Tue, 14 Jul 2026 12:43:06 +0200 Subject: [PATCH 162/171] style: translate remaining French comments in NuclearExplosionEntity and CNEntityType, update audit tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - NuclearExplosionEntity.java: translate the Alex's Caves compat comments (why `alexscaveHandler` is typed as Object, when the compat handler is instantiated, Raycat/Tremorzilla immunity handling) and the vanilla-block destroy-after-explode fix comment, expanding them with more precise explanations rather than a literal translation. - CNEntityType.java: translate the "Utilise le renderer vide par défaut de Minecraft" comment on the mushroom cloud entity's renderer registration, explaining that the particle does the actual rendering. - AUDIT_ACTUEL.md: record commit `9e8abe92` (2026-07-14), which translated the previous 9 remaining French-comment files from §6 (CNFluids, ClientEvents, the three mixins, PalettesVariantEntry, AntiRadiationArmorItem, ReactorSizeDisplaySource, IrradiatedBiomes), dropping the affected file count from 11/292 to 2/292 (~3.8% to ~0.7%); also documents the newly-found CNEntityType.java:76 comment that prior audit passes had missed, and narrows the remaining §6 scope down to NuclearExplosionEntity.java and CNEntityType.java. --- AUDIT_ACTUEL.md | 33 +++++++++---------- .../createnuclear/CNEntityType.java | 2 +- .../explosion/NuclearExplosionEntity.java | 16 ++++----- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index a6b591e4..b6dc43b8 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -26,6 +26,8 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Mise à jour (`e7900959`, 2026-07-13)** : deux items de plus tranchés. (1) `CreateNuclearJEI` : le champ statique mutable `Categories` (§2 mineurs item 5) devient un champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder` — le risque de contamination entre instances lors d'un reload JEI est éliminé ; au passage, `IJeiRuntime` est désormais exposé via `onRuntimeAvailable`. (2) Le `FIXME` de `CNStandardRecipeGen.java:226` (§4/§6/§7) est tranché : retiré, décision actée que les catégories de recette restent des marqueurs plutôt que des sections. Détail en §8.1. +**Mise à jour (`9e8abe92`, 2026-07-14)** : traduction en anglais des 9 des 10 fichiers restants du §6 (items 6, 7, 8, 10, 11, 12, 13, 14, plus l'essentiel de 5 — `CNFluids.java` traduit en intégralité). Seul l'item 9 (`NuclearExplosionEntity.java:45,50`, compat Alex's Caves) reste ouvert, non touché par ce commit. Au passage, un fichier jusque-là non repéré par cet audit a été trouvé avec un commentaire français résiduel : `CNEntityType.java:76`. Détail en §6 et §8.1. + --- ## 1. 🐛 Bugs confirmés ouverts @@ -108,40 +110,35 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Périmètre** : `src/main/java` (292 fichiers), recherche des commentaires/Javadoc non rédigés en anglais et des cas ambigus/incomplets indépendamment de la langue. Méthodologie : recherche par caractères accentués + vocabulaire français typique des commentaires, puis lecture manuelle des occurrences trouvées. -**Décompte global** *(mis à jour 2026-07-12, commit `cc532f83`)* : **11 fichiers sur 292** (~3,8 %) contiennent encore du français détectable, pour environ **22 lignes** de commentaires/Javadoc concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires et Javadoc**, pas à l'API elle-même. +**Décompte global** *(mis à jour 2026-07-14, commit `9e8abe92`)* : **2 fichiers sur 292** (~0,7 %) contiennent encore du français détectable, pour environ **4 lignes** de commentaires concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires**, pas à l'API elle-même. **Résolu** : - Les 4 cas de Javadoc public bilingue, seul sous-item classé 🟢 prioritaire au tour précédent, ont été traduits en intégralité (commit `3be6252a`, *"style: translate French comments and Javadoc to English in VicinityEffect and CNPonderReactorScenes"*) : - `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)` entièrement repassée en anglais. - `infrastructure/ponder/scenes/CNPonderReactorScenes.java` — fichier intégralement traduit : Javadoc de `Positions` (l.32), de `STATIC_POS` (l.50, reformulée en documentation stable plutôt qu'en note à soi-même) et de `positionsFor` (l.85), plus tous les commentaires inline restants (pedestal, exemples T1/T2/T3, fallback, positions devant/derrière/droite). Ce fichier ne contient plus aucun français. - Les 3 commentaires français de garde défensive (« Sécurité Triple-Check ») de `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:51,75,114` (ex-item 9) ont disparu avec le refactor `ReactorSummary` (commit `cc532f83`) : le fichier a été réécrit avec un Javadoc anglais complet sur la classe et chacune de ses méthodes publiques/privées, et ne contient plus aucun français (revérifié par grep accents, 2026-07-12). +- **Les 8 des 9 fichiers restants du tour précédent (`9e8abe92`, 2026-07-14)** : `CNFluids.java` (commentaires uranium/azote liquide/thorium, dont la compensation de désync gel/dégel), `ClientEvents.java` (Javadoc tick handling + tremblement de caméra, reformulés plutôt que simplement traduits), `foundation/mixin/RadiationHeartMixin.java`, `foundation/mixin/CameraAccessor.java`, `foundation/mixin/GameRendererMixin.java`, `content/decoration/palettes/PalettesVariantEntry.java` (le commentaire français hébergeait en fait un bloc `if` mort — supprimé plutôt que traduit), `content/equipment/armor/AntiRadiationArmorItem.java`, `content/redstone/displayLink/source/ReactorSizeDisplaySource.java`, `infrastructure/worldgen/biome/IrradiatedBiomes.java` (5 commentaires de couleurs de biome). Aucun de ces fichiers ne contient plus de français (revérifié par grep accents, 2026-07-14). Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la table de §8.1. -**Cas les plus significatifs restants** : +**Cas restants** : + +*Commentaire sur logique métier non triviale :* +1. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. Seul cas restant touchant une logique non triviale — priorité la plus haute du peu qu'il reste. -*Commentaires sur logique métier non triviale :* -5. `CNFluids.java:139,153,156,159` — bloc de commentaires français documentant une correction fine de désynchronisation client/serveur des ticks de gel/dégel (compensation d'offset). Logique fragile, documentée uniquement en français. -6. `ClientEvents.java:24,60-78` — logique de tremblement de caméra liée à l'explosion nucléaire, entièrement commentée en français, y compris la formule de puissance ; non documentée en anglais du tout. -7. `foundation/mixin/RadiationHeartMixin.java:13,21,32` — mixin overridant le rendu du cœur HUD vanilla, commentaires français expliquant le ciblage. Les mixins sont le code le plus fragile aux montées de version MC/Forge — mérite une documentation claire et bilingue a minima. -8. `foundation/mixin/CameraAccessor.java:9` — accessor mixin, commentaire français isolé sur le pattern « invoker » Mixin. -9. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. -10. `content/decoration/palettes/PalettesVariantEntry.java:54` — commentaire français sur un changement d'architecture de rendu déjà effectué ailleurs, utile pour éviter une régression, en français uniquement. -11. `infrastructure/worldgen/biome/IrradiatedBiomes.java:26-40` — 5 commentaires français sur des choix esthétiques de biome (numéros de ligne re-décalés par `ae1e394d`/`6bc20956`, contenu inchangé) ; mineur. L'item §4 « template non terminé » lui-même est désormais clos (voir §4), seul le décalage de ces commentaires reste à suivre ici. -12. `content/equipment/armor/AntiRadiationArmorItem.java:48` — commentaire français sur `getArmorTexture` (override d'API Forge publique) ; trivial sur le fond, à harmoniser en anglais par cohérence. -13. `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:33` — commentaire français isolé, sur une classe explicitement exclue du refactor de mutualisation `drawGauge` (§8.1) — bon candidat à documenter proprement au prochain passage sur ce fichier. -14. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. +*Commentaire cosmétique trouvé lors de cette mise à jour :* +2. `CNEntityType.java:76` — commentaire français isolé (« Utilise le renderer vide par défaut de Minecraft ») sur l'enregistrement du renderer no-op de l'entité d'explosion ; n'avait jamais été repéré par les tours précédents de cet audit (absent de la liste 5-14 ci-dessus). Trivial, à traduire au prochain passage sur ce fichier. **Ambiguïtés/incomplétudes indépendantes de la langue relevées au passage** : - ~~`CNPonderReactorScenes.java:50,90`~~ — **résolu** (`3be6252a`) : les deux Javadoc ont été reformulées en documentation stable en même temps que leur traduction (voir ci-dessus). - `ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée — ambiguïté fonctionnelle non résolue. - ~~`CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers~~ — **résolu** (`e7900959`, 2026-07-13), voir §4/§8.1. -**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité mais se réduit** : il se concentre désormais sur les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSizeDisplaySource` uniquement désormais), et `CNFluids`/`ClientEvents`. Les scènes Ponder (`CNPonderReactorScenes`) et `ReactorSummaryDisplaySource` sortent de cette liste, assainies respectivement par `3be6252a` et `cc532f83`. Point positif : le sous-ensemble concerné continue de rétrécir (11/292 fichiers désormais, ~3,8 %) — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger, refactor `ReactorSummary`) n'ont pas introduit de nouveau commentaire français. +**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **est désormais quasiment clos** : il ne reste que `NuclearExplosionEntity.java` (logique non triviale) et `CNEntityType.java` (cosmétique, nouvellement trouvé). Tous les mixins, `CNFluids`, `ClientEvents`, le rendu Display Link, les palettes de décoration et le worldgen irradié sont désormais entièrement en anglais. Le sous-ensemble concerné est passé de 11/292 à 2/292 fichiers (~3,8 % → ~0,7 %) en un seul commit (`9e8abe92`) — aucun nouveau commentaire français n'a été introduit entre-temps par les commits fonctionnels (JEI, worldgen, tests). -**Pourquoi ça doit être suivi** : ces commentaires portent presque toujours l'explication du *pourquoi* d'un choix non trivial (compat cross-mod, compensation de désync réseau, garde défensive) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). +**Pourquoi ça doit être suivi** : le dernier cas non trivial restant (`NuclearExplosionEntity.java`) porte l'explication du *pourquoi* d'un choix non trivial (compat cross-mod) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). -**Priorité recommandée** : 🟢 **cosmétique, à faire au fil de l'eau — pas bloquant.** Aucun symbole d'API n'est en français, donc pas d'impact sur la lisibilité des signatures pour un contributeur externe. Les 4 cas de Javadoc public (`VicinityEffect.java` et `CNPonderReactorScenes.java` ×3, seuls vrais cas de Javadoc public bilingue) sont traduits et committés (`3be6252a`). Pas de chantier de traduction dédié à ouvrir pour le reste (~25 lignes restantes) : chaque futur commit touchant l'un des 12 fichiers restants devrait normaliser en anglais les commentaires qu'il modifie. **Suivi** : cet item reste en §6, à re-scanner périodiquement. +**Priorité recommandée** : 🟢 **cosmétique, à faire au fil de l'eau — pas bloquant.** Aucun symbole d'API n'est en français, donc pas d'impact sur la lisibilité des signatures pour un contributeur externe. Les 4 cas de Javadoc public (`VicinityEffect.java` et `CNPonderReactorScenes.java` ×3) et les 9 fichiers de commentaires inline du tour précédent (`3be6252a`, `9e8abe92`) sont traduits et committés. Il ne reste que 2 fichiers, ~4 lignes : `NuclearExplosionEntity.java:45,50` (à traduire en priorité, logique non triviale) et `CNEntityType.java:76` (cosmétique). **Suivi** : cet item reste en §6, à re-scanner périodiquement — proche de la clôture complète. --- @@ -177,7 +174,8 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq **8. Documentation (nouveau, §6)** - ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait**, commit `3be6252a`. - ~~Traduire/documenter en anglais les 3 commentaires de garde défensive de `ReactorSummaryDisplaySource`~~ — **fait**, commit `cc532f83` (Javadoc anglais complet ajouté sur la classe et ses méthodes en même temps que le refactor `ReactorSummary`). -- Reste : les commentaires métier non triviaux listés en §6 (items 5-14, ~22 lignes sur 11 fichiers), au fil des prochains passages sur ces fichiers. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais ce sont typiquement des commentaires qui expliquent un « pourquoi » non trivial (compat, désync réseau) — les laisser en français limite l'audit/onboarding futur. +- ~~Traduire les 9 fichiers de commentaires métier non triviaux listés en §6 (items 5-8, 10-14)~~ — **fait**, commit `9e8abe92`, 2026-07-14 (`CNFluids`, `ClientEvents`, mixins, `PalettesVariantEntry`, `AntiRadiationArmorItem`, `ReactorSizeDisplaySource`, `IrradiatedBiomes`). +- Reste : `content/explosion/NuclearExplosionEntity.java:45,50` (compat Alex's Caves, logique non triviale) et `CNEntityType.java:76` (cosmétique, nouvellement trouvé) — voir §6. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais le premier explique un « pourquoi » non trivial (compat cross-mod) — le laisser en français limite l'audit/onboarding futur. **9. À surveiller sans action immédiate** - `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. @@ -199,6 +197,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| Traduction en anglais de 9 fichiers de commentaires métier non triviaux (§6 items 5-8, 10-14) : `CNFluids.java` (uranium/azote liquide/thorium, compensation désync gel/dégel), `ClientEvents.java` (Javadoc tick + tremblement caméra), `RadiationHeartMixin.java`, `CameraAccessor.java`, `GameRendererMixin.java`, `PalettesVariantEntry.java` (+ suppression d'un bloc `if` mort qui n'hébergeait que le commentaire), `AntiRadiationArmorItem.java`, `ReactorSizeDisplaySource.java`, `IrradiatedBiomes.java` (5 commentaires de couleurs) | `9e8abe92` | 2026-07-14 | Aucun changement de comportement (commentaires/Javadoc uniquement, sauf le bloc `if` mort de `PalettesVariantEntry` qui ne changeait rien à l'exécution). Ramène §6 de 11 à 2 fichiers concernés. Reste ouvert : `NuclearExplosionEntity.java` (non touché par ce commit) et `CNEntityType.java` (nouvellement trouvé, non repéré par les tours précédents). | | `CreateNuclearJEI` : champ statique mutable `Categories` converti en champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder` (nouveau paramètre `targetCategories`) ; exposition d'`IJeiRuntime` via `onRuntimeAvailable` ; retrait du `FIXME` de `CNStandardRecipeGen.java:226` (décision actée : catégories de recette = marqueurs, pas des sections) | `e7900959` | 2026-07-13 | Clôt §2 mineurs item 5, §4/§6/§7 (`CNStandardRecipeGen` FIXME) et §7 item 9 (surveillance `CreateNuclearJEI`). Aucun changement de comportement observable pour le FIXME (retrait de commentaire + décision documentée dans le message de commit) ; pour `CreateNuclearJEI`, chaque instance du plugin a désormais sa propre liste, éliminant le risque de contamination inter-instances en cas de reload JEI. | | Retrait de `addDefaultIrradiatedOres()` (dernier contenu : le carver `NETHER_CAVE`) et de son unique site d'appel dans `IrradiatedBiomes.irradiated()` ; régénération de `irradiated_land.json`/`.cache` (bloc `carvers` désormais vide) | `6bc20956` | 2026-07-13 | **Clôt entièrement** l'item « worldgen irradié » du §4/§7 (`BLUE_ICE`/`VOID_START_PLATFORM` déjà retirés par `ae1e394d` juste avant). Seul point restant sur ce sujet : `CNNoiseGeneratorSettings.java:25` (`STEEL_BLOCK`), sans rapport avec ce commit. | | Retrait des références commentées à `SPEED` dans `ReactorOutput` (`createBlockStateDefinition`, `getStateForPlacement`) ; retrait de `BLUE_ICE` et de `addDefaultSoftDisks()`/`VOID_START_PLATFORM` (+ son unique site d'appel) dans `IrradiatedBiomes` ; suppression de `OriginalBiomeLookup.java` (classe de résolution de biome jamais appelée, non repérée jusqu'ici par cet audit) ; ajout de `@ParametersAreNonnullByDefault` sur `ReactorOutput` et retrait du `@NotNull` désormais redondant sur `getShape()` | `ae1e394d` | 2026-07-13 | Clôt le premier bullet de §4/§7 item 7 (`SPEED`). Entame le second (« worldgen irradié »), achevé juste après par `6bc20956` (ci-dessus). `OriginalBiomeLookup` est un bonus hors-périmètre de l'audit courant (jamais listé en §4). | diff --git a/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java b/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java index 524702ce..1dc3ee45 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNEntityType.java @@ -73,7 +73,7 @@ public class CNEntityType { .setUpdateInterval(1) .setShouldReceiveVelocityUpdates(true) ) - // Utilise le renderer vide par défaut de Minecraft + // Invisible entity: the mushroom cloud particle does the actual rendering .renderer(() -> NoopRenderer::new) .register(); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java index c6ea3416..9ce068b5 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/explosion/NuclearExplosionEntity.java @@ -42,12 +42,13 @@ public class NuclearExplosionEntity extends Entity { private Explosion dummyExplosion; - // Changé en Object pour éviter le crash ClassNotFound si Alex's Caves n'est pas installé + // Typed as Object (not AlexscaveCompat) so this field can exist even when Alex's Caves + // isn't installed and its classes are unavailable on the classpath private Object alexscaveHandler; public NuclearExplosionEntity(EntityType entityType, Level level) { super(entityType, level); - // On instancie la compatibilité SEULEMENT si le mod est présent + // Only instantiate the compat handler when the addon is actually loaded if (Mods.ALEXS_CAVE.isLoaded()) { this.alexscaveHandler = new AlexscaveCompat(); } @@ -112,9 +113,8 @@ public void tick() { float playerFling = entity instanceof Player ? 0.5F * flingStrength : flingStrength; if (damage > 0) { - // Gestion Raycat (Avec accolades obligatoires) + // Raycat (Alex's Caves) is immune to the explosion if (Mods.ALEXS_CAVE.isLoaded() && alexscaveHandler != null) { - // isRaycat doit retourner un boolean dans votre Compat if (((AlexscaveCompat) alexscaveHandler).isRaycat(entity)) { damage = 0; } @@ -124,9 +124,8 @@ public void tick() { damage *= 0.25F; playerFling *= 0.1F; - // Gestion Tremorzilla + // Tremorzilla (Alex's Caves) is fully immune, on top of the irradiated-immune reduction above if (Mods.ALEXS_CAVE.isLoaded() && alexscaveHandler != null) { - // isTremorzilla doit retourner un boolean dans votre Compat if (((AlexscaveCompat) alexscaveHandler).isTremorzilla(entity)) { CreateNuclear.LOGGER.warn("Entity explosion compatibility with Alex's Cave"); damage = 0; @@ -224,10 +223,9 @@ private void removeChunk(int radius) { // 2. Call the explosion behavior state.onBlockExploded(level(), immutablePos, dummyExplosion); - // 3. FIX: If the block is still there (vanilla blocks like Stone/Dirt), force removal + // 3. onBlockExploded() doesn't remove plain vanilla blocks (e.g. stone/dirt) by + // itself, so force removal here and let items drop normally if (level().getBlockState(immutablePos).is(state.getBlock())) { - // false = do not drop standard mining items, let the explosion logic handle drops if needed - // or set to true if you want items to drop like before level().destroyBlock(immutablePos, true); } } From c3179febf6d191307834fff70140b9a5432caf2a Mon Sep 17 00:00:00 2001 From: Giovanni Date: Tue, 14 Jul 2026 12:47:44 +0200 Subject: [PATCH 163/171] =?UTF-8?q?docs:=20update=20AUDIT=5FACTUEL.md=20to?= =?UTF-8?q?=20record=20=C2=A76=20closure=20and=20ReactorOutput.SPEED=20cro?= =?UTF-8?q?ss-reference=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-14 update for commit `eeffe4fe`, translating the last 2 remaining French-comment files (NuclearExplosionEntity.java, CNEntityType.java) and confirming via a full src/main/java grep that §6 (French comments/Javadoc) is now entirely closed, 0/292 files. - §6: rewrite the section to reflect full closure — replace the "Résolu"/"Cas restants" split with a single chronological "Historique de la résolution" list covering all four translation commits (`3be6252a`, `cc532f83`, `9e8abe92`, `eeffe4fe`), update the global count to 0/292 files, mark the ReactorOutput.SPEED ambiguity note as resolved (cross-referencing the earlier `ae1e394d` fix that this section had not yet reflected), and rewrite the "pattern récurrent" and "priorité recommandée" paragraphs to state the item is closed. - §7 (item 8 "Documentation"): mark the last remaining translation bullet (NuclearExplosionEntity.java/CNEntityType.java) as done, with a note that §6 is now fully closed at 0/292 files. - §8.1: add a changelog row documenting `eeffe4fe` (Alex's Caves compat comment translation plus a correction to a stale English comment about destroyBlock's drop-items parameter, and the CNEntityType.java renderer comment), noting no behavioral change and full §6 closure. --- AUDIT_ACTUEL.md | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index b6dc43b8..f2af64ba 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -28,6 +28,8 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Mise à jour (`9e8abe92`, 2026-07-14)** : traduction en anglais des 9 des 10 fichiers restants du §6 (items 6, 7, 8, 10, 11, 12, 13, 14, plus l'essentiel de 5 — `CNFluids.java` traduit en intégralité). Seul l'item 9 (`NuclearExplosionEntity.java:45,50`, compat Alex's Caves) reste ouvert, non touché par ce commit. Au passage, un fichier jusque-là non repéré par cet audit a été trouvé avec un commentaire français résiduel : `CNEntityType.java:76`. Détail en §6 et §8.1. +**Mise à jour (`eeffe4fe`, 2026-07-14)** : les 2 derniers fichiers du §6 sont traduits — `NuclearExplosionEntity.java` (commentaires de compat Alex's Caves : typage `Object` du handler, instanciation conditionnelle, immunité Raycat/Tremorzilla, et clarification du commentaire déjà anglais mais devenu incohérent sur `destroyBlock`) et `CNEntityType.java` (commentaire sur le renderer no-op de l'entité d'explosion, reformulé pour expliquer que c'est la particule qui fait le rendu visuel). **Confirmé par grep sur tout `src/main/java` (292 fichiers) : plus aucun caractère accentué français, §6 est intégralement clos.** Détail en §6 et §8.1. + --- ## 1. 🐛 Bugs confirmés ouverts @@ -110,35 +112,26 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Périmètre** : `src/main/java` (292 fichiers), recherche des commentaires/Javadoc non rédigés en anglais et des cas ambigus/incomplets indépendamment de la langue. Méthodologie : recherche par caractères accentués + vocabulaire français typique des commentaires, puis lecture manuelle des occurrences trouvées. -**Décompte global** *(mis à jour 2026-07-14, commit `9e8abe92`)* : **2 fichiers sur 292** (~0,7 %) contiennent encore du français détectable, pour environ **4 lignes** de commentaires concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires**, pas à l'API elle-même. +**Décompte global** *(mis à jour 2026-07-14, commit `eeffe4fe`)* : **0 fichier sur 292** ne contient plus de français détectable. **Item entièrement clos** — confirmé par grep sur caractères accentués français, sur tout `src/main/java`, 2026-07-14 : zéro résultat. Aucun symbole de code (nom de classe, méthode, champ) n'avait de toute façon jamais été trouvé en français — le problème était localisé aux commentaires/Javadoc, désormais traités. -**Résolu** : +**Historique de la résolution** (du plus ancien au plus récent) : - Les 4 cas de Javadoc public bilingue, seul sous-item classé 🟢 prioritaire au tour précédent, ont été traduits en intégralité (commit `3be6252a`, *"style: translate French comments and Javadoc to English in VicinityEffect and CNPonderReactorScenes"*) : - `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)` entièrement repassée en anglais. - `infrastructure/ponder/scenes/CNPonderReactorScenes.java` — fichier intégralement traduit : Javadoc de `Positions` (l.32), de `STATIC_POS` (l.50, reformulée en documentation stable plutôt qu'en note à soi-même) et de `positionsFor` (l.85), plus tous les commentaires inline restants (pedestal, exemples T1/T2/T3, fallback, positions devant/derrière/droite). Ce fichier ne contient plus aucun français. -- Les 3 commentaires français de garde défensive (« Sécurité Triple-Check ») de `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:51,75,114` (ex-item 9) ont disparu avec le refactor `ReactorSummary` (commit `cc532f83`) : le fichier a été réécrit avec un Javadoc anglais complet sur la classe et chacune de ses méthodes publiques/privées, et ne contient plus aucun français (revérifié par grep accents, 2026-07-12). -- **Les 8 des 9 fichiers restants du tour précédent (`9e8abe92`, 2026-07-14)** : `CNFluids.java` (commentaires uranium/azote liquide/thorium, dont la compensation de désync gel/dégel), `ClientEvents.java` (Javadoc tick handling + tremblement de caméra, reformulés plutôt que simplement traduits), `foundation/mixin/RadiationHeartMixin.java`, `foundation/mixin/CameraAccessor.java`, `foundation/mixin/GameRendererMixin.java`, `content/decoration/palettes/PalettesVariantEntry.java` (le commentaire français hébergeait en fait un bloc `if` mort — supprimé plutôt que traduit), `content/equipment/armor/AntiRadiationArmorItem.java`, `content/redstone/displayLink/source/ReactorSizeDisplaySource.java`, `infrastructure/worldgen/biome/IrradiatedBiomes.java` (5 commentaires de couleurs de biome). Aucun de ces fichiers ne contient plus de français (revérifié par grep accents, 2026-07-14). - -Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la table de §8.1. - -**Cas restants** : +- Les 3 commentaires français de garde défensive (« Sécurité Triple-Check ») de `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:51,75,114` (ex-item 9) ont disparu avec le refactor `ReactorSummary` (commit `cc532f83`) : le fichier a été réécrit avec un Javadoc anglais complet sur la classe et chacune de ses méthodes publiques/privées, et ne contient plus aucun français. +- **9 fichiers traduits par `9e8abe92` (2026-07-14)** : `CNFluids.java` (commentaires uranium/azote liquide/thorium, dont la compensation de désync gel/dégel), `ClientEvents.java` (Javadoc tick handling + tremblement de caméra, reformulés plutôt que simplement traduits), `foundation/mixin/RadiationHeartMixin.java`, `foundation/mixin/CameraAccessor.java`, `foundation/mixin/GameRendererMixin.java`, `content/decoration/palettes/PalettesVariantEntry.java` (le commentaire français hébergeait en fait un bloc `if` mort — supprimé plutôt que traduit), `content/equipment/armor/AntiRadiationArmorItem.java`, `content/redstone/displayLink/source/ReactorSizeDisplaySource.java`, `infrastructure/worldgen/biome/IrradiatedBiomes.java` (5 commentaires de couleurs de biome). +- **Les 2 derniers fichiers traduits par `eeffe4fe` (2026-07-14)** : `content/explosion/NuclearExplosionEntity.java` (compat Alex's Caves — typage `Object` du handler pour éviter une dépendance dure au classpath du mod, instanciation conditionnelle, immunité Raycat/Tremorzilla ; au passage, un commentaire déjà en anglais mais devenu incohérent — décrivait un paramètre `false` alors que le code appelait `destroyBlock(pos, true)` — a été réécrit pour décrire fidèlement le comportement actuel) et `CNEntityType.java:76` (commentaire sur le renderer no-op de l'entité d'explosion, reformulé pour expliquer que c'est la particule de champignon atomique qui fait le rendu visuel, pas le renderer). -*Commentaire sur logique métier non triviale :* -1. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. Seul cas restant touchant une logique non triviale — priorité la plus haute du peu qu'il reste. - -*Commentaire cosmétique trouvé lors de cette mise à jour :* -2. `CNEntityType.java:76` — commentaire français isolé (« Utilise le renderer vide par défaut de Minecraft ») sur l'enregistrement du renderer no-op de l'entité d'explosion ; n'avait jamais été repéré par les tours précédents de cet audit (absent de la liste 5-14 ci-dessus). Trivial, à traduire au prochain passage sur ce fichier. +Tous ces fichiers sont déplacés dans la table de §8.1. **Ambiguïtés/incomplétudes indépendantes de la langue relevées au passage** : - ~~`CNPonderReactorScenes.java:50,90`~~ — **résolu** (`3be6252a`) : les deux Javadoc ont été reformulées en documentation stable en même temps que leur traduction (voir ci-dessus). -- `ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée — ambiguïté fonctionnelle non résolue. +- ~~`ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée~~ — **résolu** (`ae1e394d`, 2026-07-13) : les références commentées ont été retirées (revérifié par grep, plus aucune trace de `SPEED` dans le fichier), voir §4/§8.1. - ~~`CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers~~ — **résolu** (`e7900959`, 2026-07-13), voir §4/§8.1. -**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **est désormais quasiment clos** : il ne reste que `NuclearExplosionEntity.java` (logique non triviale) et `CNEntityType.java` (cosmétique, nouvellement trouvé). Tous les mixins, `CNFluids`, `ClientEvents`, le rendu Display Link, les palettes de décoration et le worldgen irradié sont désormais entièrement en anglais. Le sous-ensemble concerné est passé de 11/292 à 2/292 fichiers (~3,8 % → ~0,7 %) en un seul commit (`9e8abe92`) — aucun nouveau commentaire français n'a été introduit entre-temps par les commits fonctionnels (JEI, worldgen, tests). - -**Pourquoi ça doit être suivi** : le dernier cas non trivial restant (`NuclearExplosionEntity.java`) porte l'explication du *pourquoi* d'un choix non trivial (compat cross-mod) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). +**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **est désormais entièrement clos** — plus aucun fichier de `src/main/java` ne contient de français. Le sous-ensemble concerné est passé de 14 fichiers (premier décompte de ce document) à 0, en plusieurs vagues (`3be6252a`, `cc532f83`, `9e8abe92`, `eeffe4fe`). -**Priorité recommandée** : 🟢 **cosmétique, à faire au fil de l'eau — pas bloquant.** Aucun symbole d'API n'est en français, donc pas d'impact sur la lisibilité des signatures pour un contributeur externe. Les 4 cas de Javadoc public (`VicinityEffect.java` et `CNPonderReactorScenes.java` ×3) et les 9 fichiers de commentaires inline du tour précédent (`3be6252a`, `9e8abe92`) sont traduits et committés. Il ne reste que 2 fichiers, ~4 lignes : `NuclearExplosionEntity.java:45,50` (à traduire en priorité, logique non triviale) et `CNEntityType.java:76` (cosmétique). **Suivi** : cet item reste en §6, à re-scanner périodiquement — proche de la clôture complète. +**Priorité recommandée** : ✅ **clos.** Aucun symbole d'API n'a jamais été en français, donc aucun impact sur la lisibilité des signatures n'a jamais existé pour un contributeur externe. **Suivi** : à re-scanner ponctuellement (grep accents sur `src/main/java`) si un doute apparaît sur un futur commit, mais aucune action de fond restante. --- @@ -175,7 +168,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq - ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait**, commit `3be6252a`. - ~~Traduire/documenter en anglais les 3 commentaires de garde défensive de `ReactorSummaryDisplaySource`~~ — **fait**, commit `cc532f83` (Javadoc anglais complet ajouté sur la classe et ses méthodes en même temps que le refactor `ReactorSummary`). - ~~Traduire les 9 fichiers de commentaires métier non triviaux listés en §6 (items 5-8, 10-14)~~ — **fait**, commit `9e8abe92`, 2026-07-14 (`CNFluids`, `ClientEvents`, mixins, `PalettesVariantEntry`, `AntiRadiationArmorItem`, `ReactorSizeDisplaySource`, `IrradiatedBiomes`). -- Reste : `content/explosion/NuclearExplosionEntity.java:45,50` (compat Alex's Caves, logique non triviale) et `CNEntityType.java:76` (cosmétique, nouvellement trouvé) — voir §6. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais le premier explique un « pourquoi » non trivial (compat cross-mod) — le laisser en français limite l'audit/onboarding futur. +- ~~Traduire les 2 derniers fichiers restants (`NuclearExplosionEntity.java`, `CNEntityType.java`)~~ — **fait**, commit `eeffe4fe`, 2026-07-14. **§6 est désormais entièrement clos, 0/292 fichier concerné.** **9. À surveiller sans action immédiate** - `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. @@ -197,6 +190,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| Traduction en anglais des 2 derniers fichiers du §6 : `NuclearExplosionEntity.java` (compat Alex's Caves — typage `Object`, instanciation conditionnelle, immunité Raycat/Tremorzilla ; correction au passage d'un commentaire anglais devenu incohérent sur `destroyBlock`) et `CNEntityType.java:76` (renderer no-op de l'entité d'explosion) | `eeffe4fe` | 2026-07-14 | Aucun changement de comportement dans `CNEntityType.java` (commentaire seul) ; dans `NuclearExplosionEntity.java`, seuls les commentaires ont changé, sauf le petit ajustement de formulation autour de `destroyBlock` qui ne touche pas le code exécuté. **Clôt entièrement §6** : grep sur caractères accentués français, tout `src/main/java` (292 fichiers), zéro résultat. | | Traduction en anglais de 9 fichiers de commentaires métier non triviaux (§6 items 5-8, 10-14) : `CNFluids.java` (uranium/azote liquide/thorium, compensation désync gel/dégel), `ClientEvents.java` (Javadoc tick + tremblement caméra), `RadiationHeartMixin.java`, `CameraAccessor.java`, `GameRendererMixin.java`, `PalettesVariantEntry.java` (+ suppression d'un bloc `if` mort qui n'hébergeait que le commentaire), `AntiRadiationArmorItem.java`, `ReactorSizeDisplaySource.java`, `IrradiatedBiomes.java` (5 commentaires de couleurs) | `9e8abe92` | 2026-07-14 | Aucun changement de comportement (commentaires/Javadoc uniquement, sauf le bloc `if` mort de `PalettesVariantEntry` qui ne changeait rien à l'exécution). Ramène §6 de 11 à 2 fichiers concernés. Reste ouvert : `NuclearExplosionEntity.java` (non touché par ce commit) et `CNEntityType.java` (nouvellement trouvé, non repéré par les tours précédents). | | `CreateNuclearJEI` : champ statique mutable `Categories` converti en champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder` (nouveau paramètre `targetCategories`) ; exposition d'`IJeiRuntime` via `onRuntimeAvailable` ; retrait du `FIXME` de `CNStandardRecipeGen.java:226` (décision actée : catégories de recette = marqueurs, pas des sections) | `e7900959` | 2026-07-13 | Clôt §2 mineurs item 5, §4/§6/§7 (`CNStandardRecipeGen` FIXME) et §7 item 9 (surveillance `CreateNuclearJEI`). Aucun changement de comportement observable pour le FIXME (retrait de commentaire + décision documentée dans le message de commit) ; pour `CreateNuclearJEI`, chaque instance du plugin a désormais sa propre liste, éliminant le risque de contamination inter-instances en cas de reload JEI. | | Retrait de `addDefaultIrradiatedOres()` (dernier contenu : le carver `NETHER_CAVE`) et de son unique site d'appel dans `IrradiatedBiomes.irradiated()` ; régénération de `irradiated_land.json`/`.cache` (bloc `carvers` désormais vide) | `6bc20956` | 2026-07-13 | **Clôt entièrement** l'item « worldgen irradié » du §4/§7 (`BLUE_ICE`/`VOID_START_PLATFORM` déjà retirés par `ae1e394d` juste avant). Seul point restant sur ce sujet : `CNNoiseGeneratorSettings.java:25` (`STEEL_BLOCK`), sans rapport avec ce commit. | From 2ac837fd1cc8baf99b7941aef67b3bb45dbe3b8f Mon Sep 17 00:00:00 2001 From: Giovanni Date: Tue, 14 Jul 2026 13:52:36 +0200 Subject: [PATCH 164/171] =?UTF-8?q?docs:=20close=20AUDIT=5FACTUEL.md=20?= =?UTF-8?q?=C2=A72.4/=C2=A77=20heat-display=20"inconsistency"=20as=20a=20r?= =?UTF-8?q?efuted=20false=20positive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-14 documentation-only update noting that the ReactorSummaryDisplaySource.formatValue "heat display mode inconsistency" item (§2.4/§7 priority 5) is refuted and closed after deeper analysis, not fixed by code. - §2 (item 4): mark the item as refuted/closed with a strikethrough, pointing to the new §8.2 write-up instead of describing it as an open, unchanged inconsistency. - §5 (design/UX improvements): mark the corresponding recommendation as refuted/closed without code, same cross-reference. - §8.2: add a detailed rebuttal explaining that forcing a gauge for `heat` in normal mode (gaugeOnNormal=true) isn't an isolated exception — formatFluid does the same for `fluid` — so the summary widget consistently gauges its two most glance-critical stats while keeping fuel/cooler as text; HeatDisplaySource is a single-line, single-stat widget with different space constraints, so there was never an implicit rule that the two widgets' default modes should match. Also documents why a shared ReactorDisplayFormatting utility was considered and rejected: the three existing mode->render mappings have different semantics (3 vs 4 modes, per-stat gaugeOnNormal flag, optional unit suffix), so unifying them would cost more than the purely cosmetic inconsistency it would fix. --- AUDIT_ACTUEL.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f2af64ba..d9946143 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -28,6 +28,8 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Mise à jour (`9e8abe92`, 2026-07-14)** : traduction en anglais des 9 des 10 fichiers restants du §6 (items 6, 7, 8, 10, 11, 12, 13, 14, plus l'essentiel de 5 — `CNFluids.java` traduit en intégralité). Seul l'item 9 (`NuclearExplosionEntity.java:45,50`, compat Alex's Caves) reste ouvert, non touché par ce commit. Au passage, un fichier jusque-là non repéré par cet audit a été trouvé avec un commentaire français résiduel : `CNEntityType.java:76`. Détail en §6 et §8.1. +**Mise à jour (2026-07-14, pas de commit — décision documentaire seule)** : le point §2.4/§7 priorité 5 (« harmoniser le mode d'affichage du heat de `ReactorSummaryDisplaySource` avec `HeatDisplaySource` ») est **réfuté et clos** après analyse approfondie — ce n'est pas une incohérence mais un choix de design volontaire du widget de synthèse (`fluid` et `heat` en jauge par défaut car plus lisibles en vue d'ensemble, `fuel`/`cooler` en texte), sans rapport avec le mode par défaut de l'affichage individuel `HeatDisplaySource`. Détail complet en §8.2. + **Mise à jour (`eeffe4fe`, 2026-07-14)** : les 2 derniers fichiers du §6 sont traduits — `NuclearExplosionEntity.java` (commentaires de compat Alex's Caves : typage `Object` du handler, instanciation conditionnelle, immunité Raycat/Tremorzilla, et clarification du commentaire déjà anglais mais devenu incohérent sur `destroyBlock`) et `CNEntityType.java` (commentaire sur le renderer no-op de l'entité d'explosion, reformulé pour expliquer que c'est la particule qui fait le rendu visuel). **Confirmé par grep sur tout `src/main/java` (292 fichiers) : plus aucun caractère accentué français, §6 est intégralement clos.** Détail en §6 et §8.1. --- @@ -58,8 +60,7 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod 3. ~~`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles~~ — **résolu**, voir §8.1 (`cc532f83`). -4. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** *(inchangé)* - `HeatDisplaySource` affiche `"500 °C"` en mode normal alors que `ReactorSummaryDisplaySource` force une jauge pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle toujours présente. +4. ~~`ReactorSummaryDisplaySource.formatValue` — incohérence de mode~~ — **réfuté, clos sans code** (2026-07-14) : voir §8.2. ### 🟡 Mineurs @@ -152,7 +153,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq - Flicker de vitesse de sortie : valider en jeu que le seuil d'hystérésis (`RPM_DIVIDER/2`, déjà implémenté par `a18038db`) supprime bien la perception du flicker en fin de ressources (§1). **Justification** : le code est déjà en place, il ne reste qu'une validation de gameplay — priorité basse en effort mais à ne pas oublier, sinon le point restera indéfiniment « à moitié fait » dans la mémoire du projet. **5. Amélioration de conception / cohérence UX** -- `ReactorSummaryDisplaySource.formatValue` : harmoniser le mode d'affichage du heat avec `HeatDisplaySource` (§2.4). **Justification** : incohérence visible par le joueur, mais purement cosmétique, aucun risque fonctionnel. +- ~~`ReactorSummaryDisplaySource.formatValue` : harmoniser le mode d'affichage du heat avec `HeatDisplaySource`~~ — **réfuté, clos sans code** (2026-07-14) : voir §8.2. - ~~`ReactorSummaryDisplaySource` : remplacer l'accès positionnel fragile~~ — **fait**, voir §8.1 (`cc532f83`). **6. Optimisation mineure (gain faible, risque nul)** @@ -228,6 +229,7 @@ Ces affirmations historiques ont été vérifiées comme **fausses ou déjà clo - **God class `ReactorControllerBlockEntity`** — ✅ chantier clos, croissance maîtrisée : **533 lignes** (886 dans `AUDIT_V1.md`, 492 puis 529 aux tours intermédiaires), délégation à 34 fichiers de support (`service/` 14, `manager/` 12, `consumable/` 6, `display/` 2). *Pas de hash unique — résultat cumulatif de dizaines de commits d'extraction progressive vers `manager/service/consumable`, non attribuable avec certitude à un commit isolé.* - **Coordinateur de verrou fluide dédié** — ✅ toujours non justifié : `PersistentFluidLocks` reste le seul système ; pas de `FluidLockManager` concurrent retrouvé (celui décrit en `AUDIT_V1.md` B14 a disparu, hash non déterminé — voir §8.4). `clearLockIfAllInputsEmpty` utilise `getFuildHandlers(level)` (pas de scan 3D), double itération mineure sans gravité. - **`clearLockIfAllInputsEmpty` : pas de scan cubique O(n³)** — ✅ acceptable, confirmé sain. +- **`ReactorSummaryDisplaySource.formatValue` — "incohérence" de mode d'affichage du heat vs `HeatDisplaySource`** — ❌ réfuté, ce n'est pas un bug : c'est un choix de design volontaire du widget de synthèse, mal formulé par l'audit initial. Analyse détaillée : `formatValue` force une jauge en mode "normal" pour `heat` (`gaugeOnNormal=true`), mais `formatFluid` (`ReactorSummaryDisplaySource.java:203-207`) fait exactement la même chose pour `fluid` (`mode == 0 || mode == 3` → jauge) — ce n'est donc pas une exception isolée sur `heat`, mais un pattern cohérent et répété : les deux stats les plus critiques à lire d'un coup d'œil dans une vue de synthèse (`fluid`, `heat`) sont en jauge par défaut, `fuel`/`cooler` restent en texte. `HeatDisplaySource`, à l'inverse, est un affichage individuel une-ligne où la jauge occuperait toute la largeur disponible pour une seule information — un défaut texte y est tout aussi légitime. Les deux widgets ont des contraintes d'espace et des objectifs différents ; il n'y a jamais eu de règle implicite selon laquelle un mode par défaut devait être identique entre les deux. **Pas de hash applicable** — aucun changement de code, décision de clôture actée après clarification du comportement voulu. Écarté aussi : la création d'une classe utilitaire `ReactorDisplayFormatting` pour mutualiser les 3 mappings mode→rendu existants (`AbstractReactorStatDisplaySource.provideLine`, `ReactorSummaryDisplaySource.formatValue`, `ReactorSummaryDisplaySource.formatFluid`) — ces 3 mappings ont des sémantiques différentes (3 modes vs 4 modes, flag `gaugeOnNormal` par stat, suffixe d'unité optionnel), donc les unifier demanderait un enum de mode partagé mal aligné entre appelants (le type même de fragilité par index déjà corrigée en `cc532f83`) ou une fonction à autant de paramètres que de sources de divergence — coût supérieur au gain pour un point cosmétique sans risque fonctionnel. ### 8.3 Décisions produit exécutées From 1497c56ffad74c5b65a4c4de6101ef272974f5fd Mon Sep 17 00:00:00 2001 From: Giovanni Date: Tue, 14 Jul 2026 17:40:43 +0200 Subject: [PATCH 165/171] =?UTF-8?q?docs:=20close=20AUDIT=5FACTUEL.md=20?= =?UTF-8?q?=C2=A73/=C2=A77=20non-player=20radiation=20dirty-check=20item?= =?UTF-8?q?=20as=20confirmed=20status=20quo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §0: add a 2026-07-14 documentation-only update confirming the §3/§7 item 9 status quo — RadiationCapability.tickRadiation's lack of an inventory dirty-check for non-player LivingEntity is analyzed in depth and kept as-is, since the mob scan (6 slots, O(1) HashMap lookups via RadiationRegistry) is too small for a player-style hash (41 slots) to pay off, and the rest of tickRadiation likely dominates per-mob cost anyway. - §3 table: rewrite the RadiationCapability.tickRadiation row from "point à surveiller" to "statu quo recommandé", summarizing why hashing 6 slots wouldn't be cheaper than the direct computation it would replace, and that event-driven invalidation (LivingEquipmentChangeEvent) — not a hash — would be the only approach worth revisiting if profiling ever flags this loop as hot. - §7 (item 9 "à surveiller"): update the watch-item description with the same summary and §8.2 cross-reference. - §8.2: add a detailed rebuttal with code references (RadiationCapability.java, RadiationRegistry.java) covering: the 41-vs-6-slot asymmetry, why hashing wouldn't be cost-effective at mob scale, why the rest of tickRadiation likely dominates the per-mob cost regardless, the event-driven invalidation fallback if profiling ever justifies it, and a clarification that computeItemRadiation(Player) intentionally excludes player armor since no armor item in this mod is a radiation source (only resistance equipment). --- AUDIT_ACTUEL.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index d9946143..f3df8031 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -30,6 +30,8 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod **Mise à jour (2026-07-14, pas de commit — décision documentaire seule)** : le point §2.4/§7 priorité 5 (« harmoniser le mode d'affichage du heat de `ReactorSummaryDisplaySource` avec `HeatDisplaySource` ») est **réfuté et clos** après analyse approfondie — ce n'est pas une incohérence mais un choix de design volontaire du widget de synthèse (`fluid` et `heat` en jauge par défaut car plus lisibles en vue d'ensemble, `fuel`/`cooler` en texte), sans rapport avec le mode par défaut de l'affichage individuel `HeatDisplaySource`. Détail complet en §8.2. +**Mise à jour (2026-07-14, pas de commit — décision documentaire seule)** : le point §3/§7 item 9 (« `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire ») est **analysé en détail et le statu quo est confirmé** — le scan mob (6 slots, lookups `HashMap` O(1) via `RadiationRegistry`) est trop petit pour qu'un hash façon joueur (41 slots) soit rentable ; le reste de `tickRadiation` (biome, attribut, `MobEffectInstance`) domine probablement le coût par mob de toute façon. Détail complet en §8.2. + **Mise à jour (`eeffe4fe`, 2026-07-14)** : les 2 derniers fichiers du §6 sont traduits — `NuclearExplosionEntity.java` (commentaires de compat Alex's Caves : typage `Object` du handler, instanciation conditionnelle, immunité Raycat/Tremorzilla, et clarification du commentaire déjà anglais mais devenu incohérent sur `destroyBlock`) et `CNEntityType.java` (commentaire sur le renderer no-op de l'entité d'explosion, reformulé pour expliquer que c'est la particule qui fait le rendu visuel). **Confirmé par grep sur tout `src/main/java` (292 fichiers) : plus aucun caractère accentué français, §6 est intégralement clos.** Détail en §6 et §8.1. --- @@ -75,7 +77,7 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod |---|---| | **`src/test`** | ❌ **Toujours vide** — confirmé, 0 fichier `.java` sous `src/test`. Sans objet ici : les types Minecraft/Forge (`Item`, `ItemStack`, `Level`, registres du mod) ne s'initialisent pas hors d'un jeu démarré (confirmé empiriquement en tentant de les mocker via Mockito, voir §0/§8.1), donc la couverture de ce projet passe nécessairement par `GameTest`, pas par du JUnit isolé sous `src/test`. | | **Couverture `GameTest` (`src/main/java/.../gametest/`)** | 🟡 **Partielle, 2 composants sur 4 couverts** — `ReactorInputFluidManager` (`200df62f`) et `DefaultHeatCalculator.computeHeat` (`498f9dc6`, 3 cas : fuel isolé, cooler isolé, asymétrie de voisinage fuel/cooler documentée en §2.2) ont une suite dédiée. Le pattern matcher (`ReactorPattern`/`CNMultiblock`, §2.1) et `PersistentFluidLocks` (§8.2) restent **entièrement sans test** — ce sont les deux items restants de la priorité 1 du §7. | -| **`RadiationCapability.tickRadiation` pour `LivingEntity` non-joueurs** | ⚠️ **Point à surveiller, pas un bug** — recalcule `computeItemRadiation` à chaque tick sans dirty-check (le hash d'inventaire existant, `InventoryHashUtil`, ne couvre que le joueur). Compromis assumé explicitement dans le commit `9ded502c` (« no equivalent inventory to diff against ») — à reconsidérer seulement si la densité de mobs équipés en zone irradiée augmente et qu'un problème de perf est mesuré. | +| **`RadiationCapability.tickRadiation` pour `LivingEntity` non-joueurs** | ⚠️ **Statu quo recommandé, pas un bug** — recalcule `computeItemRadiation` à chaque tick sans dirty-check (le hash d'inventaire existant, `InventoryHashUtil`, ne couvre que le joueur). Compromis assumé explicitement dans le commit `9ded502c` (« no equivalent inventory to diff against »), et **réévalué en détail le 2026-07-14 sans changement de code** — analyse complète en §8.2. Résumé : le scan mob ne porte que sur 6 stacks (`getArmorSlots()` + main + offhand), résolus par de simples lookups `HashMap` dans `RadiationRegistry`, contre 41 slots hashés côté joueur ; recalculer un hash sur seulement 6 slots coûterait à peu près autant que le calcul direct qu'il est censé éviter, donc reproduire la technique du joueur n'apporterait aucun gain net. Le reste de `tickRadiation` (résolution de biome, lecture d'attribut, gestion de `MobEffectInstance`) s'exécute de toute façon inconditionnellement à chaque tick pour chaque `LivingEntity`, dirty-check ou non — cette boucle de 6 lookups n'est donc probablement pas le poste dominant du coût par mob. À reconsidérer **uniquement** si un profiling réel identifie cette boucle comme point chaud (ex. `IRadiationSource` tiers coûteux, ou densité extrême de mobs équipés) — dans ce cas la piste recommandée n'est pas un hash mais une invalidation événementielle (`LivingEquipmentChangeEvent`), seule approche qui changerait réellement l'ordre de grandeur du coût amorti. | *(Les autres affirmations historiques de cette table — inversion `api/`, deux frameworks multiblock concurrents, god class `ReactorControllerBlockEntity`, coordinateur de verrou fluide dédié — ont toutes été réfutées ou closes ; voir §8.2.)* @@ -172,7 +174,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq - ~~Traduire les 2 derniers fichiers restants (`NuclearExplosionEntity.java`, `CNEntityType.java`)~~ — **fait**, commit `eeffe4fe`, 2026-07-14. **§6 est désormais entièrement clos, 0/292 fichier concerné.** **9. À surveiller sans action immédiate** -- `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. +- `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3, analyse détaillée en §8.2). Statu quo recommandé — le scan mob (6 slots, lookups `HashMap` O(1)) est trop petit pour qu'un hash façon joueur (41 slots) soit rentable ; à reconsidérer seulement si un profiling mesure cette boucle comme point chaud, auquel cas privilégier une invalidation événementielle (`LivingEquipmentChangeEvent`) plutôt qu'un hash. - `ReactorOutput`/`ReactorFluidInput` : garde `!state.is(newState.getBlock())` absente dans `onRemove` malgré des propriétés mutables (§2.1). Pas un bug confirmé, à surveiller. - ~~`CreateNuclearJEI` : champ statique mutable `Categories`~~ — **fait**, commit `e7900959` (§2.5/§8.1). @@ -230,6 +232,13 @@ Ces affirmations historiques ont été vérifiées comme **fausses ou déjà clo - **Coordinateur de verrou fluide dédié** — ✅ toujours non justifié : `PersistentFluidLocks` reste le seul système ; pas de `FluidLockManager` concurrent retrouvé (celui décrit en `AUDIT_V1.md` B14 a disparu, hash non déterminé — voir §8.4). `clearLockIfAllInputsEmpty` utilise `getFuildHandlers(level)` (pas de scan 3D), double itération mineure sans gravité. - **`clearLockIfAllInputsEmpty` : pas de scan cubique O(n³)** — ✅ acceptable, confirmé sain. - **`ReactorSummaryDisplaySource.formatValue` — "incohérence" de mode d'affichage du heat vs `HeatDisplaySource`** — ❌ réfuté, ce n'est pas un bug : c'est un choix de design volontaire du widget de synthèse, mal formulé par l'audit initial. Analyse détaillée : `formatValue` force une jauge en mode "normal" pour `heat` (`gaugeOnNormal=true`), mais `formatFluid` (`ReactorSummaryDisplaySource.java:203-207`) fait exactement la même chose pour `fluid` (`mode == 0 || mode == 3` → jauge) — ce n'est donc pas une exception isolée sur `heat`, mais un pattern cohérent et répété : les deux stats les plus critiques à lire d'un coup d'œil dans une vue de synthèse (`fluid`, `heat`) sont en jauge par défaut, `fuel`/`cooler` restent en texte. `HeatDisplaySource`, à l'inverse, est un affichage individuel une-ligne où la jauge occuperait toute la largeur disponible pour une seule information — un défaut texte y est tout aussi légitime. Les deux widgets ont des contraintes d'espace et des objectifs différents ; il n'y a jamais eu de règle implicite selon laquelle un mode par défaut devait être identique entre les deux. **Pas de hash applicable** — aucun changement de code, décision de clôture actée après clarification du comportement voulu. Écarté aussi : la création d'une classe utilitaire `ReactorDisplayFormatting` pour mutualiser les 3 mappings mode→rendu existants (`AbstractReactorStatDisplaySource.provideLine`, `ReactorSummaryDisplaySource.formatValue`, `ReactorSummaryDisplaySource.formatFluid`) — ces 3 mappings ont des sémantiques différentes (3 modes vs 4 modes, flag `gaugeOnNormal` par stat, suffixe d'unité optionnel), donc les unifier demanderait un enum de mode partagé mal aligné entre appelants (le type même de fragilité par index déjà corrigée en `cc532f83`) ou une fonction à autant de paramètres que de sources de divergence — coût supérieur au gain pour un point cosmétique sans risque fonctionnel. +- **`RadiationCapability.tickRadiation` pour `LivingEntity` non-joueurs — absence de dirty-check d'inventaire** — ❌ réfuté comme piste d'amélioration, le statu quo (§3, §7 item 9) est maintenu après analyse approfondie du 2026-07-14. Détail : + - **Asymétrie constatée** : côté joueur, `InventoryHashUtil.compute(player)` hashe 41 slots (`items` 36 + `offhand` 1 + `getArmorSlots()` 4) et `computeItemRadiation(Player)` n'est recalculé que si ce hash change ([RadiationCapability.java:112-121](src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java#L112-L121)). Côté mob, `computeItemRadiation(LivingEntity)` recalcule inconditionnellement à chaque tick, mais sur seulement 6 slots (`getArmorSlots()` 4 + main + offhand). + - **Pourquoi un hash ne serait pas rentable pour les mobs** : chaque stack est résolu par `RadiationRegistry.get(ItemStack)`, un simple `HashMap.get` en O(1) (ou une petite itération de tags en cas d'absence) — voir [RadiationRegistry.java:25-38](src/main/java/net/nuclearteam/createnuclear/api/radiation/RadiationRegistry.java#L25-L38). Hasher ces mêmes 6 slots pour détecter un changement coûterait sensiblement la même chose que le calcul direct qu'il est censé éviter (même nombre d'accès aux stacks). Le hash côté joueur est rentable uniquement parce qu'il amortit un scan bien plus large (41 slots, potentiellement des `IRadiationSource` tiers coûteux) sur des ticks où rien n'a changé — ce rapport gain/effort ne tient pas à l'échelle 6 slots. + - **Le reste de `tickRadiation` domine probablement le coût par mob** : résolution de biome (`level.getBiome`), lecture d'attribut (`getRadiationResistance`), et gestion de `MobEffectInstance` (`getEffect`/`removeEffect`/`addEffect`) s'exécutent de toute façon à chaque tick pour chaque `LivingEntity`, dirty-check ou non ([RadiationCapability.java:123-141](src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java#L123-L141)). Un dirty-check sur l'inventaire ne changerait donc pas la classe de complexité globale (toujours O(N) sur le nombre de mobs), seulement une petite constante déjà faible. + - **Seule piste qui changerait réellement l'ordre de grandeur, si un jour nécessaire** : invalidation événementielle via `LivingEquipmentChangeEvent` (Forge) plutôt qu'un hash — un flag booléen positionné uniquement quand un slot d'équipement change réellement, lu en O(1) au lieu d'un scan/hash systématique de 6 slots. Non implémenté car non justifié tant qu'aucun profiling ne montre cette boucle comme point chaud (critère déjà posé par le commit d'origine `9ded502c`). + - **Point annexe repéré au passage, clarifié comme intentionnel** : `computeItemRadiation(Player)` n'inclut pas l'armure du joueur ([RadiationCapability.java:145-158](src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java#L145-L158)) alors que `InventoryHashUtil.compute(player)` la hashe bien (le hash reste correct pour déclencher un recalcul si l'inventaire principal/offhand change, l'armure n'y contribuant simplement jamais de radiation). **Confirmé volontaire, pas un oubli** : dans ce mod, les items d'armure existants sont des équipements de *résistance* à la radiation (ex. armure anti-radiation), jamais des *sources* de radiation — le rôle d'une armure ici est structurellement de protéger, pas d'irradier. Aucun item d'armure n'implémente `IRadiationSource` ni n'est enregistré dans `RadiationRegistry`, donc l'omission est cohérente avec le design actuel plutôt qu'une lacune. À revisiter uniquement si une future armure est conçue comme source de radiation (auquel cas il faudrait l'ajouter explicitement à `computeItemRadiation(Player)`, symétriquement à ce qui existe déjà pour `computeItemRadiation(LivingEntity)`). + - **Pas de hash applicable** — aucun changement de code, décision de statu quo actée après analyse. ### 8.3 Décisions produit exécutées From 6f3d7bb93cdef89089b6ad6cb71dd636749503c0 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 18 Jul 2026 16:47:00 +0200 Subject: [PATCH 166/171] docs: spot-check AUDIT_V1.md B7/B10/B17/B18 legacy bugs, confirm one as still open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Coverage-limits note (intro): mark B7, B10, B17 and B18 as re-verified by direct code reading instead of "neither confirmed nor refuted"; note that the unnumbered "minor" list from AUDIT_V1.md §2 is still entirely unverified. - §1 (bug table): add a new open bug row for IrradiatedOverlayRendererVision (foundation/events/overlay/IrradiatedOverlayRendererVision.java:23) — ex-B10 — mc.gameMode.getPlayerMode() is called with no null-guard on mc.gameMode, which can be null during world (re)load; the existing mc.player null-check happens later in the method and does not protect this earlier access. One-line fix identified but not yet applied. - §8.2 (refuted/closed investigations): add two new entries refuting legacy AUDIT_V1.md claims after direct code inspection — CNNoiseData.bootstrapRegistries (B7): EROSION noise parameters are in fact registered, contrary to the "entirely commented out" claim; RodsTooltipHandler (B17): the namespace check is confirmed intentional (explicit in-code comment) to avoid double tooltips on mod rods already handled via Registrate's setTooltipModifierFactory, not an accidental inversion. --- AUDIT_ACTUEL.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index f3df8031..8114bb05 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -4,7 +4,13 @@ **Méthodologie de cette réorganisation** : nouvelle relecture complète du code actuel (`src/main/java`, **292 fichiers**, hors `src/generated`/`src/main/resources`), croisée avec `AUDIT_V1.md`, les versions précédentes de ce fichier, et l'historique Git (`git log`, 1437 commits au total sur le dépôt) — aucun des deux audits n'a été pris comme vérité absolue : plusieurs points ont été revérifiés directement dans le code et un point s'est avéré **périmé** (voir §0). -**Limite de couverture honnête** : les bugs mineurs/robustesse listés au §1 de l'historique (`B7, B10, B17, B18` et la liste « mineurs » non numérotée d'`AUDIT_V1.md`) n'ont pas été re-vérifiés faute de signal de changement — ni confirmés ni infirmés, à re-vérifier ponctuellement avant traitement. Beaucoup de corrections d'`AUDIT_V1.md` (B1, B2, B4, B5, B9, B13, B18, et l'essentiel des listes de dead code) sont antérieures à la fenêtre de commits explorée en détail (avant le 2026-06-24) ; l'archéologie Git ciblée sur ces items n'a pas abouti à un hash certain dans la majorité des cas — voir §8.4. +**Limite de couverture honnête** *(mise à jour 2026-07-18 après spot-check de `B7`/`B10`/`B17`/`B18`)* : sur les quatre bugs mineurs/robustesse d'`AUDIT_V1.md` autrefois marqués « ni confirmés ni infirmés », trois ont maintenant un statut tranché par lecture directe du code — **ne pas répéter cette relecture, le résultat est acté** : +- **B7** (`CNNoiseData.bootstrapRegistries`) — n'est plus un bug : `EROSION` est bien enregistré, la méthode n'est pas commentée. Voir §8.2. +- **B17** (`RodsTooltipHandler`) — n'est pas un bug : la condition de namespace est intentionnelle (commentaire explicite dans le fichier), pas une inversion par erreur. Voir §8.2. +- **B18** (`CNCClient`, clé TOML `screenShaking`) — corrigé, confirmé dans le code (§8.4) ; seul le hash du commit reste indéterminé. +- **B10** (`IrradiatedOverlayRendererVision`) — **reste un vrai bug ouvert**, seul survivant du lot : `mc.gameMode.getPlayerMode()` (l.23) est encore appelé sans garde sur `mc.gameMode`, qui peut être `null` pendant le chargement d'un monde ; le null-check ajouté depuis ne protège que `mc.player`, plus loin dans la méthode. Voir §1 pour le détail et le fix (une ligne). + +**Ce qui manque réellement encore** : la liste « mineurs » **non numérotée** d'`AUDIT_V1.md` §2 (mineurs/robustesse — `ReactorOutputEntity.tick()`, `ReactorInput.mobInteract` retournant `PASS`, `RenderHelper` champs cache jamais lus, etc.) n'a **jamais** été relue dans cette réorganisation et reste entièrement non vérifiée. Par ailleurs, une bonne partie des corrections d'`AUDIT_V1.md` (B1, B2, B4, B5, B9, B13, et l'essentiel des listes de dead code) sont antérieures à la fenêtre de commits explorée en détail (avant le 2026-06-24) : le code actuel confirme qu'elles sont bien appliquées, mais l'archéologie Git n'a pas retrouvé de hash certain pour la majorité d'entre elles — voir §8.4. --- @@ -42,6 +48,7 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod |---|---|---|---| | **ReactorInputFluidManager — sur-extraction** | `controller/manager/ReactorInputFluidManager.java:137-155` | 🟠 | `fluidNeeded` (paramètre de `extractFluids`) n'est **toujours jamais décrémenté** entre handlers (l.146-151) → chaque handler de la boucle tente d'extraire le besoin complet, sur-extraction possible avec plusieurs inputs. `if (toExtract > 1)` (l.147) ignore toujours les extractions de 1 unité. **Détail supplémentaire trouvé cette revue** : la garde `if (fluidNeeded <= 0) break;` (l.151) est **du code mort** — `fluidNeeded` n'étant jamais réassigné dans la boucle, cette condition ne peut être vraie que si le paramètre est déjà ≤ 0 en entrée. Toléré aujourd'hui (tank mono-slot en pratique), reste une violation de contrat latente. | | **Flicker vitesse de sortie en fin de ressources — partiellement corrigé, validation en jeu restante** *(reclassé le 2026-07-12, code de correction déjà présent depuis `a18038db`, 2026-07-05)* | `content/multiblock/reactorLogic/DefaultOverheatController.java:13-30` + `controller/ReactorControllerBlockEntity.java:430-433` | 🟡 | `overHeat` continue de s'incrémenter de `+1`/`-2` à un rythme régulier, indépendamment du réapprovisionnement — l'oscillateur de base n'a **pas** été supprimé. Mais son symptôme (bascule de vitesse de sortie entre `0` et `X`) est désormais amorti : `ReactorControllerBlockEntity` ne réapplique `rotateOutputs` que si `\|heat - lastAppliedOutputHeat\| >= RPM_DIVIDER/2` (code vérifié présent). **Reste ouvert** : (1) valider en jeu que ce seuil élimine réellement la perception du flicker en fin de ressources (le commit d'origine le signale lui-même comme non validé) ; (2) décider si l'oscillateur `overHeat` doit être revu à la racine ou si l'hystérésis en aval suffit durablement. | +| **`IrradiatedOverlayRendererVision` — NPE potentielle sur `mc.gameMode`** *(ex-`B10` d'`AUDIT_V1.md`, spot-check 2026-07-18)* | `foundation/events/overlay/IrradiatedOverlayRendererVision.java:23` | 🟡 | `GameType playerMode = mc.gameMode.getPlayerMode();` est appelé **sans garde** sur `mc.gameMode`, qui peut être `null` (écran de chargement, entre la déconnexion et la reconnexion). Le null-check sur `mc.player` a bien été ajouté depuis (l.31, `if (localPlayer == null) return;`), mais **après** l'accès à `mc.gameMode` — donc partiellement corrigé seulement. Fix trivial : ajouter `if (mc.gameMode == null) return;` avant la ligne 23. | --- @@ -239,6 +246,8 @@ Ces affirmations historiques ont été vérifiées comme **fausses ou déjà clo - **Seule piste qui changerait réellement l'ordre de grandeur, si un jour nécessaire** : invalidation événementielle via `LivingEquipmentChangeEvent` (Forge) plutôt qu'un hash — un flag booléen positionné uniquement quand un slot d'équipement change réellement, lu en O(1) au lieu d'un scan/hash systématique de 6 slots. Non implémenté car non justifié tant qu'aucun profiling ne montre cette boucle comme point chaud (critère déjà posé par le commit d'origine `9ded502c`). - **Point annexe repéré au passage, clarifié comme intentionnel** : `computeItemRadiation(Player)` n'inclut pas l'armure du joueur ([RadiationCapability.java:145-158](src/main/java/net/nuclearteam/createnuclear/content/radiation/capability/RadiationCapability.java#L145-L158)) alors que `InventoryHashUtil.compute(player)` la hashe bien (le hash reste correct pour déclencher un recalcul si l'inventaire principal/offhand change, l'armure n'y contribuant simplement jamais de radiation). **Confirmé volontaire, pas un oubli** : dans ce mod, les items d'armure existants sont des équipements de *résistance* à la radiation (ex. armure anti-radiation), jamais des *sources* de radiation — le rôle d'une armure ici est structurellement de protéger, pas d'irradier. Aucun item d'armure n'implémente `IRadiationSource` ni n'est enregistré dans `RadiationRegistry`, donc l'omission est cohérente avec le design actuel plutôt qu'une lacune. À revisiter uniquement si une future armure est conçue comme source de radiation (auquel cas il faudrait l'ajouter explicitement à `computeItemRadiation(Player)`, symétriquement à ce qui existe déjà pour `computeItemRadiation(LivingEntity)`). - **Pas de hash applicable** — aucun changement de code, décision de statu quo actée après analyse. +- **`CNNoiseData.bootstrapRegistries` — `B7` d'`AUDIT_V1.md`, prétendument entièrement commenté (noise `EROSION` jamais enregistré)** — ❌ réfuté par lecture directe (2026-07-18) : la méthode enregistre bien `EROSION` (`context.register(key, new NoiseParameters(...))`, non commenté). *Pas de hash applicable — la correction (ou le fait que le bug n'a jamais existé sous cette forme dans le code observé) est antérieure à la fenêtre de commits explorée en détail, cf. §8.4.* +- **`RodsTooltipHandler` — `B17` d'`AUDIT_V1.md`, prétendument condition de namespace inversée par erreur** — ❌ réfuté comme bug, clarifié comme intentionnel (2026-07-18) : le fichier retourne bien tôt pour les items du mod (`if (id != null && CreateNuclear.MOD_ID.equals(id.getNamespace())) return;`), mais un commentaire explicite documente désormais que c'est voulu — les items du mod ont déjà leur tooltip via `setTooltipModifierFactory` de Registrate, ce handler ne sert que les items externes/datapack que cette factory ne peut pas couvrir ; inverser la condition doublerait le tooltip sur les rods du mod. *Pas de hash applicable — soit le commentaire de clarification est antérieur à la fenêtre explorée en détail (§8.4), soit le bug initial d'`AUDIT_V1.md` décrivait un état de code jamais confirmé dans l'historique récent.* ### 8.3 Décisions produit exécutées From 9e0e38d3f4fdadd6cc57bdeeb26a3ab74c62ef56 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 18 Jul 2026 17:01:10 +0200 Subject: [PATCH 167/171] refactor: move ClientEvents into foundation.events package - Relocate ClientEvents from the createnuclear root package to net.nuclearteam.createnuclear.foundation.events, aligning it with the rest of the foundation/events/* classes (e.g. the overlay renderers). - Update the package declaration and add explicit imports for CNClientProxy and CreateNuclear (previously implicit same-package references from the root package). - No behavioral changes: nuke flash/shake ticking, camera-shake computation, and anti-radiation armor model-part hiding logic are unchanged. --- .../createnuclear/{ => foundation/events}/ClientEvents.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/main/java/net/nuclearteam/createnuclear/{ => foundation/events}/ClientEvents.java (96%) diff --git a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java similarity index 96% rename from src/main/java/net/nuclearteam/createnuclear/ClientEvents.java rename to src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java index 40b0128c..39be171c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/ClientEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear; +package net.nuclearteam.createnuclear.foundation.events; import net.minecraft.client.Minecraft; import net.minecraft.util.RandomSource; @@ -12,6 +12,8 @@ import net.minecraft.client.model.PlayerModel; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; +import net.nuclearteam.createnuclear.CNClientProxy; +import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; import net.nuclearteam.createnuclear.foundation.mixin.CameraAccessor; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; From 390fcc27d8c51a2fe26fe281fb4a47d10e594138 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 18 Jul 2026 17:29:57 +0200 Subject: [PATCH 168/171] refactor: move client-only mixins into foundation.mixin.client and register them under the "client" mixin block - Relocate CameraAccessor, GameRendererMixin and RadiationHeartMixin from foundation.mixin to a new foundation.mixin.client subpackage, and update ClientEvents' import of CameraAccessor accordingly. - createnuclear.forge.mixins.json: move RadiationHeartMixin, GameRendererMixin and CameraAccessor out of the common "mixins" list into the "client" list (with their new "client." prefix), so they are only applied on the client distribution instead of being loaded on dedicated servers; also drop the now-unused "accessWidener" entry. - Rename mixin injector methods to the "CN$" prefix convention (cn_tick -> CN$tick, cn_render -> CN$render, createnuclear$changeHeartTexture -> CN$changeHeartTexture) for consistency across the mixin classes. - RadiationHeartMixin: fix VANILLA_ICONS to use the single-argument ResourceLocation constructor (implicit "minecraft" namespace) instead of the deprecated explicit-namespace constructor. --- .../createnuclear/foundation/events/ClientEvents.java | 2 +- .../foundation/mixin/{ => client}/CameraAccessor.java | 2 +- .../foundation/mixin/{ => client}/GameRendererMixin.java | 6 +++--- .../foundation/mixin/{ => client}/RadiationHeartMixin.java | 6 +++--- src/main/resources/createnuclear.forge.mixins.json | 7 +++---- 5 files changed, 11 insertions(+), 12 deletions(-) rename src/main/java/net/nuclearteam/createnuclear/foundation/mixin/{ => client}/CameraAccessor.java (85%) rename src/main/java/net/nuclearteam/createnuclear/foundation/mixin/{ => client}/GameRendererMixin.java (88%) rename src/main/java/net/nuclearteam/createnuclear/foundation/mixin/{ => client}/RadiationHeartMixin.java (87%) diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java b/src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java index 39be171c..e9df5892 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/events/ClientEvents.java @@ -15,7 +15,7 @@ import net.nuclearteam.createnuclear.CNClientProxy; import net.nuclearteam.createnuclear.CreateNuclear; import net.nuclearteam.createnuclear.content.equipment.armor.AntiRadiationArmorItem; -import net.nuclearteam.createnuclear.foundation.mixin.CameraAccessor; +import net.nuclearteam.createnuclear.foundation.mixin.client.CameraAccessor; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; @Mod.EventBusSubscriber(modid = CreateNuclear.MOD_ID, value = Dist.CLIENT) diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/CameraAccessor.java similarity index 85% rename from src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java rename to src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/CameraAccessor.java index e49cb8b8..20f459f9 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/CameraAccessor.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/CameraAccessor.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.mixin; +package net.nuclearteam.createnuclear.foundation.mixin.client; import net.minecraft.client.Camera; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/GameRendererMixin.java similarity index 88% rename from src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java rename to src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/GameRendererMixin.java index 51b7751a..cd8619ab 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/GameRendererMixin.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/GameRendererMixin.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.mixin; +package net.nuclearteam.createnuclear.foundation.mixin.client; import net.minecraft.client.renderer.GameRenderer; import net.nuclearteam.createnuclear.CNClientProxy; @@ -20,7 +20,7 @@ public abstract class GameRendererMixin { remap = true, at = @At(value = "TAIL") ) - public void cn_tick(CallbackInfo ci) { + public void CN$tick(CallbackInfo ci) { if (CNClientProxy.renderNukeSkyDarkFor > 0 && darkenWorldAmount < 1.0F) { darkenWorldAmount = Math.min(darkenWorldAmount + 0.3F, 1.0F); } @@ -36,7 +36,7 @@ public void cn_tick(CallbackInfo ci) { shift = At.Shift.AFTER ) ) - public void cn_render(float partialTick, long nanos, boolean idk, CallbackInfo ci) { + public void CN$render(float partialTick, long nanos, boolean idk, CallbackInfo ci) { CNClientProxy.preScreenRender(partialTick); } } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/RadiationHeartMixin.java similarity index 87% rename from src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java rename to src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/RadiationHeartMixin.java index f4779a93..8e53aaf6 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/RadiationHeartMixin.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/mixin/client/RadiationHeartMixin.java @@ -1,4 +1,4 @@ -package net.nuclearteam.createnuclear.foundation.mixin; +package net.nuclearteam.createnuclear.foundation.mixin.client; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Gui; @@ -15,7 +15,7 @@ public class RadiationHeartMixin { private static final ResourceLocation RADIATION_ICONS = CreateNuclear.asResource("textures/gui/icons.png"); - private static final ResourceLocation VANILLA_ICONS = new ResourceLocation("minecraft", "textures/gui/icons.png"); + private static final ResourceLocation VANILLA_ICONS = new ResourceLocation("textures/gui/icons.png"); @ModifyArg( method = "renderHeart", // The single-heart method that actually draws each heart icon @@ -25,7 +25,7 @@ public class RadiationHeartMixin { ), index = 0 ) - private ResourceLocation createnuclear$changeHeartTexture(ResourceLocation originalTexture) { + private ResourceLocation CN$changeHeartTexture(ResourceLocation originalTexture) { if (originalTexture.equals(VANILLA_ICONS)) { Player player = Minecraft.getInstance().player; diff --git a/src/main/resources/createnuclear.forge.mixins.json b/src/main/resources/createnuclear.forge.mixins.json index b87e4099..e90be855 100644 --- a/src/main/resources/createnuclear.forge.mixins.json +++ b/src/main/resources/createnuclear.forge.mixins.json @@ -6,13 +6,12 @@ "refmap": "createnuclear.refmap.json", "mixins": [ "BaseFireBlockMixin", - "RadiationHeartMixin", - "GameRendererMixin", - "CameraAccessor", "SmithingTransformRecipeMixin" ], - "accessWidener": "createnuclear.accesswidener", "client": [ + "client.RadiationHeartMixin", + "client.GameRendererMixin", + "client.CameraAccessor" ], "injectors": { "defaultRequire": 1 From e8fd2c6f75030ff3f8b6fb1491e19b3c03c1c3c5 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 25 Jul 2026 12:38:11 +0200 Subject: [PATCH 169/171] refactor: change RodType/ReactorFluidType from item/fluid lists to a single Holder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RodType and ReactorFluidType now hold a single Holder/Holder (fields renamed item/fluid) instead of a HolderSet/HolderSet that always contained exactly one entry in practice; codecs switch from RegistryCodecs.homogeneousList to RegistryFixedCodec, and generated JSON data (fluids/type/*.json, rods/type/*.json) is regenerated with the singular "fluid"/"item" fields instead of "fluids"/"items" arrays. - RodType.Builder.addItems(ItemLike...) is replaced by a single-item item(ItemLike) setter; ReactorFluidType.Builder.fluid(...) now replaces rather than accumulates. Update all call sites (ItemRodTypesValue, CNRodTypes javadoc, DefaultHeatCalculator's rod.items().size() > 0 checks switched to rod.isNotEmptyItem()). - Default sentinel instances (ItemRodTypesValue.DEFAULT_ROD_TYPE, ReactorFluidTypesValue.DEFAULT_REACTOR_FLUID_TYPE) now use Items.AIR.builtInRegistryHolder() / Fluids.EMPTY.builtInRegistryHolder() instead of an empty HolderSet, and isNotEmptyItem()/isNotEmptyFluid() check identity against AIR/EMPTY instead of checking set size. - ReactorFluidType: remove the unused useConfig/setRodConfig config-override mechanism (dead code — the CNConfigs lookup was already commented out) along with its now-redundant maxHeat()/ efficiency() overrides. - toString() on both records is updated to report the single fluid/item name instead of joining a list. --- .../fed443662143001aeb5341375f6f5ef31d10baea | 10 +- .../createnuclear/fluids/type/fallback.json | 2 +- .../createnuclear/fluids/type/nitrogen.json | 2 +- .../createnuclear/fluids/type/water.json | 2 +- .../createnuclear/rods/type/fallback.json | 2 +- .../createnuclear/api/ItemRodTypesValue.java | 11 +- .../api/ReactorFluidTypesValue.java | 6 +- .../multiblock/fluid/ReactorFluidType.java | 112 ++++++------------ .../api/multiblock/rods/RodType.java | 68 ++++++----- .../reactorLogic/DefaultHeatCalculator.java | 8 +- .../content/multiblock/rod/CNRodTypes.java | 2 +- 11 files changed, 91 insertions(+), 134 deletions(-) diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 69cb7ea4..145eb0e1 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,8 +1,8 @@ -// 1.20.1 2026-07-13T15:35:50.3841285 CreateNuclear Generated Registry Entries -aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json -d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json -afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json -706132bf26d87ed4a83f8d5f8793ab69a60b98fe data/createnuclear/createnuclear/rods/type/fallback.json +// 1.20.1 2026-07-25T12:28:12.5162369 CreateNuclear Generated Registry Entries +46e263393c1672a180bc12b99f9e39adf22e66b5 data/createnuclear/createnuclear/fluids/type/fallback.json +2837d5ecbd5735f39c1fac545469486e09c502e0 data/createnuclear/createnuclear/fluids/type/nitrogen.json +152a58adb9f86e1c9fac62fd2095ba8413142568 data/createnuclear/createnuclear/fluids/type/water.json +15403b1cee46d300af2247a08485c04ccd80cfc0 data/createnuclear/createnuclear/rods/type/fallback.json 9b26dc9810e426fa58e03de22a96f45403e5f1b3 data/createnuclear/damage_type/fan_radiation.json 8c374052eefd34e87959a1f643e60b674f0345f8 data/createnuclear/damage_type/radiation.json 5edbd74546f4088818e02bb7a5c5eb2ecfe25623 data/createnuclear/forge/biome_modifier/lead_ore.json diff --git a/src/generated/resources/data/createnuclear/createnuclear/fluids/type/fallback.json b/src/generated/resources/data/createnuclear/createnuclear/fluids/type/fallback.json index 4c5a3faa..ea208e24 100644 --- a/src/generated/resources/data/createnuclear/createnuclear/fluids/type/fallback.json +++ b/src/generated/resources/data/createnuclear/createnuclear/fluids/type/fallback.json @@ -1,5 +1,5 @@ { "efficiency": -1, - "fluids": [], + "fluid": "minecraft:empty", "maxHeat": -1 } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/createnuclear/fluids/type/nitrogen.json b/src/generated/resources/data/createnuclear/createnuclear/fluids/type/nitrogen.json index 8056badd..62e15f99 100644 --- a/src/generated/resources/data/createnuclear/createnuclear/fluids/type/nitrogen.json +++ b/src/generated/resources/data/createnuclear/createnuclear/fluids/type/nitrogen.json @@ -1,5 +1,5 @@ { "efficiency": 100, - "fluids": "createnuclear:nitrogen", + "fluid": "createnuclear:nitrogen", "maxHeat": 8196 } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/createnuclear/fluids/type/water.json b/src/generated/resources/data/createnuclear/createnuclear/fluids/type/water.json index b8ae757a..5a3ff585 100644 --- a/src/generated/resources/data/createnuclear/createnuclear/fluids/type/water.json +++ b/src/generated/resources/data/createnuclear/createnuclear/fluids/type/water.json @@ -1,5 +1,5 @@ { "efficiency": 1000, - "fluids": "minecraft:water", + "fluid": "minecraft:water", "maxHeat": 2048 } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/createnuclear/rods/type/fallback.json b/src/generated/resources/data/createnuclear/createnuclear/rods/type/fallback.json index 4e42f40f..57c68b48 100644 --- a/src/generated/resources/data/createnuclear/createnuclear/rods/type/fallback.json +++ b/src/generated/resources/data/createnuclear/createnuclear/rods/type/fallback.json @@ -1,7 +1,7 @@ { "type": "NONE", "baseRodHeat": -1, - "items": [], + "item": "minecraft:air", "proximityRodHeat": -1.0, "rodTimer": -1 } \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java b/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java index 745111d7..cdf01109 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/ItemRodTypesValue.java @@ -3,20 +3,17 @@ import com.simibubi.create.api.registry.SimpleRegistry; import com.tterrag.registrate.util.nullness.NonNullConsumer; import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; import net.nuclearteam.createnuclear.api.multiblock.rods.RodType; import static net.nuclearteam.createnuclear.api.multiblock.rods.RodType.TypeRod.NONE; -import java.util.Collections; - -import net.minecraft.core.HolderSet; - public class ItemRodTypesValue { public static final SimpleRegistry ROD_TYPE = SimpleRegistry.create(); /** * Default RodType returned when no mapping exists in the registry. * Built once to avoid allocating a new instance on each lookup. */ - public static final RodType DEFAULT_ROD_TYPE = new RodType(HolderSet.direct(Collections.emptyList()), -1, -1, -1, NONE); + public static final RodType DEFAULT_ROD_TYPE = new RodType(Items.AIR.builtInRegistryHolder(), -1, -1, -1, NONE); /** * Get the {@link RodType} associated with the given {@link Item}. @@ -39,7 +36,7 @@ public static RodType getRodType(Item item) { * @throws NullPointerException if {@code type} is null */ public static NonNullConsumer setRodTypeInfos(RodType.Builder type) { - return item -> ROD_TYPE.register(item, type.addItems(item).build()); + return item -> ROD_TYPE.register(item, type.item(item).build()); } /** @@ -70,7 +67,7 @@ public static NonNullConsumer setRodTypeInfos(int baseRodHeat, int proximi } return item -> { - RodType built = builder.addItems(item).build(); + RodType built = builder.item(item).build(); ROD_TYPE.register(item, built); }; } diff --git a/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java b/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java index 67a05e4f..f9bd5502 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/ReactorFluidTypesValue.java @@ -2,12 +2,10 @@ import com.simibubi.create.api.registry.SimpleRegistry; import com.tterrag.registrate.util.nullness.NonNullConsumer; -import net.minecraft.core.HolderSet; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; import net.nuclearteam.createnuclear.api.multiblock.fluid.ReactorFluidType; -import java.util.Collections; - /** * Registry-backed accessors for {@link ReactorFluidType} mappings. *

    @@ -26,7 +24,7 @@ public class ReactorFluidTypesValue { * Default {@link ReactorFluidType} returned when no mapping exists in the * registry. Constructed once to avoid allocating a new instance on each lookup. */ - public static final ReactorFluidType DEFAULT_REACTOR_FLUID_TYPE = new ReactorFluidType(HolderSet.direct(Collections.emptyList()), -1, -1); + public static final ReactorFluidType DEFAULT_REACTOR_FLUID_TYPE = new ReactorFluidType(Fluids.EMPTY.builtInRegistryHolder(), -1, -1); /** * Get the {@link ReactorFluidType} associated with the given {@link Fluid}. diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java index 56485efc..a8478232 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/fluid/ReactorFluidType.java @@ -3,15 +3,15 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; import net.minecraft.core.RegistryAccess; -import net.minecraft.core.RegistryCodecs; import net.minecraft.core.registries.Registries; import net.minecraft.core.Holder.Reference; +import net.minecraft.resources.RegistryFixedCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.registries.ForgeRegistries; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; @@ -21,23 +21,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; /** * Represents a reactor fluid type used by the mod's multiblock. *

    - * A {@code ReactorFluidType} holds a set of fluids that identify this - * fluid type, heat-related and efficiency values, and a flag indicating - * whether those values should be read from configuration at runtime. + * A {@code ReactorFluidType} holds the single fluid that identifies this + * fluid type, along with its heat-related and efficiency values. */ -public record ReactorFluidType(HolderSet fluids, int maxHeat, int efficiency, boolean useConfig) { - public ReactorFluidType(HolderSet fluids, int maxHeat, int efficiency) { - this(fluids, maxHeat, efficiency, false); - } +public record ReactorFluidType(Holder fluid, int maxHeat, int efficiency) { /** Serialization codec for saving/loading {@link ReactorFluidType} instances. */ public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - RegistryCodecs.homogeneousList(Registries.FLUID).fieldOf("fluids").forGetter(ReactorFluidType::fluids), + RegistryFixedCodec.create(Registries.FLUID).fieldOf("fluid").forGetter(ReactorFluidType::fluid), Codec.INT.fieldOf("maxHeat").forGetter(ReactorFluidType::maxHeat), Codec.INT.fieldOf("efficiency").forGetter(ReactorFluidType::efficiency) ).apply(i, ReactorFluidType::new)); @@ -57,10 +52,9 @@ public static Optional> getTypeForFluid(RegistryAcce return registryAccess.lookupOrThrow(CreateNuclearRegistries.FLUID_TYPE) .listElements() - .filter(ref -> ref.value().fluids.stream() - .anyMatch(h -> h.unwrapKey() - .map(k -> k.location().equals(fluidKey)) - .orElse(false))) + .filter(ref -> ref.value().fluid.unwrapKey() + .map(k -> k.location().equals(fluidKey)) + .orElse(false)) .findFirst(); } @@ -91,12 +85,13 @@ public static ReactorFluidType resolveReactorFluidType(Fluid fluid, Level world) /** - * Returns whether this {@code ReactorFluidType} has at least one associated fluid. + * Returns whether this {@code ReactorFluidType} has an associated fluid + * (i.e. is not the empty/sentinel fluid). * - * @return {@code true} if one or more fluids are defined, {@code false} otherwise + * @return {@code true} if a real fluid is defined, {@code false} otherwise */ public boolean isNotEmptyFluid() { - return this.fluids.size() >= 1; + return this.fluid.value() != Fluids.EMPTY; } /** @@ -106,12 +101,9 @@ public boolean isNotEmptyFluid() { * resulting instance. */ public static class Builder { - private final List> fluids = new ArrayList<>(); + private Holder fluid = null; private int maxHeat = 0; private int efficiency = 0; - private boolean useConfig = false; - - private boolean fluidSet = false; private boolean maxHeatSet = false; private boolean efficiencySet = false; @@ -140,36 +132,24 @@ public Builder efficiency(int efficiency) { } /** - * Adds a fluid to this type from a {@link FluidStack}. + * Sets the fluid identifying this type from a {@link FluidStack}. * * @param fluidStack the fluid stack providing the fluid * @return this builder */ public Builder fluid(FluidStack fluidStack) { - this.fluids.add(fluidStack.getFluid().builtInRegistryHolder()); - this.fluidSet = true; - return this; + return fluid(fluidStack.getFluid()); } /** - * Adds a fluid to this type directly. + * Sets the fluid identifying this type. Calling this again replaces + * the previously set fluid. * - * @param fluid the fluid to add + * @param fluid the fluid to associate with this type * @return this builder */ public Builder fluid(Fluid fluid) { - this.fluids.add(fluid.builtInRegistryHolder()); - this.fluidSet = true; - return this; - } - - /** - * Marks this type to resolve numeric values from configuration at runtime. - * - * @return this builder - */ - public Builder setRodConfig() { - this.useConfig = true; + this.fluid = fluid.builtInRegistryHolder(); return this; } @@ -181,52 +161,26 @@ public Builder setRodConfig() { */ public ReactorFluidType build() { List missing = new ArrayList<>(); - if (!fluidSet || fluids.isEmpty()) missing.add("fluids"); - - if (!this.useConfig) { - if (!maxHeatSet) missing.add("maxHeat"); - if (!efficiencySet) missing.add("efficiency"); - } + if (fluid == null) missing.add("fluid"); + if (!maxHeatSet) missing.add("maxHeat"); + if (!efficiencySet) missing.add("efficiency"); if (!missing.isEmpty()) - throw new IllegalStateException("Missing required RodType fields: " + String.join(", ", missing)); + throw new IllegalStateException("Missing required ReactorFluidType fields: " + String.join(", ", missing)); - return new ReactorFluidType(HolderSet.direct(fluids), maxHeat, efficiency, useConfig); - } - } - - @Override - public int maxHeat() { - if (!useConfig) return maxHeat; - try { - return 12; //CNConfigs.server().rods.maxHeat.get(); - } catch (IllegalStateException e) { - return maxHeat; - } - } - - @Override - public int efficiency() { - if (!useConfig) return efficiency; - try { - return 12; //CNConfigs.server().rods.maxHeat.get(); - } catch (IllegalStateException e) { - return efficiency; + return new ReactorFluidType(fluid, maxHeat, efficiency); } } @Override public @NotNull String toString() { - String fluidNames = this.fluids.stream() - .map(h -> h.unwrapKey() - .map(k -> k.location().toString()) - .orElseGet(() -> { - ResourceLocation rl = ForgeRegistries.FLUIDS.getKey(h.value()); - return rl != null ? rl.toString() : h.value().toString(); - }) - ) - .collect(Collectors.joining(", ")); - - return "ReactorFluidType{fluids=[" + fluidNames + "], maxHeat=" + maxHeat() + ", efficiency=" + efficiency() + "}"; + String fluidName = this.fluid.unwrapKey() + .map(k -> k.location().toString()) + .orElseGet(() -> { + ResourceLocation rl = ForgeRegistries.FLUIDS.getKey(this.fluid.value()); + return rl != null ? rl.toString() : this.fluid.value().toString(); + }); + + return "ReactorFluidType{fluid=" + fluidName + ", maxHeat=" + maxHeat() + ", efficiency=" + efficiency() + "}"; } } diff --git a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java index 5f430709..a913c742 100644 --- a/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java +++ b/src/main/java/net/nuclearteam/createnuclear/api/multiblock/rods/RodType.java @@ -5,15 +5,17 @@ import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.Holder; import net.minecraft.core.Holder.Reference; -import net.minecraft.core.HolderSet; import net.minecraft.core.RegistryAccess; -import net.minecraft.core.RegistryCodecs; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.RegistryFixedCodec; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.StringRepresentable; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.Level; +import net.minecraftforge.registries.ForgeRegistries; import net.nuclearteam.createnuclear.api.CreateNuclearRegistries; import net.nuclearteam.createnuclear.api.ItemRodTypesValue; @@ -27,35 +29,35 @@ /** * Represents a rod type used by the mod's multiblock. *

    - * A {@code RodType} holds a set of items that can represent this rod type, + * A {@code RodType} holds the single item that represents this rod type, * heat-related values, a timing value, and a {@link TypeRod} indicating the * category (fuel, cooler, or mixed). */ @MethodsReturnNonnullByDefault -public record RodType(HolderSet items, +public record RodType(Holder item, Supplier baseRodHeat, Supplier proximityRodHeat, Supplier rodTimer, Supplier heatRatio, TypeRod type) { - public RodType(HolderSet items, + public RodType(Holder item, int baseRodHeat, float proximityRodHeat, int rodTimer, TypeRod type) { - this(items, baseRodHeat, proximityRodHeat, rodTimer, type, 1); + this(item, baseRodHeat, proximityRodHeat, rodTimer, type, 1); } - public RodType(HolderSet items, + public RodType(Holder item, int baseRodHeat, float proximityRodHeat, int rodTimer, TypeRod type, int heatRatio) { - this(items, () -> baseRodHeat, () -> proximityRodHeat, () -> rodTimer, () -> heatRatio, type); + this(item, () -> baseRodHeat, () -> proximityRodHeat, () -> rodTimer, () -> heatRatio, type); } /** * Serialization codec for saving/loading {@link RodType} instances. */ public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - RegistryCodecs.homogeneousList(Registries.ITEM).fieldOf("items").forGetter(RodType::items), + RegistryFixedCodec.create(Registries.ITEM).fieldOf("item").forGetter(RodType::item), Codec.INT.fieldOf("baseRodHeat").forGetter(rt -> rt.baseRodHeat().get()), Codec.FLOAT.fieldOf("proximityRodHeat").forGetter(rt -> rt.proximityRodHeat().get()), Codec.INT.fieldOf("rodTimer").forGetter(rt -> rt.rodTimer().get()), @@ -75,7 +77,7 @@ public RodType(HolderSet items, public static Optional> getTypeForItem(RegistryAccess registryAccess, Item item) { return registryAccess.lookupOrThrow(CreateNuclearRegistries.ROD_TYPE) .listElements() - .filter(ref -> ref.value().items.contains(item.builtInRegistryHolder())) + .filter(ref -> ref.value().item.equals(item.builtInRegistryHolder())) .findFirst(); } @@ -103,12 +105,13 @@ public static RodType resolveRodType(Item item, Level world) { } /** - * Returns whether this {@code RodType} has no associated items. + * Returns whether this {@code RodType} has an associated item (i.e. is + * not the empty/sentinel item). * - * @return {@code true} if no items are defined, {@code false} otherwise + * @return {@code true} if a real item is defined, {@code false} otherwise */ public boolean isNotEmptyItem() { - return this.items.size() >= 1; + return this.item.value() != Items.AIR; } /** @@ -125,13 +128,13 @@ public boolean isNotEmptyItem() { * such as a config option (see {@code CNItems} for examples), so that * changes are picked up without rebuilding the {@code RodType}. *

    - * {@code items}, {@code type}, {@code baseRodHeat}, {@code proximityRodHeat} + * {@code item}, {@code type}, {@code baseRodHeat}, {@code proximityRodHeat} * and {@code rodTimer} are required; {@code heatRatio} defaults to a * constant {@code 1} and never needs to be set explicitly. Call * {@link #build()} once all required values are configured. */ public static class Builder { - private final List> items = new ArrayList<>(); + private Holder item = null; private Supplier baseRodHeat = null; private Supplier proximityRodHeat = null; private Supplier rodTimer = null; @@ -267,27 +270,25 @@ public Builder fuelRodType() { } /** - * Adds one or more items that represent this rod type. Can be called - * multiple times; items accumulate rather than replace one another. - * At least one item must be added before {@link #build()}. + * Sets the item that represents this rod type. Calling this again + * replaces the previously set item. * - * @param items array of {@link ItemLike} elements to associate + * @param item the item to associate with this rod type * @return this builder */ - public Builder addItems(ItemLike... items) { - for (ItemLike provider : items) - this.items.add(provider.asItem().builtInRegistryHolder()); + public Builder item(ItemLike item) { + this.item = item.asItem().builtInRegistryHolder(); return this; } /** * Builds the immutable {@link RodType} instance. *

    - * Validates that {@code items} is non-empty and that {@code type}, - * {@code baseRodHeat}, {@code proximityRodHeat} and {@code rodTimer} - * have all been set (either as a fixed value or as a dynamic - * {@link Supplier}); {@code heatRatio} is exempt since it defaults - * to a constant {@code 1}. + * Validates that {@code item} and {@code type}, {@code baseRodHeat}, + * {@code proximityRodHeat} and {@code rodTimer} have all been set + * (either as a fixed value or as a dynamic {@link Supplier}); + * {@code heatRatio} is exempt since it defaults to a constant + * {@code 1}. * * @throws IllegalStateException if one or more required fields are missing, * naming every missing field in the exception message @@ -295,7 +296,7 @@ public Builder addItems(ItemLike... items) { */ public RodType build() { List missing = new ArrayList<>(); - if (items.isEmpty()) missing.add("items"); + if (item == null) missing.add("item"); if (type == null) missing.add("type"); if (baseRodHeat == null) missing.add("baseRodHeat"); if (proximityRodHeat == null) missing.add("proximityRodHeat"); @@ -304,7 +305,7 @@ public RodType build() { if (!missing.isEmpty()) throw new IllegalStateException("Missing required RodType fields: " + String.join(", ", missing)); - return new RodType(HolderSet.direct(items), baseRodHeat, proximityRodHeat, rodTimer, heatRatio, type); + return new RodType(item, baseRodHeat, proximityRodHeat, rodTimer, heatRatio, type); } } @@ -350,7 +351,14 @@ public static String tooltipKey(ItemStack stack, Level level) { @Override public String toString() { - return "RodType [items: " + this.items() + + String itemName = this.item.unwrapKey() + .map(k -> k.location().toString()) + .orElseGet(() -> { + ResourceLocation rl = ForgeRegistries.ITEMS.getKey(this.item.value()); + return rl != null ? rl.toString() : this.item.value().toString(); + }); + + return "RodType [item: " + itemName + ", baseRodHeat: " + this.baseRodHeat().get() + ", proximityRodHeat: " + this.proximityRodHeat().get() + ", rodTimer: " + this.rodTimer().get() + diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java index b6aa1f0a..d2e82c15 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/reactorLogic/DefaultHeatCalculator.java @@ -55,10 +55,10 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re ItemStack currentStack = entry.getValue(); RodType rod = RodType.resolveRodType(currentStack.getItem(), level); String currentRod = ""; - if (rod.items().size() > 0 && rod.type() == RodType.TypeRod.FUEL) { + if (rod.isNotEmptyItem() && rod.type() == RodType.TypeRod.FUEL) { heat += rod.baseRodHeat().get(); currentRod = "fuel"; - } else if (rod.items().size() > 0 && rod.type() == RodType.TypeRod.COOLER) { + } else if (rod.isNotEmptyItem() && rod.type() == RodType.TypeRod.COOLER) { heat += rod.baseRodHeat().get(); currentRod = "cooler"; } @@ -79,9 +79,9 @@ public double computeHeat(BigFluidStack bigFluidStack, ReactorFluidType type, Re if ("fuel".equals(currentRod)) { ItemStack stack = actualRods.get(neighborSlot); RodType neighborRod = RodType.resolveRodType(stack.getItem(), level); - if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.FUEL) { + if (neighborRod.isNotEmptyItem() && neighborRod.type() == RodType.TypeRod.FUEL) { heat += rod.proximityRodHeat().get(); - } else if (neighborRod.items().size() > 0 && neighborRod.type() == RodType.TypeRod.COOLER) { + } else if (neighborRod.isNotEmptyItem() && neighborRod.type() == RodType.TypeRod.COOLER) { heat += rod.baseRodHeat().get() / neighborRod.proximityRodHeat().get(); } } diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java index 79c17292..24d56c8c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/rod/CNRodTypes.java @@ -24,7 +24,7 @@ public class CNRodTypes { * .baseRodHeat(int) * .proximityRodHeat(int) * .rodTimer(int) - * .addItems(Item) + * .item(Item) * .fuelRodType() * .build()); * } From 6dd461222619221fbef9912a1be830d9869afec4 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 25 Jul 2026 13:52:40 +0200 Subject: [PATCH 170/171] chore: tune overworld ore worldgen rarity and document nitrate drop-mechanism discrepancy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CNConfiguredFeatures: bump lead ore's OreConfiguration vein size from 10 to 12. - CNPlacedFeatures: rebalance ore placement counts — uranium 5 -> 4, thorium 8 -> 6 per chunk, and reduce striated_ores_overworld frequency from "on average once every 1 chunk" to once every 64 chunks (was effectively placed almost everywhere before). - Regenerate the corresponding datagen output (worldgen/configured_feature/lead_ore.json, worldgen/placed_feature/{striated_ores_overworld,thorium_ore,uranium_ore}.json). - AUDIT_ACTUEL.md: add a new "on hold" §2 note (per user request, 2026-07-25) flagging that Nitrate Ore's loot table uses vanilla minecraft:ore_drops while Thorium/Uranium use set_count + uniform_bonus_count — a pattern inconsistency to resolve later (harmonize or document as intentional), not addressed in this change. --- AUDIT_ACTUEL.md | 4 ++++ .../.cache/fed443662143001aeb5341375f6f5ef31d10baea | 10 +++++----- .../worldgen/configured_feature/lead_ore.json | 2 +- .../placed_feature/striated_ores_overworld.json | 2 +- .../worldgen/placed_feature/thorium_ore.json | 2 +- .../worldgen/placed_feature/uranium_ore.json | 2 +- .../infrastructure/worldgen/CNConfiguredFeatures.java | 2 +- .../infrastructure/worldgen/CNPlacedFeatures.java | 6 +++--- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 8114bb05..ca8ea08d 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -76,6 +76,10 @@ La dette la plus structurelle reste **l'absence de tests sur la majorité du cod 5. ~~**`CreateNuclearJEI`** — champ statique mutable `Categories`~~ — **résolu** (`e7900959`, 2026-07-13) : converti en champ d'instance `allCategories`, enfilé explicitement dans `CategoryBuilder`. Voir §8.1. 6. **`CNPonderReactorScenes.showReactorStructure`** — boucle triple (~11×13×13) avec comparaisons positionnelles ; coût ponctuel (ouverture ponder), remplaçable par une `Map` précalculée. +### ⏸️ Worldgen minerais — écarts relevés, **mis en attente à la demande de l'utilisateur (2026-07-25), à trancher plus tard** + +7. **Nitrate Ore — mécanisme de drop incohérent avec Thorium/Uranium** ([nitrate_ore.json](src/generated/resources/data/createnuclear/loot_tables/blocks/nitrate_ore.json)) : utilise la formule vanilla `minecraft:ore_drops` (bonus probabiliste façon charbon/diamant, count de base implicite = 1) alors que Thorium et Uranium utilisent `set_count` (min/max explicite) + `uniform_bonus_count` (`bonusMultiplier` fixe). Pas forcément un bug — peut être volontaire — mais rupture de pattern à trancher : soit harmoniser Nitrate sur le même système, soit documenter que c'est intentionnel. + --- ## 3. 🏗️ Architecture — points encore ouverts diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 145eb0e1..8563540a 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-07-25T12:28:12.5162369 CreateNuclear Generated Registry Entries +// 1.20.1 2026-07-25T13:29:59.5906396 CreateNuclear Generated Registry Entries 46e263393c1672a180bc12b99f9e39adf22e66b5 data/createnuclear/createnuclear/fluids/type/fallback.json 2837d5ecbd5735f39c1fac545469486e09c502e0 data/createnuclear/createnuclear/fluids/type/nitrogen.json 152a58adb9f86e1c9fac62fd2095ba8413142568 data/createnuclear/createnuclear/fluids/type/water.json @@ -11,7 +11,7 @@ 1d15657126bab7c0b4355d0dcb9addc2d417ed01 data/createnuclear/forge/biome_modifier/thorium_ore.json fa32145101dc12ec914684fec8c5cbb995d2c051 data/createnuclear/forge/biome_modifier/uranium_ore.json a3399faccac4549c2c7d41a5863883ecea074e99 data/createnuclear/worldgen/biome/irradiated_land.json -211d1391981d173b8bc490e5af1471441e1df37f data/createnuclear/worldgen/configured_feature/lead_ore.json +d9a89f0f1804d33867b4e0c28cbe0cf69ce131f5 data/createnuclear/worldgen/configured_feature/lead_ore.json c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_feature/nitrate_ore.json 4f11c0a518c0de7857919983fc638ba551c6630a data/createnuclear/worldgen/configured_feature/striated_ores_overworld.json aaa284a4e57635bf05f4539125b33a2f9176ed5b data/createnuclear/worldgen/configured_feature/thorium_ore.json @@ -22,6 +22,6 @@ b0e1ee7314412507fd7346cb48b29d105f6186ad data/createnuclear/worldgen/configured_ ea836bafce53bcb743cb2de5ba38271291483865 data/createnuclear/worldgen/noise_settings/irradiated_noise.json f11d981e79cf92130a47ad564925d7be26ffbc0b data/createnuclear/worldgen/placed_feature/lead_ore.json e69f61cbb4bf2c50a6123ddc87c024c801bb78d1 data/createnuclear/worldgen/placed_feature/nitrate_ore.json -b46fca88702d24526baa96e08b6b09b7c43e0563 data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json -403caabb9eefec1012db63d6cbd5c1f22ac9e88d data/createnuclear/worldgen/placed_feature/thorium_ore.json -3ecef6758d08745789d07e23377e348cf1ddb126 data/createnuclear/worldgen/placed_feature/uranium_ore.json +d0e47433fc86ee2acd9dde56f0465aae54fe5fe0 data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json +5e64cf339847e8c89e4bbb94a2382262a0ce66ac data/createnuclear/worldgen/placed_feature/thorium_ore.json +148db47005efc228a743e41fd60011b8bff8e78a data/createnuclear/worldgen/placed_feature/uranium_ore.json diff --git a/src/generated/resources/data/createnuclear/worldgen/configured_feature/lead_ore.json b/src/generated/resources/data/createnuclear/worldgen/configured_feature/lead_ore.json index 3c272941..1825d43f 100644 --- a/src/generated/resources/data/createnuclear/worldgen/configured_feature/lead_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/configured_feature/lead_ore.json @@ -2,7 +2,7 @@ "type": "minecraft:ore", "config": { "discard_chance_on_air_exposure": 0.0, - "size": 10, + "size": 12, "targets": [ { "state": { diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json index c217fb10..87db06f6 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/striated_ores_overworld.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:rarity_filter", - "chance": 1 + "chance": 64 }, { "type": "minecraft:in_square" diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json index 4eaee977..3a1cfe26 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/thorium_ore.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:count", - "count": 8 + "count": 6 }, { "type": "minecraft:in_square" diff --git a/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json b/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json index fa2d9e57..84872041 100644 --- a/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json +++ b/src/generated/resources/data/createnuclear/worldgen/placed_feature/uranium_ore.json @@ -3,7 +3,7 @@ "placement": [ { "type": "minecraft:count", - "count": 5 + "count": 4 }, { "type": "minecraft:in_square" diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java index a79a9ac9..cdee138f 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNConfiguredFeatures.java @@ -46,7 +46,7 @@ public static void bootstrap(BootstapContext> ctx) { OreConfiguration.target(stoneOreReplaceable, CNBlocks.LEAD_ORE.getDefaultState()), OreConfiguration.target(deepslateOreReplaceable, CNBlocks.DEEPSLATE_LEAD_ORE.getDefaultState()) ); - register(ctx, LEAD_ORE, Feature.ORE, new OreConfiguration(leadTargetStates, 10)); + register(ctx, LEAD_ORE, Feature.ORE, new OreConfiguration(leadTargetStates, 12)); List thoriumTargetStates = List.of( OreConfiguration.target(stoneOreReplaceable, CNBlocks.THORIUM_ORE.getDefaultState()), diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java index a4427c23..3a0e2221 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/CNPlacedFeatures.java @@ -35,11 +35,11 @@ public static void bootstrap(BootstapContext ctx) { Holder> nitrateOre = featureLookup.getOrThrow(CNConfiguredFeatures.NITRATE_ORE); Holder> striatedOresOverworld = featureLookup.getOrThrow(CNConfiguredFeatures.STRIATED_ORES_OVERWORLD); - register(ctx, URANIUM_ORE, uraniumOre, placementOres(CountPlacement.of(5), -63, 16)); + register(ctx, URANIUM_ORE, uraniumOre, placementOres(CountPlacement.of(4), -63, 16)); register(ctx, LEAD_ORE, leadOre, placementOres(CountPlacement.of(10), -16, 60)); - register(ctx, THORIUM_ORE, thoriumOre, placementOres(CountPlacement.of(8), -16, 55)); + register(ctx, THORIUM_ORE, thoriumOre, placementOres(CountPlacement.of(6), -16, 55)); register(ctx, NITRATE_ORE, nitrateOre, placementOres(CountPlacement.of(6), -63, 64)); - register(ctx, STRIATED_ORES_OVERWORLD, striatedOresOverworld, placement(RarityFilter.onAverageOnceEvery(1), -63, 16)); + register(ctx, STRIATED_ORES_OVERWORLD, striatedOresOverworld, placement(RarityFilter.onAverageOnceEvery(64), -63, 16)); } From dc13d396c868d707aeeeb3333d938dcbc5f822a5 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sat, 25 Jul 2026 17:30:27 +0200 Subject: [PATCH 171/171] feat: rename Biome Restore Cell into Biome Irradiation Extractor and add its Reinforced Glass Bottle recipe chain - Rename BiomeRestoreCellItem -> BiomeIrradationExtractorItem and the registered item biome_restore_cell -> biome_irradiation_extractor ("Biome Irradiation Extractor"), updating every reference (CNItems, CreateNuclearClient, CNBuilderTransformers) and the item model/texture path from item/biome_restore_cell/* to item/biome_irradiation_extractor/*. Old biome_restore_cell models and textures are deleted; new biome_irradiation_extractor models, advancement and lang entries are generated in their place. - The extractor is no longer a standalone craftable item: it now has a shaped crafting recipe (8x) from 8 Reinforced Glass Bottles + 1 Nether Star, gated behind a new has_reinforced_glass_bottle advancement/unlock, and its max stack size changes from 1 to 16. - Add a new REINFORCED_GLASS_BOTTLE item (CNItems), craftable (3x) from Reinforced Glass in a diamond pattern, with its own generated model, recipe and texture. - CBiomeRestore config: lower the default maxCharge from 16 to 8, and remove the now-unused alwaysShowBar option (and its comment). - tooltips.json: add a beta-warning tooltip and a biome_irradiation_extractor restorations-counter tooltip ("Restorations: %d / %d"); minor unrelated whitespace cleanup (removed stray blank lines). - Regenerate affected datagen output: en_us.json/en_ud.json lang files, the .cache index, and new recipe/advancement JSON for both biome_irradiation_extractor and reinforced_glass_bottle. --- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 21 +++++++---- .../assets/createnuclear/lang/en_ud.json | 5 ++- .../assets/createnuclear/lang/en_us.json | 5 ++- ....json => biome_irradiation_extractor.json} | 10 ++--- .../biome_irradiation_extractor/full.json | 6 +++ .../biome_irradiation_extractor/half.json | 6 +++ .../biome_irradiation_extractor/quarter.json | 6 +++ .../three_quarters.json | 6 +++ .../models/item/biome_restore_cell/half.json | 6 --- .../item/biome_restore_cell/quarter.json | 6 --- .../biome_restore_cell/three_quarters.json | 6 --- ...full.json => reinforced_glass_bottle.json} | 2 +- .../crafting/reinforced_glass_bottle.json | 35 ++++++++++++++++++ .../crafting/biome_irradiation_extractor.json | 35 ++++++++++++++++++ .../crafting/biome_irradiation_extractor.json | 22 +++++++++++ .../crafting/reinforced_glass_bottle.json | 18 +++++++++ .../nuclearteam/createnuclear/CNItems.java | 34 +++++++++++++---- .../createnuclear/CreateNuclearClient.java | 10 ++--- ...java => BiomeIrradationExtractorItem.java} | 35 +++++++++++++++--- .../data/CNBuilderTransformers.java | 14 +++---- .../infrastructure/config/CBiomeRestore.java | 5 +-- .../createnuclear/lang/default/tooltips.json | 4 +- .../biome_irradiation_extractor/empty.png | Bin 0 -> 534 bytes .../item/biome_irradiation_extractor/full.png | Bin 0 -> 572 bytes .../item/biome_irradiation_extractor/half.png | Bin 0 -> 558 bytes .../biome_irradiation_extractor/quarter.png | Bin 0 -> 546 bytes .../three_quarters.png | Bin 0 -> 566 bytes .../item/biome_restore_cell/empty.png | Bin 835 -> 0 bytes .../textures/item/biome_restore_cell/full.png | Bin 807 -> 0 bytes .../textures/item/biome_restore_cell/half.png | Bin 815 -> 0 bytes .../item/biome_restore_cell/quarter.png | Bin 841 -> 0 bytes .../biome_restore_cell/three_quarters.png | Bin 819 -> 0 bytes .../textures/item/reinforced_glass_bottle.png | Bin 0 -> 509 bytes 33 files changed, 233 insertions(+), 64 deletions(-) rename src/generated/resources/assets/createnuclear/models/item/{biome_restore_cell.json => biome_irradiation_extractor.json} (54%) create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/full.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/half.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/quarter.json create mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/three_quarters.json delete mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json delete mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json delete mode 100644 src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json rename src/generated/resources/assets/createnuclear/models/item/{biome_restore_cell/full.json => reinforced_glass_bottle.json} (51%) create mode 100644 src/generated/resources/data/createnuclear/advancements/recipes/brewing/crafting/reinforced_glass_bottle.json create mode 100644 src/generated/resources/data/createnuclear/advancements/recipes/misc/crafting/biome_irradiation_extractor.json create mode 100644 src/generated/resources/data/createnuclear/recipes/crafting/biome_irradiation_extractor.json create mode 100644 src/generated/resources/data/createnuclear/recipes/crafting/reinforced_glass_bottle.json rename src/main/java/net/nuclearteam/createnuclear/content/biome/{BiomeRestoreCellItem.java => BiomeIrradationExtractorItem.java} (64%) create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/empty.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/full.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/half.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/quarter.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/three_quarters.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/empty.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/full.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/half.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/quarter.png delete mode 100644 src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/three_quarters.png create mode 100644 src/main/resources/assets/createnuclear/textures/item/reinforced_glass_bottle.png diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index d180ad3e..3be1c5e7 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-07-13T13:10:31.7900303 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-07-25T17:11:58.5826537 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -85c5d84aa370008d3ebd1059ae9f01384c84ad92 assets/createnuclear/lang/en_ud.json -d9642fb0dc87dba15b8b9952591d2c9d901866c9 assets/createnuclear/lang/en_us.json +2bc4073631a9c4665f643e94b16e21956660b366 assets/createnuclear/lang/en_ud.json +3e88627550ba81bd8f7df9b720fd04afbc816f1b assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json @@ -119,11 +119,11 @@ d234edb3b6bc81b7300ee65722973b66db0b82d9 assets/createnuclear/models/block/urani a4d5ee44c830e329034a46792280edea53343034 assets/createnuclear/models/block/uranium_ore.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/item/autunite.json 30b11d8da5d02a3e9cebb739b3b9efbee087573c assets/createnuclear/models/item/autunite_pillar.json -28aecd314b7f04b49ab32f2edd943b9281d49c65 assets/createnuclear/models/item/biome_restore_cell.json -a37e2ee1f055b543b19d919e7755de6f60147263 assets/createnuclear/models/item/biome_restore_cell/full.json -caa3620ba4350002f5ac7016be82ab19cd4ae957 assets/createnuclear/models/item/biome_restore_cell/half.json -2969af139b314746afbf862710e8cf2fe7694d7c assets/createnuclear/models/item/biome_restore_cell/quarter.json -a34a98be95112a5ba17cac7eaa78de8d5550ca79 assets/createnuclear/models/item/biome_restore_cell/three_quarters.json +dd462819c7477f9d416f6783b27651385d3ac16f assets/createnuclear/models/item/biome_irradiation_extractor.json +55f1cb77f9e4decaa0ed9a08e71aa861c6e05366 assets/createnuclear/models/item/biome_irradiation_extractor/full.json +c9ea333225e88893332265930dc3a52dce185cf9 assets/createnuclear/models/item/biome_irradiation_extractor/half.json +0cbeee214db51866795c62777e45ca5ed980d7e7 assets/createnuclear/models/item/biome_irradiation_extractor/quarter.json +c8a996760a2e68b408df64fe3702fd8933908e35 assets/createnuclear/models/item/biome_irradiation_extractor/three_quarters.json 3036f3b383b40ca2021856366cd0f01cb279285b assets/createnuclear/models/item/black_cloth.json 3a5955f81eeed80e907bf8e2ee4df14fe42843f0 assets/createnuclear/models/item/blue_cloth.json 8cdcca32a87171e2c709e762165330b2f0389f90 assets/createnuclear/models/item/brown_cloth.json @@ -257,6 +257,7 @@ ee9b06de6d4e5f722543a83e5d9f7564ac6d7f70 assets/createnuclear/models/item/reacto 08b156175821e1ce7820783f2f1ba92924e54a7d assets/createnuclear/models/item/reactor_rod_input.json 4db93da70d6a7549155201b7d9d68355449652ac assets/createnuclear/models/item/red_cloth.json 78a9e80073512a111cb936a516d290a824846ff2 assets/createnuclear/models/item/reinforced_glass.json +736521abdac62d6fa4292aafb8c86bb3d7c9623f assets/createnuclear/models/item/reinforced_glass_bottle.json 60dc6eb917ee1567461f02aca765e061d3d9f55a assets/createnuclear/models/item/small_autunite_brick.json 9b83b53d90891eaf7aa4693eafe2876a831e0be2 assets/createnuclear/models/item/small_autunite_brick_slab.json 3e80ef1d80473c73a723d3c4b5c1409c7998d70f assets/createnuclear/models/item/small_autunite_brick_stairs.json @@ -279,6 +280,7 @@ ea04609e8b5c12a7805b1c564bca07fefd6d38ba assets/createnuclear/models/item/uraniu 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/createnuclear/models/item/wolf_irradiated_spawn_egg.json 8bdc2fabbfc9fcc7c2ad4a3273897659d90b95ab assets/createnuclear/models/item/yellowcake.json a1970879fd57836f5ae5d23352cdca277095bc7d assets/createnuclear/models/item/yellow_cloth.json +dabba9d38be6825bc8c7684f10de5e23f5d2870f data/createnuclear/advancements/recipes/brewing/crafting/reinforced_glass_bottle.json 72b0cec0c98e9ead9562ff0cc1231a5028e2a22f data/createnuclear/advancements/recipes/building_blocks/autunite_from_stone_types_autunite_stonecutting.json e7967751f132676cb1d523743adaac3aea1f0814 data/createnuclear/advancements/recipes/building_blocks/autunite_pillar_from_stone_types_autunite_stonecutting.json 8e9cfc8ab1ddd7b818cb52cbd0fb60c0c4713bad data/createnuclear/advancements/recipes/building_blocks/crafting/enriched_soul_soil.json @@ -403,6 +405,7 @@ dfd6b4a2aadbd3c301bb02e980f7790caa4a3746 data/createnuclear/advancements/recipes 0d806e128a0eab473c822824e1914cd39d684efa data/createnuclear/advancements/recipes/decorations/crafting/raw_lead_block.json 570d06b2ab9f3b2d9d8265baac395e896e8b171e data/createnuclear/advancements/recipes/decorations/crafting/raw_uranium_block.json eafffaaada04af83623ebf8e940df2b507d933eb data/createnuclear/advancements/recipes/decorations/crafting/reactor/reinforced_glass.json +f9cc69b93befb0fda996ebe1c9d5e48c1753ed3b data/createnuclear/advancements/recipes/misc/crafting/biome_irradiation_extractor.json 0221cf60748260f92b94be675249afc98de1d707 data/createnuclear/advancements/recipes/misc/crafting/enriching_campfire.json cc3ec047cc113f80a1163aeb2277dad33af8e424 data/createnuclear/advancements/recipes/misc/crafting/lead_ingot_from_decompacting.json 58477747b204491c22a9aecb751d99054f71310b data/createnuclear/advancements/recipes/misc/crafting/lead_nugget_from_decompacting.json @@ -467,6 +470,7 @@ fba1a7bdb0835c034aa5ef52ebf589123d41b33e data/createnuclear/loot_tables/entities f91f43a39c80f583f878ea1a0d944798c05f2388 data/createnuclear/loot_tables/entities/irradiated_wolf.json 4c985d77908c367245c3b4d56e1302a843522eff data/createnuclear/recipes/autunite_from_stone_types_autunite_stonecutting.json 9819e80259d08c1518b30ee9d4cf5c18689d3efc data/createnuclear/recipes/autunite_pillar_from_stone_types_autunite_stonecutting.json +163d7fc43633fd6ebdc124a487e55e427f47d147 data/createnuclear/recipes/crafting/biome_irradiation_extractor.json af0091392c2d5784455a57783bfa62d0d60d13ae data/createnuclear/recipes/crafting/enriched_soul_soil.json 3ce1aa65e8260fbe5fe84c9064b8de3745762605 data/createnuclear/recipes/crafting/enriching_campfire.json 3c2942b0a34c94bf074e19169a7f35834d5cb1cb data/createnuclear/recipes/crafting/items/armors/default_anti_radiation_boots.json @@ -483,6 +487,7 @@ befcdaaf4abf86e29d7f7008d489638c5f3cd6bd data/createnuclear/recipes/crafting/raw 997f2bf339dd63253d9a98d16a9efeffac4eea81 data/createnuclear/recipes/crafting/raw_uranium_from_decompacting.json a7ff79f9d11a46e52fb25819a7c9e9604e8a317a data/createnuclear/recipes/crafting/reactor/reinforced_glass.json 77f77148406d34c065b55efa9d6e7a2b107831c5 data/createnuclear/recipes/crafting/reactor_blueprint_item.json +236a031ceec7fa78e963941df8eec874a2d589fe data/createnuclear/recipes/crafting/reinforced_glass_bottle.json ae6d07dc30751bfa39edbcdb8758a2faababa5da data/createnuclear/recipes/crafting/steel_ingot_from_decompacting.json 5fb04284d66de4bf54471a3db0d9a3bfa6b7a18c data/createnuclear/recipes/crafting/steel_nugget_from_decompacting.json 047c50559746a9ffb5835ff960ba500400e7e299 data/createnuclear/recipes/crafting/thorium_ingot_from_decompacting.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 57340f50..66ef52f5 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -296,6 +296,7 @@ "createnuclear.subtitle.reacteur/running": "buıuunᴚ ɹoʇɔɐǝᴚ", "createnuclear.subtitle.reacteur/shut_off": "ɟɟO ʇnɥS ɹoʇɔɐǝᴚ", "createnuclear.tooltip.baseRodHeat": "Ὁ %d :ʇɐǝH poᴚ ǝsɐᗺ", + "createnuclear.tooltip.biome_irradiation_extractor.biome_restore": "%d / %d :suoıʇɐɹoʇsǝᴚ", "createnuclear.tooltip.fluid": " %s :pınןℲ", "createnuclear.tooltip.fluid.amount": "qɯ %d", "createnuclear.tooltip.fluid.none": " ǝuoN :pınןℲ", @@ -331,7 +332,8 @@ "gui.createnuclear.reactor_controller.title": "ɹǝןןoɹʇuoƆ ɹoʇɔɐǝᴚ", "gui.createnuclear.reactor_input.title": "ǝbɐɹoʇS ʇnduI ɹoʇɔɐǝᴚ", "irradiated.taming.wip": "ssǝɹboɹd uı ʞɹoʍ ɐ ןןıʇs ǝɹɐ sqoɯ pǝʇɐıpɐɹɹı - ʇǝʎ pǝɯɐʇ ǝq ʇouuɐɔ ǝɹnʇɐǝɹɔ sıɥ⟘", - "item.createnuclear.biome_restore_cell": "ןןǝƆ ǝɹoʇsǝᴚ ǝɯoıᗺ", + "item.createnuclear.biome_irradiation_extractor": "ɹoʇɔɐɹʇxƎ uoıʇɐıpɐɹɹI ǝɯoıᗺ", + "item.createnuclear.biome_irradiation_extractor.tooltip.summary": "˙ǝʇɐpdn ʇxǝu ǝɥʇ uı ǝɹnʇxǝʇ & ɯɹoɟ s,ʇı ǝbuɐɥɔ ןןıʍ puɐ ‾ɐʇǝq‾ uı ʎןʇuǝɹɹnɔ sı ɯǝʇı sıɥ⟘", "item.createnuclear.black_cloth": "ɥʇoןƆ ʞɔɐןᗺ", "item.createnuclear.blue_cloth": "ɥʇoןƆ ǝnןᗺ", "item.createnuclear.brown_cloth": "ɥʇoןƆ uʍoɹᗺ", @@ -376,6 +378,7 @@ "item.createnuclear.reactor_blueprint_item.tooltip.condition2": "pǝןqɯǝssɐ ǝq ʇsnɯ ɹoʇɔɐǝɹ ǝɥ⟘", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "˙uɹǝʇʇɐd uʍo ɹnoʎ ǝɹnbıɟuoɔ oʇ noʎ sʍoןןɐ ʇI", "item.createnuclear.red_cloth": "ɥʇoןƆ pǝᴚ", + "item.createnuclear.reinforced_glass_bottle": "ǝןʇʇoᗺ ssɐן⅁ pǝɔɹoɟuıǝᴚ", "item.createnuclear.steel_ingot": "ʇobuI ןǝǝʇS", "item.createnuclear.steel_nugget": "ʇǝbbnN ןǝǝʇS", "item.createnuclear.thorium_bucket": "ʇǝʞɔnᗺ ɯnıɹoɥ⟘", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index d5d3a31a..b994eb5e 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -296,6 +296,7 @@ "createnuclear.subtitle.reacteur/running": "Reactor Running", "createnuclear.subtitle.reacteur/shut_off": "Reactor Shut Off", "createnuclear.tooltip.baseRodHeat": "Base Rod Heat: %d Q", + "createnuclear.tooltip.biome_irradiation_extractor.biome_restore": "Restorations: %d / %d", "createnuclear.tooltip.fluid": "Fluid: %s ", "createnuclear.tooltip.fluid.amount": "%d mb", "createnuclear.tooltip.fluid.none": "Fluid: None ", @@ -331,7 +332,8 @@ "gui.createnuclear.reactor_controller.title": "Reactor Controller", "gui.createnuclear.reactor_input.title": "Reactor Input Storage", "irradiated.taming.wip": "This creature cannot be tamed yet - irradiated mobs are still a work in progress", - "item.createnuclear.biome_restore_cell": "Biome Restore Cell", + "item.createnuclear.biome_irradiation_extractor": "Biome Irradiation Extractor", + "item.createnuclear.biome_irradiation_extractor.tooltip.summary": "This item is currently in _beta_ and will change it's form & texture in the next update.", "item.createnuclear.black_cloth": "Black Cloth", "item.createnuclear.blue_cloth": "Blue Cloth", "item.createnuclear.brown_cloth": "Brown Cloth", @@ -376,6 +378,7 @@ "item.createnuclear.reactor_blueprint_item.tooltip.condition2": "The reactor must be assembled", "item.createnuclear.reactor_blueprint_item.tooltip.summary": "It allows you to configure your own pattern.", "item.createnuclear.red_cloth": "Red Cloth", + "item.createnuclear.reinforced_glass_bottle": "Reinforced Glass Bottle", "item.createnuclear.steel_ingot": "Steel Ingot", "item.createnuclear.steel_nugget": "Steel Nugget", "item.createnuclear.thorium_bucket": "Thorium Bucket", diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor.json similarity index 54% rename from src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json rename to src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor.json index 4e0bf8e0..5afa3b26 100644 --- a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell.json +++ b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor.json @@ -2,31 +2,31 @@ "parent": "minecraft:item/generated", "overrides": [ { - "model": "createnuclear:item/biome_restore_cell/quarter", + "model": "createnuclear:item/biome_irradiation_extractor/quarter", "predicate": { "createnuclear:biome_restore": 0.25 } }, { - "model": "createnuclear:item/biome_restore_cell/half", + "model": "createnuclear:item/biome_irradiation_extractor/half", "predicate": { "createnuclear:biome_restore": 0.5 } }, { - "model": "createnuclear:item/biome_restore_cell/three_quarters", + "model": "createnuclear:item/biome_irradiation_extractor/three_quarters", "predicate": { "createnuclear:biome_restore": 0.75 } }, { - "model": "createnuclear:item/biome_restore_cell/full", + "model": "createnuclear:item/biome_irradiation_extractor/full", "predicate": { "createnuclear:biome_restore": 1.0 } } ], "textures": { - "layer0": "createnuclear:item/biome_restore_cell/empty" + "layer0": "createnuclear:item/biome_irradiation_extractor/empty" } } \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/full.json b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/full.json new file mode 100644 index 00000000..1f07daec --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/full.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_irradiation_extractor/full" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/half.json b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/half.json new file mode 100644 index 00000000..25634c8a --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/half.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_irradiation_extractor/half" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/quarter.json b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/quarter.json new file mode 100644 index 00000000..35b311ab --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/quarter.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_irradiation_extractor/quarter" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/three_quarters.json b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/three_quarters.json new file mode 100644 index 00000000..dd251fd8 --- /dev/null +++ b/src/generated/resources/assets/createnuclear/models/item/biome_irradiation_extractor/three_quarters.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "createnuclear:item/biome_irradiation_extractor/three_quarters" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json deleted file mode 100644 index 2364e432..00000000 --- a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/half.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "createnuclear:item/biome_restore_cell/half" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json deleted file mode 100644 index a5d1a4d9..00000000 --- a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/quarter.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "createnuclear:item/biome_restore_cell/quarter" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json b/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json deleted file mode 100644 index 9f589b37..00000000 --- a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/three_quarters.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "createnuclear:item/biome_restore_cell/three_quarters" - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json b/src/generated/resources/assets/createnuclear/models/item/reinforced_glass_bottle.json similarity index 51% rename from src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json rename to src/generated/resources/assets/createnuclear/models/item/reinforced_glass_bottle.json index 057d5cf5..c29947f4 100644 --- a/src/generated/resources/assets/createnuclear/models/item/biome_restore_cell/full.json +++ b/src/generated/resources/assets/createnuclear/models/item/reinforced_glass_bottle.json @@ -1,6 +1,6 @@ { "parent": "minecraft:item/generated", "textures": { - "layer0": "createnuclear:item/biome_restore_cell/full" + "layer0": "createnuclear:item/reinforced_glass_bottle" } } \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/advancements/recipes/brewing/crafting/reinforced_glass_bottle.json b/src/generated/resources/data/createnuclear/advancements/recipes/brewing/crafting/reinforced_glass_bottle.json new file mode 100644 index 00000000..d668153c --- /dev/null +++ b/src/generated/resources/data/createnuclear/advancements/recipes/brewing/crafting/reinforced_glass_bottle.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_reinforced_glass": { + "conditions": { + "items": [ + { + "items": [ + "createnuclear:reinforced_glass" + ] + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "createnuclear:crafting/reinforced_glass_bottle" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_reinforced_glass", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "createnuclear:crafting/reinforced_glass_bottle" + ] + }, + "sends_telemetry_event": false +} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/advancements/recipes/misc/crafting/biome_irradiation_extractor.json b/src/generated/resources/data/createnuclear/advancements/recipes/misc/crafting/biome_irradiation_extractor.json new file mode 100644 index 00000000..ffc2d3d6 --- /dev/null +++ b/src/generated/resources/data/createnuclear/advancements/recipes/misc/crafting/biome_irradiation_extractor.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_reinforced_glass_bottle": { + "conditions": { + "items": [ + { + "items": [ + "createnuclear:reinforced_glass_bottle" + ] + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "createnuclear:crafting/biome_irradiation_extractor" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_reinforced_glass_bottle", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "createnuclear:crafting/biome_irradiation_extractor" + ] + }, + "sends_telemetry_event": false +} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/crafting/biome_irradiation_extractor.json b/src/generated/resources/data/createnuclear/recipes/crafting/biome_irradiation_extractor.json new file mode 100644 index 00000000..614a619f --- /dev/null +++ b/src/generated/resources/data/createnuclear/recipes/crafting/biome_irradiation_extractor.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "B": { + "item": "createnuclear:reinforced_glass_bottle" + }, + "S": { + "item": "minecraft:nether_star" + } + }, + "pattern": [ + "BBB", + "BSB", + "BBB" + ], + "result": { + "count": 8, + "item": "createnuclear:biome_irradiation_extractor" + }, + "show_notification": true +} \ No newline at end of file diff --git a/src/generated/resources/data/createnuclear/recipes/crafting/reinforced_glass_bottle.json b/src/generated/resources/data/createnuclear/recipes/crafting/reinforced_glass_bottle.json new file mode 100644 index 00000000..2fb590a3 --- /dev/null +++ b/src/generated/resources/data/createnuclear/recipes/crafting/reinforced_glass_bottle.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "G": { + "item": "createnuclear:reinforced_glass" + } + }, + "pattern": [ + "G G", + " G " + ], + "result": { + "count": 3, + "item": "createnuclear:reinforced_glass_bottle" + }, + "show_notification": true +} \ No newline at end of file diff --git a/src/main/java/net/nuclearteam/createnuclear/CNItems.java b/src/main/java/net/nuclearteam/createnuclear/CNItems.java index 992f06c1..792edaef 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNItems.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNItems.java @@ -14,7 +14,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.ForgeSpawnEggItem; -import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; +import net.nuclearteam.createnuclear.content.biome.BiomeIrradationExtractorItem; import net.nuclearteam.createnuclear.foundation.data.CNBuilderTransformers; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import net.nuclearteam.createnuclear.api.data.recipe.SmithingClothRecipeBuilder; @@ -364,8 +364,8 @@ public class CNItems { .tag(CNItemTags.CLOTH.tag) .recipe((c, p) -> ShapelessRecipeBuilder.shapeless(RecipeCategory.BUILDING_BLOCKS, c.get()) .unlockedBy("has_white_cloth", RegistrateRecipeProvider.has(ClothItem.Cloths.WHITE_CLOTH.getItem())) - // Accept any cloth EXCEPT one already of the target colour, otherwise the - // recipe would let you "dye" a cloth into the colour it already is. + // Accept any cloth EXCEPT one already of the target color, otherwise the + // recipe would let you "dye" a cloth into the color it already is. .requires(Ingredient.of(Arrays.stream(DyeColor.values()) .filter(other -> other != color) .map(other -> ClothItem.Cloths.getByColor(other).get()) @@ -405,10 +405,30 @@ public class CNItems { .properties(p -> p.stacksTo(1)) .register(); - public static final ItemEntry BIOME_RESTORE_CELL = CreateNuclear.REGISTRATE - .item("biome_restore_cell", BiomeRestoreCellItem::new) - .lang("Biome Restore Cell") - .properties(p -> p.stacksTo(1).fireResistant().setNoRepair()) + public static final ItemEntry REINFORCED_GLASS_BOTTLE = CreateNuclear.REGISTRATE + .item("reinforced_glass_bottle", Item::new) + .lang("Reinforced Glass Bottle") + .recipe((c, p) -> ShapedRecipeBuilder.shaped(RecipeCategory.BREWING, c.get(), 3) + .unlockedBy("has_reinforced_glass", RegistrateRecipeProvider.has(CNBlocks.REINFORCED_GLASS.get())) + .define('G', CNBlocks.REINFORCED_GLASS) + .pattern("G G") + .pattern(" G ") + .save(p, CreateNuclear.asResource("crafting/" + c.getName()))) + .properties(p -> p.stacksTo(16)) + .register(); + + public static final ItemEntry IRRADIATION_BIOME_EXTRACTOR = CreateNuclear.REGISTRATE + .item("biome_irradiation_extractor", BiomeIrradationExtractorItem::new) + .lang("Biome Irradiation Extractor") + .recipe((c, p) -> ShapedRecipeBuilder.shaped(RecipeCategory.MISC, c.get(), 8) + .unlockedBy("has_reinforced_glass_bottle", RegistrateRecipeProvider.has(CNItems.REINFORCED_GLASS_BOTTLE.get())) + .define('B', CNItems.REINFORCED_GLASS_BOTTLE) + .define('S', Items.NETHER_STAR) + .pattern("BBB") + .pattern("BSB") + .pattern("BBB") + .save(p, CreateNuclear.asResource("crafting/" + c.getName()))) + .properties(p -> p.stacksTo(16).fireResistant().setNoRepair()) .model(biomeRestoreModel()) .register(); diff --git a/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java b/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java index 417266ce..53553613 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java +++ b/src/main/java/net/nuclearteam/createnuclear/CreateNuclearClient.java @@ -12,7 +12,7 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.nuclearteam.createnuclear.content.particles.NuclearMushroomCloudParticle; import net.nuclearteam.createnuclear.content.particles.SmallNuclearExplosionParticle; -import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; +import net.nuclearteam.createnuclear.content.biome.BiomeIrradationExtractorItem; import net.nuclearteam.createnuclear.foundation.ponder.CreateNuclearPonderPlugin; import net.nuclearteam.createnuclear.foundation.utility.ClothTagHelper; @@ -64,14 +64,14 @@ private static void clothItemProperties() { * model to pick a texture variant based on its current charge ratio (0.0 = empty, 1.0 = full). */ private static void biomeRestoreItemProperties() { - ResourceLocation biomeRestore = CreateNuclear.asResource(BiomeRestoreCellItem.TAG); + ResourceLocation biomeRestore = CreateNuclear.asResource(BiomeIrradationExtractorItem.TAG); ClampedItemPropertyFunction fn = ((stack, level, entity, seed) -> { - int max = BiomeRestoreCellItem.getMaxCharge(); + int max = BiomeIrradationExtractorItem.getMaxCharge(); - return (float) BiomeRestoreCellItem.getChargeTag(stack, 0) / max; + return (float) BiomeIrradationExtractorItem.getChargeTag(stack, 0) / max; }); - ItemProperties.register(CNItems.BIOME_RESTORE_CELL.get(), biomeRestore, fn); + ItemProperties.register(CNItems.IRRADIATION_BIOME_EXTRACTOR.get(), biomeRestore, fn); } public static void setupParticles(RegisterParticleProvidersEvent registry) { diff --git a/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java b/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeIrradationExtractorItem.java similarity index 64% rename from src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java rename to src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeIrradationExtractorItem.java index 518eaa03..480e64a1 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeRestoreCellItem.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/biome/BiomeIrradationExtractorItem.java @@ -1,6 +1,8 @@ package net.nuclearteam.createnuclear.content.biome; +import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; @@ -8,15 +10,19 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; +import net.nuclearteam.createnuclear.foundation.utility.CreateNuclearLang; import net.nuclearteam.createnuclear.infrastructure.config.CNConfigs; import net.nuclearteam.createnuclear.infrastructure.worldgen.biome.BiomeIrradiationService; -public class BiomeRestoreCellItem extends Item { +import java.util.List; + +public class BiomeIrradationExtractorItem extends Item { public static final String TAG = "biome_restore"; private static final int CHARGE_PER_CLICK = 1; - public BiomeRestoreCellItem(Properties pProperties) { + public BiomeIrradationExtractorItem(Properties pProperties) { super(pProperties); } @@ -33,14 +39,33 @@ public InteractionResultHolder use(Level level, Player player, Intera boolean restored = BiomeIrradiationService.restoreArea(serverLevel, player.blockPosition()); if (!restored) return InteractionResultHolder.pass(stack); - addCharge(stack, CHARGE_PER_CLICK); + ItemStack charged = stack.copyWithCount(1); + addCharge(charged, CHARGE_PER_CLICK); + + stack.shrink(1); + if (stack.isEmpty()) { + return InteractionResultHolder.success(charged); + } + if (!player.getInventory().add(charged)) { + player.drop(charged, false); + } return InteractionResultHolder.success(stack); } @Override - public boolean isBarVisible(ItemStack stack) { - return CNConfigs.server().biomeRestore.alwaysShowBar.get() || getCharge(stack) > 0; + public void appendHoverText(ItemStack stack, Level level, List tooltip, TooltipFlag tooltipFlag) { + super.appendHoverText(stack, level, tooltip, tooltipFlag); + if (tooltipFlag.isAdvanced() && getCharge(stack) > 0) { + tooltip + .add(CreateNuclearLang.translateDirect("tooltip.biome_irradiation_extractor." + TAG, getCharge(stack), getMaxCharge()) + .withStyle(ChatFormatting.GRAY)); + } + } + + @Override + public int getMaxStackSize(ItemStack stack) { + return getCharge(stack) > 0 ? 1 : this.getMaxStackSize(); } @Override diff --git a/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java b/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java index de448ca4..d54fcaae 100644 --- a/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java +++ b/src/main/java/net/nuclearteam/createnuclear/foundation/data/CNBuilderTransformers.java @@ -12,7 +12,7 @@ import net.minecraftforge.client.model.generators.ItemModelBuilder; import net.minecraftforge.common.ForgeSpawnEggItem; import net.nuclearteam.createnuclear.CreateNuclear; -import net.nuclearteam.createnuclear.content.biome.BiomeRestoreCellItem; +import net.nuclearteam.createnuclear.content.biome.BiomeIrradationExtractorItem; import java.util.List; import java.util.function.Supplier; @@ -65,7 +65,7 @@ public static NonNullBiConsumer, Regist */ public static NonNullBiConsumer, RegistrateItemModelProvider> biomeRestoreModel() { return (c, p) -> { - ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/biome_restore_cell/empty")); + ItemModelBuilder outer = p.generated(c, CreateNuclear.asResource("item/biome_irradiation_extractor/empty")); record Tier(String name, float threshold) {} List tiers = List.of( @@ -76,13 +76,13 @@ record Tier(String name, float threshold) {} ); for (Tier tier : tiers) { - ItemModelBuilder child = p.withExistingParent("item/biome_restore_cell/" + tier.name(), p.mcLoc("item/generated")) - .texture("layer0", CreateNuclear.asResource("item/biome_restore_cell/" + tier.name())); + ItemModelBuilder child = p.withExistingParent("item/biome_irradiation_extractor/" + tier.name(), p.mcLoc("item/generated")) + .texture("layer0", CreateNuclear.asResource("item/biome_irradiation_extractor/" + tier.name())); outer.override() - .predicate(CreateNuclear.asResource(BiomeRestoreCellItem.TAG), tier.threshold()) - .model(child) - .end(); + .predicate(CreateNuclear.asResource(BiomeIrradationExtractorItem.TAG), tier.threshold()) + .model(child) + .end(); } }; } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java index eba118a1..38721c2e 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/config/CBiomeRestore.java @@ -3,8 +3,7 @@ import net.createmod.catnip.config.ConfigBase; public class CBiomeRestore extends ConfigBase { - public final ConfigInt maxCharge = i(16, 1, 64, "maxCharge", Comments.maxCharge); - public final ConfigBool alwaysShowBar = b(false, "alwaysShowBar", Comments.alwaysShowBar); + public final ConfigInt maxCharge = i(8, 1, 64, "maxCharge", Comments.maxCharge); public final ConfigBool restoreInCircle = b(false, "restoreInCircle", Comments.restoreInCircle); public final ConfigInt restoreRadiusChunks = i(1, 1, 3, "restoreRadiusChunks", Comments.restoreRadiusChunks); @@ -15,8 +14,6 @@ public String getName() { private static class Comments { static String maxCharge = "Maximum number of charges the Biome Restore Cell can hold."; - static String alwaysShowBar = "If true, the durability-style bar is always shown, even when the cell is empty. " - + "If false, the bar is hidden when the charge is 0."; static String restoreInCircle = "If true, restoring a chunk also restores nearby chunks in a circle " + "(see restoreRadiusChunks). If false, only the chunk the player stands in is restored."; static String restoreRadiusChunks = "Radius in chunks used when restoreInCircle is true (1 to 3)."; diff --git a/src/main/resources/assets/createnuclear/lang/default/tooltips.json b/src/main/resources/assets/createnuclear/lang/default/tooltips.json index 6e027b70..1aaa260f 100644 --- a/src/main/resources/assets/createnuclear/lang/default/tooltips.json +++ b/src/main/resources/assets/createnuclear/lang/default/tooltips.json @@ -51,6 +51,8 @@ "block.createnuclear.enriched_soul_soil.tooltip.summary": "The _only_ block who create _enriched fire_.Can be used to _craft_ enriched campfire or just to make a _green fire_.", + "item.createnuclear.biome_irradiation_extractor.tooltip.summary": "This item is currently in _beta_ and will change it's form & texture in the next update.", + "createnuclear.tooltip.biome_irradiation_extractor.biome_restore": "Restorations: %d / %d", "createnuclear.tooltip.statRod": "Rod Stat Pattern:", "createnuclear.tooltip.baseRodHeat": "Base Rod Heat: %d Q", @@ -74,7 +76,5 @@ "tag.item.trinkets.head.face": "Head Face", - - "attribute.name.createnuclear.generic.irradiated_resistance": "Radiation Resistance" } \ No newline at end of file diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/empty.png b/src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..fd63d514a3c1583260b7ac3214fae676eb196f97 GIT binary patch literal 534 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}Z0G|-oE4iL4-BpVk=ejz&1w`jhHy6t+pQxaslU+I4(!tNb%xT}LQ^zh} zIDG!}>1)@#Leefgy6fN>3Do_;I(RRT5-thy3;vG*7&g`3;Q&f=7I;J!GcfQS1YyP< z6SLm}1tm*dBT9nv(@M${i&7Z^5;OBk^!!{y6ioFD^$d-K8Qn{Oigu(%c&2%JYB7L} zVP%kFWMyCkvb=y;8p;NFS%Z-oEY1XE8!|F62m*AXODo@guhD}-53P84fgCh!TgCqYVm~QTbqvM{+{TyLZ^Lm8NS%G}-0G|-oE4iL4-BpVk=ejz&1w`jhHy6t+pZMgfvVw|EcID*ML%fy_ex}(h z({G9xm^pb&VH5RW*mvsGvC9_@pFe&2+BL6`vKt-Gd9+AZi415Pcm~qF%?6+W@t`Q}{`DrEPiAAXl0g0J;C3=3YAqu8?hI)oZ z!i?@EKt(%JBRtbQJ+&A(fE-o^DMnTXMj*=zh^3)yP*7+vGK0mLfNVoXCI&$u9R2NOb{>AX|Xn|~~}vG^Z@kkbSysrUK5ygT2%yZwpTwz0$^zHtUqe}uytR-sE; z@c|ON+0U50jEg*2t1emC#Rqq~P5O0jvE^}#v$qxN@9WL|Dtx(dE^ivh4W6!kF6*2U FngEY}r|19x literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/half.png b/src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/half.png new file mode 100644 index 0000000000000000000000000000000000000000..1f22e807bd44e36bf86f2db13334de706f3434df GIT binary patch literal 558 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}l0G|-oE4iL4-BpVk=ejz&1w`jhHy6t+pQxaslU+I4(!tNb%*iyHCG`-m zs0YKoQ>Q$pupPU6;qdv>r>|Y}3Q4>0=&pljB+#U_t`C4DgLp}hU+{mdfZ>_LvpAp< z&H|6fVg?4jgCNYfV`BDOprB-lYeY$Kep*R+Vo@qXKw@TIiJqTph=Qq}p`M|UFr#}3 zP|=Rm2+uT6Pb~%xAcvJfijkFp5ye&Heg%;F&AVf>jH>b(|~LcU;>)V1XdYj zX#r$Gbr~8MfMnZt8-#7S!ngs*O!IVc4ABTKJs-~3V8FwCfzK_&K>Ggw6)QrfFe$}f zoSdWDw%)Klp{KUt^S#|dTG_8xv6$stE^6GP@N74eOl!)C2RG)(sWy78zhHN5jzR!y vo1rti#NS%G}}0G|-oE4iL4-BpVk=ejz&1w`jhHy6t+pQxaslU+I4(!tNb%xT}LQ=%RW zrr9jVE?+o&{`Bc<*Stc~Eeh%9Dc z;5!Jyj5{V~zXb|PmbgZg1m~xflqVLYG6W=M=9TFAxrQj1>KW=88VNJHmjD&*NR9AJ z^YqkW-~e)18Kf9l85n^qFCdnNvO!+gU}Of1GXdF#j7$uIKspMDGuv6f;yFMz2;3}V zWOxA#AsCHrD+2>iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oIWG1l6AWI7%3#!Y| zzyKuMw%Z_V%N52AKxUGsi(`mJaOwF-z6J#zmJ6F!1iWrK_xF4j1M86!;gy-{x(lnn zu)Dlsy(O_YdV?45HrAdQMIRepE1dhyW+KC&x4=-XzsNbqq04i^{$f`BO(%A}UD&dz kW5?n)rZW%Ebl0rg%Mf~BuwOZqLk(oJr>mdKI;Vst07aUcM*si- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/three_quarters.png b/src/main/resources/assets/createnuclear/textures/item/biome_irradiation_extractor/three_quarters.png new file mode 100644 index 0000000000000000000000000000000000000000..fc46c1842f5614c78237a0e8d321108e0b8df478 GIT binary patch literal 566 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G|y0G|-oE4iL4-BpVk=ejz&1w`jhHy6t+pQxaslU+I4(!tL(nim ztTM>b0?2~uGBhv%$+qn_2-|XnaRZQ<<>}%Wq7htr{w80m0SC(kJw1-?vgQB&`}?ks zTJ1LPgl8I)n|$)V0}|ED&-a$AhFrTA%6Thex4!xX=AeDr2Mjy^II$h?^_Vi_34;)u z_o|=Fjgl{t+xQZA9-BPB#LzHpb%<$8D+TDzyM};k48+){YT;S>I=d#Wzp$Py= C`lE~h literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/empty.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/empty.png deleted file mode 100644 index d4baa0efe6f998f30f033338b8964e8d36716afb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv=}#LT=BJwMkF1yemk zJwqd5M)wk+q8+Ibo@t(*S_~XO4l9EcBP#Xw4R^)bF#(UvL3ZZ zZc*ZP7gntZaBXQ?G)1dZA&-T^A`yE?&Z0^g$y`}GTe!R8M-l4g# zw_}~ScUb@K-^-g`acjOja`X1eGczv!G|jhqdHpc+y5oNW_vd}{n;;`(9=&aG-umqO z;l1UZr+90^6$E5TjQ8(-aMs0ejfW4jL3i_N{^RS{@XK0m&D654(oe7R-nBDcOkzG4 z@3zDG?N1MEot1HPt%7jij5Av~8xxfN3w><%yyN@4EeP>u=mw()NE#*=ZqT#x;xv zAbD@)6o1h--dl^G>}9wXduMWz%MYXSZCjKrr`Re8l`_BhYP3&(N04bO^9G>iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV8~qdba4!^@W1Nk?-5)m^S`FPI=@&dI69!+ zq(z~NN3f?+Q{`G(JBy~)i@=TR*qqK~$OK#cYOJN=Z1>4%X^ETZTsKzwDIy@7n4Y>*XMVB z^Jnf|T>MY^u>Uio$kZ%n-KcKw)0yu$->s1D56%vG{CUm=Uhh}gyTx;lJfCgdcU#=` z;_rFsb-y1xj#{brKs<%vt89ta+`pd|+%5kb_C2lcY2?Bme^t-_{nR+=@}aiW`I(0L ztS+x_8!}wD#{Jmmi`!LJl}8cVE3bWZIGM?)y1e(6*{)UL=imASFRH%1WzD_2;ca$D z8{Zmfu}fSOEntG6fHamRgeBjw3=xMxnBymV33*4N*Bwyu7xGV{;1hwEA2@+QX# z9*|wm&fpt8sXjmVYVh)BQWtoCH{@N;mS1^vf+S~w?ZlZ8x-WQrlVASOmYz{w7Q_7e zJ1hJ0N%B#q&R;A`8K$$QO<|N_-SEgHhPk~dB`53H-5-B$1jTW`GxSN~-z=Pd-u%eD z-X%%)HZGSLg3j?-a<;3er!wd=%wlyrxG8gQg3CsC=DGRWo9kOu)L*MuR&EG-{)6)X W_loJ9Z4b;rQSIsK=d#Wzp$Pz}Fdhp4 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/half.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/half.png deleted file mode 100644 index 0ccf70331a851e945cd1352d1f9546d52620e057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 815 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP_o1|q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&(KJi(Y*wyXh&*iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV94C|ba4!^@J~*VD0<+vF8#?>8~j5e7t|PdEUI%lN%Rkxw2~e z?MZo(mR|Pv@ALSa2`}HIShiJ%+VuTTj)=Ueci_r{l7nlf+q3?#i2NlfA;I$B_)q`c z&pGo}+eRt>7 zwXY7Rvh80Jy#D&3D@KblpCl(FtoZeRe&feWi~FO0T0~y^E!D-5Z}-2gv9a;s^qI52 zFP<*-TQS8}LoXpIZcvq*w|*IvEBbyJG;K_&xA);Hgt1G@^^7> zi?5n}@Z6!472iy!e6~5=bzH38_Q!;$bFZ7}8Vfwmj0nki&L`|#c<{ab|Eu-?(``qqM8)8{h#2F^Iy@o cq)>u^Vcyae@89l|KMIO+Pgg&ebxsLQ0C^lRssI20 diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/quarter.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/quarter.png deleted file mode 100644 index 27a791ed10314046f655c7dd37791a7f48863415..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 841 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP_o1|q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&(KJi(Y*wyXh&*iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV90#+ba4!^@J~*VD0<+vF8#?>8~j5e7t|PdEUI%lN%Rkxw2~e z?MZo(mR|Pv@ALSa2`}HIShiJ%+VuTTj)=Ueci_r{l7nlf+q3?#i2NlfA;I$B_)q`c z&pGo}+eRt>7 zwXY7Rvh80Jy#D&3D@KblpCl(FtoZeRe&feWi~FO0T0~y^E!D-5Z}-2gv9a;s^qI52 zFP<*-TQS8}LoXpIZcvq*w|*IvEBbyJG;K_&xA);Hgt2l@*6#W zID5U-`TOKYZZ8g<}T}94PpG(75e&xxDd~s?|nU)>~W0w#`qr-6SW%T=)Oy z`hUOeAD_IxzwT~oTH30Ae}D5ozF+@eLPApVbfsnFpDnIC&i*$xka54(oYc^@r{HCq z^YxxLHx8xE{8uzP=kya}O-H*_BW7mjrv8dhCT8YlNoMB5wLllMWpEn*`}yaufB4sr z=cHZRe^2}S^Yn==A1=FVdQ&MBb@ E0GCrd+yDRo diff --git a/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/three_quarters.png b/src/main/resources/assets/createnuclear/textures/item/biome_restore_cell/three_quarters.png deleted file mode 100644 index d417e4949918c61f7f82de1721a7e7657b09c1c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 819 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP_o1|q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&(KJi(Y*wyXh&*iasoR83s9|rk+A{e0*JXFJ6RV%%$f#dg8&oI zWG1l6AWI7%3#!Y|zyKuMT(2)vbm8)SV94C}ba4!^@J~*VD0<+vF8#?>8~j5e7t|PdEUI%lN%Rkxw2~e z?MZo(mR|Pv@ALSa2`}HIShiJ%+VuTTj)=Ueci_r{l7nlf+q3?#i2NlfA;I$B_)q`c z&pGo}+eRt>7 zwXY7Rvh80Jy#D&3D@KblpCl(FtoZeRe&fXNl`W@Ir|skutGAs7^rFF>gnJviXU_h< zc)HYY#S~i&y@aHcE6Hg|CC}?$=@rdP%@go3W@ct?J{r%zeZIW?5)0EekDM+xpQ-%u zZ1uU%-|zby8gATZWMHrbXxI%$L!eS-=fAr)UrzmDc}@AXqv3<^^Z&ov|KE6CO8TD< z7ay%}=l7{Oc-Yc^n*Hqk(a|lp|JXAhE(F@kw&Dc$^gN4_voC(jhn2Chv8C)+D=6Mn zlai2N0CfD0ewDtghG_k_cQzS^rUukzx7+ZT9qT|H$Uf* gZ}OL1#M>DeEdDHyj@x(hIw;ybUHx3vIVCg!0Lca~_5c6? diff --git a/src/main/resources/assets/createnuclear/textures/item/reinforced_glass_bottle.png b/src/main/resources/assets/createnuclear/textures/item/reinforced_glass_bottle.png new file mode 100644 index 0000000000000000000000000000000000000000..2cfcd77e51824ba5516056c6063dde43fbbaf1e8 GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}50G|-oE4iL4-BpVk=ejz&1w`jhHy6t+pQxaslU+I4(!tNb%*iVx&A~Gg zsC-R*AN9$JwrW1BVk7O5}=|TsS%!Oo}O9^96$~$gA^kx10#^-1;o-&HpqJ# zjLcwhCLr68k%>VNNJjy2W;+X5JO{`Iflp-A-dE?mA3WJY?rIEH8hm!1z4 zYEa-{32+HM{O#ZM+y

+ * The underlying data is built by {@link #getReactorSummary} into a + * {@link ReactorSummary}, which is only converted to Create's positional + * {@code List>} format at the last moment via + * {@link ReactorSummary#toRows()}, right before returning it to the caller. + */ public class ReactorSummaryDisplaySource extends DisplaySource { + /** Fallback line shown when only a single display row is available. */ public static final List notEnoughSpaceSingle = List.of(CreateNuclearLang.translateDirect("display_source.reactor.not_enough_space") .append(CreateNuclearLang.translateDirect("display_source.reactor.for_reactor_status"))); + /** Fallback lines shown when fewer than 6 rows are available (not enough for the full summary). */ public static final List notEnoughSpaceDouble = List.of(CreateNuclearLang.translateDirect("display_source.reactor.not_enough_space"), CreateNuclearLang.translateDirect("display_source.reactor.for_reactor_status")); + /** Fallback flap display rows, mirroring {@link #notEnoughSpaceDouble} for the flap layout. */ public static final List> notEnoughSpaceFlap = List.of(List.of(CreateNuclearLang.translateDirect("display_source.reactor.not_enough_space")), List.of(CreateNuclearLang.translateDirect("display_source.reactor.for_reactor_status"))); + /** + * Provides the text lines for a regular (non-flap) display target. + * Falls back to {@link #notEnoughSpaceSingle}/{@link #notEnoughSpaceDouble} when there + * isn't enough room, and to the "no controller" message when no reactor controller + * could be resolved for this source. + */ @Override public List provideText(DisplayLinkContext context, DisplayTargetStats stats) { if (stats.maxRows() < 2) return notEnoughSpaceSingle; @@ -46,13 +67,13 @@ public List provideText(DisplayLinkContext context, DisplayTar int gaugeWidth = (stats.maxColumns() >= 80) ? 10 : 6; - List> components = getComponents(context, false, gaugeWidth).toList(); - - // Sécurité : Si le contrôleur est absent, on affiche juste le message d'erreur (index 0) - if (components.size() < 6) { - return List.of(components.get(0).stream().reduce(MutableComponent::append).orElse(EMPTY_LINE)); + Optional summary = getReactorSummary(context, gaugeWidth); + if (summary.isEmpty()) { + return List.of(CreateNuclearLang.translateDirect("display_source.reactor.no_controller")); } + List> components = summary.get().toRows(); + if (context.getTargetBlockEntity() instanceof LecternBlockEntity) { Stream componentList = components.stream().map(list -> list.stream().reduce(MutableComponent::append).orElse(EMPTY_LINE)); return List.of(componentList.reduce((c1, c2) -> c1.append(Component.literal("\n")).append(c2)).orElse(EMPTY_LINE)); @@ -61,6 +82,11 @@ public List provideText(DisplayLinkContext context, DisplayTar return components.stream().map(list -> list.stream().reduce(MutableComponent::append).orElse(EMPTY_LINE)).toList(); } + /** + * Provides the rows for a flap display target. Disables the flap display context + * (falls back to the default layout) when there isn't enough room, either because + * of the row count or because the fuel value wouldn't fit the available columns. + */ @Override public List> provideFlapDisplayText(DisplayLinkContext context, DisplayTargetStats stats) { if (stats.maxRows() < 6) { @@ -69,24 +95,28 @@ public List> provideFlapDisplayText(DisplayLinkContext co } int gaugeWidth = 6; - List> components = getComponents(context, true, gaugeWidth).toList(); + Optional summary = getReactorSummary(context, gaugeWidth); - // --- FIX DU CRASH --- - // On vérifie que le contrôleur est bien présent (liste complète de 6 éléments) - // avant de tenter le calcul de largeur sur l'index 2. - if (components.size() < 6) { - return components; + if (summary.isEmpty()) { + return notEnoughSpaceFlap; } - if (stats.maxColumns() * FlapDisplaySection.MONOSPACE < 6 * FlapDisplaySection.MONOSPACE + components.get(2) - .get(1).getString().length() * FlapDisplaySection.WIDE_MONOSPACE) { + ReactorSummary reactorSummary = summary.get(); + + if (stats.maxColumns() * FlapDisplaySection.MONOSPACE < 6 * FlapDisplaySection.MONOSPACE + reactorSummary.fuel() + .value().getString().length() * FlapDisplaySection.WIDE_MONOSPACE) { context.flapDisplayContext = Boolean.FALSE; return notEnoughSpaceFlap; } - return components; + return reactorSummary.toRows(); } + /** + * Configures the flap display layout: the default layout for the first line + * (or when the flap display context was disabled by {@link #provideFlapDisplayText}), + * otherwise a two-section "Reactor" layout (label column + value/gauge column). + */ @Override public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout, int lineIndex) { if (lineIndex == 0 || context.flapDisplayContext instanceof Boolean b && !b) { @@ -108,12 +138,17 @@ public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEn layout.configure(layoutKey, List.of(label, symbols)); } - private Stream> getComponents(DisplayLinkContext context, boolean forFlapDisplay, int gaugeWidth) { + /** + * Resolves the reactor controller for this source and builds a {@link ReactorSummary} + * from its current state. Returns {@link Optional#empty()} when no controller is + * assigned to this display source or it has been removed, so callers can distinguish + * that case from a valid summary without relying on list size/positional access. + */ + private Optional getReactorSummary(DisplayLinkContext context, int gaugeWidth) { ReactorControllerBlockEntity controller = MultiblockHelpers.getControllerForPart(context.level(), context.getSourcePos()); - // Sécurité Triple-Check : null, removed ou non assemblé if (controller == null || controller.isRemoved()) { - return Stream.of(List.of(CreateNuclearLang.translateDirect("display_source.reactor.no_controller"))); + return Optional.empty(); } int mode = context.sourceConfig().getInt("display_mode"); @@ -121,8 +156,9 @@ private Stream> getComponents(DisplayLinkContext context, int heat = (int) controller.getConfiguredPattern().getOrCreateTag().getDouble("heat"); int fuel = 0; int cooler = 0; + if (controller.getDisplayState() != null && controller.getDisplayState().items() != null) { - for (var entry : controller.getDisplayState().items().entrySet()) { + for (Map.Entry entry : controller.getDisplayState().items().entrySet()) { if (TypeRodPredicate.isFuel(entry.getKey().getDefaultInstance(), context.level())) { fuel += entry.getValue(); } else if (TypeRodPredicate.isCooled(entry.getKey().getDefaultInstance(), context.level())) { @@ -130,9 +166,10 @@ private Stream> getComponents(DisplayLinkContext context, } } } + int size = controller.getMultiblockSize(); - var fluidList = controller.getBigFluidStack(); - int fluid = (fluidList != null && !fluidList.isEmpty() && fluidList.get(0) != null) ? (int) fluidList.get(0).amount : 0; + List fluidList = controller.getBigFluidStack(); + int fluid = (fluidList != null && !fluidList.isEmpty() && fluidList.get(0) != null) ? fluidList.get(0).amount : 0; int lw = labelWidth(); MutableComponent lStatus = padLabel("status", lw).append(" "); @@ -142,20 +179,20 @@ private Stream> getComponents(DisplayLinkContext context, MutableComponent lFluid = padLabel("fluid", lw).append(" "); MutableComponent lHeat = padLabel("heat", lw).append(" "); - return Stream.of( - List.of(lStatus, controller.isAssembled() ? + return Optional.of(new ReactorSummary.Builder() + .status(lStatus, controller.isAssembled() ? CreateNuclearLang.translateDirect("display_source.reactor.active").withStyle(ChatFormatting.GOLD) : - CreateNuclearLang.translateDirect("display_source.reactor.idle").withStyle(ChatFormatting.GRAY)), - List.of(lSize, formatSize(size)), - List.of(lFuel, formatValue(fuel, ReactorDisplayConstants.MAX_FUEL, mode, false, ChatFormatting.GREEN, gaugeWidth)), - List.of(lCooler, formatValue(cooler, ReactorDisplayConstants.MAX_COOLER, mode, false, ChatFormatting.AQUA, gaugeWidth)), - List.of(lFluid, formatFluid(fluid, ReactorDisplayConstants.MAX_FLUID, mode, ChatFormatting.BLUE, gaugeWidth)), - List.of(lHeat, formatValue(heat, ReactorDisplayConstants.MAX_HEAT, mode, true, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth)) - ); + CreateNuclearLang.translateDirect("display_source.reactor.idle").withStyle(ChatFormatting.GRAY)) + .size(lSize, formatSize(size)) + .fuel(lFuel, formatValue(fuel, ReactorDisplayConstants.MAX_FUEL, mode, false, ChatFormatting.GREEN, gaugeWidth)) + .cooler(lCooler, formatValue(cooler, ReactorDisplayConstants.MAX_COOLER, mode, false, ChatFormatting.AQUA, gaugeWidth)) + .fluid(lFluid, formatFluid(fluid, ReactorDisplayConstants.MAX_FLUID, mode, ChatFormatting.BLUE, gaugeWidth)) + .heat(lHeat, formatValue(heat, ReactorDisplayConstants.MAX_HEAT, mode, true, IHeat.HeatLevel.of(heat, controller.getMultiblockSize()).getTextColor(), gaugeWidth)) + .build()); } private MutableComponent padLabel(String key, int lw) { - return Component.literal(Strings.repeat(' ', lw - labelWidthOf(key))).append(labelOf(key)); + return Component.literal(" ".repeat(lw - labelWidthOf(key))).append(labelOf(key)); } private MutableComponent formatSize(int size) { From c05a96ed27e8a119be43e24c1f2cf5bea062fca9 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Sun, 12 Jul 2026 21:12:44 +0200 Subject: [PATCH 149/171] =?UTF-8?q?docs:=20update=20AUDIT=5FACTUEL.md=20to?= =?UTF-8?q?=20record=20ReactorSummary=20refactor=20and=20close=20=C2=A72.3?= =?UTF-8?q?/=C2=A76=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump HEAD reference and §0 changelog entry to commit `cc532f83` (ReactorSummary refactor), noting it also removes the last French comments from ReactorSummaryDisplaySource. - Close §2.3 ("sentinelle de taille + accès positionnel fragiles"): mark resolved with a strikethrough pointing to §8.1 / `cc532f83`. - Close §5 recommendation on replacing the fragile positional access with the same resolution note. - Update §6 (French comment audit): move the resolved ReactorSummaryDisplaySource guard-clause comments (ex-item 9) into the "Résolu" list, renumber the remaining items (9-14, was 9-15), and update the file/line counts from 12/292 (~25 lines) to 11/292 (~22 lines). - Update the §6 recurring-pattern summary and §8 documentation section to reflect that ReactorSummaryDisplaySource, alongside CNPonderReactorScenes, is now fully translated. - Add a new §8.1 table row documenting the `cc532f83` fix in detail (ReactorSummary record/Builder, Optional-based getReactorSummary(), String.repeat replacing joptsimple's Strings.repeat, added Javadoc). --- AUDIT_ACTUEL.md | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/AUDIT_ACTUEL.md b/AUDIT_ACTUEL.md index 3e770a31..fff15eea 100644 --- a/AUDIT_ACTUEL.md +++ b/AUDIT_ACTUEL.md @@ -1,6 +1,6 @@ # Audit consolidé — CreateNuclearForge (branche V2-CorrectifAudit) -**Réorganisation du 2026-07-12 (HEAD `8b0428e3`).** Ce document a été restructuré pour ne conserver dans ses sections principales (§1 à §7) **que les problèmes encore ouverts**. Tout ce qui est corrigé, réfuté ou décidé (produit) a été déplacé en **§8 Mémoire**, avec le hash du commit correspondant quand il a pu être déterminé avec certitude par archéologie Git (`git log -S`, `git show`, `git blame`) — sinon c'est indiqué explicitement, sans hash inventé. +**Réorganisation du 2026-07-12 (HEAD `cc532f83`).** Ce document a été restructuré pour ne conserver dans ses sections principales (§1 à §7) **que les problèmes encore ouverts**. Tout ce qui est corrigé, réfuté ou décidé (produit) a été déplacé en **§8 Mémoire**, avec le hash du commit correspondant quand il a pu être déterminé avec certitude par archéologie Git (`git log -S`, `git show`, `git blame`) — sinon c'est indiqué explicitement, sans hash inventé. **Méthodologie de cette réorganisation** : nouvelle relecture complète du code actuel (`src/main/java`, **292 fichiers**, hors `src/generated`/`src/main/resources`), croisée avec `AUDIT_V1.md`, les versions précédentes de ce fichier, et l'historique Git (`git log`, 1437 commits au total sur le dépôt) — aucun des deux audits n'a été pris comme vérité absolue : plusieurs points ont été revérifiés directement dans le code et un point s'est avéré **périmé** (voir §0). @@ -10,7 +10,7 @@ ## 0. Constat global -Depuis la dernière consolidation (2026-06-28), le projet a continué d'évoluer : retrait de `IrradiatedBiomes.monsters()` (`8b0428e3`), blocage explicite (message "WIP") de l'apprivoisement des mobs irradiés (`261b26d8`), retrait complet de la mécanique de collier teignable jamais câblée (`17b29aa3`), correction de la tautologie `IHeat.isNotDanger` et ajout d'une hystérésis sur le heat appliqué aux sorties (`fb0897d3`, `a18038db`), guard NBT sur `ReactorFrameDisplayManager.write` (`381c7a5f`), et déduplication complète de `drawGauge` via `ReactorGaugeRenderer`/`AbstractReactorStatDisplaySource` (`35e474e3`, `d0da13d1`, `a8b6b23f`). Détail de chaque correction en §8.1. +Depuis la dernière consolidation (2026-06-28), le projet a continué d'évoluer : retrait de `IrradiatedBiomes.monsters()` (`8b0428e3`), blocage explicite (message "WIP") de l'apprivoisement des mobs irradiés (`261b26d8`), retrait complet de la mécanique de collier teignable jamais câblée (`17b29aa3`), correction de la tautologie `IHeat.isNotDanger` et ajout d'une hystérésis sur le heat appliqué aux sorties (`fb0897d3`, `a18038db`), guard NBT sur `ReactorFrameDisplayManager.write` (`381c7a5f`), déduplication complète de `drawGauge` via `ReactorGaugeRenderer`/`AbstractReactorStatDisplaySource` (`35e474e3`, `d0da13d1`, `a8b6b23f`), traduction en anglais des scènes Ponder (`3be6252a`), et — le jour même de cette réorganisation — remplacement de la sentinelle de taille/accès positionnels fragiles de `ReactorSummaryDisplaySource` par un `record ReactorSummary` typé (`cc532f83`), qui clôt du même coup le dernier commentaire français de ce fichier. Détail de chaque correction en §8.1. **Point périmé trouvé lors de cette réorganisation** : l'item « Flicker vitesse de sortie en fin de ressources » était encore documenté en §1 comme un bug entièrement ouvert, proposant comme correction l'ajout d'un champ `lastAppliedOutputHeat` avec hystérésis sur `RPM_DIVIDER/2. **Cette correction a en réalité déjà été appliquée** par le commit `a18038db` (2026-07-05) — vérifié par lecture directe : `ReactorControllerBlockEntity.java:62` (champ `lastAppliedOutputHeat`), `:430-433` (comparaison au seuil et appel à `rotateOutputs` avec la valeur bufferisée). Le commit lui-même documente que le point reste partiellement ouvert : l'oscillateur `overHeat` sous-jacent (+1/-2 par tick) n'est pas supprimé, seul son symptôme visible (flicker RPM) est amorti, et le seuil de l'hystérésis n'a pas été validé en jeu. L'item est donc reclassé en §1 comme **partiellement résolu, validation en jeu restante** plutôt que comme bug non traité — voir §1. @@ -44,8 +44,7 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to Le neighbor lookup est passé de O(n) à O(1) (map `actualRods`, déjà corrigé — voir §8.1), mais chaque rod continue de boucler sur toute la grille `formattedPattern` (9×9=81 cellules) pour retrouver sa propre position — non remplacée par une map slot→position précalculée (coût ~57×81 ≈ 4617 itérations/tick sur réacteur plein). **Recommandation** : précalculer une `Map` — gain mineur, risque nul, priorité basse. - **Asymétrie toujours présente** : l'examen des voisins ne se fait que si `"fuel".equals(currentRod)` ; un cooler ne déclenche jamais l'examen de ses voisins, et `heat += rod.baseRodHeat() / neighborRod.proximityRodHeat()` (division) côté fuel→cooler-voisin vs addition côté fuel→fuel-voisin. **Ne pas toucher sans confirmation balance** — c'est potentiellement voulu. -3. **`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles** *(inchangé)* - `getComponents()` retourne toujours une liste de taille 1 (pas de contrôleur) ou 6 (normal) ; les appelants gardent `if (components.size() < 6)` avant un accès positionnel `components.get(2).get(1)` (ligne « fuel »). Toujours fragile à tout réordonnancement de ligne. +3. ~~`ReactorSummaryDisplaySource` — sentinelle de taille + accès positionnel fragiles~~ — **résolu**, voir §8.1 (`cc532f83`). 4. **`ReactorSummaryDisplaySource.formatValue` — incohérence de mode** *(inchangé)* `HeatDisplaySource` affiche `"500 °C"` en mode normal alors que `ReactorSummaryDisplaySource` force une jauge pour le heat dans le même mode (`gaugeOnNormal=true` pour heat uniquement) — incohérence visuelle toujours présente. @@ -99,13 +98,15 @@ La dette la plus structurelle reste **l'absence totale de tests** (`src/test` to **Périmètre** : `src/main/java` (292 fichiers), recherche des commentaires/Javadoc non rédigés en anglais et des cas ambigus/incomplets indépendamment de la langue. Méthodologie : recherche par caractères accentués + vocabulaire français typique des commentaires, puis lecture manuelle des occurrences trouvées. -**Décompte global** *(mis à jour 2026-07-12, commit `3be6252a`)* : **12 fichiers sur 292** (~4 %) contiennent encore du français détectable, pour environ **25 lignes** de commentaires/Javadoc concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires et Javadoc**, pas à l'API elle-même. +**Décompte global** *(mis à jour 2026-07-12, commit `cc532f83`)* : **11 fichiers sur 292** (~3,8 %) contiennent encore du français détectable, pour environ **22 lignes** de commentaires/Javadoc concernées. **Aucun symbole de code** (nom de classe, méthode, champ) en français n'a été trouvé — le problème est **localisé aux commentaires et Javadoc**, pas à l'API elle-même. -**Résolu** — les 4 cas de Javadoc public bilingue, seul sous-item classé 🟢 prioritaire au tour précédent, ont été traduits en intégralité (commit `3be6252a`, *"style: translate French comments and Javadoc to English in VicinityEffect and CNPonderReactorScenes"*) : -- `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)` entièrement repassée en anglais. -- `infrastructure/ponder/scenes/CNPonderReactorScenes.java` — fichier intégralement traduit : Javadoc de `Positions` (l.32), de `STATIC_POS` (l.50, reformulée en documentation stable plutôt qu'en note à soi-même) et de `positionsFor` (l.85), plus tous les commentaires inline restants (pedestal, exemples T1/T2/T3, fallback, positions devant/derrière/droite). Ce fichier ne contient plus aucun français. +**Résolu** : +- Les 4 cas de Javadoc public bilingue, seul sous-item classé 🟢 prioritaire au tour précédent, ont été traduits en intégralité (commit `3be6252a`, *"style: translate French comments and Javadoc to English in VicinityEffect and CNPonderReactorScenes"*) : + - `content/effects/VicinityEffect.java:53-57` — Javadoc de `onContaminate(LivingEntity)` entièrement repassée en anglais. + - `infrastructure/ponder/scenes/CNPonderReactorScenes.java` — fichier intégralement traduit : Javadoc de `Positions` (l.32), de `STATIC_POS` (l.50, reformulée en documentation stable plutôt qu'en note à soi-même) et de `positionsFor` (l.85), plus tous les commentaires inline restants (pedestal, exemples T1/T2/T3, fallback, positions devant/derrière/droite). Ce fichier ne contient plus aucun français. +- Les 3 commentaires français de garde défensive (« Sécurité Triple-Check ») de `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:51,75,114` (ex-item 9) ont disparu avec le refactor `ReactorSummary` (commit `cc532f83`) : le fichier a été réécrit avec un Javadoc anglais complet sur la classe et chacune de ses méthodes publiques/privées, et ne contient plus aucun français (revérifié par grep accents, 2026-07-12). -Ces deux fichiers sortent donc de la liste ci-dessous et sont déplacés dans la table de §8.1. +Ces fichiers sortent donc de la liste ci-dessous et sont déplacés dans la table de §8.1. **Cas les plus significatifs restants** : @@ -114,20 +115,19 @@ Ces deux fichiers sortent donc de la liste ci-dessous et sont déplacés dans la 6. `ClientEvents.java:24,60-78` — logique de tremblement de caméra liée à l'explosion nucléaire, entièrement commentée en français, y compris la formule de puissance ; non documentée en anglais du tout. 7. `foundation/mixin/RadiationHeartMixin.java:13,21,32` — mixin overridant le rendu du cœur HUD vanilla, commentaires français expliquant le ciblage. Les mixins sont le code le plus fragile aux montées de version MC/Forge — mérite une documentation claire et bilingue a minima. 8. `foundation/mixin/CameraAccessor.java:9` — accessor mixin, commentaire français isolé sur le pattern « invoker » Mixin. -9. `content/redstone/displayLink/source/ReactorSummaryDisplaySource.java:51,75,114` — trois commentaires français de garde défensive (« Sécurité Triple-Check ») sur le chemin d'affichage, seule trace de documentation de cette logique de garde. -10. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. -11. `content/decoration/palettes/PalettesVariantEntry.java:54` — commentaire français sur un changement d'architecture de rendu déjà effectué ailleurs, utile pour éviter une régression, en français uniquement. -12. `infrastructure/worldgen/biome/IrradiatedBiomes.java:39-48` — 4 commentaires français sur des choix esthétiques de biome ; mineur, mais dans un fichier déjà pointé par §4 comme « template non terminé ». -13. `content/equipment/armor/AntiRadiationArmorItem.java:48` — commentaire français sur `getArmorTexture` (override d'API Forge publique) ; trivial sur le fond, à harmoniser en anglais par cohérence. -14. `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:33` — commentaire français isolé, sur une classe explicitement exclue du refactor de mutualisation `drawGauge` (§8.1) — bon candidat à documenter proprement au prochain passage sur ce fichier. -15. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. +9. `content/explosion/NuclearExplosionEntity.java:45,50` — commentaire français expliquant un contournement de compatibilité addon (cast en `Object` pour éviter un crash `ClassNotFoundError` si Alex's Caves est absent) : information cruciale sur une dépendance optionnelle, uniquement en français, à l'endroit le plus délicat du fichier. +10. `content/decoration/palettes/PalettesVariantEntry.java:54` — commentaire français sur un changement d'architecture de rendu déjà effectué ailleurs, utile pour éviter une régression, en français uniquement. +11. `infrastructure/worldgen/biome/IrradiatedBiomes.java:39-48` — 4 commentaires français sur des choix esthétiques de biome ; mineur, mais dans un fichier déjà pointé par §4 comme « template non terminé ». +12. `content/equipment/armor/AntiRadiationArmorItem.java:48` — commentaire français sur `getArmorTexture` (override d'API Forge publique) ; trivial sur le fond, à harmoniser en anglais par cohérence. +13. `content/redstone/displayLink/source/ReactorSizeDisplaySource.java:33` — commentaire français isolé, sur une classe explicitement exclue du refactor de mutualisation `drawGauge` (§8.1) — bon candidat à documenter proprement au prochain passage sur ce fichier. +14. `foundation/mixin/GameRendererMixin.java:17` — commentaire français seul sur le mixin gérant l'assombrissement du ciel pendant l'explosion — même remarque que 7/8. **Ambiguïtés/incomplétudes indépendantes de la langue relevées au passage** : - ~~`CNPonderReactorScenes.java:50,90`~~ — **résolu** (`3be6252a`) : les deux Javadoc ont été reformulées en documentation stable en même temps que leur traduction (voir ci-dessus). - `ReactorOutput.java` (§4) — propriété `SPEED` commentée sans décision documentée — ambiguïté fonctionnelle non résolue. - `CNStandardRecipeGen.java:226` (§4) — `FIXME` en anglais mais sans contexte suffisant pour un tiers. -**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité mais se réduit** : il se concentre désormais sur les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSummaryDisplaySource`, `ReactorSizeDisplaySource`), et `CNFluids`/`ClientEvents`. Les scènes Ponder (`CNPonderReactorScenes`) sortent de cette liste, assainies cette session. Point positif : le sous-ensemble concerné continue de rétrécir (12/292 fichiers désormais, ~4 %) — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger) n'ont pas introduit de nouveau commentaire français. +**Pattern récurrent** : le point « commentaires FR/EN mêlés » déjà signalé dans `AUDIT_V1.md` §5 (sans jamais être suivi comme item séparé) **reste d'actualité mais se réduit** : il se concentre désormais sur les mixins (`CameraAccessor`, `RadiationHeartMixin`, `GameRendererMixin`), le rendu Display Link (`ReactorSizeDisplaySource` uniquement désormais), et `CNFluids`/`ClientEvents`. Les scènes Ponder (`CNPonderReactorScenes`) et `ReactorSummaryDisplaySource` sortent de cette liste, assainies respectivement par `3be6252a` et `cc532f83`. Point positif : le sous-ensemble concerné continue de rétrécir (11/292 fichiers désormais, ~3,8 %) — les derniers commits (retrait de `monsters()`, retrait du collier teignable, sons Geiger, refactor `ReactorSummary`) n'ont pas introduit de nouveau commentaire français. **Pourquoi ça doit être suivi** : ces commentaires portent presque toujours l'explication du *pourquoi* d'un choix non trivial (compat cross-mod, compensation de désync réseau, garde défensive) — c'est-à-dire exactement le contenu qu'un commentaire doit porter selon les conventions du projet. Le laisser uniquement en français limite la relecture/contribution à l'équipe francophone actuelle et complique tout audit ou onboarding futur non francophone (y compris par un outil ou un contributeur externe à la communauté Create). @@ -153,7 +153,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq **5. Amélioration de conception / cohérence UX** - `ReactorSummaryDisplaySource.formatValue` : harmoniser le mode d'affichage du heat avec `HeatDisplaySource` (§2.4). **Justification** : incohérence visible par le joueur, mais purement cosmétique, aucun risque fonctionnel. -- `ReactorSummaryDisplaySource` : remplacer l'accès positionnel fragile (`components.get(2).get(1)`) par un accès nommé/typé (§2.3). **Justification** : dette de conception qui ne casse rien aujourd'hui mais rendra toute évolution de l'ordre des lignes affichées dangereuse sans le vouloir. +- ~~`ReactorSummaryDisplaySource` : remplacer l'accès positionnel fragile~~ — **fait**, voir §8.1 (`cc532f83`). **6. Optimisation mineure (gain faible, risque nul)** - `DefaultHeatCalculator` : précalculer une map slot→position pour éliminer la boucle O(81) restante (§2.2, §5). **Ne pas** toucher à l'asymétrie fuel/cooler sans validation balance. @@ -165,7 +165,9 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq - Worldgen « irradié » : retirer le contenu vanilla sans rapport (`BLUE_ICE`, `NETHER_CAVE`, `VOID_START_PLATFORM`) et choisir un bloc de remplissage cohérent à la place de `STEEL_BLOCK` (§4). **Justification** : n'affecte que la cohérence thématique du biome, pas de risque technique. **8. Documentation (nouveau, §6)** -- ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait cette session** (working tree, à committer). Reste : les commentaires métier non triviaux listés en §6 (items 5-15, ~25 lignes sur 12 fichiers), au fil des prochains passages sur ces fichiers. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais ce sont typiquement des commentaires qui expliquent un « pourquoi » non trivial (compat, désync réseau) — les laisser en français limite l'audit/onboarding futur. +- ~~Traduire en anglais les 4 cas de Javadoc public bilingue (`VicinityEffect.java`, `CNPonderReactorScenes.java` ×3)~~ — **fait**, commit `3be6252a`. +- ~~Traduire/documenter en anglais les 3 commentaires de garde défensive de `ReactorSummaryDisplaySource`~~ — **fait**, commit `cc532f83` (Javadoc anglais complet ajouté sur la classe et ses méthodes en même temps que le refactor `ReactorSummary`). +- Reste : les commentaires métier non triviaux listés en §6 (items 5-14, ~22 lignes sur 11 fichiers), au fil des prochains passages sur ces fichiers. **Justification** : cosmétique et non bloquant (aucun symbole d'API en français), mais ce sont typiquement des commentaires qui expliquent un « pourquoi » non trivial (compat, désync réseau) — les laisser en français limite l'audit/onboarding futur. **9. À surveiller sans action immédiate** - `RadiationCapability.tickRadiation` pour les `LivingEntity` non-joueurs : pas de dirty-check d'inventaire (§3). Compromis assumé, à reconsidérer seulement si la densité de mobs équipés irradiés pose un problème de perf mesuré. @@ -187,6 +189,7 @@ Classement par catégorie et impact, du plus important au plus cosmétique. Chaq | Correction | Hash(es) | Date | Détail | |---|---|---|---| +| `ReactorSummaryDisplaySource` — remplacement de la sentinelle de taille (liste 1/6 éléments) et des accès positionnels fragiles (`components.get(2).get(1)`) par un `record ReactorSummary` typé (`ReactorSummaryRow` + `Builder` validant les 6 champs requis) ; `getComponents()` → `getReactorSummary()` retournant `Optional` ; remplacement de `joptsimple.internal.Strings.repeat` (dépendance transitive non déclarée) par `String.repeat` natif ; Javadoc anglais ajouté sur la classe et ses méthodes, retirant au passage les 3 commentaires français "Sécurité Triple-Check" (§6) | `cc532f83` | 2026-07-12 | Nouveau fichier `ReactorSummary.java` (§2.3 et §6, item ex-9, tous deux clos). `toRows()` reste le seul point de conversion vers le format positionnel `List>` exigé par l'API `DisplaySource` de Create. | | Traduction en anglais des 4 cas de Javadoc public bilingue relevés en §6 (`VicinityEffect.onContaminate`, `CNPonderReactorScenes.Positions`/`STATIC_POS`/`positionsFor`), plus l'intégralité des commentaires inline restants de `CNPonderReactorScenes.java` | `3be6252a` | 2026-07-12 | `VicinityEffect.java` et `CNPonderReactorScenes.java` ne contiennent plus aucun français ; sortis de la liste §6 (14→12 fichiers concernés, ~40→~25 lignes). | | Retrait de `IrradiatedBiomes.monsters()` (corps vide, arguments ignorés) | `8b0428e3` | 2026-07-12 | Méthode et son unique site d'appel supprimés ; les réglages de spawn passent désormais uniquement par `MobSpawnSettings.Builder`. | | Blocage explicite (message "WIP") de l'apprivoisement des mobs irradiés (`AnimalUtil.blockTamingWip`) | `261b26d8` | 2026-07-11 | Remplace un apprivoisement cassé/incohérent (chat : collier non fonctionnel ; loup : aucun chemin d'apprivoisement) par un message explicite "pas encore implémenté". Ce même commit a aussi retiré la mécanique de collier (§8.3). | From 0ede748519db9189bab8d1d6ff64d0f1cfd2cd16 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 13 Jul 2026 13:16:39 +0200 Subject: [PATCH 150/171] feat(sound): add biome ambient sound and motor assemble/disassemble sounds - Add new sound assets: biomes/wasteland.ogg (ambient loop for the irradiated biome) and reacteur/assemble_deassemble/motor_assemble.ogg / motor_disassemble.ogg. - Register them in CNSoundEvents as BIOME_WASTELAND, MOTOR_ASSEMBLE, and MOTOR_DISASSEMBLE. - Rename several CNSoundEvents entries for clarity and to fix a typo: REACTOR_CASING_BREAD -> REACTOR_CASING_BREAK, REACTOR_ALARM -> REACTOR_ALARM_ONESHOT, REACTOR_ALARM_2 -> REACTOR_ALARM_LOOP (with updated subtitle "Reactor Alarm Loop"), LARGE_NUCLEAR_EXPLOSION -> NUCLEAR_EXPLOSION_LARGE, and fix the "GeiGer Medium" subtitle typo to "Geiger Medium". - Update the two call sites affected by the renames: ReactorAlarmEntity (REACTOR_ALARM_LOOP) and NuclearMushroomCloudParticle (NUCLEAR_EXPLOSION_LARGE). - IrradiatedBiomes: replace the geiger low/medium ambient+additions sound pair with the new single BIOME_WASTELAND ambient loop sound, and reindent the BiomeSpecialEffects.Builder chain (tabs -> consistent spaces). - Regenerate sounds.json, en_us.json/en_ud.json lang files, irradiated_land.json biome data, and datagen .cache files to match the sound registry changes above. --- .../09bd1f7b209874b6c29086df91c49669495dd477 | 4 +-- .../3c9854c256b4d84dd9b4b92d1a03ceb45298124f | 6 ++-- .../fed443662143001aeb5341375f6f5ef31d10baea | 4 +-- .../assets/createnuclear/lang/en_ud.json | 7 ++-- .../assets/createnuclear/lang/en_us.json | 7 ++-- .../assets/createnuclear/sounds.json | 27 +++++++++++++++ .../worldgen/biome/irradiated_land.json | 6 +--- .../createnuclear/CNSoundEvents.java | 27 +++++++++++---- .../multiblock/alarm/ReactorAlarmEntity.java | 2 +- .../NuclearMushroomCloudParticle.java | 2 +- .../worldgen/biome/IrradiatedBiomes.java | 32 ++++++++---------- .../createnuclear/sounds/biomes/wasteland.ogg | Bin 0 -> 978214 bytes .../assemble_deassemble/motor_assemble.ogg | Bin 0 -> 41729 bytes .../assemble_deassemble/motor_disassemble.ogg | Bin 0 -> 21913 bytes 14 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 src/main/resources/assets/createnuclear/sounds/biomes/wasteland.ogg create mode 100644 src/main/resources/assets/createnuclear/sounds/reacteur/assemble_deassemble/motor_assemble.ogg create mode 100644 src/main/resources/assets/createnuclear/sounds/reacteur/assemble_deassemble/motor_disassemble.ogg diff --git a/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 b/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 index fdae2c9e..280b24e5 100644 --- a/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 +++ b/src/generated/resources/.cache/09bd1f7b209874b6c29086df91c49669495dd477 @@ -1,2 +1,2 @@ -// 1.20.1 2026-06-22T14:19:43.5342033 CreateNuclear's Custom Sounds -b698e29669f03e4d5baba058a24194333d16ebf6 assets/createnuclear/sounds.json +// 1.20.1 2026-07-13T12:45:23.7622268 CreateNuclear's Custom Sounds +a1cba2accedfe5ba470f187b54e4cc88cf174853 assets/createnuclear/sounds.json diff --git a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f index 62a8f9f6..d180ad3e 100644 --- a/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f +++ b/src/generated/resources/.cache/3c9854c256b4d84dd9b4b92d1a03ceb45298124f @@ -1,4 +1,4 @@ -// 1.20.1 2026-07-11T21:44:40.1947842 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] +// 1.20.1 2026-07-13T13:10:31.7900303 Registrate Provider for createnuclear [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)] 0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json 5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json 5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json @@ -48,8 +48,8 @@ a2fc21fa320e677fe7690b260ee3f57ebdbd50b6 assets/createnuclear/blockstates/small_ 643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json 4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json -6fc3f1ba9893df163bc9dc3208342eaf271b7cb7 assets/createnuclear/lang/en_ud.json -c411e7160186d59d54c2c499ce6af3163b0653f9 assets/createnuclear/lang/en_us.json +85c5d84aa370008d3ebd1059ae9f01384c84ad92 assets/createnuclear/lang/en_ud.json +d9642fb0dc87dba15b8b9952591d2c9d901866c9 assets/createnuclear/lang/en_us.json a8495d2cd5e38213683becaf1c84b2852f8b06f5 assets/createnuclear/models/block/autunite_natural_0.json 29394a22ee8655dc22ea51563411505fbcfd2dab assets/createnuclear/models/block/autunite_natural_1.json 9e4f83de1ca7a9ab5363f43fc7c3f7f4ec6164d5 assets/createnuclear/models/block/autunite_natural_2.json diff --git a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea index 4d8d75f6..8d559aee 100644 --- a/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea +++ b/src/generated/resources/.cache/fed443662143001aeb5341375f6f5ef31d10baea @@ -1,4 +1,4 @@ -// 1.20.1 2026-07-12T14:09:29.2536256 CreateNuclear Generated Registry Entries +// 1.20.1 2026-07-13T12:22:03.9183298 CreateNuclear Generated Registry Entries aa1897ff27a6aa83e2efbee29e12ad6dab2f6a0a data/createnuclear/createnuclear/fluids/type/fallback.json d7c754aa51cea393a10bce85986c1c0c641150d5 data/createnuclear/createnuclear/fluids/type/nitrogen.json afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids/type/water.json @@ -10,7 +10,7 @@ afee3d8f15bf8285e175f73befba7b46fdc94b19 data/createnuclear/createnuclear/fluids 72173023e6a31748692e750db0f5fa8c555d1009 data/createnuclear/forge/biome_modifier/striated_ores_overworld.json 1d15657126bab7c0b4355d0dcb9addc2d417ed01 data/createnuclear/forge/biome_modifier/thorium_ore.json fa32145101dc12ec914684fec8c5cbb995d2c051 data/createnuclear/forge/biome_modifier/uranium_ore.json -291523426e13be57633005f545b13a3d6c52f752 data/createnuclear/worldgen/biome/irradiated_land.json +6abf282b710f320cc2fbfe150cca1d08bfc28954 data/createnuclear/worldgen/biome/irradiated_land.json 211d1391981d173b8bc490e5af1471441e1df37f data/createnuclear/worldgen/configured_feature/lead_ore.json c3bb421f6bf5a02b09a178d4d1f003679b86c919 data/createnuclear/worldgen/configured_feature/nitrate_ore.json 4f11c0a518c0de7857919983fc638ba551c6630a data/createnuclear/worldgen/configured_feature/striated_ores_overworld.json diff --git a/src/generated/resources/assets/createnuclear/lang/en_ud.json b/src/generated/resources/assets/createnuclear/lang/en_ud.json index 5cc37c4a..57340f50 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_ud.json +++ b/src/generated/resources/assets/createnuclear/lang/en_ud.json @@ -272,8 +272,9 @@ "createnuclear.reactor.debug.title": "--- sɔıʇsoubɐıp ɹoʇɔɐǝᴚ ---", "createnuclear.reactor.debug.valid_position": "%s @ pıןɐʌ ", "createnuclear.snow_powder.fan.recipe": "uɐɟ ɔıuǝboʎɹƆ", - "createnuclear.subtitle.alarm/alarm": "ɯɹɐןⱯ ɹoʇɔɐǝᴚ", + "createnuclear.subtitle.alarm/alarm": "dooꞀ ɯɹɐןⱯ ɹoʇɔɐǝᴚ", "createnuclear.subtitle.alarm/reactor_alarm": "ɯɹɐןⱯ ɹoʇɔɐǝᴚ", + "createnuclear.subtitle.biomes/wasteland": "puɐןǝʇsɐM", "createnuclear.subtitle.explosion/large_nuclear_explosion": "uoısoןdxƎ ɹɐǝןɔnN ǝbɹɐꞀ", "createnuclear.subtitle.explosion/main": "uıɐW uoısoןdxƎ ɹɐǝןɔnN", "createnuclear.subtitle.explosion/nuclear_explosion": "uoısoןdxƎ ɹɐǝןɔnN", @@ -283,8 +284,10 @@ "createnuclear.subtitle.explosion/shockwave": "ǝʌɐʍʞɔoɥS uoısoןdxƎ ɹɐǝןɔnN", "createnuclear.subtitle.geiger/high": "ɥbıH ɹǝbıǝ⅁", "createnuclear.subtitle.geiger/low": "ʍoꞀ ɹǝbıǝ⅁", - "createnuclear.subtitle.geiger/medium": "ɯnıpǝW ɹǝ⅁ıǝ⅁", + "createnuclear.subtitle.geiger/medium": "ɯnıpǝW ɹǝbıǝ⅁", "createnuclear.subtitle.reacteur/activation": "uoıʇɐʌıʇɔⱯ ɹoʇɔɐǝᴚ", + "createnuclear.subtitle.reacteur/assemble_deassemble/motor_assemble": "ǝןqɯǝssⱯ ɹoʇoW", + "createnuclear.subtitle.reacteur/assemble_deassemble/motor_disassemble": "ǝןqɯǝssɐsıᗡ ɹoʇoW", "createnuclear.subtitle.reacteur/casing_break": "buısɐƆ ɹoʇɔɐǝᴚ ʞɐǝɹᗺ", "createnuclear.subtitle.reacteur/casing_fall": "ןןɐℲ buısɐƆ ɹoʇɔɐǝᴚ", "createnuclear.subtitle.reacteur/casing_hit": "buısɐƆ ɹoʇɔɐǝᴚ ʇıH", diff --git a/src/generated/resources/assets/createnuclear/lang/en_us.json b/src/generated/resources/assets/createnuclear/lang/en_us.json index 06a2ca67..d5d3a31a 100644 --- a/src/generated/resources/assets/createnuclear/lang/en_us.json +++ b/src/generated/resources/assets/createnuclear/lang/en_us.json @@ -272,8 +272,9 @@ "createnuclear.reactor.debug.title": "--- Reactor diagnostics ---", "createnuclear.reactor.debug.valid_position": " valid @ %s", "createnuclear.snow_powder.fan.recipe": "Cryogenic fan", - "createnuclear.subtitle.alarm/alarm": "Reactor Alarm", + "createnuclear.subtitle.alarm/alarm": "Reactor Alarm Loop", "createnuclear.subtitle.alarm/reactor_alarm": "Reactor Alarm", + "createnuclear.subtitle.biomes/wasteland": "Wasteland", "createnuclear.subtitle.explosion/large_nuclear_explosion": "Large Nuclear Explosion", "createnuclear.subtitle.explosion/main": "Nuclear Explosion Main", "createnuclear.subtitle.explosion/nuclear_explosion": "Nuclear Explosion", @@ -283,8 +284,10 @@ "createnuclear.subtitle.explosion/shockwave": "Nuclear Explosion Shockwave", "createnuclear.subtitle.geiger/high": "Geiger High", "createnuclear.subtitle.geiger/low": "Geiger Low", - "createnuclear.subtitle.geiger/medium": "GeiGer Medium", + "createnuclear.subtitle.geiger/medium": "Geiger Medium", "createnuclear.subtitle.reacteur/activation": "Reactor Activation", + "createnuclear.subtitle.reacteur/assemble_deassemble/motor_assemble": "Motor Assemble", + "createnuclear.subtitle.reacteur/assemble_deassemble/motor_disassemble": "Motor Disassemble", "createnuclear.subtitle.reacteur/casing_break": "Break Reactor Casing", "createnuclear.subtitle.reacteur/casing_fall": "Reactor Casing Fall", "createnuclear.subtitle.reacteur/casing_hit": "Hit Reactor Casing", diff --git a/src/generated/resources/assets/createnuclear/sounds.json b/src/generated/resources/assets/createnuclear/sounds.json index 23537568..a6d3073a 100644 --- a/src/generated/resources/assets/createnuclear/sounds.json +++ b/src/generated/resources/assets/createnuclear/sounds.json @@ -17,6 +17,15 @@ ], "subtitle": "createnuclear.subtitle.alarm/reactor_alarm" }, + "biomes/wasteland": { + "sounds": [ + { + "type": "file", + "name": "createnuclear:biomes/wasteland" + } + ], + "subtitle": "createnuclear.subtitle.biomes/wasteland" + }, "explosion/large_nuclear_explosion": { "sounds": [ { @@ -116,6 +125,24 @@ ], "subtitle": "createnuclear.subtitle.reacteur/activation" }, + "reacteur/assemble_deassemble/motor_assemble": { + "sounds": [ + { + "type": "file", + "name": "createnuclear:reacteur/assemble_deassemble/motor_assemble" + } + ], + "subtitle": "createnuclear.subtitle.reacteur/assemble_deassemble/motor_assemble" + }, + "reacteur/assemble_deassemble/motor_disassemble": { + "sounds": [ + { + "type": "file", + "name": "createnuclear:reacteur/assemble_deassemble/motor_disassemble" + } + ], + "subtitle": "createnuclear.subtitle.reacteur/assemble_deassemble/motor_disassemble" + }, "reacteur/casing_break": { "sounds": [ { diff --git a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json index adbd57b2..442b9cfc 100644 --- a/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json +++ b/src/generated/resources/data/createnuclear/worldgen/biome/irradiated_land.json @@ -4,11 +4,7 @@ }, "downfall": 0.0, "effects": { - "additions_sound": { - "sound": "createnuclear:geiger/medium", - "tick_chance": 0.0111 - }, - "ambient_sound": "createnuclear:geiger/low", + "ambient_sound": "createnuclear:biomes/wasteland", "fog_color": 4742718, "foliage_color": 5660222, "grass_color": 9211739, diff --git a/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java b/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java index dd04aaf8..0889bc44 100644 --- a/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java +++ b/src/main/java/net/nuclearteam/createnuclear/CNSoundEvents.java @@ -35,7 +35,7 @@ public class CNSoundEvents { public static final Map ALL = new HashMap<>(); public static final SoundEntry - REACTOR_CASING_BREAD = create("reacteur/casing", "break") + REACTOR_CASING_BREAK = create("reacteur/casing", "break") .subtitle("Break Reactor Casing") .category(SoundSource.BLOCKS) .build(), @@ -75,13 +75,13 @@ public class CNSoundEvents { .category(SoundSource.BLOCKS) .build(), - REACTOR_ALARM = create("alarm/reactor", "alarm") + REACTOR_ALARM_ONESHOT = create("alarm/reactor", "alarm") .subtitle("Reactor Alarm") .category(SoundSource.BLOCKS) .build(), - REACTOR_ALARM_2 = create("alarm/alarm") - .subtitle("Reactor Alarm") + REACTOR_ALARM_LOOP = create("alarm/alarm") + .subtitle("Reactor Alarm Loop") .category(SoundSource.BLOCKS) .build(), @@ -90,7 +90,7 @@ public class CNSoundEvents { .category(SoundSource.AMBIENT) .build(), - LARGE_NUCLEAR_EXPLOSION = create("explosion/large_nuclear_explosion") + NUCLEAR_EXPLOSION_LARGE = create("explosion/large_nuclear_explosion") .subtitle("Large Nuclear Explosion") .category(SoundSource.AMBIENT) .build(), @@ -105,6 +105,16 @@ public class CNSoundEvents { .category(SoundSource.AMBIENT) .build(), + MOTOR_ASSEMBLE = create("reacteur/assemble_deassemble/motor_assemble") + .subtitle("Motor Assemble") + .category(SoundSource.BLOCKS) + .build(), + + MOTOR_DISASSEMBLE = create("reacteur/assemble_deassemble/motor_disassemble") + .subtitle("Motor Disassemble") + .category(SoundSource.BLOCKS) + .build(), + NUCLEAR_EXPLOSION_RUMBLE_2 = create("explosion/rumble") .subtitle("Nuclear Explosion Rumble") .category(SoundSource.AMBIENT) @@ -131,7 +141,12 @@ public class CNSoundEvents { .build(), GEIGER_MEDIUM = create("geiger/medium") - .subtitle("GeiGer Medium") + .subtitle("Geiger Medium") + .category(SoundSource.AMBIENT) + .build(), + + BIOME_WASTELAND = create("biomes/wasteland") + .subtitle("Wasteland") .category(SoundSource.AMBIENT) .build() ; diff --git a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java index e7fad4ca..4e63a755 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/multiblock/alarm/ReactorAlarmEntity.java @@ -54,7 +54,7 @@ protected void tickAudio() { if (soundInstance == null || soundInstance.isStopped()) { Minecraft minecraft = Minecraft.getInstance(); try { - soundInstance = new ReactorAlarmSoundInstance(level, worldPosition, CNSoundEvents.REACTOR_ALARM_2.getMainEvent()); + soundInstance = new ReactorAlarmSoundInstance(level, worldPosition, CNSoundEvents.REACTOR_ALARM_LOOP.getMainEvent()); minecraft.getSoundManager().play(soundInstance); } catch (Exception e) { CreateNuclear.LOGGER.warn("Failed to start alarm sound: " + e.getMessage()); diff --git a/src/main/java/net/nuclearteam/createnuclear/content/particles/NuclearMushroomCloudParticle.java b/src/main/java/net/nuclearteam/createnuclear/content/particles/NuclearMushroomCloudParticle.java index ec879247..69f5e677 100644 --- a/src/main/java/net/nuclearteam/createnuclear/content/particles/NuclearMushroomCloudParticle.java +++ b/src/main/java/net/nuclearteam/createnuclear/content/particles/NuclearMushroomCloudParticle.java @@ -78,7 +78,7 @@ public void tick() { playSound(large ? nuclear_explosions[0] : nuclear_explosions[1], lifetime - 20, lifetime, 0.2F, false); } else { CreateNuclear.LOGGER.info("EXPLOSIOOOOOON, (WITHOUT Alex's Cave)"); - playSound(large ? CNSoundEvents.LARGE_NUCLEAR_EXPLOSION.getMainEvent() : CNSoundEvents.NUCLEAR_EXPLOSION.getMainEvent(), lifetime - 20, lifetime, 0.2F, false); + playSound(large ? CNSoundEvents.NUCLEAR_EXPLOSION_LARGE.getMainEvent() : CNSoundEvents.NUCLEAR_EXPLOSION.getMainEvent(), lifetime - 20, lifetime, 0.2F, false); } } } diff --git a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java index 91c52244..0120f40c 100644 --- a/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java +++ b/src/main/java/net/nuclearteam/createnuclear/infrastructure/worldgen/biome/IrradiatedBiomes.java @@ -32,29 +32,25 @@ public static Biome irradiated(HolderGetter featureGetter, Holder BiomeSpecialEffects.Builder effectBuilder = new BiomeSpecialEffects.Builder(); effectBuilder - // Eau : Verte croupie - .waterColor(0x3B5133) - .waterFogColor(0x0A0E0A) + // Eau : Verte croupie + .waterColor(0x3B5133) + .waterFogColor(0x0A0E0A) - // BROUILLARD : Vert radioactif maladif (plus vif pour être visible) - .fogColor(0x485E3E) + // BROUILLARD : Vert radioactif maladif (plus vif pour être visible) + .fogColor(0x485E3E) - // CIEL : Gris-vert délavé (permet de voir le soleil/lune et le cycle jour/nuit) - .skyColor(0x324132) + // CIEL : Gris-vert délavé (permet de voir le soleil/lune et le cycle jour/nuit) + .skyColor(0x324132) - // HERBE : Jaune "soufre" / Brûlée - .grassColorOverride(0x8C8F5B) + // HERBE : Jaune "soufre" / Brûlée + .grassColorOverride(0x8C8F5B) - // FEUILLES : Olive desséché - .foliageColorOverride(0x565E3E) + // FEUILLES : Olive desséché + .foliageColorOverride(0x565E3E) - .ambientParticle(new AmbientParticleSettings(new IrradiatedParticlesData(), 0.025F)) - .ambientMoodSound(AmbientMoodSettings.LEGACY_CAVE_SETTINGS) - .ambientLoopSound(soundLookup.getOrThrow(ResourceKey.create(Registries.SOUND_EVENT, CNSoundEvents.GEIGER_LOW.getId()))) - .ambientAdditionsSound(new AmbientAdditionsSettings( - soundLookup.getOrThrow(ResourceKey.create(Registries.SOUND_EVENT, CNSoundEvents.GEIGER_MEDIUM.getId())), - 0.0111 - )) + .ambientParticle(new AmbientParticleSettings(new IrradiatedParticlesData(), 0.025F)) + .ambientMoodSound(AmbientMoodSettings.LEGACY_CAVE_SETTINGS) + .ambientLoopSound(soundLookup.getOrThrow(ResourceKey.create(Registries.SOUND_EVENT, CNSoundEvents.BIOME_WASTELAND.getId()))) ; IrradiatedBiomes.addDefaultIrradiatedOres(generation); diff --git a/src/main/resources/assets/createnuclear/sounds/biomes/wasteland.ogg b/src/main/resources/assets/createnuclear/sounds/biomes/wasteland.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a8b5bfb86df6353ad557a6e4f83116c5603ac262 GIT binary patch literal 978214 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 z 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