diff --git a/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d b/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d index 52e1b85..d5e61b8 100644 --- a/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d +++ b/src/generated/resources/.cache/59eb3dbb5f86130e09b3c62d89b9525ee01cf52d @@ -1,8 +1,9 @@ -// 1.21.1 2026-01-23T22:32:50.7204827 Loot Tables +// 1.21.1 2026-01-28T08:47:15.3186366 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 +afb6519a03415b8e0d5bafc9fadb70905a398046 data/aphelion/loot_table/blocks/oxygen_test_block.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/a8139181fab9cfd94e67697230cbaca839a05e1f b/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f index 5980f6c..2bf172c 100644 --- a/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f +++ b/src/generated/resources/.cache/a8139181fab9cfd94e67697230cbaca839a05e1f @@ -1,15 +1,18 @@ -// 1.21.1 2026-01-18T19:51:57.3548439 Block States: aphelion +// 1.21.1 2026-01-28T08:47:15.3176368 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 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 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 74418ef1cf678e72e7534924274688ef5a68af0e assets/aphelion/models/item/test_block.json 88ca3602517e99f7feaed57eddfc96965a25761c assets/aphelion/models/item/vacuum_arc_furnace_controller.json diff --git a/src/main/java/net/xevianlight/aphelion/Aphelion.java b/src/main/java/net/xevianlight/aphelion/Aphelion.java index e64d09f..3e45d9f 100644 --- a/src/main/java/net/xevianlight/aphelion/Aphelion.java +++ b/src/main/java/net/xevianlight/aphelion/Aphelion.java @@ -1,6 +1,5 @@ package net.xevianlight.aphelion; -import net.minecraft.client.renderer.entity.ThrownItemRenderer; import net.minecraft.resources.ResourceLocation; import net.neoforged.api.distmarker.Dist; import net.neoforged.fml.common.EventBusSubscriber; @@ -10,6 +9,7 @@ import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent; import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent; import net.neoforged.neoforge.event.AddReloadListenerEvent; import net.xevianlight.aphelion.block.dummy.renderer.MultiblockDummyRenderer; +import net.xevianlight.aphelion.block.entity.custom.renderer.OxygenTestRenderer; import net.xevianlight.aphelion.client.AphelionConfig; import net.xevianlight.aphelion.planet.AphelionPlanetJSONLoader; import net.xevianlight.aphelion.core.init.*; @@ -132,6 +132,7 @@ public class Aphelion { @SubscribeEvent public static void registerBER(EntityRenderersEvent.RegisterRenderers event) { event.registerBlockEntityRenderer(ModBlockEntities.VAF_MULTIBLOCK_DUMMY_ENTITY.get(), MultiblockDummyRenderer::new); + event.registerBlockEntityRenderer(ModBlockEntities.OXYGEN_TEST_BLOCK_ENTITY.get(), OxygenTestRenderer::new); } @SubscribeEvent diff --git a/src/main/java/net/xevianlight/aphelion/block/custom/OxygenTestBlock.java b/src/main/java/net/xevianlight/aphelion/block/custom/OxygenTestBlock.java new file mode 100644 index 0000000..7f98102 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/block/custom/OxygenTestBlock.java @@ -0,0 +1,25 @@ +package net.xevianlight.aphelion.block.custom; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.xevianlight.aphelion.block.entity.custom.OxygenTestBlockEntity; +import org.jetbrains.annotations.Nullable; + +public class OxygenTestBlock extends Block implements EntityBlock { + + public OxygenTestBlock(Properties properties) { + super(properties); + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return new OxygenTestBlockEntity(blockPos, blockState); + } + + public static Properties getProperties() { + return Properties.of(); + } +} diff --git a/src/main/java/net/xevianlight/aphelion/block/entity/custom/OxygenTestBlockEntity.java b/src/main/java/net/xevianlight/aphelion/block/entity/custom/OxygenTestBlockEntity.java new file mode 100644 index 0000000..030091c --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/block/entity/custom/OxygenTestBlockEntity.java @@ -0,0 +1,81 @@ +package net.xevianlight.aphelion.block.entity.custom; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import static net.xevianlight.aphelion.Aphelion.LOGGER; +import net.xevianlight.aphelion.core.init.ModBlockEntities; + +import java.util.*; + +public class OxygenTestBlockEntity extends BlockEntity { + + + public OxygenTestBlockEntity(BlockPos pos, BlockState blockState) { + super(ModBlockEntities.OXYGEN_TEST_BLOCK_ENTITY.get(), pos, blockState); + } + + public boolean canSpreadTo(BlockPos pos) { + return level != null && level.getBlockState(pos).isAir(); + } + + public static final int MAX_RANGE = 8; + public boolean isInRange(BlockPos pos, int radius) { + return radius <= MAX_RANGE; + } + + private List enclosedCache; + public List getEnclosedBlocks() { + if (level == null) return List.of(); + if (enclosedCache != null) return enclosedCache; + + List enclosedBlocks = new ArrayList<>(); + Set seen = new HashSet<>(); + + // It's... a reasonable assumption that we won't have to include more blocks at once than the area of a sphere? + // maybe a bit more, IDK how exactly it scales to blocks. + Deque queue = new ArrayDeque<>((int)(4 * Math.PI * MAX_RANGE * MAX_RANGE)); + Deque radiusQueue = new ArrayDeque<>((int)(4 * Math.PI * MAX_RANGE * MAX_RANGE)); + + queue.add(this.getBlockPos()); + radiusQueue.add(0); + + // Do flood fill out from this block + // Push on the top of the stack (newest), pop from the bottom of the stack (oldest). + // Ends up being breadth-first; if you wanted, you could label each position pushed to the queue + // by how many "layers deep" it is (i.e. how many steps it took to get there), + // and you'd see that every pos of layer 1 is together, then layer 2, then layer 3... + + long start = System.nanoTime(); + while (!queue.isEmpty()) { + BlockPos spreadFromPos = queue.removeFirst(); + int radius = radiusQueue.removeFirst(); + for (Direction d : Direction.values()) { + BlockPos relativePos = spreadFromPos.relative(d); + if (seen.contains(relativePos)) continue; + + if (canSpreadTo(relativePos) && isInRange(relativePos, radius)) { + seen.add(relativePos); + enclosedBlocks.add(relativePos); + + queue.add(relativePos); + radiusQueue.add(radius + 1); + } + } + } + long durationNanos = System.nanoTime() - start; + double durationMicros = durationNanos / 1000.0d; + LOGGER.info("Flood fill completed in {}µs, {}µs/block", durationMicros, durationMicros / enclosedBlocks.size()); + + enclosedCache = enclosedBlocks; + return enclosedBlocks; + } + + private void helper() { + var myVar = new BlockPos(1, 1, 1).hashCode(); + } + + +} diff --git a/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/OxygenTestRenderer.java b/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/OxygenTestRenderer.java new file mode 100644 index 0000000..3ed33b5 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/block/entity/custom/renderer/OxygenTestRenderer.java @@ -0,0 +1,115 @@ +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.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.world.phys.AABB; +import net.xevianlight.aphelion.block.entity.custom.OxygenTestBlockEntity; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import java.util.*; +import java.util.stream.Collectors; + +public class OxygenTestRenderer implements BlockEntityRenderer { + public OxygenTestRenderer (BlockEntityRendererProvider.Context context) {} + + private List toBlockPositions(OxygenTestBlockEntity be) { + return be.getEnclosedBlocks(); + } + + @Override + public AABB getRenderBoundingBox(OxygenTestBlockEntity blockEntity) { + return AABB.ofSize(blockEntity.getBlockPos().getCenter(), OxygenTestBlockEntity.MAX_RANGE*2, OxygenTestBlockEntity.MAX_RANGE*2, OxygenTestBlockEntity.MAX_RANGE*2); + } + + private Set relativePositionsCache; + @Override + // If in debug mode, renders a model made from the blocks + // that are currently returned by toBlockPositions(OxygenTestBlockEntity). + public void render(OxygenTestBlockEntity be, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) { + // This bit's debug only, folks! + if (!Minecraft.getInstance().gui.getDebugOverlay().showDebugScreen()) return; + + // Renderers are relative to our block pos, so transform all points to be relative to block pos as well + List positionsToRender = toBlockPositions(be); + BlockPos originPos = be.getBlockPos(); + + Set relativePositions; + if (relativePositionsCache != null) relativePositions = relativePositionsCache; + else relativePositions = positionsToRender.stream().map(bp -> bp.offset(new Vec3i(-originPos.getX(), -originPos.getY(), -originPos.getZ()))).collect(Collectors.toSet()); + + poseStack.pushPose(); + Matrix4f mat = poseStack.last().pose(); + VertexConsumer buf = buffer.getBuffer(RenderType.LIGHTNING); // for slightly transparent, lighting-ignoring textures (?), from what I already tested + for (BlockPos p1 : relativePositions) { + // Render a face for every side this block cannot find a neighbor in + boolean upUncovered = !relativePositions.contains(p1.relative(Direction.UP)); + boolean downUncovered = !relativePositions.contains(p1.relative(Direction.DOWN)); + boolean northUncovered = !relativePositions.contains(p1.relative(Direction.NORTH)); + boolean southUncovered = !relativePositions.contains(p1.relative(Direction.SOUTH)); + boolean eastUncovered = !relativePositions.contains(p1.relative(Direction.EAST)); + boolean westUncovered = !relativePositions.contains(p1.relative(Direction.WEST)); + + Vector3f centerPos = p1.getCenter().toVector3f(); + final Vector3f c000 = new Vector3f(centerPos).add(-0.500001f,-0.500001f,-0.500001f); + final Vector3f c001 = new Vector3f(centerPos).add(0.500001f,-0.500001f,-0.500001f); + final Vector3f c010 = new Vector3f(centerPos).add(-0.500001f,0.500001f,-0.500001f); + final Vector3f c011 = new Vector3f(centerPos).add(0.500001f,0.500001f,-0.500001f); + final Vector3f c100 = new Vector3f(centerPos).add(-0.500001f,-0.500001f,0.500001f); + final Vector3f c101 = new Vector3f(centerPos).add(0.500001f,-0.500001f,0.500001f); + final Vector3f c110 = new Vector3f(centerPos).add(-0.500001f,0.500001f,0.500001f); + final Vector3f c111 = new Vector3f(centerPos).add(0.500001f,0.500001f,0.500001f); + + if (upUncovered) { + addQuad(buf, mat, c110, c111, c011, c010, 0x6666FF); + } + if (downUncovered) { + addQuad(buf, mat, c000, c001, c101, c100, 0x6666FF); + } + if (northUncovered) { + addQuad(buf, mat, c001, c000, c010, c011, 0x6666FF); + } + if (eastUncovered) { + addQuad(buf, mat, c101, c001, c011, c111, 0x6666FF); + } + if (southUncovered) { + addQuad(buf, mat, c101, c111, c110, c100, 0x6666FF); + } + if (westUncovered) { + addQuad(buf, mat, c100, c110, c010, c000, 0x6666FF); + } + } + poseStack.popPose(); + } + + private void addQuad(VertexConsumer buf, Matrix4f matrix, Vector3f p0, Vector3f p1, Vector3f p2, Vector3f p3, int hexColor) { + addVertex(buf, matrix, p0, hexColor); + addVertex(buf, matrix, p1, hexColor); + addVertex(buf, matrix, p2, hexColor); + addVertex(buf, matrix, p3, hexColor); + } + + private void addVertex(VertexConsumer buf, Matrix4f matrix, Vector3f vec, int hexColor) { + float x = vec.x(); + float y = vec.y(); + float z = vec.z(); + int r = (hexColor & 0xFF0000) >> 16; + int g = (hexColor & 0x00FF00) >> 8; + int b = hexColor & 0x0000FF; + buf.addVertex(matrix, x, y, z) + .setColor(r, g, b, 255) + .setUv(0, 0) // No texture, so this gets ignored + .setOverlay(OverlayTexture.NO_OVERLAY) + .setLight(15728880) //0xF000F0, or fully bright(?) + .setNormal(0, 1, 0); // Facing upwards + } +} diff --git a/src/main/java/net/xevianlight/aphelion/core/init/ModBlockEntities.java b/src/main/java/net/xevianlight/aphelion/core/init/ModBlockEntities.java index 537ebcf..57ae8c8 100644 --- a/src/main/java/net/xevianlight/aphelion/core/init/ModBlockEntities.java +++ b/src/main/java/net/xevianlight/aphelion/core/init/ModBlockEntities.java @@ -2,6 +2,7 @@ package net.xevianlight.aphelion.core.init; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.entity.BlockEntityType; +import net.neoforged.fml.common.Mod; import net.neoforged.neoforge.registries.DeferredRegister; import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.block.dummy.entity.VAFMultiblockDummyBlockEntity; @@ -41,4 +42,9 @@ public class ModBlockEntities { BLOCK_ENTITIES.register("vaf_multiblock_dummy_entity", () -> BlockEntityType.Builder.of( VAFMultiblockDummyBlockEntity::new, ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get()).build(null) ); + + public static final Supplier> OXYGEN_TEST_BLOCK_ENTITY = + BLOCK_ENTITIES.register("oxygen_test_block_entity", () -> BlockEntityType.Builder.of( + OxygenTestBlockEntity::new, ModBlocks.OXYGEN_TEST_BLOCK.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 82f43d0..028ee25 100644 --- a/src/main/java/net/xevianlight/aphelion/core/init/ModBlocks.java +++ b/src/main/java/net/xevianlight/aphelion/core/init/ModBlocks.java @@ -1,6 +1,7 @@ package net.xevianlight.aphelion.core.init; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.neoforged.neoforge.registries.DeferredBlock; import net.neoforged.neoforge.registries.DeferredRegister; import net.xevianlight.aphelion.Aphelion; @@ -17,4 +18,5 @@ public class ModBlocks { public static final DeferredBlock ARC_FURNACE_CASING_BLOCK = BLOCKS.register("arc_furnace_casing", () -> new ArcFurnaceCasingBlock(ArcFurnaceCasingBlock.getProperties())); 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())); } 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 c11f8cf..885a61b 100644 --- a/src/main/java/net/xevianlight/aphelion/core/init/ModItems.java +++ b/src/main/java/net/xevianlight/aphelion/core/init/ModItems.java @@ -35,5 +35,6 @@ public static final DeferredItem MUSIC_DISC_BIT_SHIFT = ITEMS.register("mu public static final DeferredItem BLOCK_STEEL = ITEMS.register("block_steel", () -> new BlockItem(ModBlocks.BLOCK_STEEL.get(), BlockSteel.getItemProperties())); public static final DeferredItem ARC_FURNACE_CASING_BLOCK = ITEMS.register("arc_furnace_casing", () -> new BlockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK.get(), ArcFurnaceCasingBlock.getItemProperties())); 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 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 f8e3ee1..c9040ca 100644 --- a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockLootTableProvider.java +++ b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockLootTableProvider.java @@ -23,6 +23,7 @@ public class ModBlockLootTableProvider extends BlockLootSubProvider { dropSelf(ModBlocks.ELECTRIC_ARC_FURNACE.get()); dropSelf(ModBlocks.ARC_FURNACE_CASING_BLOCK.get()); dropSelf(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get()); + dropSelf(ModBlocks.OXYGEN_TEST_BLOCK.get()); dropOther(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), ItemStack.EMPTY.getItem()); } diff --git a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java index e873abb..6278cf9 100644 --- a/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java +++ b/src/main/java/net/xevianlight/aphelion/datagen/ModBlockStateProvider.java @@ -28,6 +28,7 @@ public class ModBlockStateProvider extends BlockStateProvider { blockWithItem(ModBlocks.BLOCK_STEEL); blockWithItem(ModBlocks.DIMENSION_CHANGER); blockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK); + blockWithItem(ModBlocks.OXYGEN_TEST_BLOCK); } private void blockWithItem(DeferredBlock deferredBlock) { diff --git a/src/main/resources/assets/aphelion/textures/block/oxygen_test_block.png b/src/main/resources/assets/aphelion/textures/block/oxygen_test_block.png new file mode 100644 index 0000000..b20e014 Binary files /dev/null and b/src/main/resources/assets/aphelion/textures/block/oxygen_test_block.png differ