Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 1.21.1 2026-08-05T15:29:29.6932028 Registrate Provider for createnuclear [Registries, Data Maps, Recipes, Advancements, Loot Tables, Tags (blocks), Tags (enchantments), Tags (items), Tags (fluids), Tags (entity_types), generic_server_provider, Blockstates, Item models, Lang (en_us/en_ud), generic_client_provider]
// 1.21.1 2026-07-28T15:27:40.454156 Registrate Provider for createnuclear [Registries, Data Maps, Recipes, Advancements, Loot Tables, Tags (enchantments), Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), generic_server_provider, Blockstates, Item models, Lang (en_us/en_ud), generic_client_provider]
0b2c76c9cff305eacfdfb57c4b703f94ca6dc903 assets/createnuclear/blockstates/autunite.json
5d06bc544bcbeb7443178d66955bb5101cf696da assets/createnuclear/blockstates/autunite_pillar.json
5b375444ac5057e63776f4991589c57824574b4a assets/createnuclear/blockstates/cut_autunite.json
Expand Down Expand Up @@ -48,8 +48,13 @@ b9c915389ea6cf8338d20c48e908591f8baa2108 assets/createnuclear/blockstates/small_
643a4d44b491a84d0d26e1a8944dffc40e83ce14 assets/createnuclear/blockstates/thorium_ore.json
de2884054a21315d8b167f64b206be331d388420 assets/createnuclear/blockstates/uranium.json
4557f548df100ae1d05e3b5711797225f6a39673 assets/createnuclear/blockstates/uranium_ore.json
<<<<<<< HEAD
ec0b4fa9b99c97e1812fbf1d2e7c21f17a3cf2ca assets/createnuclear/lang/en_ud.json
d79b3c4818d54f51162b121c29f4ef1d6375131c assets/createnuclear/lang/en_us.json
=======
d0222636b430f46f1e94b0ae330879e0f1c78ddf assets/createnuclear/lang/en_ud.json
153afa32083963f7ad037e0f44ef3290a6cf2c47 assets/createnuclear/lang/en_us.json
>>>>>>> V2
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
@SuppressWarnings("deprecation")
public class ReactorControllerBlock extends HorizontalDirectionalReactorBlock implements IWrenchable, IBE<ReactorControllerBlockEntity> {
public static final BooleanProperty ASSEMBLED = BooleanProperty.create("assembled");
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");

public ReactorControllerBlock(Properties properties) {
super(properties);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@
import net.nuclearteam.createnuclear.content.multiblock.IHeat;
import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.PatternData;
import net.nuclearteam.createnuclear.content.multiblock.bluePrintItem.ReactorBluePrintData;
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.manager.*;
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.input.fluid.PersistentFluidLocks;
import net.nuclearteam.createnuclear.content.multiblock.input.fluid.ReactorFluidInputEntity;
Expand Down Expand Up @@ -148,6 +152,10 @@ public class ReactorControllerBlockEntity extends SmartBlockEntity implements II
private final ReactorInputFluidManagerI inputFluidManager;
private final ReactorAlarmManagerI alarmManager;

private ReactorDisplayState displayState = ReactorDisplayState.EMPTY;

//private final IReactorHeatUpdateCoordinator heatCoordinator;

// Client Display Data (Synced via NBT)
private Map<Item, Integer> clientDisplayItems = new HashMap<>();
private List<BigFluidStack> clientDisplayFluids = new ArrayList<>();
Expand Down Expand Up @@ -304,6 +312,14 @@ public void setLiquidLife(double l) {
this.liquidLife = l;
}

public void setDisplayState(ReactorDisplayState state) {
this.displayState = state;
}

public ReactorDisplayState getDisplayState() {
return this.displayState;
}

/**
* Main constructor allowing dependency injection for testability and DIP
* compliance.
Expand Down Expand Up @@ -338,27 +354,14 @@ public boolean getAssembled() { // permet de savoir si le réacteur est formé o

@Override
public boolean addToGoggleTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
if(!configuredPattern.isEmpty()) {
CreateLang.translate("gui.gauge.info_header").style(ChatFormatting.GRAY).forGoggles(tooltip);
IHeat.HeatLevel.getName("reactor_controller").style(ChatFormatting.GRAY).forGoggles(tooltip);
CompoundTag patternTag = this.getConfiguredPatternTag();

IHeat.HeatLevel.getFormattedHeatText(heat).forGoggles(tooltip);

if (fuelItem.isEmpty()) {
// if rod empty we initialize it at 1 (and display it as 0) to avoid having air item displayed instead of the rod
IHeat.HeatLevel.getFormattedItemText(new ItemStack(CNItems.URANIUM_ROD.asItem(), 1), true).forGoggles(tooltip);
} else {
IHeat.HeatLevel.getFormattedItemText(fuelItem, false).forGoggles(tooltip);
}

if (fuelItem.isEmpty()) {
// if rod empty we initialize it at 1 (and display it as 0) to avoid having air item displayed instead of the rod
IHeat.HeatLevel.getFormattedItemText(new ItemStack(CNItems.GRAPHITE_ROD.asItem(), 1), true).forGoggles(tooltip);
} else {
IHeat.HeatLevel.getFormattedItemText(coolerItem, false).forGoggles(tooltip);
}
if (patternTag == null || patternTag.isEmpty()) {
return false;
}

ReactorGoggleTooltipRenderer.render(tooltip, displayState, patternTag.getInt("heat"), isPlayerSneaking, reactorSize);

return true;
}

Expand Down Expand Up @@ -424,6 +427,22 @@ public enum State {
ON, OFF
}

private void updateReactorStateVisibility() {
if (level == null || level.isClientSide) return;

BlockState state = getBlockState();
if (!(state.getBlock() instanceof ReactorControllerBlock)) return;

boolean currentActive = state.getValue(ReactorControllerBlock.ACTIVE);

// 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) {
level.setBlock(worldPosition, state.setValue(ReactorControllerBlock.ACTIVE, targetActive), 3);
}*/
}

@Override
public void tick() {
super.tick();
Expand Down Expand Up @@ -483,6 +502,10 @@ public void tick() {
return;
}
}

ReactorInputSnapshot snapshot = ReactorInputSnapshotBuilder.build(level, inputManager, inputFluidManager);
this.displayState = new ReactorDisplayState(snapshot.items(), snapshot.fluids(), snapshot.maxFluidCapacity());

this.notifyUpdate();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package net.nuclearteam.createnuclear.content.multiblock.controller.display;

import net.minecraft.core.HolderLookup;
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.minecraft.core.registries.BuiltInRegistries;
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}).
* <p>
* 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(HolderLookup.Provider)} / {@link #deserializeNBT(HolderLookup.Provider, 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.
* <p>
* Usage:
* <pre>{@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;
* }</pre>
*
* @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<Item, Integer> items, List<BigFluidStack> 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(HolderLookup.Provider, CompoundTag)}
* to restore an equivalent instance on the client.
* @param registries holder lookup provider for serialization
* @return a new {@link CompoundTag} containing the serialized item map,
* fluid list and max fluid capacity
*/
public CompoundTag serializeNBT(HolderLookup.Provider registries) {
CompoundTag compound = new CompoundTag();

ListTag displayItemsTag = new ListTag();
for (Entry<Item, Integer> entry : items().entrySet()) {
CompoundTag tag = new CompoundTag();
ResourceLocation rl = BuiltInRegistries.ITEM.getKey(entry.getKey());
if (rl != null) {
tag.putString(COMPONENT_ITEM, rl.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(registries));
}
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(HolderLookup.Provider)}. Acts as a static factory since records cannot be
* mutated in place.
* <p>
* 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(HolderLookup.Provider registries, CompoundTag compound) {
Map<Item, Integer> 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);
ResourceLocation rl = ResourceLocation.tryParse(tag.getString(COMPONENT_ITEM));
if (rl != null) {
Item item = BuiltInRegistries.ITEM.get(rl);
if (item != null) {
items.put(item, tag.getInt(COMPONENT_COUNT));
}
}
}
}

List<BigFluidStack> 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(registries, list.getCompound(i)));
}
}

long maxFluidCapacity = compound.getLong(COMPONENT_CLIENT_MAX_FLUIDS_CAPACITY);

return new ReactorDisplayState(items, fluids, maxFluidCapacity);
}
}
Loading