From c0daaf2cfa8345a4aeb3c9ad99275470ec4c9eef Mon Sep 17 00:00:00 2001 From: XevianLight <63034748+XevianLight@users.noreply.github.com> Date: Sun, 8 Feb 2026 00:00:51 -0700 Subject: [PATCH] RocketAssembler now creates rockets! --- .../59eb3dbb5f86130e09b3c62d89b9525ee01cf52d | 5 +- .../9c517586575525115dfb9b0c4d592f540cb43d3e | 3 +- .../a8139181fab9cfd94e67697230cbaca839a05e1f | 6 +- .../models/item/rocket_assembler.json | 3 + .../models/item/rocket_assembler_block.json | 3 - ...mbler_block.json => rocket_assembler.json} | 4 +- .../loot_table/blocks/rocket_seat.json | 21 ++ .../data/aphelion/tags/block/rocket_seat.json | 5 + .../block/custom/ElectricArcFurnace.java | 3 +- ...semblerBlock.java => RocketAssembler.java} | 20 +- .../aphelion/block/custom/RocketSeat.java | 24 +++ .../custom/RocketAssemblerBlockEntity.java | 194 +++++++++++++----- .../RocketAssemblerBlockEntityRenderer.java | 2 +- .../aphelion/core/init/ModBlockEntities.java | 2 +- .../aphelion/core/init/ModBlocks.java | 3 +- .../aphelion/core/init/ModCreativeTabs.java | 2 +- .../aphelion/core/init/ModItems.java | 4 +- .../datagen/ModBlockLootTableProvider.java | 3 +- .../datagen/ModBlockStateProvider.java | 2 +- .../aphelion/datagen/ModBlockTagProvider.java | 3 + .../entites/vehicles/RocketEntity.java | 22 +- .../aphelion/util/FloodFill3D.java | 2 +- .../xevianlight/aphelion/util/ModTags.java | 1 + .../aphelion/util/RocketStructure.java | 20 +- .../blockstates/rocket_assembler.json | 34 +++ .../blockstates/rocket_assembler_block.json | 34 --- ...mbler_block.json => rocket_assembler.json} | 0 ...rmed.json => rocket_assembler_formed.json} | 0 28 files changed, 311 insertions(+), 114 deletions(-) create mode 100644 src/generated/resources/assets/aphelion/models/item/rocket_assembler.json delete mode 100644 src/generated/resources/assets/aphelion/models/item/rocket_assembler_block.json rename src/generated/resources/data/aphelion/loot_table/blocks/{rocket_assembler_block.json => rocket_assembler.json} (72%) create mode 100644 src/generated/resources/data/aphelion/loot_table/blocks/rocket_seat.json create mode 100644 src/generated/resources/data/aphelion/tags/block/rocket_seat.json rename src/main/java/net/xevianlight/aphelion/block/custom/{RocketAssemblerBlock.java => RocketAssembler.java} (65%) create mode 100644 src/main/java/net/xevianlight/aphelion/block/custom/RocketSeat.java create mode 100644 src/main/resources/assets/aphelion/blockstates/rocket_assembler.json delete mode 100644 src/main/resources/assets/aphelion/blockstates/rocket_assembler_block.json rename src/main/resources/assets/aphelion/models/block/{rocket_assembler_block.json => rocket_assembler.json} (100%) rename src/main/resources/assets/aphelion/models/block/{rocket_assembler_block_formed.json => rocket_assembler_formed.json} (100%) diff --git a/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d b/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d index 86bd7cd..b2ae2bc 100644 --- a/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d +++ b/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d @@ -1,11 +1,12 @@ -// 1.21.1 2026-02-04T21:03:31.3164337 Loot Tables +// 1.21.1 2026-02-07T22:29:56.7198656 Loot Tables 69d8318ddba171526d1fabb87d9d93548ed8598e data/aphelion/loot_table/blocks/arc_furnace_casing.json 05f08985e601d30116f67e2f07b48b03b40cdca6 data/aphelion/loot_table/blocks/block_steel.json ff43a9c3741faf10b1e156a7a74d5cfb035cc118 data/aphelion/loot_table/blocks/dimension_changer.json b63130d9c10485676303d729807b6fcaac080294 data/aphelion/loot_table/blocks/electric_arc_furnace.json b9cfe672ead8e2673a7b2f5c4cec831e7e8e7040 data/aphelion/loot_table/blocks/launch_pad.json afb6519a03415b8e0d5bafc9fadb70905a398046 data/aphelion/loot_table/blocks/oxygen_test_block.json -f3178154dadee30cc28f5ff23af45be98f2766cf data/aphelion/loot_table/blocks/rocket_assembler_block.json +87dfbcce4a96ea0ee6e9fc7908aa77d42d1904e5 data/aphelion/loot_table/blocks/rocket_assembler.json +9e269f103ac1ce517c1a089b8ca5474af085bd66 data/aphelion/loot_table/blocks/rocket_seat.json 1ab50c99e9f478840b9d003fd56ebdcab12fbbce data/aphelion/loot_table/blocks/test_block.json 7d8eeb99a1bc942a6e2cf292b21fd4534062b5ab data/aphelion/loot_table/blocks/vacuum_arc_furnace_controller.json 797bf9839d79e08b4832c9eaf3cb303b0471ed0c data/aphelion/loot_table/blocks/vaf_dummy_block.json diff --git a/src/generated/resources/.cache/9c517586575525115dfb9b0c4d592f540cb43d3e b/src/generated/resources/.cache/9c517586575525115dfb9b0c4d592f540cb43d3e index bc024f0..49659bf 100644 --- a/src/generated/resources/.cache/9c517586575525115dfb9b0c4d592f540cb43d3e +++ b/src/generated/resources/.cache/9c517586575525115dfb9b0c4d592f540cb43d3e @@ -1,5 +1,6 @@ -// 1.21.1 2026-01-26T19:04:46.4981336 Tags for minecraft:block mod id aphelion +// 1.21.1 2026-02-07T23:23:26.8270373 Tags for minecraft:block mod id aphelion 46f0160a007d32a06624ad98f25e8a1a8d01bb08 data/aphelion/tags/block/launch_pad.json +883d37ed36ecbde487d467ddb26b34082067aa09 data/aphelion/tags/block/rocket_seat.json 058c56a0c17204ed5d9cadaffae84292b4752213 data/c/tags/block/storage_blocks.json 058c56a0c17204ed5d9cadaffae84292b4752213 data/c/tags/block/storage_blocks/steel.json 7d420216f15b8f78d2a3b298f9bb773a9e5f79c3 data/minecraft/tags/block/mineable/pickaxe.json diff --git a/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f b/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f index 30401f9..ab6192a 100644 --- a/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f +++ b/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f @@ -1,21 +1,19 @@ -// 1.21.1 2026-02-04T21:03:31.3154339 Block States: aphelion +// 1.21.1 2026-02-07T22:29:56.7183649 Block States: aphelion 851ff42f7b21dec86107c8e0cefb3934ae4ebc08 assets/aphelion/blockstates/block_steel.json 30b9c0efd7aaadb5412d98e4568f98b3632adbb9 assets/aphelion/blockstates/dimension_changer.json cb4287104006c80c8396b290ab5258df65d62cef assets/aphelion/blockstates/electric_arc_furnace.json 28131a570d3666b7f323de4ad8a69e52ceec92e2 assets/aphelion/blockstates/oxygen_test_block.json -85c7c0dab53d0219b315c822147a90ade9075844 assets/aphelion/blockstates/rocket_assembler_block.json b86c50fddcf6c8c6c19cb748529239d5962a3ede assets/aphelion/blockstates/test_block.json a810b97f4dace35d026f28d96cb9c47c93600d75 assets/aphelion/models/block/block_steel.json 2d3592b7ab7132908709243e97540151e0fb762e assets/aphelion/models/block/dimension_changer.json 5f7e8674070f31a63875b5d6147153bfa0eef61a assets/aphelion/models/block/electric_arc_furnace.json 746f23f150a01524ad03cbd1eb822bfbb7cf453b assets/aphelion/models/block/oxygen_test_block.json -17eb7327e504f7a88028af804e046281d9719fdf assets/aphelion/models/block/rocket_assembler_block.json e0971228b4a1c4bc9dbab58a7dacdc3ae6037e02 assets/aphelion/models/block/test_block.json cdc831b0f1c462be64825fd34bd446e5b95afac6 assets/aphelion/models/item/arc_furnace_casing.json 3599f9037eb2f66de1765318b97ab564c3eae92f assets/aphelion/models/item/block_steel.json db0ec473a016ce05c258cde18a217d47a9ea8324 assets/aphelion/models/item/dimension_changer.json 279080c06ada87f54fd0a7b885b256dbe25a946a assets/aphelion/models/item/electric_arc_furnace.json 24cf60e70f7d9450b0e70cf017662e80971bae17 assets/aphelion/models/item/oxygen_test_block.json -dafa6e1a3cfd753e211ae94179a433c69e9d2a28 assets/aphelion/models/item/rocket_assembler_block.json +ab6884315b8f6c99666a87f673b059b5659ff13d assets/aphelion/models/item/rocket_assembler.json 74418ef1cf678e72e7534924274688ef5a68af0e assets/aphelion/models/item/test_block.json 88ca3602517e99f7feaed57eddfc96965a25761c assets/aphelion/models/item/vacuum_arc_furnace_controller.json diff --git a/src/generated/resources/assets/aphelion/models/item/rocket_assembler.json b/src/generated/resources/assets/aphelion/models/item/rocket_assembler.json new file mode 100644 index 0000000..79d68ac --- /dev/null +++ b/src/generated/resources/assets/aphelion/models/item/rocket_assembler.json @@ -0,0 +1,3 @@ +{ + "parent": "aphelion:block/rocket_assembler" +} \ No newline at end of file diff --git a/src/generated/resources/assets/aphelion/models/item/rocket_assembler_block.json b/src/generated/resources/assets/aphelion/models/item/rocket_assembler_block.json deleted file mode 100644 index 247366e..0000000 --- a/src/generated/resources/assets/aphelion/models/item/rocket_assembler_block.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "aphelion:block/rocket_assembler_block" -} \ No newline at end of file diff --git a/src/generated/resources/data/aphelion/loot_table/blocks/rocket_assembler_block.json b/src/generated/resources/data/aphelion/loot_table/blocks/rocket_assembler.json similarity index 72% rename from src/generated/resources/data/aphelion/loot_table/blocks/rocket_assembler_block.json rename to src/generated/resources/data/aphelion/loot_table/blocks/rocket_assembler.json index c37829f..55ca05b 100644 --- a/src/generated/resources/data/aphelion/loot_table/blocks/rocket_assembler_block.json +++ b/src/generated/resources/data/aphelion/loot_table/blocks/rocket_assembler.json @@ -11,11 +11,11 @@ "entries": [ { "type": "minecraft:item", - "name": "aphelion:rocket_assembler_block" + "name": "aphelion:rocket_assembler" } ], "rolls": 1.0 } ], - "random_sequence": "aphelion:blocks/rocket_assembler_block" + "random_sequence": "aphelion:blocks/rocket_assembler" } \ No newline at end of file diff --git a/src/generated/resources/data/aphelion/loot_table/blocks/rocket_seat.json b/src/generated/resources/data/aphelion/loot_table/blocks/rocket_seat.json new file mode 100644 index 0000000..f05d1d2 --- /dev/null +++ b/src/generated/resources/data/aphelion/loot_table/blocks/rocket_seat.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "aphelion:rocket_seat" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "aphelion:blocks/rocket_seat" +} \ No newline at end of file diff --git a/src/generated/resources/data/aphelion/tags/block/rocket_seat.json b/src/generated/resources/data/aphelion/tags/block/rocket_seat.json new file mode 100644 index 0000000..460806d --- /dev/null +++ b/src/generated/resources/data/aphelion/tags/block/rocket_seat.json @@ -0,0 +1,5 @@ +{ + "values": [ + "aphelion:rocket_seat" + ] +} \ No newline at end of file diff --git a/src/main/java/net/xevianlight/aphelion/block/custom/ElectricArcFurnace.java b/src/main/java/net/xevianlight/aphelion/block/custom/ElectricArcFurnace.java index 9488cc6..188775c 100644 --- a/src/main/java/net/xevianlight/aphelion/block/custom/ElectricArcFurnace.java +++ b/src/main/java/net/xevianlight/aphelion/block/custom/ElectricArcFurnace.java @@ -25,6 +25,7 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.phys.BlockHitResult; import net.neoforged.neoforge.items.ItemStackHandler; +import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.block.custom.base.BasicEntityBlock; import net.xevianlight.aphelion.block.custom.base.BasicHorizontalEntityBlock; import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity; @@ -77,7 +78,7 @@ public class ElectricArcFurnace extends BasicHorizontalEntityBlock { public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult result) { if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity) { - serverPlayer.openMenu(new SimpleMenuProvider(electricArcFurnaceEntity, Component.literal("Electric Arc Furnace")), pos); + serverPlayer.openMenu(new SimpleMenuProvider(electricArcFurnaceEntity, Component.literal("Electric Arc Furnace")), pos); } return InteractionResult.sidedSuccess(level.isClientSide); } diff --git a/src/main/java/net/xevianlight/aphelion/block/custom/RocketAssemblerBlock.java b/src/main/java/net/xevianlight/aphelion/block/custom/RocketAssembler.java similarity index 65% rename from src/main/java/net/xevianlight/aphelion/block/custom/RocketAssemblerBlock.java rename to src/main/java/net/xevianlight/aphelion/block/custom/RocketAssembler.java index 2fe72fc..64fb6b9 100644 --- a/src/main/java/net/xevianlight/aphelion/block/custom/RocketAssemblerBlock.java +++ b/src/main/java/net/xevianlight/aphelion/block/custom/RocketAssembler.java @@ -2,27 +2,33 @@ package net.xevianlight.aphelion.block.custom; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; 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.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.BlockHitResult; import net.xevianlight.aphelion.block.custom.base.BasicHorizontalEntityBlock; import net.xevianlight.aphelion.block.entity.custom.RocketAssemblerBlockEntity; +import net.xevianlight.aphelion.entites.vehicles.RocketEntity; import net.xevianlight.aphelion.util.AphelionBlockStateProperties; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class RocketAssemblerBlock extends BasicHorizontalEntityBlock { +public class RocketAssembler extends BasicHorizontalEntityBlock { public static final BooleanProperty FORMED = AphelionBlockStateProperties.FORMED; - public RocketAssemblerBlock(Properties properties) { + public RocketAssembler(Properties properties) { super(properties, true); } - public static final MapCodec CODEC = simpleCodec(RocketAssemblerBlock::new); + public static final MapCodec CODEC = simpleCodec(RocketAssembler::new); @Override protected @NotNull MapCodec codec() { @@ -53,4 +59,12 @@ public class RocketAssemblerBlock extends BasicHorizontalEntityBlock { builder.add(FORMED); super.createBlockStateDefinition(builder); } + + @Override + protected @NotNull InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof RocketAssemblerBlockEntity rocketAssemblerBlockEntity) { + RocketEntity rocket = rocketAssemblerBlockEntity.assemble(); + } + return InteractionResult.sidedSuccess(level.isClientSide()); + } } diff --git a/src/main/java/net/xevianlight/aphelion/block/custom/RocketSeat.java b/src/main/java/net/xevianlight/aphelion/block/custom/RocketSeat.java new file mode 100644 index 0000000..1828b07 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/block/custom/RocketSeat.java @@ -0,0 +1,24 @@ +package net.xevianlight.aphelion.block.custom; + +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; + +public class RocketSeat extends Block { + public RocketSeat(Properties properties) { + super(properties); + } + + public static Properties getProperties() { + return Properties + .of() + .sound(SoundType.STONE) + .destroyTime(2f) + .explosionResistance(10f) + .requiresCorrectToolForDrops(); + } + + public static Item.Properties getItemProperties() { + return new Item.Properties(); + } +} diff --git a/src/main/java/net/xevianlight/aphelion/block/entity/custom/RocketAssemblerBlockEntity.java b/src/main/java/net/xevianlight/aphelion/block/entity/custom/RocketAssemblerBlockEntity.java index 5693492..500f611 100644 --- a/src/main/java/net/xevianlight/aphelion/block/entity/custom/RocketAssemblerBlockEntity.java +++ b/src/main/java/net/xevianlight/aphelion/block/entity/custom/RocketAssemblerBlockEntity.java @@ -20,6 +20,7 @@ import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.block.custom.base.TickableBlockEntity; import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlocks; +import net.xevianlight.aphelion.entites.vehicles.RocketEntity; import net.xevianlight.aphelion.util.AphelionBlockStateProperties; import net.xevianlight.aphelion.util.ModTags; import net.xevianlight.aphelion.util.RocketStructure; @@ -62,45 +63,6 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB private final Block TOWER_BLOCK = ModBlocks.BLOCK_STEEL.get(); public BlockPos towerBasePos; - public @Nullable PadInfo getPlatform() { - // TODO - int y = this.padScanStart.getY(); - BlockPos start = this.padScanStart; - - if (level == null) return null; - if (!isPad(level.getBlockState(start))) return null; - - int minX = start.getX(); - while (isPad(level.getBlockState(new BlockPos(minX - 1, y, start.getZ())))) minX--; - - // Find maxX by walking east - int maxX = start.getX(); - while (isPad(level.getBlockState(new BlockPos(maxX + 1, y, start.getZ())))) maxX++; - - // Find minZ by walking north - int minZ = start.getZ(); - while (isPad(level.getBlockState(new BlockPos(start.getX(), y, minZ - 1)))) minZ--; - - // Find maxZ by walking south - int maxZ = start.getZ(); - while (isPad(level.getBlockState(new BlockPos(start.getX(), y, maxZ + 1)))) maxZ++; - - int width = (maxX - minX) + 1; - int length = (maxZ - minZ) + 1; - - // Must be square - if (width != length) return null; - - // Verify the entire rectangle is filled with pad blocks - for (int x = minX; x <= maxX; x++) { - for (int z = minZ; z <= maxZ; z++) { - if (!isPad(level.getBlockState(new BlockPos(x, y, z)))) return null; - } - } - - 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); @@ -111,7 +73,7 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB }; } - public @Nullable PadInfo getPlatformFill() { + public @Nullable PadInfo getPlatformViaFill() { if (level == null) return null; BlockPos start = this.padScanStart; @@ -128,8 +90,8 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB 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; + // When the $#$# are we going to have a rocket larger than 32x32... don't... + final int MAX_PAD_BLOCKS = 1024; boolean towerFound = false; while (!queue.isEmpty()) { @@ -144,7 +106,7 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB BlockPos n = p.relative(d); if (!connected(s, d)) { - if (level.getBlockState(n).is(TOWER_BLOCK)) { + if (isTower(level.getBlockState(n))) { if (!towerFound) { towerBasePos = n; towerFound = true; @@ -194,16 +156,148 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB int h = 0; BlockPos p = base.above(); - while (level.getBlockState(p).is(TOWER_BLOCK)) { + while (isTower(level.getBlockState(p))) { h++; p = p.above(); } return h; } - public RocketStructure scan() { - // TODO - throw new NotImplementedException(); + private BlockPos seatPos; + + public @Nullable RocketStructure scan() { + if (level == null) return null; + + seatPos = null; + + PadInfo bounds = padBounds; + if (bounds == null) return null; + + + BlockPos min = bounds.min(); + BlockPos max = bounds.max(); + + // Find seat, every rocket must have a seat and all blocks in the rocket must be attached to it + for (int y = min.getY(); y <= max.getY(); y++) { + for (int x = min.getX(); x <= max.getX(); x++) { + for (int z = min.getZ(); z <= max.getZ(); z++) { + BlockPos p = new BlockPos(x, y, z); + BlockState st = level.getBlockState(p); + + if (!st.is(ModTags.Blocks.ROCKET_SEAT)) continue; + + if (seatPos != null && !seatPos.equals(p)) { + Aphelion.LOGGER.warn("Rocket scan failed: multiple seats found"); + seatPos = null; + return null; + } + seatPos = p; + } + } + } + + if (seatPos == null) { + Aphelion.LOGGER.warn("Rocket scan failed: no seat found"); + seatPos = null; + return null; + } + + final Direction[] DIRS = Direction.values(); + + ArrayDeque queue = new ArrayDeque<>(); + LongOpenHashSet visited = new LongOpenHashSet(); + + queue.add(seatPos); + visited.add(seatPos.asLong()); + + RocketStructure structure = new RocketStructure(s -> {}); + structure.addSeatOffset(0,0,0); + + final int MAX_ROCKET_BLOCKS = 1000; + + while (!queue.isEmpty()) { + BlockPos p = queue.removeFirst(); + BlockState st = level.getBlockState(p); + + if (!within(bounds, p)) continue; + + // Any block cases we should IGNORE + if (st.isAir()) continue; // ignore air + if (isPad(st)) continue; // ignore the pad + if (isTower(st)) continue; // ignore the tower + if (p.equals(this.worldPosition)) continue; // ignore the assembler + + // Reject block entities + if (st.hasBlockEntity() || level.getBlockEntity(p) != null) { + Aphelion.LOGGER.warn("Rocket scan failed: found block entity at {}", p); + return null; + } + + int dx = p.getX() - seatPos.getX(); + int dy = p.getY() - seatPos.getY(); + int dz = p.getZ() - seatPos.getZ(); + + if (!fitsSignedByte(dx) || !fitsSignedByte(dy) || !fitsSignedByte(dz)) { + Aphelion.LOGGER.warn("Rocket scan failed: structure too large to pack at {} (dx={},dy={},dz={})", p, dx, dy, dz); + return null; + } + + // All checks succeeded, add the block to the rocket + structure.add(dx, dy, dz, st); + + // Explore neighbors + for (Direction d : DIRS) { + BlockPos n = p.relative(d); + + if (!within(bounds, n)) continue; // Skip neighbor outside of rocket assembler bounds + + long key = n.asLong(); + if (visited.contains(key)) continue; // Skip visited blocks + + BlockState ns = level.getBlockState(n); + + if (ns.isAir()) continue; + if (isPad(ns)) continue; + if (isTower(ns)) continue; + if (n.equals(this.worldPosition)) continue; + + visited.add(key); + queue.addLast(n); + + if (visited.size() >= MAX_ROCKET_BLOCKS) { + Aphelion.LOGGER.warn("Rocket scan failed: exceeded max blocks ({})", MAX_ROCKET_BLOCKS); + return null; + } + } + } + + if (structure.size() == 0) return null; + return structure; + } + + public @Nullable RocketEntity assemble() { + if (level == null) return null; + RocketStructure structure = scan(); + RocketEntity rocket = null; + if (structure != null && seatPos != null) { + RocketStructure.clearCaptured(level, seatPos, structure); + rocket = RocketEntity.spawnRocket(level, seatPos, structure); + Aphelion.LOGGER.info("Spawn rocket result: {}", rocket); + } + return rocket; + } + + private static boolean within(PadInfo pad, BlockPos p) { + BlockPos min = pad.min; + BlockPos max = pad.max; + + return p.getX() >= min.getX() && p.getX() <= max.getX() + && p.getY() >= min.getY() && p.getY() <= max.getY() + && p.getZ() >= min.getZ() && p.getZ() <= max.getZ(); + } + + private static boolean fitsSignedByte(int v) { + return v >= -128 && v <= 127; } @Override @@ -213,7 +307,7 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB @Override public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) { - PadInfo newBounds = getPlatformFill(); + PadInfo newBounds = getPlatformViaFill(); setPadBoundsAndSync(newBounds); boolean formed = newBounds != null; @@ -234,6 +328,10 @@ public class RocketAssemblerBlockEntity extends BlockEntity implements TickableB return s.is(ModTags.Blocks.LAUNCH_PAD); // or s.getBlock() == ModBlocks.PAD.get() } + private static boolean isTower(BlockState s) { + return s.is(ModBlocks.BLOCK_STEEL); + } + @Override protected void saveAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) { super.saveAdditional(tag, registries); diff --git a/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/RocketAssemblerBlockEntityRenderer.java b/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/RocketAssemblerBlockEntityRenderer.java index 1469525..8c5f065 100644 --- a/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/RocketAssemblerBlockEntityRenderer.java +++ b/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/RocketAssemblerBlockEntityRenderer.java @@ -21,7 +21,7 @@ public class RocketAssemblerBlockEntityRenderer implements BlockEntityRenderer> ROCKET_ASSEMBLER_BLOCK_ENTITY = BLOCK_ENTITIES.register("rocket_assembler_block_entity", () -> BlockEntityType.Builder.of( - RocketAssemblerBlockEntity::new, ModBlocks.ROCKET_ASSEMBLER_BLOCK.get()).build(null) + RocketAssemblerBlockEntity::new, ModBlocks.ROCKET_ASSEMBLER.get()).build(null) ); } diff --git a/src/main/java/net/xevianlight/aphelion/core/init/ModBlocks.java b/src/main/java/net/xevianlight/aphelion/core/init/ModBlocks.java index 37e1af2..ca922bc 100644 --- a/src/main/java/net/xevianlight/aphelion/core/init/ModBlocks.java +++ b/src/main/java/net/xevianlight/aphelion/core/init/ModBlocks.java @@ -19,5 +19,6 @@ public class ModBlocks { public static final DeferredBlock VACUUM_ARC_FURNACE_CONTROLLER = BLOCKS.register("vacuum_arc_furnace_controller", () -> new VacuumArcFurnaceController(VacuumArcFurnaceController.getProperties())); public static final DeferredBlock VAF_MULTIBLOCK_DUMMY_BLOCK = BLOCKS.register("vaf_dummy_block", () -> new VAFMultiblockDummyBlock(VAFMultiblockDummyBlock.getProperties())); public static final DeferredBlock OXYGEN_TEST_BLOCK = BLOCKS.register("oxygen_test_block", () -> new OxygenTestBlock(OxygenTestBlock.getProperties())); - public static final DeferredBlock ROCKET_ASSEMBLER_BLOCK = BLOCKS.register("rocket_assembler_block", () -> new RocketAssemblerBlock(RocketAssemblerBlock.getProperties())); + public static final DeferredBlock ROCKET_ASSEMBLER = BLOCKS.register("rocket_assembler", () -> new RocketAssembler(RocketAssembler.getProperties())); + public static final DeferredBlock ROCKET_SEAT = BLOCKS.register("rocket_seat", () -> new RocketSeat(RocketSeat.getProperties())); } diff --git a/src/main/java/net/xevianlight/aphelion/core/init/ModCreativeTabs.java b/src/main/java/net/xevianlight/aphelion/core/init/ModCreativeTabs.java index bcc6d9e..d997703 100644 --- a/src/main/java/net/xevianlight/aphelion/core/init/ModCreativeTabs.java +++ b/src/main/java/net/xevianlight/aphelion/core/init/ModCreativeTabs.java @@ -42,6 +42,6 @@ public class ModCreativeTabs { output.accept(ModItems.ARC_FURNACE_CASING_BLOCK); output.accept(ModItems.VACUUM_ARC_FURNACE_CONTROLLER); output.accept(ModItems.LAUNCH_PAD); - output.accept(ModItems.ROCKET_ASSEMBLER_BLOCK); + output.accept(ModItems.ROCKET_ASSEMBLER); }).build()); } diff --git a/src/main/java/net/xevianlight/aphelion/core/init/ModItems.java b/src/main/java/net/xevianlight/aphelion/core/init/ModItems.java index 5a1071a..b513112 100644 --- a/src/main/java/net/xevianlight/aphelion/core/init/ModItems.java +++ b/src/main/java/net/xevianlight/aphelion/core/init/ModItems.java @@ -7,7 +7,6 @@ import net.neoforged.neoforge.registries.DeferredItem; import net.neoforged.neoforge.registries.DeferredRegister; import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.block.custom.*; -import net.xevianlight.aphelion.block.dummy.VAFMultiblockDummyBlock; import net.xevianlight.aphelion.item.*; public class ModItems { @@ -37,6 +36,7 @@ public static final DeferredItem MUSIC_DISC_BIT_SHIFT = ITEMS.register("mu public static final DeferredItem VACUUM_ARC_FURNACE_CONTROLLER = ITEMS.register("vacuum_arc_furnace_controller", () -> new BlockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get(), VacuumArcFurnaceController.getItemProperties())); public static final DeferredItem OXYGEN_TEST_BLOCK = ITEMS.register("oxygen_test_block", () -> new BlockItem(ModBlocks.OXYGEN_TEST_BLOCK.get(), new Item.Properties())); public static final DeferredItem LAUNCH_PAD = ITEMS.register("launch_pad", () -> new BlockItem(ModBlocks.LAUNCH_PAD.get(), LaunchPad.getItemProperties())); - public static final DeferredItem ROCKET_ASSEMBLER_BLOCK = ITEMS.register("rocket_assembler_block", () -> new BlockItem(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get(), RocketAssemblerBlock.getItemProperties())); + public static final DeferredItem ROCKET_ASSEMBLER = ITEMS.register("rocket_assembler", () -> new BlockItem(ModBlocks.ROCKET_ASSEMBLER.get(), RocketAssembler.getItemProperties())); + public static final DeferredItem ROCKET_SEAT = ITEMS.register("rocket_seat", () -> new BlockItem(ModBlocks.ROCKET_SEAT.get(), RocketSeat.getItemProperties())); // public static final DeferredItem VAF_MULTIBLOCK_DUMMY_BLOCK = ITEMS.register("vaf_multiblock_dummy_block", () -> new BlockItem(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), VAFMultiblockDummyBlock.getItemProperties())); } diff --git a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockLootTableProvider.java b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockLootTableProvider.java index 4aff4d1..d898d3b 100644 --- a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockLootTableProvider.java +++ b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockLootTableProvider.java @@ -26,7 +26,8 @@ public class ModBlockLootTableProvider extends BlockLootSubProvider { dropSelf(ModBlocks.OXYGEN_TEST_BLOCK.get()); dropOther(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), ItemStack.EMPTY.getItem()); dropSelf(ModBlocks.LAUNCH_PAD.get()); - dropSelf(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get()); + dropSelf(ModBlocks.ROCKET_ASSEMBLER.get()); + dropSelf(ModBlocks.ROCKET_SEAT.get()); } @Override diff --git a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java index a062883..554b5ed 100644 --- a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java +++ b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java @@ -29,7 +29,7 @@ public class ModBlockStateProvider extends BlockStateProvider { // modLoc("block/test_block"), // mcLoc("block/furnace_front"), // modLoc("block/test_block"))); - blockItem(ModBlocks.ROCKET_ASSEMBLER_BLOCK); + blockItem(ModBlocks.ROCKET_ASSEMBLER); blockWithItem(ModBlocks.BLOCK_STEEL); blockWithItem(ModBlocks.DIMENSION_CHANGER); diff --git a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockTagProvider.java b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockTagProvider.java index 9316350..6fcf59a 100644 --- a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockTagProvider.java +++ b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockTagProvider.java @@ -44,5 +44,8 @@ public class ModBlockTagProvider extends BlockTagsProvider { tag(ModTags.Blocks.LAUNCH_PAD) .add(ModBlocks.LAUNCH_PAD.get()); + tag(ModTags.Blocks.ROCKET_SEAT) + .add(ModBlocks.ROCKET_SEAT.get()); + } } diff --git a/src/main/java/net/xevianlight/aphelion/entites/vehicles/RocketEntity.java b/src/main/java/net/xevianlight/aphelion/entites/vehicles/RocketEntity.java index 28a3a60..8c21eed 100644 --- a/src/main/java/net/xevianlight/aphelion/entites/vehicles/RocketEntity.java +++ b/src/main/java/net/xevianlight/aphelion/entites/vehicles/RocketEntity.java @@ -51,7 +51,7 @@ public class RocketEntity extends VehicleEntity implements IEntityWithComplexSpa private double landingPosX; private double landingPosZ; - private static final double TELEPORT_Y = 1000.0; + private static final double TELEPORT_Y = 600.0; private static final double ASCEND_ACCEL = 0.0125; private static final double DESCEND_SPEED = 1; @@ -224,6 +224,7 @@ public class RocketEntity extends VehicleEntity implements IEntityWithComplexSpa if (isOnGround()) { resetDeltaMovement(); setPhase(FlightPhase.LANDED); + yVel = 0; return; } setDeltaMovement(0, -DESCEND_SPEED, 0); @@ -436,15 +437,24 @@ public class RocketEntity extends VehicleEntity implements IEntityWithComplexSpa return EntityDimensions.scalable(w, h).withEyeHeight(Math.max(0.1f, h - 0.2f)); } + + public Vec3 getSeatWorldPos(int seatIndex, float partialTicks) { + int packed = structure.packedSeatAt(seatIndex); + + int dx = RocketStructure.unpackX(packed); + int dy = RocketStructure.unpackY(packed); + int dz = RocketStructure.unpackZ(packed); + + return this.position().add(dx, dy, dz); + } + @Override - protected void positionRider(@NotNull Entity passenger, @NotNull MoveFunction moveFunction) { + public void positionRider(Entity passenger, MoveFunction move) { if (!this.hasPassenger(passenger)) return; - // Choose a stable seat position relative to the rocket. - // Example: centered, and 1.5 blocks above your base Y. - Vec3 seat = new Vec3(this.getX(), this.getY() + structure.computeExtents().toLocalAABB().getYsize() / 2, this.getZ()); + Vec3 seat = getSeatWorldPos(0, 0); // primary seat + move.accept(passenger, seat.x, seat.y, seat.z); - moveFunction.accept(passenger, seat.x, seat.y, seat.z); } @Override diff --git a/src/main/java/net/xevianlight/aphelion/util/FloodFill3D.java b/src/main/java/net/xevianlight/aphelion/util/FloodFill3D.java index 4bf9a77..e2974ac 100644 --- a/src/main/java/net/xevianlight/aphelion/util/FloodFill3D.java +++ b/src/main/java/net/xevianlight/aphelion/util/FloodFill3D.java @@ -47,7 +47,7 @@ public final class FloodFill3D { }; public static Set run(Level level, BlockPos start, int limit, SolidBlockPredicate predicate, boolean retainOrder) { - level.getProfiler().push("adastra-floodfill"); + level.getProfiler().push("aphelion-floodfill"); LongSet positions = retainOrder ? new LongLinkedOpenHashSet(limit) : new LongOpenHashSet(limit); LongArrayFIFOQueue queue = new LongArrayFIFOQueue(limit); diff --git a/src/main/java/net/xevianlight/aphelion/util/ModTags.java b/src/main/java/net/xevianlight/aphelion/util/ModTags.java index f82348c..54ad776 100644 --- a/src/main/java/net/xevianlight/aphelion/util/ModTags.java +++ b/src/main/java/net/xevianlight/aphelion/util/ModTags.java @@ -20,6 +20,7 @@ public class ModTags { public static final TagKey LAUNCH_PAD = createTag("launch_pad"); public static final TagKey PASSES_FLOOD_FILL = createTag("passes_flood_fill"); public static final TagKey BLOCKS_FLOOD_FILL = createTag("blocks_flood_fill"); + public static final TagKey ROCKET_SEAT = createTag("rocket_seat"); private static TagKey commonTag(String name) { return BlockTags.create(ResourceLocation.fromNamespaceAndPath("c", name)); diff --git a/src/main/java/net/xevianlight/aphelion/util/RocketStructure.java b/src/main/java/net/xevianlight/aphelion/util/RocketStructure.java index c24f042..e347b77 100644 --- a/src/main/java/net/xevianlight/aphelion/util/RocketStructure.java +++ b/src/main/java/net/xevianlight/aphelion/util/RocketStructure.java @@ -19,6 +19,8 @@ public final class RocketStructure { private final IntList packedPositions = new IntArrayList(); private final IntList paletteIndices = new IntArrayList(); + private final IntList seatOffsets = new IntArrayList(); + public RocketStructure(Builder builder) { builder.build(this); } @@ -34,6 +36,7 @@ public final class RocketStructure { palette.clear(); packedPositions.clear(); paletteIndices.clear(); + seatOffsets.clear(); } public void add(int x, int y, int z, BlockState state) { @@ -69,6 +72,8 @@ public final class RocketStructure { tag.put("pos", posArr); tag.put("idx", idxArr); + tag.put("seats", new IntArrayTag(seatOffsets.toIntArray())); + return tag; } @@ -92,6 +97,11 @@ public final class RocketStructure { packedPositions.add(pos[i]); paletteIndices.add(idx[i]); } + + if (tag.contains("seats", Tag.TAG_INT_ARRAY)) { + int[] seats = tag.getIntArray("seats"); + for (int s : seats) seatOffsets.add(s); + } } public static int packPos (int x, int y, int z) { @@ -167,7 +177,15 @@ public final class RocketStructure { int dz = RocketStructure.unpackZ(packed); BlockPos wp = origin.offset(dx, dy, dz); - level.setBlock(wp, Blocks.AIR.defaultBlockState(), 3); + if (level.getBlockState(wp).is(struct.stateAt(i).getBlock())) + level.setBlock(wp, Blocks.AIR.defaultBlockState(), 3); } } + + public int seatCount() { return seatOffsets.size(); } + public int packedSeatAt(int i) { return seatOffsets.getInt(i); } + + public void addSeatOffset(int dx, int dy, int dz) { + seatOffsets.add(packPos(dx, dy, dz)); + } } diff --git a/src/main/resources/assets/aphelion/blockstates/rocket_assembler.json b/src/main/resources/assets/aphelion/blockstates/rocket_assembler.json new file mode 100644 index 0000000..1cb773b --- /dev/null +++ b/src/main/resources/assets/aphelion/blockstates/rocket_assembler.json @@ -0,0 +1,34 @@ +{ + "variants": { + "facing=east,formed=false": { + "model": "aphelion:block/rocket_assembler", + "y": 90 + }, + "facing=north,formed=false": { + "model": "aphelion:block/rocket_assembler" + }, + "facing=south,formed=false": { + "model": "aphelion:block/rocket_assembler", + "y": 180 + }, + "facing=west,formed=false": { + "model": "aphelion:block/rocket_assembler", + "y": 270 + }, + "facing=east,formed=true": { + "model": "aphelion:block/rocket_assembler_formed", + "y": 90 + }, + "facing=north,formed=true": { + "model": "aphelion:block/rocket_assembler_formed" + }, + "facing=south,formed=true": { + "model": "aphelion:block/rocket_assembler_formed", + "y": 180 + }, + "facing=west,formed=true": { + "model": "aphelion:block/rocket_assembler_formed", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/aphelion/blockstates/rocket_assembler_block.json b/src/main/resources/assets/aphelion/blockstates/rocket_assembler_block.json deleted file mode 100644 index 3f6c25d..0000000 --- a/src/main/resources/assets/aphelion/blockstates/rocket_assembler_block.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "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 - } - } -} \ No newline at end of file diff --git a/src/main/resources/assets/aphelion/models/block/rocket_assembler_block.json b/src/main/resources/assets/aphelion/models/block/rocket_assembler.json similarity index 100% rename from src/main/resources/assets/aphelion/models/block/rocket_assembler_block.json rename to src/main/resources/assets/aphelion/models/block/rocket_assembler.json diff --git a/src/main/resources/assets/aphelion/models/block/rocket_assembler_block_formed.json b/src/main/resources/assets/aphelion/models/block/rocket_assembler_formed.json similarity index 100% rename from src/main/resources/assets/aphelion/models/block/rocket_assembler_block_formed.json rename to src/main/resources/assets/aphelion/models/block/rocket_assembler_formed.json