Skip to content

Commit

Permalink
More work on reactors
Browse files Browse the repository at this point in the history
  • Loading branch information
Rearth committed Dec 1, 2024
1 parent 593391a commit 821ade3
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package rearth.oritech.block.blocks.reactor;

import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
Expand Down Expand Up @@ -42,9 +43,15 @@ public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, Block
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {

if (!world.isClient && world.getBlockEntity(pos) instanceof ReactorControllerBlockEntity reactorController)
if (!world.isClient && world.getBlockEntity(pos) instanceof ReactorControllerBlockEntity reactorController) {
reactorController.init(player);

if (reactorController.active) {
var handler = (ExtendedScreenHandlerFactory) world.getBlockEntity(pos);
player.openHandledScreen(handler);
}
}

return super.onUse(state, world, pos, player, hit);
return ActionResult.SUCCESS;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
package rearth.oritech.block.blocks.reactor;

public class ReactorRodBlock extends BaseReactorBlock {
public ReactorRodBlock(Settings settings) {

private final int rodCount;
private final int internalPulseCount;

public ReactorRodBlock(Settings settings, int rodCount, int internalPulseCount) {
super(settings);
this.rodCount = rodCount;
this.internalPulseCount = internalPulseCount;
}

public int getRodCount() {
return rodCount;
}

public int getInternalPulseCount() {
return internalPulseCount;
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,49 @@
package rearth.oritech.block.entity.reactor;

import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector2i;
import rearth.oritech.block.blocks.reactor.*;
import rearth.oritech.client.init.ModScreens;
import rearth.oritech.client.ui.ReactorScreenHandler;
import rearth.oritech.init.BlockEntitiesContent;
import rearth.oritech.network.NetworkContent;
import rearth.oritech.util.energy.EnergyApi;
import rearth.oritech.util.energy.containers.SimpleEnergyStorage;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class ReactorControllerBlockEntity extends BlockEntity implements BlockEntityTicker<ReactorControllerBlockEntity> {
public class ReactorControllerBlockEntity extends BlockEntity implements BlockEntityTicker<ReactorControllerBlockEntity>, EnergyApi.BlockProvider, ExtendedScreenHandlerFactory {

public static final int MAX_SIZE = 64;

private int reactorHeat; // the heat of the entire casing
private final HashMap<Vector2i, BaseReactorBlock> activeComponents = new HashMap<>();
private final HashMap<Vector2i, Integer> componentHeats = new HashMap<>();

public boolean active = false;
private int reactorHeat; // the heat of the entire casing
private int reactorStackHeight;
private BlockPos areaMin;
private BlockPos areaMax;
private SimpleEnergyStorage energyStorage = new SimpleEnergyStorage(0, 1_000_000, 10_000_000, this::markDirty);

// client only
public NetworkContent.ReactorUIDataPacket uiData;

public ReactorControllerBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntitiesContent.REACTOR_CONTROLLER_BLOCK_ENTITY, pos, state);
}
Expand All @@ -43,7 +62,30 @@ public void tick(World world, BlockPos pos, BlockState state, ReactorControllerB
var componentHeat = componentHeats.get(localPos);
if (component instanceof ReactorRodBlock rodBlock) {

reactorHeat += 4;
var ownRodCount = rodBlock.getRodCount();
var receivedPulses = rodBlock.getInternalPulseCount();

// check how many pulses are received from neighbors / reflectors
for (var neighborPos : getNeighborsInBounds(localPos, activeComponents.keySet())) {

var neighbor = activeComponents.get(neighborPos);
if (neighbor instanceof ReactorRodBlock neighborRod) {
receivedPulses += neighborRod.getRodCount();
} else if (neighbor instanceof ReactorReflectorBlock reflectorBlock) {
receivedPulses += rodBlock.getRodCount();
}
}

// generate 5 RF per pulse
energyStorage.insertIgnoringLimit(5 * receivedPulses * reactorStackHeight, false);

// generate heat per pulse
componentHeat += (receivedPulses / 2 * receivedPulses + 4);

// move a base amount of heat to the reactor hull
var moved = ownRodCount * 4;
componentHeat -= moved;
reactorHeat += moved * reactorStackHeight;

} else if (component instanceof ReactorHeatPipeBlock heatPipeBlock) {

Expand All @@ -59,39 +101,26 @@ public void tick(World world, BlockPos pos, BlockState state, ReactorControllerB
}

// move heat to reactor
var moveAmount = Math.min(10, componentHeat);
reactorHeat += moveAmount;
var moveAmount = Math.min(12, componentHeat);
reactorHeat += moveAmount * reactorStackHeight;
componentHeat -= moveAmount;

} else if (component instanceof ReactorHeatVentBlock ventBlock) {

reactorHeat = Math.max(reactorHeat - 4, 0);

} else if (component instanceof ReactorReflectorBlock reflectorBlock) {

// do extra ticks on neighboring rods
for (var neighborPos : getNeighborsInBounds(localPos, activeComponents.keySet())) {

var neighbor = activeComponents.get(neighborPos);
if (neighbor instanceof ReactorRodBlock neighborRod) {
var rodHeat = componentHeats.get(neighborPos);
rodHeat += 4;
componentHeats.put(neighborPos, rodHeat);
}
}
var moved = (reactorHeat - 6) * reactorStackHeight;
reactorHeat = Math.max(moved, 0);

}

componentHeats.put(localPos, componentHeat);
}

System.out.println(reactorHeat);
System.out.println(Arrays.toString(componentHeats.entrySet().toArray()));

}

public void init(PlayerEntity player) {

active = false;

// find low and high corners of reactor
var cornerA = pos;
cornerA = expandWall(cornerA, new Vec3i(0, -1, 0), true); // first go down through other wall blocks
Expand Down Expand Up @@ -137,7 +166,9 @@ public void init(PlayerEntity player) {
var interiorHeight = cornerB.getY() - cornerA.getY() - 1;
var cornerAFlat = cornerA.add(1, 1, 1);
var cornerBFlat = new BlockPos(cornerB.getX() - 1, cornerA.getY() + 1, cornerB.getZ() - 1);

activeComponents.clear();
reactorStackHeight = interiorHeight;

var interiorStackedRight = BlockPos.stream(cornerAFlat, cornerBFlat).allMatch(pos -> {

Expand Down Expand Up @@ -165,6 +196,10 @@ public void init(PlayerEntity player) {
return;
}

areaMin = finalCornerA;
areaMax = finalCornerB;
active = true;

System.out.println("walls: " + wallsValid + " interiorStack: " + interiorStackedRight + " height: " + interiorHeight);

}
Expand Down Expand Up @@ -224,4 +259,26 @@ private BlockPos expandWall(BlockPos from, Vec3i direction, boolean allReactorBl

}

@Override
public EnergyApi.EnergyContainer getStorage(Direction direction) {
return energyStorage;
}

@Override
public Object getScreenOpeningData(ServerPlayerEntity player) {
var previewMax = new BlockPos(areaMax.getX(), areaMin.getY() + 1, areaMax.getZ());
NetworkContent.MACHINE_CHANNEL.serverHandle(this).send(new NetworkContent.ReactorUIDataPacket(pos, areaMin, areaMax, previewMax));
return new ModScreens.BasicData(pos);
}

@Override
public Text getDisplayName() {
return Text.of("");
}

@Nullable
@Override
public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
return new ReactorScreenHandler(syncId, playerInventory, this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class ModScreens implements ArchitecturyRegistryContainer<ScreenHandlerTy
public static final ExtendedScreenHandlerType<SteamEngineScreenHandler, UpgradableData> STEAM_ENGINE_SCREEN = new ExtendedScreenHandlerType<>(new UpgradeFactory<>(SteamEngineScreenHandler.class), UpgradableData.PACKET_CODEC);
public static final ExtendedScreenHandlerType<ItemFilterScreenHandler, BasicData> ITEM_FILTER_SCREEN = new ExtendedScreenHandlerType<>(new BasicFactory<>(ItemFilterScreenHandler.class), BasicData.PACKET_CODEC);
public static final ExtendedScreenHandlerType<InventoryProxyScreenHandler, InventoryProxyScreenHandler.InvProxyData> INVENTORY_PROXY_SCREEN = new ExtendedScreenHandlerType<>(new InventoryProxyScreenHandler.HandlerFactory(), InventoryProxyScreenHandler.InvProxyData.PACKET_CODEC);
public static final ExtendedScreenHandlerType<ReactorScreenHandler, BasicData> REACTOR_SCREEN = new ExtendedScreenHandlerType<>(new ReactorScreenHandler.HandlerFactory(), BasicData.PACKET_CODEC);

public static void assignScreens() {
HandledScreens.register(TANK_SCREEN, BasicMachineScreen<BasicMachineScreenHandler>::new);
Expand All @@ -83,6 +84,7 @@ public static void assignScreens() {
HandledScreens.register(LASER_SCREEN, UpgradableMachineScreen<UpgradableMachineScreenHandler>::new);

HandledScreens.register(INVENTORY_PROXY_SCREEN, InventoryProxyScreen::new);
HandledScreens.register(REACTOR_SCREEN, ReactorScreen::new);
HandledScreens.register(ITEM_FILTER_SCREEN, ItemFilterScreen::new);
HandledScreens.register(DRONE_SCREEN, DroneScreen::new);
HandledScreens.register(REDSTONE_ADDON_SCREEN, RedstoneAddonScreen::new);
Expand Down
86 changes: 86 additions & 0 deletions common/src/main/java/rearth/oritech/client/ui/ReactorScreen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package rearth.oritech.client.ui;

import io.wispforest.owo.ui.base.BaseOwoHandledScreen;
import io.wispforest.owo.ui.component.Components;
import io.wispforest.owo.ui.container.Containers;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.core.*;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.NotNull;

public class ReactorScreen extends BaseOwoHandledScreen<FlowLayout, ReactorScreenHandler> {

public ReactorScreen(ReactorScreenHandler handler, PlayerInventory inventory, Text title) {
super(handler, inventory, title);
}

@Override
protected @NotNull OwoUIAdapter<FlowLayout> createAdapter() {
return OwoUIAdapter.create(this, Containers::verticalFlow);
}

@Override
protected void build(FlowLayout rootComponent) {
rootComponent
.surface(Surface.VANILLA_TRANSLUCENT)
.horizontalAlignment(HorizontalAlignment.CENTER)
.verticalAlignment(VerticalAlignment.CENTER);

var overlay = Containers.horizontalFlow(Sizing.fixed(240), Sizing.fixed(200));

if (handler.reactorEntity.uiData != null) {
addReactorComponentPreview(overlay);
}

rootComponent.child(overlay.surface(Surface.PANEL));

addTitle(overlay);
}

private void addReactorComponentPreview(FlowLayout overlay) {

var holoPreviewContainer = Containers.horizontalFlow(Sizing.fixed(180), Sizing.fixed(180));
holoPreviewContainer.surface(Surface.PANEL_INSET);
holoPreviewContainer.margins(Insets.of(2));

var uiData = handler.reactorEntity.uiData;
var rightMostPoint = uiData.min();
var leftMostPoint = uiData.previewMax();
var dist = rightMostPoint.getManhattanDistance(leftMostPoint);

var availableDist = 170 / 20;
var scaling = availableDist / (float) dist * 2;
if (dist > 10) scaling *= 1.15f;

System.out.println(dist + " | " + scaling);

BlockPos.stream(uiData.min(), uiData.previewMax()).forEach(pos -> {
var offset = pos.subtract(uiData.min());
var uiPos = new BlockPos(-offset.getX(), offset.getY(), -offset.getZ());
var preview = Components.block(handler.world.getBlockState(pos), handler.world.getBlockEntity(pos))
.sizing(Sizing.fixed(170))
.positioning(Positioning.absolute(5, 85));
if (uiPos.getY() == 1) {
System.out.println("added tooltip!");
preview.tooltip(handler.world.getBlockState(pos).getBlock().getName());
}
holoPreviewContainer.child(preview);

});

overlay.child(holoPreviewContainer);

}

private void addTitle(FlowLayout overlay) {
var blockTitle = handler.reactorEntity.getCachedState().getBlock().getName();
var label = Components.label(blockTitle);
label.color(new Color(64 / 255f, 64 / 255f, 64 / 255f));
label.sizing(Sizing.fixed(176), Sizing.content(2));
label.horizontalTextAlignment(HorizontalAlignment.CENTER);
label.zIndex(1);
overlay.child(label.positioning(Positioning.relative(50, 2)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package rearth.oritech.client.ui;

import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.world.World;
import rearth.oritech.block.entity.reactor.ReactorControllerBlockEntity;
import rearth.oritech.client.init.ModScreens;

public class ReactorScreenHandler extends ScreenHandler {

public final ReactorControllerBlockEntity reactorEntity;
public final World world;

// this calls the second version
public ReactorScreenHandler(int syncId, PlayerInventory inventory, ModScreens.BasicData setupData) {
this(syncId, inventory, inventory.player.getWorld().getBlockEntity(setupData.pos()));
}

// on server, also called from client constructor
public ReactorScreenHandler(int syncId, PlayerInventory playerInventory, BlockEntity blockEntity) {
super(ModScreens.REACTOR_SCREEN, syncId);

reactorEntity = (ReactorControllerBlockEntity) blockEntity;
world = blockEntity.getWorld();
}

@Override
public ItemStack quickMove(PlayerEntity player, int slot) {
return ItemStack.EMPTY;
}
public boolean canUse(PlayerEntity player) {
return true;
}

public static class HandlerFactory implements ExtendedScreenHandlerType.ExtendedFactory<ReactorScreenHandler, ModScreens.BasicData> {
@Override
public ReactorScreenHandler create(int syncId, PlayerInventory inventory, ModScreens.BasicData data) {
return new ReactorScreenHandler(syncId, inventory, data);
}
}
}
Loading

0 comments on commit 821ade3

Please sign in to comment.