mirror of
https://github.com/XevianLight/Aphelion.git
synced 2026-05-11 01:50:56 +01:00
Rocket assembler block bounds calculation and debug renderer
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "aphelion:block/rocket_assembler_block"
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"type": "minecraft:block",
|
||||||
|
"pools": [
|
||||||
|
{
|
||||||
|
"bonus_rolls": 0.0,
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"condition": "minecraft:survives_explosion"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"type": "minecraft:item",
|
||||||
|
"name": "aphelion:rocket_assembler_block"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rolls": 1.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"random_sequence": "aphelion:blocks/rocket_assembler_block"
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
|||||||
import net.neoforged.neoforge.network.PacketDistributor;
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
import net.xevianlight.aphelion.block.dummy.renderer.MultiblockDummyRenderer;
|
import net.xevianlight.aphelion.block.dummy.renderer.MultiblockDummyRenderer;
|
||||||
import net.xevianlight.aphelion.block.entity.custom.renderer.OxygenTestRenderer;
|
import net.xevianlight.aphelion.block.entity.custom.renderer.OxygenTestRenderer;
|
||||||
|
import net.xevianlight.aphelion.block.entity.custom.renderer.RocketAssemblerBlockEntityRenderer;
|
||||||
import net.xevianlight.aphelion.client.AphelionConfig;
|
import net.xevianlight.aphelion.client.AphelionConfig;
|
||||||
import net.xevianlight.aphelion.core.saveddata.EnvironmentSavedData;
|
import net.xevianlight.aphelion.core.saveddata.EnvironmentSavedData;
|
||||||
import net.xevianlight.aphelion.network.packet.PartitionPayload;
|
import net.xevianlight.aphelion.network.packet.PartitionPayload;
|
||||||
@@ -139,6 +140,7 @@ public class Aphelion {
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void registerBER(EntityRenderersEvent.RegisterRenderers event) {
|
public static void registerBER(EntityRenderersEvent.RegisterRenderers event) {
|
||||||
event.registerBlockEntityRenderer(ModBlockEntities.VAF_MULTIBLOCK_DUMMY_ENTITY.get(), MultiblockDummyRenderer::new);
|
event.registerBlockEntityRenderer(ModBlockEntities.VAF_MULTIBLOCK_DUMMY_ENTITY.get(), MultiblockDummyRenderer::new);
|
||||||
|
event.registerBlockEntityRenderer(ModBlockEntities.ROCKET_ASSEMBLER_BLOCK_ENTITY.get(), RocketAssemblerBlockEntityRenderer::new);
|
||||||
// event.registerBlockEntityRenderer(ModBlockEntities.OXYGEN_TEST_BLOCK_ENTITY.get(), OxygenTestRenderer::new);
|
// event.registerBlockEntityRenderer(ModBlockEntities.OXYGEN_TEST_BLOCK_ENTITY.get(), OxygenTestRenderer::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,21 +2,22 @@ package net.xevianlight.aphelion.block.custom;
|
|||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.block.*;
|
import net.minecraft.world.level.block.*;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
|
||||||
import net.xevianlight.aphelion.block.custom.base.BasicHorizontalEntityBlock;
|
import net.xevianlight.aphelion.block.custom.base.BasicHorizontalEntityBlock;
|
||||||
import net.xevianlight.aphelion.block.entity.custom.RocketAssemblerBlockEntity;
|
import net.xevianlight.aphelion.block.entity.custom.RocketAssemblerBlockEntity;
|
||||||
|
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class RocketAssemblerBlock extends BasicHorizontalEntityBlock {
|
public class RocketAssemblerBlock extends BasicHorizontalEntityBlock {
|
||||||
|
|
||||||
|
public static final BooleanProperty FORMED = AphelionBlockStateProperties.FORMED;
|
||||||
|
|
||||||
public RocketAssemblerBlock(Properties properties) {
|
public RocketAssemblerBlock(Properties properties) {
|
||||||
super(properties, true);
|
super(properties, true);
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,7 @@ public class RocketAssemblerBlock extends BasicHorizontalEntityBlock {
|
|||||||
public static final MapCodec<RocketAssemblerBlock> CODEC = simpleCodec(RocketAssemblerBlock::new);
|
public static final MapCodec<RocketAssemblerBlock> CODEC = simpleCodec(RocketAssemblerBlock::new);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MapCodec<? extends BaseEntityBlock> codec() {
|
protected @NotNull MapCodec<? extends BaseEntityBlock> codec() {
|
||||||
return CODEC;
|
return CODEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +39,18 @@ public class RocketAssemblerBlock extends BasicHorizontalEntityBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
|
public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos blockPos, @NotNull BlockState blockState) {
|
||||||
return new RocketAssemblerBlockEntity(blockPos, blockState);
|
return new RocketAssemblerBlockEntity(blockPos, blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||||
|
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()).setValue(FORMED, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
|
builder.add(FORMED);
|
||||||
|
super.createBlockStateDefinition(builder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,43 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
|
|
||||||
public interface TickableBlockEntity {
|
public interface TickableBlockEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on both the client AND server.
|
||||||
|
* @param level
|
||||||
|
* @param time
|
||||||
|
* @param state
|
||||||
|
* @param pos
|
||||||
|
*/
|
||||||
|
default void tick (Level level, long time, BlockState state, BlockPos pos) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on the client only
|
||||||
|
* @param level
|
||||||
|
* @param time
|
||||||
|
* @param state
|
||||||
|
* @param pos
|
||||||
|
*/
|
||||||
void clientTick(ClientLevel level, long time, BlockState state, BlockPos pos);
|
void clientTick(ClientLevel level, long time, BlockState state, BlockPos pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on the server only
|
||||||
|
* @param level
|
||||||
|
* @param time
|
||||||
|
* @param state
|
||||||
|
* @param pos
|
||||||
|
*/
|
||||||
void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos);
|
void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos);
|
||||||
|
|
||||||
default boolean isInitialized() {
|
default boolean isInitialized() {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs on client AND server, once only.
|
||||||
|
* @param level
|
||||||
|
* @param state
|
||||||
|
* @param pos
|
||||||
|
*/
|
||||||
void firstTick(Level level, BlockState state, BlockPos pos);
|
void firstTick(Level level, BlockState state, BlockPos pos);
|
||||||
|
|
||||||
default void onRemoved() {}
|
default void onRemoved() {}
|
||||||
|
|||||||
@@ -1,23 +1,43 @@
|
|||||||
package net.xevianlight.aphelion.block.entity.custom;
|
package net.xevianlight.aphelion.block.entity.custom;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.Level;
|
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.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
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.BlockStateProperties;
|
||||||
|
import net.xevianlight.aphelion.Aphelion;
|
||||||
import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity;
|
import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity;
|
||||||
import net.xevianlight.aphelion.core.init.ModBlockEntities;
|
import net.xevianlight.aphelion.core.init.ModBlockEntities;
|
||||||
|
import net.xevianlight.aphelion.core.init.ModBlocks;
|
||||||
|
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
|
||||||
import net.xevianlight.aphelion.util.ModTags;
|
import net.xevianlight.aphelion.util.ModTags;
|
||||||
import net.xevianlight.aphelion.util.RocketStructure;
|
import net.xevianlight.aphelion.util.RocketStructure;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
public class RocketAssemblerBlockEntity extends BlockEntity implements TickableBlockEntity {
|
public class RocketAssemblerBlockEntity extends BlockEntity implements TickableBlockEntity {
|
||||||
|
|
||||||
Direction facing;
|
Direction facing;
|
||||||
BlockPos padScanStart = BlockPos.ZERO;
|
BlockPos padScanStart = BlockPos.ZERO;
|
||||||
|
private PadInfo padBounds;
|
||||||
|
|
||||||
|
public @Nullable PadInfo getPadBounds() {
|
||||||
|
return padBounds;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isInitialized;
|
public boolean isInitialized;
|
||||||
@Override
|
@Override
|
||||||
@@ -29,9 +49,20 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
|||||||
super(ModBlockEntities.ROCKET_ASSEMBLER_BLOCK_ENTITY.get(), pos, blockState);
|
super(ModBlockEntities.ROCKET_ASSEMBLER_BLOCK_ENTITY.get(), pos, blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public record PadInfo(BlockPos min, BlockPos max, int size) {};
|
public record PadInfo(BlockPos min, BlockPos max) {
|
||||||
|
public int getVolume() {
|
||||||
|
int dx = max.getX() - min.getX() + 1;
|
||||||
|
int dy = max.getY() - min.getY() + 1;
|
||||||
|
int dz = max.getZ() - min.getZ() + 1;
|
||||||
|
|
||||||
public PadInfo getPlatform() {
|
return dx * dy * dz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Block TOWER_BLOCK = ModBlocks.BLOCK_STEEL.get();
|
||||||
|
public BlockPos towerBasePos;
|
||||||
|
|
||||||
|
public @Nullable PadInfo getPlatform() {
|
||||||
// TODO
|
// TODO
|
||||||
int y = this.padScanStart.getY();
|
int y = this.padScanStart.getY();
|
||||||
BlockPos start = this.padScanStart;
|
BlockPos start = this.padScanStart;
|
||||||
@@ -67,7 +98,107 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PadInfo(new BlockPos(minX, y, minZ), new BlockPos(maxX, y, maxZ), width);
|
return new PadInfo(new BlockPos(minX, y, minZ), new BlockPos(maxX, y, maxZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean connected(BlockState state, Direction dir) {
|
||||||
|
return switch (dir) {
|
||||||
|
case NORTH -> state.getValue(BlockStateProperties.NORTH);
|
||||||
|
case SOUTH -> state.getValue(BlockStateProperties.SOUTH);
|
||||||
|
case EAST -> state.getValue(BlockStateProperties.EAST);
|
||||||
|
case WEST -> state.getValue(BlockStateProperties.WEST);
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable PadInfo getPlatformFill() {
|
||||||
|
if (level == null) return null;
|
||||||
|
|
||||||
|
BlockPos start = this.padScanStart;
|
||||||
|
if (!isPad(level.getBlockState(start))) return null;
|
||||||
|
|
||||||
|
|
||||||
|
final int y = start.getY();
|
||||||
|
int towerHeight = 0;
|
||||||
|
|
||||||
|
ArrayDeque<BlockPos> queue = new ArrayDeque<>();
|
||||||
|
LongOpenHashSet visited = new LongOpenHashSet();
|
||||||
|
|
||||||
|
queue.add(start);
|
||||||
|
visited.add(start.asLong());
|
||||||
|
|
||||||
|
final Direction[] CARDINALS = {Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST};
|
||||||
|
// When the $#$# are we going to have a rocket larger than 64x64... don't...
|
||||||
|
final int MAX_PAD_BLOCKS = 4096;
|
||||||
|
|
||||||
|
boolean towerFound = false;
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
BlockPos p = queue.removeFirst();
|
||||||
|
BlockState s = level.getBlockState(p);
|
||||||
|
|
||||||
|
// We trust block states entirely. If a block state says it has a pad in a direction and is wrong, something else has failed. To minimize level checks and have this run as fast as possible, I won't compare the block
|
||||||
|
// if (!isPad(s)) continue;
|
||||||
|
|
||||||
|
for (Direction d : CARDINALS) {
|
||||||
|
// Only keep going if the block claims to have a neighbor in that direction
|
||||||
|
BlockPos n = p.relative(d);
|
||||||
|
|
||||||
|
if (!connected(s, d)) {
|
||||||
|
if (level.getBlockState(n).is(TOWER_BLOCK)) {
|
||||||
|
if (!towerFound) {
|
||||||
|
towerBasePos = n;
|
||||||
|
towerFound = true;
|
||||||
|
} else if (!n.equals(towerBasePos)) {
|
||||||
|
Aphelion.LOGGER.warn("Multiple towers found, rocket pad invalid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visited.contains(n.asLong())) continue; // skip if we've already seen this block
|
||||||
|
|
||||||
|
visited.add(n.asLong());
|
||||||
|
queue.addLast(n);
|
||||||
|
|
||||||
|
if (visited.size() > MAX_PAD_BLOCKS) return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pads missing a tower should be invalid
|
||||||
|
if (!towerFound || towerBasePos == null) return null;
|
||||||
|
towerHeight = getTowerHeight(level, towerBasePos);
|
||||||
|
if (towerHeight <= 0) return null;
|
||||||
|
|
||||||
|
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
|
||||||
|
int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
for (Long p : visited) {
|
||||||
|
minX = Math.min(minX, BlockPos.of(p).getX());
|
||||||
|
maxX = Math.max(maxX, BlockPos.of(p).getX());
|
||||||
|
minZ = Math.min(minZ, BlockPos.of(p).getZ());
|
||||||
|
maxZ = Math.max(maxZ, BlockPos.of(p).getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = (maxX - minX) + 1;
|
||||||
|
int length = (maxZ - minZ) + 1;
|
||||||
|
|
||||||
|
// SQUARE AND SOLID??? The math works out here that this will only be true if the number of blocks found matches the side lengths squared. We don't need to check for holes manually!
|
||||||
|
if (visited.size() != length * width || length != width) return null;
|
||||||
|
|
||||||
|
return new PadInfo(new BlockPos(minX, y + 1, minZ), new BlockPos(maxX, y + towerHeight, maxZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getTowerHeight(@NotNull Level level, @NotNull BlockPos base) {
|
||||||
|
int h = 0;
|
||||||
|
BlockPos p = base.above();
|
||||||
|
|
||||||
|
while (level.getBlockState(p).is(TOWER_BLOCK)) {
|
||||||
|
h++;
|
||||||
|
p = p.above();
|
||||||
|
}
|
||||||
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RocketStructure scan() {
|
public RocketStructure scan() {
|
||||||
@@ -82,7 +213,13 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) {
|
public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) {
|
||||||
|
PadInfo newBounds = getPlatformFill();
|
||||||
|
setPadBoundsAndSync(newBounds);
|
||||||
|
|
||||||
|
boolean formed = newBounds != null;
|
||||||
|
if (state.getValue(AphelionBlockStateProperties.FORMED) != formed) {
|
||||||
|
level.setBlockAndUpdate(pos, state.setValue(AphelionBlockStateProperties.FORMED, formed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,4 +233,67 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB
|
|||||||
private static boolean isPad(BlockState s) {
|
private static boolean isPad(BlockState s) {
|
||||||
return s.is(ModTags.Blocks.LAUNCH_PAD); // or s.getBlock() == ModBlocks.PAD.get()
|
return s.is(ModTags.Blocks.LAUNCH_PAD); // or s.getBlock() == ModBlocks.PAD.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void saveAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
|
||||||
|
super.saveAdditional(tag, registries);
|
||||||
|
|
||||||
|
PadInfo pad = this.padBounds;
|
||||||
|
if (pad != null) {
|
||||||
|
tag.putLong("PadMin", padBounds.min().asLong());
|
||||||
|
tag.putLong("PadMax", padBounds.max().asLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
|
||||||
|
super.loadAdditional(tag, registries);
|
||||||
|
|
||||||
|
if (tag.contains("PadMin") && tag.contains("PadMax")) {
|
||||||
|
BlockPos min = BlockPos.of(tag.getLong("PadMin"));
|
||||||
|
BlockPos max = BlockPos.of(tag.getLong("PadMax"));
|
||||||
|
this.padBounds = new PadInfo(min, max);
|
||||||
|
} else {
|
||||||
|
this.padBounds = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull CompoundTag getUpdateTag(HolderLookup.@NotNull Provider registries) {
|
||||||
|
CompoundTag tag = super.getUpdateTag(registries);
|
||||||
|
saveAdditional(tag, registries);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleUpdateTag(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
|
||||||
|
loadAdditional(tag, registries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPadBoundsAndSync(@Nullable PadInfo newBounds) {
|
||||||
|
if (java.util.Objects.equals(this.padBounds, newBounds)) return;
|
||||||
|
|
||||||
|
this.padBounds = newBounds;
|
||||||
|
setChanged(); // marks BE dirty for saving
|
||||||
|
|
||||||
|
if (level instanceof ServerLevel server) {
|
||||||
|
BlockState state = getBlockState();
|
||||||
|
server.sendBlockUpdated(worldPosition, state, state, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Packet<ClientGamePacketListener> getUpdatePacket() {
|
||||||
|
// sends the tag from getUpdateTag()
|
||||||
|
return ClientboundBlockEntityDataPacket.create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDataPacket(@NotNull Connection net, ClientboundBlockEntityDataPacket pkt, HolderLookup.@NotNull Provider registries) {
|
||||||
|
// apply the received tag on client
|
||||||
|
CompoundTag tag = pkt.getTag();
|
||||||
|
if (tag != null) {
|
||||||
|
this.loadAdditional(tag, registries);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package net.xevianlight.aphelion.block.entity.custom.renderer;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.xevianlight.aphelion.block.entity.custom.RocketAssemblerBlockEntity;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class RocketAssemblerBlockEntityRenderer implements BlockEntityRenderer<RocketAssemblerBlockEntity> {
|
||||||
|
|
||||||
|
public RocketAssemblerBlockEntityRenderer (BlockEntityRendererProvider.Context context) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
|
||||||
|
if (be.getPadBounds() == null) return;
|
||||||
|
BlockPos min = be.getPadBounds().min();
|
||||||
|
BlockPos max = be.getPadBounds().max();
|
||||||
|
|
||||||
|
AABB box = new AABB(
|
||||||
|
min.getX(), min.getY(), min.getZ(),
|
||||||
|
max.getX() + 1, max.getY() + 1, max.getZ() + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(-be.getBlockPos().getX(), -be.getBlockPos().getY(), -be.getBlockPos().getZ());
|
||||||
|
|
||||||
|
VertexConsumer vc = multiBufferSource.getBuffer(RenderType.lines());
|
||||||
|
|
||||||
|
LevelRenderer.renderLineBox(poseStack, vc, box, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,10 +25,10 @@ public class ModBlockStateProvider extends BlockStateProvider {
|
|||||||
blockItem(ModBlocks.ELECTRIC_ARC_FURNACE);
|
blockItem(ModBlocks.ELECTRIC_ARC_FURNACE);
|
||||||
blockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER);
|
blockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER);
|
||||||
|
|
||||||
horizontalBlock(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get(), models().orientable("aphelion:rocket_assembler_block",
|
// horizontalBlock(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get(), models().orientable("aphelion:rocket_assembler_block",
|
||||||
modLoc("block/test_block"),
|
// modLoc("block/test_block"),
|
||||||
mcLoc("block/furnace_front"),
|
// mcLoc("block/furnace_front"),
|
||||||
modLoc("block/test_block")));
|
// modLoc("block/test_block")));
|
||||||
blockItem(ModBlocks.ROCKET_ASSEMBLER_BLOCK);
|
blockItem(ModBlocks.ROCKET_ASSEMBLER_BLOCK);
|
||||||
|
|
||||||
blockWithItem(ModBlocks.BLOCK_STEEL);
|
blockWithItem(ModBlocks.BLOCK_STEEL);
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=east,formed=false": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=north,formed=false": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block"
|
||||||
|
},
|
||||||
|
"facing=south,formed=false": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,formed=false": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block",
|
||||||
|
"y": 270
|
||||||
|
},
|
||||||
|
"facing=east,formed=true": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block_formed",
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=north,formed=true": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block_formed"
|
||||||
|
},
|
||||||
|
"facing=south,formed=true": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block_formed",
|
||||||
|
"y": 180
|
||||||
|
},
|
||||||
|
"facing=west,formed=true": {
|
||||||
|
"model": "aphelion:block/rocket_assembler_block_formed",
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/orientable",
|
||||||
|
"textures": {
|
||||||
|
"front": "minecraft:block/furnace_front",
|
||||||
|
"side": "aphelion:block/test_block",
|
||||||
|
"top": "aphelion:block/test_block"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:block/orientable",
|
||||||
|
"textures": {
|
||||||
|
"front": "minecraft:block/furnace_front",
|
||||||
|
"side": "aphelion:block/arc_furnace_casing_formed",
|
||||||
|
"top": "aphelion:block/arc_furnace_casing_formed"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user