mirror of
https://github.com/XevianLight/Aphelion.git
synced 2026-05-11 01:50:56 +01:00
RocketEntity.disassemble and dupe fixes. Fixed VAF menu not appearing.
This commit is contained in:
@@ -42,7 +42,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvider, TickableBlockEntity {
|
||||
public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvider, TickableBlockEntity, IArcFurnaceLike {
|
||||
|
||||
private final int SIZE = 4;
|
||||
private int ENERGY_CAPACITY = 64000;
|
||||
@@ -309,6 +309,11 @@ public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvide
|
||||
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEnergyStorage getTrueEnergyStorage() {
|
||||
return ENERGY_STORAGE;
|
||||
}
|
||||
|
||||
private final IItemHandler fullHandler = new SidedSlotHandler(inventory, new int[]{INPUT_SLOT, SECONDARY_INPUT_SLOT, OUTPUT_SLOT, ENERGY_SLOT}, true, true);
|
||||
private final IItemHandler emptyJeiHandler = new SidedSlotHandler(inventory, new int[]{}, false, false);
|
||||
private final IItemHandler inputHandler = new SidedSlotHandler(inventory, new int[]{0,1}, true, true);
|
||||
@@ -344,6 +349,11 @@ public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvide
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModEnergyStorage getEnergy() {
|
||||
return ENERGY_STORAGE;
|
||||
}
|
||||
|
||||
public void drops() {
|
||||
SimpleContainer inv = new SimpleContainer(inventory.getSlots());
|
||||
for(int i = 0; i < inventory.getSlots(); i++) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.xevianlight.aphelion.block.entity.custom;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.neoforged.neoforge.energy.IEnergyStorage;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
import net.xevianlight.aphelion.block.entity.energy.ModEnergyStorage;
|
||||
|
||||
|
||||
public interface IArcFurnaceLike {
|
||||
ItemStackHandler getInventory();
|
||||
ModEnergyStorage getEnergy();
|
||||
|
||||
void sendUpdate();
|
||||
|
||||
BlockState getBlockState();
|
||||
|
||||
IEnergyStorage getTrueEnergyStorage();
|
||||
}
|
||||
@@ -16,6 +16,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.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.xevianlight.aphelion.Aphelion;
|
||||
import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity;
|
||||
import net.xevianlight.aphelion.core.init.ModBlockEntities;
|
||||
@@ -35,6 +36,7 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
||||
Direction facing;
|
||||
BlockPos padScanStart = BlockPos.ZERO;
|
||||
private PadInfo padBounds;
|
||||
RocketEntity lastRocket;
|
||||
|
||||
public @Nullable PadInfo getPadBounds() {
|
||||
return padBounds;
|
||||
@@ -279,11 +281,14 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
||||
if (level == null) return null;
|
||||
RocketStructure structure = scan();
|
||||
RocketEntity rocket = null;
|
||||
if (lastRocket != null)
|
||||
lastRocket.disassemble();
|
||||
if (structure != null && seatPos != null) {
|
||||
RocketStructure.clearCaptured(level, seatPos, structure);
|
||||
rocket = RocketEntity.spawnRocket(level, seatPos, structure);
|
||||
Aphelion.LOGGER.info("Spawn rocket result: {}", rocket);
|
||||
}
|
||||
lastRocket = rocket;
|
||||
return rocket;
|
||||
}
|
||||
|
||||
@@ -394,4 +399,6 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
||||
this.loadAdditional(tag, registries);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class VacuumArcFurnaceControllerEntity extends BlockEntity implements MenuProvider, IMultiblockController, TickableBlockEntity {
|
||||
public class VacuumArcFurnaceControllerEntity extends BlockEntity implements MenuProvider, IMultiblockController, TickableBlockEntity, IArcFurnaceLike {
|
||||
|
||||
private final int SIZE = 4;
|
||||
private final int ENERGY_CAPACITY = 64000;
|
||||
@@ -357,7 +357,8 @@ public class VacuumArcFurnaceControllerEntity extends BlockEntity implements Men
|
||||
return isFormed() ? ENERGY_STORAGE : null;
|
||||
}
|
||||
|
||||
public IEnergyStorage getTrueEnergyStorage(@Nullable Direction direction) {
|
||||
@Override
|
||||
public IEnergyStorage getTrueEnergyStorage() {
|
||||
return this.ENERGY_STORAGE;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,24 @@ public class RocketAssemblerBlockEntityRenderer implements BlockEntityRenderer<R
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AABB getRenderBoundingBox(RocketAssemblerBlockEntity blockEntity) {
|
||||
// If we don't know bounds yet, fall back to default BE culling.
|
||||
RocketAssemblerBlockEntity.PadInfo pad = blockEntity.getPadBounds();
|
||||
if (pad == null) {
|
||||
return BlockEntityRenderer.super.getRenderBoundingBox(blockEntity);
|
||||
}
|
||||
|
||||
BlockPos min = pad.min();
|
||||
BlockPos max = pad.max();
|
||||
|
||||
// Expand slightly to avoid edge precision culling
|
||||
return new AABB(
|
||||
min.getX(), min.getY(), min.getZ(),
|
||||
max.getX() + 1, max.getY() + 1, max.getZ() + 1
|
||||
).inflate(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(@NotNull RocketAssemblerBlockEntity be, float v, @NotNull PoseStack poseStack, @NotNull MultiBufferSource multiBufferSource, int i, int i1) {
|
||||
// if (!Minecraft.getInstance().gui.getDebugOverlay().showDebugScreen()) return;
|
||||
|
||||
@@ -474,6 +474,22 @@ public class AphelionCommand {
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("disassemble")
|
||||
.executes(context -> {
|
||||
Entity entity = EntityArgument.getEntity(context, "entity");
|
||||
|
||||
if (entity instanceof RocketEntity rocket) {
|
||||
if (rocket.disassemble()) {
|
||||
context.getSource().sendSuccess(() -> Component.translatable("command.aphelion.rocket.disassemble.success"), true);
|
||||
} else {
|
||||
context.getSource().sendFailure(Component.translatable("command.aphelion.rocket.disassemble.failure"));
|
||||
}
|
||||
} else {
|
||||
context.getSource().sendFailure(Component.translatable("command.aphelion.rocket.entity_invalid"));
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -506,4 +506,54 @@ public class RocketEntity extends VehicleEntity implements IEntityWithComplexSpa
|
||||
return InteractionResult.sidedSuccess(level().isClientSide);
|
||||
}
|
||||
|
||||
public boolean disassemble() {
|
||||
if (level().isClientSide) return false;
|
||||
if (!(level() instanceof ServerLevel server)) return false;
|
||||
|
||||
// Optional: only allow when not in flight
|
||||
if (getPhase() == FlightPhase.ASCEND || getPhase() == FlightPhase.TRANSIT || getPhase() == FlightPhase.DESCEND) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Kick riders off first (so we don't place blocks inside them)
|
||||
ejectPassengers();
|
||||
|
||||
// Anchor: blocks were captured relative to the scan origin.
|
||||
// Your rocket is spawned at seatPos + (0.5, 0, 0.5), so we convert back to the block origin.
|
||||
BlockPos origin = BlockPos.containing(getX(), getY(), getZ());
|
||||
|
||||
// Place blocks
|
||||
for (int i = 0; i < structure.size(); i++) {
|
||||
int packed = structure.packedPosAt(i);
|
||||
|
||||
int dx = RocketStructure.unpackX(packed);
|
||||
int dy = RocketStructure.unpackY(packed);
|
||||
int dz = RocketStructure.unpackZ(packed);
|
||||
|
||||
BlockPos wp = origin.offset(dx, dy, dz);
|
||||
var stateToPlace = structure.stateAt(i);
|
||||
|
||||
// Don't place air (shouldn't exist in structure anyway, but safe)
|
||||
if (stateToPlace.isAir()) continue;
|
||||
|
||||
// Safety: don't overwrite existing blocks
|
||||
if (!server.getBlockState(wp).isAir()) {
|
||||
// If you want strict behavior, abort entirely:
|
||||
// return false;
|
||||
|
||||
// Otherwise just skip conflicts:
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extra safety: avoid accidentally placing into portal/void/etc if desired
|
||||
// if (!server.isInWorldBounds(wp)) continue;
|
||||
|
||||
server.setBlock(wp, stateToPlace, 3);
|
||||
}
|
||||
|
||||
// Remove the rocket entity
|
||||
discard(); // preferred over kill() for "just remove this entity"
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,13 +12,14 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.neoforged.neoforge.items.SlotItemHandler;
|
||||
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
|
||||
import net.xevianlight.aphelion.block.entity.custom.IArcFurnaceLike;
|
||||
import net.xevianlight.aphelion.util.EnergyItemSlot;
|
||||
import net.xevianlight.aphelion.util.ExtractOnlySlot;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ElectricArcFurnaceMenu extends AbstractContainerMenu {
|
||||
|
||||
public final ElectricArcFurnaceEntity blockEntity;
|
||||
public final IArcFurnaceLike blockEntity;
|
||||
private final Level level;
|
||||
private final ContainerData data;
|
||||
|
||||
@@ -28,17 +29,17 @@ public class ElectricArcFurnaceMenu extends AbstractContainerMenu {
|
||||
|
||||
public ElectricArcFurnaceMenu(int i, Inventory inventory, BlockEntity blockEntity, ContainerData data) {
|
||||
super(ModMenuTypes.ELECTRIC_ARC_FURNACE_MENU.get(), i);
|
||||
this.blockEntity = ((ElectricArcFurnaceEntity) blockEntity);
|
||||
this.blockEntity = ((IArcFurnaceLike) blockEntity);
|
||||
this.level = inventory.player.level();
|
||||
this.data = data;
|
||||
|
||||
addPlayerInventory(inventory);
|
||||
addPlayerHotbar(inventory);
|
||||
|
||||
this.addSlot(new EnergyItemSlot(this.blockEntity.inventory, ElectricArcFurnaceEntity.ENERGY_SLOT, 8, 54));
|
||||
this.addSlot(new SlotItemHandler(this.blockEntity.inventory, ElectricArcFurnaceEntity.INPUT_SLOT, 63, 35));
|
||||
this.addSlot(new SlotItemHandler(this.blockEntity.inventory, ElectricArcFurnaceEntity.SECONDARY_INPUT_SLOT, 40, 35));
|
||||
this.addSlot(new ExtractOnlySlot(this.blockEntity.inventory, ElectricArcFurnaceEntity.OUTPUT_SLOT, 125, 35));
|
||||
this.addSlot(new EnergyItemSlot(this.blockEntity.getInventory(), ElectricArcFurnaceEntity.ENERGY_SLOT, 8, 54));
|
||||
this.addSlot(new SlotItemHandler(this.blockEntity.getInventory(), ElectricArcFurnaceEntity.INPUT_SLOT, 63, 35));
|
||||
this.addSlot(new SlotItemHandler(this.blockEntity.getInventory(), ElectricArcFurnaceEntity.SECONDARY_INPUT_SLOT, 40, 35));
|
||||
this.addSlot(new ExtractOnlySlot(this.blockEntity.getInventory(), ElectricArcFurnaceEntity.OUTPUT_SLOT, 125, 35));
|
||||
|
||||
addDataSlots(data);
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ public class ElectricArcFurnaceScreen extends AbstractContainerScreen<ElectricAr
|
||||
}
|
||||
|
||||
private void renderEnergyBar(GuiGraphics guiGraphics, int x, int y) {
|
||||
int stored = menu.blockEntity.getTrueEnergyStorage(null).getEnergyStored();
|
||||
int max = menu.blockEntity.getTrueEnergyStorage(null).getMaxEnergyStored();
|
||||
int stored = menu.blockEntity.getTrueEnergyStorage().getEnergyStored();
|
||||
int max = menu.blockEntity.getTrueEnergyStorage().getMaxEnergyStored();
|
||||
|
||||
int h = (max <= 0) ? 0 : (int) Math.round((stored / (double) max) * 42.0);
|
||||
h = Math.max(0, Math.min(42, h));
|
||||
@@ -79,7 +79,7 @@ public class ElectricArcFurnaceScreen extends AbstractContainerScreen<ElectricAr
|
||||
|
||||
private void assignEnergyInfoArea() {
|
||||
energyInfoArea = new EnergyDisplayTooltipArea(((width - imageWidth) / 2) + 9,
|
||||
((height - imageHeight) / 2 ) + 9, menu.blockEntity.getTrueEnergyStorage(null), 14, 42);
|
||||
((height - imageHeight) / 2 ) + 9, menu.blockEntity.getTrueEnergyStorage(), 14, 42);
|
||||
}
|
||||
|
||||
private void renderEnergyAreaTooltip(GuiGraphics guiGraphics, int pMouseX, int pMouseY, int x, int y) {
|
||||
|
||||
@@ -62,8 +62,8 @@ public class VacuumArcFurnaceScreen extends AbstractContainerScreen<VacuumArcFur
|
||||
}
|
||||
|
||||
private void renderEnergyBar(GuiGraphics guiGraphics, int x, int y) {
|
||||
int stored = menu.blockEntity.getTrueEnergyStorage(null).getEnergyStored();
|
||||
int max = menu.blockEntity.getTrueEnergyStorage(null).getMaxEnergyStored();
|
||||
int stored = menu.blockEntity.getTrueEnergyStorage().getEnergyStored();
|
||||
int max = menu.blockEntity.getTrueEnergyStorage().getMaxEnergyStored();
|
||||
|
||||
int h = (max <= 0) ? 0 : (int) Math.round((stored / (double) max) * 42.0);
|
||||
h = Math.max(0, Math.min(42, h));
|
||||
@@ -79,7 +79,7 @@ public class VacuumArcFurnaceScreen extends AbstractContainerScreen<VacuumArcFur
|
||||
|
||||
private void assignEnergyInfoArea() {
|
||||
energyInfoArea = new EnergyDisplayTooltipArea(((width - imageWidth) / 2) + 9,
|
||||
((height - imageHeight) / 2 ) + 9, menu.blockEntity.getTrueEnergyStorage(null), 14, 42);
|
||||
((height - imageHeight) / 2 ) + 9, menu.blockEntity.getTrueEnergyStorage(), 14, 42);
|
||||
}
|
||||
|
||||
private void renderEnergyAreaTooltip(GuiGraphics guiGraphics, int pMouseX, int pMouseY, int x, int y) {
|
||||
|
||||
@@ -5,8 +5,11 @@ import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -170,15 +173,54 @@ public final class RocketStructure {
|
||||
}
|
||||
|
||||
public static void clearCaptured(Level level, BlockPos origin, RocketStructure struct) {
|
||||
final int flags = Block.UPDATE_CLIENTS;
|
||||
|
||||
// Pass 1: remove blocks which implement DOUBLE_BLOCK_HALF like doors to try and prevent duplication.
|
||||
for (int i = 0; i < struct.size(); i++) {
|
||||
int packed = struct.packedPosAt(i);
|
||||
int dx = RocketStructure.unpackX(packed);
|
||||
int dy = RocketStructure.unpackY(packed);
|
||||
int dz = RocketStructure.unpackZ(packed);
|
||||
BlockPos wp = origin.offset(
|
||||
RocketStructure.unpackX(packed),
|
||||
RocketStructure.unpackY(packed),
|
||||
RocketStructure.unpackZ(packed)
|
||||
);
|
||||
|
||||
BlockPos wp = origin.offset(dx, dy, dz);
|
||||
if (level.getBlockState(wp).is(struct.stateAt(i).getBlock()))
|
||||
level.setBlock(wp, Blocks.AIR.defaultBlockState(), 3);
|
||||
BlockState st = level.getBlockState(wp);
|
||||
if (st.isAir()) continue;
|
||||
|
||||
if (st.hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF)) {
|
||||
DoubleBlockHalf half = st.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF);
|
||||
BlockPos bottom = (half == DoubleBlockHalf.LOWER) ? wp : null;
|
||||
|
||||
// Break the BOTTOM block to stop potential dupes, as it seems that is the "master" block for doors.
|
||||
// If you set the top block to air, the bottom one breaks a moment later and drops.
|
||||
// If this doesn't work I declare it NOT MY FAULT!
|
||||
// DoubleBlockHalf blocks should have a way to delete the entire thing at once god damnit
|
||||
if (bottom != null && !level.getBlockState(bottom).isAir()) {
|
||||
level.setBlock(bottom, Blocks.AIR.defaultBlockState(), flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: remove likely-attached blocks first. This should stop duplication of torches/buttons/whatever else may break due to its supporting block being broken
|
||||
for (int i = 0; i < struct.size(); i++) {
|
||||
int packed = struct.packedPosAt(i);
|
||||
BlockPos wp = origin.offset(unpackX(packed), unpackY(packed), unpackZ(packed));
|
||||
BlockState st = level.getBlockState(wp);
|
||||
if (st.isAir()) continue;
|
||||
|
||||
// Heuristic: if it isn't a full collision cube, it's often "attached" (buttons, torches, etc.)
|
||||
if (!st.isCollisionShapeFullBlock(level, wp)) {
|
||||
level.setBlock(wp, Blocks.AIR.defaultBlockState(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 3: remove the rest
|
||||
for (int i = 0; i < struct.size(); i++) {
|
||||
int packed = struct.packedPosAt(i);
|
||||
BlockPos wp = origin.offset(unpackX(packed), unpackY(packed), unpackZ(packed));
|
||||
if (!level.getBlockState(wp).isAir()) {
|
||||
level.setBlock(wp, Blocks.AIR.defaultBlockState(), flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,5 +52,7 @@
|
||||
"command.aphelion.rocket.get_dim.success": "Target dimension of rocket is %s",
|
||||
"command.aphelion.rocket.set_pos.success": "Set target position of rocket to %s",
|
||||
"command.aphelion.rocket.get_pos.success": "Target position of rocket is %s",
|
||||
"command.aphelion.rocket.get_pos.success.null": "Target position of rocket is not set"
|
||||
"command.aphelion.rocket.get_pos.success.null": "Target position of rocket is not set",
|
||||
"command.aphelion.rocket.disassemble.success": "Rocket disassembled",
|
||||
"command.aphelion.rocket.disassemble.failure": "Could not disassemble rocket"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user