added gravity test block with gui and debug renderer

This commit is contained in:
TechnoDraconic
2026-02-06 22:22:10 -08:00
parent fa41966de4
commit 9356c43ea7
25 changed files with 739 additions and 67 deletions

View File

@@ -24,10 +24,7 @@ import net.xevianlight.aphelion.fluid.BaseFluidType;
import net.xevianlight.aphelion.fluid.ModFluidTypes;
import net.xevianlight.aphelion.fluid.ModFluids;
import net.xevianlight.aphelion.recipe.ModRecipes;
import net.xevianlight.aphelion.screen.ElectricArcFurnaceScreen;
import net.xevianlight.aphelion.screen.ModMenuTypes;
import net.xevianlight.aphelion.screen.TestBlockScreen;
import net.xevianlight.aphelion.screen.VacuumArcFurnaceScreen;
import net.xevianlight.aphelion.screen.*;
import org.slf4j.Logger;
import net.xevianlight.aphelion.entites.vehicles.RocketRenderer;
@@ -147,6 +144,7 @@ public class Aphelion {
event.register(ModMenuTypes.TEST_BLOCK_MENU.get(), TestBlockScreen::new);
event.register(ModMenuTypes.ELECTRIC_ARC_FURNACE_MENU.get(), ElectricArcFurnaceScreen::new);
event.register(ModMenuTypes.VACUUM_ARC_FURNACE_MENU.get(), VacuumArcFurnaceScreen::new);
event.register(ModMenuTypes.GRAVITY_TEST_BLOCK_MENU.get(), GravityTestBlockScreen::new);
}
@SubscribeEvent

View File

@@ -0,0 +1,57 @@
package net.xevianlight.aphelion.block.custom;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.xevianlight.aphelion.block.custom.base.BasicEntityBlock;
import net.xevianlight.aphelion.block.entity.custom.GravityTestBlockEntity;
import net.xevianlight.aphelion.block.entity.custom.OxygenTestBlockEntity;
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class GravityTestBlock extends BasicEntityBlock {
public GravityTestBlock(Properties properties) {super(properties, true);}
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {return null;}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new GravityTestBlockEntity(blockPos, blockState);
}
public static Properties getProperties() {return Properties.of();}
@Override
protected void onRemove(BlockState state, @NotNull Level level, @NotNull BlockPos pos, BlockState newState, boolean movedByPiston) {
if (state.getBlock() != newState.getBlock()) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof GravityTestBlockEntity BE) {
BE.removeGravityArea();
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult result) {
if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof GravityTestBlockEntity testBlockEntity) {
serverPlayer.openMenu(new SimpleMenuProvider(testBlockEntity, Component.literal("Gravity Test Block")), pos);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
}

View File

@@ -0,0 +1,119 @@
package net.xevianlight.aphelion.block.entity.custom;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.items.ItemStackHandler;
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.core.saveddata.GravitySavedData;
import net.xevianlight.aphelion.screen.ElectricArcFurnaceMenu;
import net.xevianlight.aphelion.screen.GravityTestBlockMenu;
import net.xevianlight.aphelion.systems.GravityService;
import org.jetbrains.annotations.Nullable;
public class GravityTestBlockEntity extends BlockEntity implements TickableBlockEntity, MenuProvider {
public GravityTestBlockEntity(BlockPos pos, BlockState blockState) {super(ModBlockEntities.GRAVITY_TEST_BLOCK_ENTITY.get(), pos, blockState);}
public int areaSize = 5;
public float gravityStrength = 5f;
private boolean isInitialized = false;
public final ItemStackHandler inventory = new ItemStackHandler(0);
@Override
protected void saveAdditional(CompoundTag pTag, HolderLookup.Provider pRegistries) {
pTag.putInt("areaSize", areaSize);
pTag.putFloat("gravityStrength", gravityStrength);
super.saveAdditional(pTag, pRegistries);
}
@Override
protected void loadAdditional(CompoundTag pTag, HolderLookup.Provider pRegistries) {
areaSize = pTag.getInt("areaSize");
gravityStrength = pTag.getFloat("gravityStrength");
super.loadAdditional(pTag, pRegistries);
}
public void setRadius(float r) {
areaSize = (int) r;
}
public void setStrength(float s) {
gravityStrength = s;
}
public void addGravityArea() {
Level level = getLevel();
if (level != null && level.isClientSide()) return;
BlockPos pos = this.getBlockPos();
GravityService.setGravityArea((ServerLevel) level, pos, gravityStrength, areaSize);
}
public void removeGravityArea() {
Level level = getLevel();
if (level != null && level.isClientSide()) return;
BlockPos pos = this.getBlockPos();
GravityService.removeGravityArea((ServerLevel) level, pos);
}
@Override
public void tick(Level entityLevel, long time, BlockState blockState, BlockPos pos) {}
@Override
public void clientTick(ClientLevel level, long time, BlockState state, BlockPos pos) {}
@Override
public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) {}
@Override
public boolean isInitialized() {
return isInitialized;
}
@Override
public void firstTick(Level level, BlockState state, BlockPos pos) { addGravityArea(); isInitialized = true; }
@Override
public @Nullable AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) {
return new GravityTestBlockMenu(i, inventory, this);
}
@Override
public Component getDisplayName() {
return null;
}
public void sendUpdate() {
removeGravityArea();
addGravityArea();
}
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
return this.saveCustomOnly(registries);
}
}

View File

@@ -42,6 +42,8 @@ public class OxygenTestRenderer implements BlockEntityRenderer<OxygenTestBlockEn
// 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) {
if (true) return; // i think this is all deprecated now
// This bit's debug only, folks!
if (!Minecraft.getInstance().gui.getDebugOverlay().showDebugScreen()) return;

View File

@@ -0,0 +1,179 @@
package net.xevianlight.aphelion.client;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.core.BlockPos;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import java.util.Collection;
import java.util.Set;
public class DebugRenderUtils {
/// Utilities for dealing with longs instead of BlockPos
/// I am not actually sure if this is faster or not. it probably is
/// 99% sure that this breaks in edge cases
public static class LongPos {
private static final int PACKED_X_LENGTH = 26;
private static final int PACKED_Y_LENGTH = 12;
private static final int PACKED_Z_LENGTH = 26;
private static final long PACKED_X_MASK = 67108863L;
private static final long PACKED_Y_MASK = 4095L;
private static final long PACKED_Z_MASK = 67108863L;
private static final int Y_OFFSET = 0;
private static final int Z_OFFSET = 12;
private static final int X_OFFSET = 38;
private static final long Y_MAGIC = PACKED_Y_MASK << Y_OFFSET;
private static final long Z_MAGIC = PACKED_Z_MASK << Z_OFFSET;
private static final long X_MAGIC = PACKED_X_MASK << X_OFFSET;
// no safeguard for the maximum values, but those are
public static long above(long pos) {
long y = (((pos & Y_MAGIC) >> Y_OFFSET) + 1) << Y_OFFSET;
return (pos & (~Y_MAGIC)) | (y & Y_MAGIC);
}
public static long below(long pos) {
long y = (((pos & Y_MAGIC) >> Y_OFFSET) - 1) << Y_OFFSET;
return (pos & (~Y_MAGIC)) | (y & Y_MAGIC);
}
public static long north(long pos) {
long z = (((pos & Z_MAGIC) >> Z_OFFSET) - 1) << Z_OFFSET;
return (pos & (~Z_MAGIC)) | (z & Z_MAGIC);
}
public static long south(long pos) {
long z = (((pos & Z_MAGIC) >> Z_OFFSET) + 1) << Z_OFFSET;
return (pos & (~Z_MAGIC)) | (z & Z_MAGIC);
}
public static long east(long pos) {
long x = (((pos & X_MAGIC) >> X_OFFSET) + 1) << X_OFFSET;
return (pos & (~X_MAGIC)) | (x & X_MAGIC);
}
public static long west(long pos) {
long x = (((pos & X_MAGIC) >> X_OFFSET) - 1) << X_OFFSET;
return (pos & (~X_MAGIC)) | (x & X_MAGIC);
}
public static int getX(long pos) {
return BlockPos.getX(pos);
}
public static int getY(long pos) {
return BlockPos.getY(pos);
}
public static int getZ(long pos) {
return BlockPos.getZ(pos);
}
}
public static void drawSphere(PoseStack poseStack, VertexConsumer vc, Vector3f center, float radius) {
Matrix4f mat = poseStack.last().pose();
final int Y_SEGMENT_COUNT = 20;
for (int segmentY=0; segmentY < Y_SEGMENT_COUNT; segmentY++) {
double bottomAngle = (((double) segmentY / Y_SEGMENT_COUNT) - 0.5) * Math.PI;
double topAngle = (((double) (segmentY+1) / Y_SEGMENT_COUNT) - 0.5) * Math.PI;
float y0 = (float) Math.sin(bottomAngle) * radius + center.y();
float y1 = (float) Math.sin(topAngle) * radius + center.y();
float bottomRadius = (float) Math.cos(bottomAngle) * radius;
float topRadius = (float) Math.cos(topAngle) * radius;
final int POLAR_SEGMENT_COUNT = 20;
for (int segmentP = 0; segmentP < POLAR_SEGMENT_COUNT; segmentP++) {
// "left" and "right" As viewed from outside the sphere
double leftAngle = (((double) segmentP / POLAR_SEGMENT_COUNT) - 1) * 2 * Math.PI;
double rightAngle = (((double) (segmentP+1) / POLAR_SEGMENT_COUNT) - 1) * 2 * Math.PI;
// Points have to wind CCW, so 0->1->2->3 is CCW.
// 0 and 1 use y0, 2 and 3 use y1.
float x0, x1, x2, x3, z0, z1, z2, z3;
x0 = (float) Math.cos(leftAngle) * bottomRadius + center.x();
x1 = (float) Math.cos(rightAngle) * bottomRadius + center.x();
x2 = (float) Math.cos(rightAngle) * topRadius + center.x();
x3 = (float) Math.cos(leftAngle) * topRadius + center.x();
z0 = (float) Math.sin(leftAngle) * bottomRadius + center.z();
z1 = (float) Math.sin(rightAngle) * bottomRadius + center.z();
z2 = (float) Math.sin(rightAngle) * topRadius + center.z();
z3 = (float) Math.sin(leftAngle) * topRadius + center.z();
// Draw the sphere quad
quad(mat, vc,
x0, y0, z0,
x1, y0, z1,
x2, y1, z2,
x3, y1, z3,
0.7f, 0.2f, 0.2f, 0.5f);
}
}
}
// Sorry LOSERS, we only let FAST data structures in HERE.
public static void drawBlockArea(PoseStack poseStack, VertexConsumer vc, LongOpenHashSet blocks) {
for (long p : blocks) {
// Neighbor checks: only render faces exposed to non-oxygen
boolean up = blocks.contains(LongPos.above(p));
boolean down = blocks.contains(LongPos.below(p));
boolean north = blocks.contains(LongPos.north(p));
boolean south = blocks.contains(LongPos.south(p));
boolean east = blocks.contains(LongPos.east(p));
boolean west = blocks.contains(LongPos.west(p));
if (up && down && north && south && east && west) continue;
drawBlockFaces(poseStack, vc, p, up, down, north, south, east, west);
}
}
public static void drawBlockFaces(
PoseStack poseStack, VertexConsumer vc, long posAsLong,
boolean up, boolean down, boolean north, boolean south, boolean east, boolean west) {
final float eps = 0.0025f;
float x0 = LongPos.getX(posAsLong) + eps;
float y0 = LongPos.getY(posAsLong) + eps;
float z0 = LongPos.getZ(posAsLong) + eps;
float x1 = LongPos.getX(posAsLong) + 1 - eps;
float y1 = LongPos.getY(posAsLong) + 1 - eps;
float z1 = LongPos.getZ(posAsLong) + 1 - eps;
// Color (ARGB-ish but as floats)
float r = 0.2f, g = 0.8f, b = 1.0f, a = 0.18f;
Matrix4f mat = poseStack.last().pose();
// IMPORTANT: vertex winding should be consistent (counter-clockwise)
if (!up) quad(mat, vc, x0,y1,z0, x1,y1,z0, x1,y1,z1, x0,y1,z1, r,g,b,a);
if (!down) quad(mat, vc, x0,y0,z1, x1,y0,z1, x1,y0,z0, x0,y0,z0, r,g,b,a);
if (!north) quad(mat, vc, x1,y0,z0, x0,y0,z0, x0,y1,z0, x1,y1,z0, r,g,b,a);
if (!south) quad(mat, vc, x0,y0,z1, x1,y0,z1, x1,y1,z1, x0,y1,z1, r,g,b,a);
if (!east) quad(mat, vc, x1,y0,z1, x1,y0,z0, x1,y1,z0, x1,y1,z1, r,g,b,a);
if (!west) quad(mat, vc, x0,y0,z0, x0,y0,z1, x0,y1,z1, x0,y1,z0, r,g,b,a);
}
public static void quad(
Matrix4f mat, VertexConsumer vc,
float x0, float y0, float z0,
float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
float r, float g, float b, float a
) {
// POSITION_COLOR format: ONLY position + color.
vc.addVertex(mat, x0, y0, z0).setColor(r, g, b, a);
vc.addVertex(mat, x1, y1, z1).setColor(r, g, b, a);
vc.addVertex(mat, x2, y2, z2).setColor(r, g, b, a);
vc.addVertex(mat, x3, y3, z3).setColor(r, g, b, a);
}
}

View File

@@ -0,0 +1,74 @@
package net.xevianlight.aphelion.client;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.VertexFormat;
import it.unimi.dsi.fastutil.longs.Long2IntMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.server.IntegratedServer;
import net.minecraft.core.BlockPos;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.core.saveddata.GravitySavedData;
import net.xevianlight.aphelion.core.saveddata.types.GravityData;
@EventBusSubscriber(modid = Aphelion.MOD_ID, value = Dist.CLIENT)
public class GravityDebugRender {
// Untextured translucent quads (POSITION_COLOR only)
private static final RenderType GRAVITY_FILL = RenderType.create(
"aphelion_gravity_fill",
DefaultVertexFormat.POSITION_COLOR,
VertexFormat.Mode.QUADS,
256,
false,
true,
RenderType.CompositeState.builder()
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER)
.setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY)
.setCullState(RenderStateShard.NO_CULL)
.setDepthTestState(RenderStateShard.LEQUAL_DEPTH_TEST)
.setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE)
.createCompositeState(true)
);
@SubscribeEvent
public static void onRenderLevel(RenderLevelStageEvent event) {
// One stage only (pick one that exists and looks good)
if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) return;
Minecraft mc = Minecraft.getInstance();
if (mc.level == null || mc.player == null) return;
if (!mc.gui.getDebugOverlay().showDebugScreen()) return;
PoseStack poseStack = event.getPoseStack();
var cam = mc.gameRenderer.getMainCamera();
var camPos = cam.getPosition();
poseStack.pushPose();
poseStack.translate(-camPos.x, -camPos.y, -camPos.z);
// I'm lazy, so i'm just gonna make this work on a singleplayer server and call it a day :P
IntegratedServer singleplayer = mc.getSingleplayerServer();
if (singleplayer == null) return;
MultiBufferSource.BufferSource bufferSource = mc.renderBuffers().bufferSource();
VertexConsumer vc = bufferSource.getBuffer(GRAVITY_FILL);
for (Long2IntMap.Entry gravityEntry : GravitySavedData.get(singleplayer.getLevel(mc.level.dimension()))._debug_getGravityData().long2IntEntrySet()) {
GravityData d = GravityData.unpack(gravityEntry.getIntValue());
BlockPos p = BlockPos.of(gravityEntry.getLongKey());
DebugRenderUtils.drawSphere(poseStack, vc, p.getCenter().toVector3f(), d.getRadius());
}
poseStack.popPose();
bufferSource.endBatch(GRAVITY_FILL);
}
}

View File

@@ -17,6 +17,8 @@ import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
import net.xevianlight.aphelion.Aphelion;
import org.joml.Matrix4f;
import java.util.Collection;
@EventBusSubscriber(modid = Aphelion.MOD_ID, value = Dist.CLIENT)
public final class OxygenDebugRender {
@@ -56,63 +58,9 @@ public final class OxygenDebugRender {
MultiBufferSource.BufferSource bufferSource = mc.renderBuffers().bufferSource();
VertexConsumer vc = bufferSource.getBuffer(OXYGEN_FILL);
// Render surface faces only (fast + pretty)
for (long l : ClientOxygenCache.OXYGEN) {
BlockPos p = BlockPos.of(l);
drawSurfaceFaces(poseStack, vc, p);
}
DebugRenderUtils.drawBlockArea(poseStack, vc, ClientOxygenCache.OXYGEN);
poseStack.popPose();
bufferSource.endBatch(OXYGEN_FILL);
}
private static void drawSurfaceFaces(PoseStack poseStack, VertexConsumer vc, BlockPos p) {
// Neighbor checks: only render faces exposed to non-oxygen
boolean up = ClientOxygenCache.OXYGEN.contains(p.above().asLong());
boolean down = ClientOxygenCache.OXYGEN.contains(p.below().asLong());
boolean north = ClientOxygenCache.OXYGEN.contains(p.north().asLong());
boolean south = ClientOxygenCache.OXYGEN.contains(p.south().asLong());
boolean east = ClientOxygenCache.OXYGEN.contains(p.east().asLong());
boolean west = ClientOxygenCache.OXYGEN.contains(p.west().asLong());
if (up && down && north && south && east && west) return;
final float eps = 0.0025f;
float x0 = p.getX() + eps;
float y0 = p.getY() + eps;
float z0 = p.getZ() + eps;
float x1 = p.getX() + 1 - eps;
float y1 = p.getY() + 1 - eps;
float z1 = p.getZ() + 1 - eps;
// Color (ARGB-ish but as floats)
float r = 0.2f, g = 0.8f, b = 1.0f, a = 0.18f;
Matrix4f mat = poseStack.last().pose();
// IMPORTANT: vertex winding should be consistent (counter-clockwise)
if (!up) quad(mat, vc, x0,y1,z0, x1,y1,z0, x1,y1,z1, x0,y1,z1, r,g,b,a);
if (!down) quad(mat, vc, x0,y0,z1, x1,y0,z1, x1,y0,z0, x0,y0,z0, r,g,b,a);
if (!north) quad(mat, vc, x1,y0,z0, x0,y0,z0, x0,y1,z0, x1,y1,z0, r,g,b,a);
if (!south) quad(mat, vc, x0,y0,z1, x1,y0,z1, x1,y1,z1, x0,y1,z1, r,g,b,a);
if (!east) quad(mat, vc, x1,y0,z1, x1,y0,z0, x1,y1,z0, x1,y1,z1, r,g,b,a);
if (!west) quad(mat, vc, x0,y0,z0, x0,y0,z1, x0,y1,z1, x0,y1,z0, r,g,b,a);
}
private static void quad(
Matrix4f mat, VertexConsumer vc,
float x0, float y0, float z0,
float x1, float y1, float z1,
float x2, float y2, float z2,
float x3, float y3, float z3,
float r, float g, float b, float a
) {
// POSITION_COLOR format: ONLY position + color.
vc.addVertex(mat, x0, y0, z0).setColor(r, g, b, a);
vc.addVertex(mat, x1, y1, z1).setColor(r, g, b, a);
vc.addVertex(mat, x2, y2, z2).setColor(r, g, b, a);
vc.addVertex(mat, x3, y3, z3).setColor(r, g, b, a);
}
}

View File

@@ -51,4 +51,9 @@ public class ModBlockEntities {
BLOCK_ENTITIES.register("rocket_assembler_block_entity", () -> BlockEntityType.Builder.of(
RocketAssemblerBlockEntity::new, ModBlocks.ROCKET_ASSEMBLER_BLOCK.get()).build(null)
);
public static final Supplier<BlockEntityType<GravityTestBlockEntity>> GRAVITY_TEST_BLOCK_ENTITY =
BLOCK_ENTITIES.register("gravity_test_block_entity", () -> BlockEntityType.Builder.of(
GravityTestBlockEntity::new, ModBlocks.GRAVITY_TEST_BLOCK.get()).build(null)
);
}

View File

@@ -6,6 +6,7 @@ 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.block.entity.custom.GravityTestBlockEntity;
public class ModBlocks {
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(Aphelion.MOD_ID);
@@ -20,4 +21,5 @@ public class ModBlocks {
public static final DeferredBlock<Block> VAF_MULTIBLOCK_DUMMY_BLOCK = BLOCKS.register("vaf_dummy_block", () -> new VAFMultiblockDummyBlock(VAFMultiblockDummyBlock.getProperties()));
public static final DeferredBlock<Block> OXYGEN_TEST_BLOCK = BLOCKS.register("oxygen_test_block", () -> new OxygenTestBlock(OxygenTestBlock.getProperties()));
public static final DeferredBlock<Block> ROCKET_ASSEMBLER_BLOCK = BLOCKS.register("rocket_assemblerblock", () -> new RocketAssemblerBlock(RocketAssemblerBlock.getProperties()));
public static final DeferredBlock<Block> GRAVITY_TEST_BLOCK = BLOCKS.register("gravity_test_block", () -> new GravityTestBlock(GravityTestBlock.getProperties()));
}

View File

@@ -36,6 +36,7 @@ public static final DeferredItem<Item> MUSIC_DISC_BIT_SHIFT = ITEMS.register("mu
public static final DeferredItem<BlockItem> ARC_FURNACE_CASING_BLOCK = ITEMS.register("arc_furnace_casing", () -> new BlockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK.get(), ArcFurnaceCasingBlock.getItemProperties()));
public static final DeferredItem<BlockItem> VACUUM_ARC_FURNACE_CONTROLLER = ITEMS.register("vacuum_arc_furnace_controller", () -> new BlockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get(), VacuumArcFurnaceController.getItemProperties()));
public static final DeferredItem<BlockItem> OXYGEN_TEST_BLOCK = ITEMS.register("oxygen_test_block", () -> new BlockItem(ModBlocks.OXYGEN_TEST_BLOCK.get(), new Item.Properties()));
public static final DeferredItem<BlockItem> GRAVITY_TEST_BLOCK = ITEMS.register("gravity_test_block", () -> new BlockItem(ModBlocks.GRAVITY_TEST_BLOCK.get(), new Item.Properties()));
public static final DeferredItem<BlockItem> LAUNCH_PAD = ITEMS.register("launch_pad", () -> new BlockItem(ModBlocks.LAUNCH_PAD.get(), LaunchPad.getItemProperties()));
// public static final DeferredItem<BlockItem> VAF_MULTIBLOCK_DUMMY_BLOCK = ITEMS.register("vaf_multiblock_dummy_block", () -> new BlockItem(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), VAFMultiblockDummyBlock.getItemProperties()));
}

View File

@@ -94,6 +94,9 @@ public class GravitySavedData extends SavedData {
gravityData.put(pos.asLong(), data.pack());
}
public Long2IntOpenHashMap _debug_getGravityData() {
return gravityData;
}
/**

View File

@@ -26,6 +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.GRAVITY_TEST_BLOCK.get());
dropSelf(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get());
}
@Override

View File

@@ -32,7 +32,9 @@ public class ModBlockStateProvider extends BlockStateProvider {
// blockItem(ModBlocks.LAUNCH_PAD);
blockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK);
blockWithItem(ModBlocks.OXYGEN_TEST_BLOCK);
blockWithItem(ModBlocks.GRAVITY_TEST_BLOCK);
}
private void blockWithItem(DeferredBlock<?> deferredBlock) {

View File

@@ -16,9 +16,11 @@ import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.network.ClientPlayerStateUpdateHandler;
import net.xevianlight.aphelion.network.RocketPayloadHandlers;
import net.xevianlight.aphelion.network.PartitionPayloadHandler;
import net.xevianlight.aphelion.network.UpdateGravityTestBlockHandler;
import net.xevianlight.aphelion.network.packet.ClientPlayerStateUpdatePacket;
import net.xevianlight.aphelion.network.packet.PartitionPayload;
import net.xevianlight.aphelion.network.packet.RocketLaunchPayload;
import net.xevianlight.aphelion.network.packet.UpdateGravityTestBlockPacket;
@EventBusSubscriber(modid = Aphelion.MOD_ID)
public class ModBusEvents {
@@ -57,5 +59,10 @@ public class ModBusEvents {
ClientPlayerStateUpdateHandler::handleDataOnMain
);
registrar.playToServer(
UpdateGravityTestBlockPacket.TYPE,
UpdateGravityTestBlockPacket.STREAM_CODEC,
UpdateGravityTestBlockHandler::handleDataOnMain
);
}
}

View File

@@ -0,0 +1,27 @@
package net.xevianlight.aphelion.network;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.xevianlight.aphelion.block.entity.custom.GravityTestBlockEntity;
import net.xevianlight.aphelion.network.packet.UpdateGravityTestBlockPacket;
public class UpdateGravityTestBlockHandler {
public static void handleDataOnMain(UpdateGravityTestBlockPacket packet, IPayloadContext context) {
context.enqueueWork(() -> {
BlockPos pos = packet.pos();
float radius = packet.radius();
float strength = packet.strength();
Level level = context.player().level();
if (level.getBlockEntity(pos) instanceof GravityTestBlockEntity blockEntity) {
blockEntity.setRadius(radius);
blockEntity.setStrength(strength);
blockEntity.sendUpdate();
level.sendBlockUpdated(pos, level.getBlockState(pos), level.getBlockState(pos), Block.UPDATE_ALL);
}
});
}
}

View File

@@ -0,0 +1,30 @@
package net.xevianlight.aphelion.network.packet;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.BlockPos;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.xevianlight.aphelion.Aphelion;
public record UpdateGravityTestBlockPacket(BlockPos pos, float radius, float strength) implements CustomPacketPayload {
public static final CustomPacketPayload.Type<UpdateGravityTestBlockPacket> TYPE =
new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Aphelion.MOD_ID, "update_oxygen_test_block"));
public static final StreamCodec<ByteBuf, UpdateGravityTestBlockPacket> STREAM_CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC,
UpdateGravityTestBlockPacket::pos,
ByteBufCodecs.FLOAT,
UpdateGravityTestBlockPacket::radius,
ByteBufCodecs.FLOAT,
UpdateGravityTestBlockPacket::strength,
UpdateGravityTestBlockPacket::new
);
@Override
public CustomPacketPayload.Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View File

@@ -0,0 +1,110 @@
package net.xevianlight.aphelion.screen;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
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.GravityTestBlockEntity;
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
import org.jetbrains.annotations.NotNull;
public class GravityTestBlockMenu extends AbstractContainerMenu {
public final GravityTestBlockEntity blockEntity;
private final Level level;
public GravityTestBlockMenu(int i, Inventory inventory, FriendlyByteBuf extraData) {
this(i, inventory, inventory.player.level().getBlockEntity(extraData.readBlockPos()));
}
public GravityTestBlockMenu(int i, Inventory inventory, BlockEntity blockEntity) {
super(ModMenuTypes.GRAVITY_TEST_BLOCK_MENU.get(), i);
this.blockEntity = ((GravityTestBlockEntity) blockEntity);
this.level = inventory.player.level();
// Init stuff
addPlayerInventory(inventory);
addPlayerHotbar(inventory);
}
@Override
public boolean stillValid(Player player) {
return true;
}
// CREDIT GOES TO: diesieben07 | https://github.com/diesieben07/SevenCommons
// must assign a slot number to each of the slots used by the GUI.
// For this container, we can see both the tile inventory's slots as well as the player inventory slots and the hotbar.
// Each time we add a Slot to the container, it automatically increases the slotIndex, which means
// 0 - 8 = hotbar slots (which will map to the InventoryPlayer slot numbers 0 - 8)
// 9 - 35 = player inventory slots (which map to the InventoryPlayer slot numbers 9 - 35)
// 36 - 44 = TileInventory slots, which map to our TileEntity slot numbers 0 - 8)
private static final int HOTBAR_SLOT_COUNT = 9;
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
private static final int VANILLA_FIRST_SLOT_INDEX = 0;
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
// THIS YOU HAVE TO DEFINE!
private static final int TE_INVENTORY_SLOT_COUNT = 0; // must be the number of slots you have!
@Override
public @NotNull ItemStack quickMoveStack(Player playerIn, int pIndex) {
Slot sourceSlot = slots.get(pIndex);
if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM
ItemStack sourceStack = sourceSlot.getItem();
ItemStack copyOfSourceStack = sourceStack.copy();
// Check if the slot clicked is one of the vanilla container slots
if (pIndex < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {
// This is a vanilla container slot so merge the stack into the tile inventory
if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX
+ TE_INVENTORY_SLOT_COUNT, false)) {
blockEntity.sendUpdate();
return ItemStack.EMPTY; // EMPTY_ITEM
}
} else if (pIndex < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
blockEntity.sendUpdate();
return ItemStack.EMPTY;
}
} else {
System.out.println("Invalid slotIndex:" + pIndex);
return ItemStack.EMPTY;
}
// If stack size == 0 (the entire stack was moved) set slot contents to null
if (sourceStack.getCount() == 0) {
sourceSlot.set(ItemStack.EMPTY);
blockEntity.sendUpdate();
} else {
blockEntity.sendUpdate();
sourceSlot.setChanged();
}
sourceSlot.onTake(playerIn, sourceStack);
blockEntity.sendUpdate();
return copyOfSourceStack;
}
private void addPlayerInventory(Inventory playerInventory) {
for (int i = 0; i < 3; ++i) {
for (int l = 0; l < 9; ++l) {
this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, 84 + i * 18));
}
}
}
private void addPlayerHotbar(Inventory playerInventory) {
for (int i = 0; i < 9; ++i) {
this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 142));
}
}
}

View File

@@ -0,0 +1,94 @@
package net.xevianlight.aphelion.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.StringWidget;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.gui.screens.inventory.FurnaceScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.neoforged.neoforge.network.PacketDistributor;
import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.network.packet.UpdateGravityTestBlockPacket;
public class GravityTestBlockScreen extends AbstractContainerScreen<GravityTestBlockMenu> {
private static final ResourceLocation GUI_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Aphelion.MOD_ID, "textures/gui/gravity_test_block/gui.png");
public GravityTestBlockScreen(GravityTestBlockMenu menu, Inventory playerInventory, Component title) {
super(menu, playerInventory, title);
}
private StringWidget gravityWidget;
private StringWidget rangeWidget;
@Override
protected void init() {
super.init();
// Gets rid of labels
this.inventoryLabelY = 73;
this.titleLabelY = 5;
// Increase Gravity
this.addRenderableWidget(Button.builder(Component.literal("+"), (button) -> {
PacketDistributor.sendToServer(new UpdateGravityTestBlockPacket(menu.blockEntity.getBlockPos(), menu.blockEntity.areaSize, menu.blockEntity.gravityStrength + 0.1f));
}).bounds(this.leftPos + 7, this.topPos + 30, 9, 9).build());
// Decrease Gravity
this.addRenderableWidget(Button.builder(Component.literal("-"), (button) -> {
PacketDistributor.sendToServer(new UpdateGravityTestBlockPacket(menu.blockEntity.getBlockPos(), menu.blockEntity.areaSize, menu.blockEntity.gravityStrength - 0.1f));
}).bounds(this.leftPos + 19, this.topPos + 30, 9, 9).build());
// Increase Radius
this.addRenderableWidget(Button.builder(Component.literal("+"), (button) -> {
PacketDistributor.sendToServer(new UpdateGravityTestBlockPacket(menu.blockEntity.getBlockPos(), menu.blockEntity.areaSize + 1, menu.blockEntity.gravityStrength));
}).bounds(this.leftPos + 135, this.topPos + 32, 9, 9).build());
// Decrease Radius
this.addRenderableWidget(Button.builder(Component.literal("-"), (button) -> {
PacketDistributor.sendToServer(new UpdateGravityTestBlockPacket(menu.blockEntity.getBlockPos(), menu.blockEntity.areaSize - 1, menu.blockEntity.gravityStrength));
}).bounds(this.leftPos + 147, this.topPos + 32, 9, 9).build());
// Current Gravity
gravityWidget = new StringWidget(
this.leftPos + 11,
this.topPos+46,
26,
9,
Component.literal("" + menu.blockEntity.gravityStrength),
this.font);
this.addRenderableWidget(gravityWidget);
// Current Radius
rangeWidget = new StringWidget(
this.leftPos + 139,
this.topPos+46,
26,
9,
Component.literal("" + menu.blockEntity.areaSize),
this.font);
this.addRenderableWidget(rangeWidget);
}
@Override
protected void renderBg(GuiGraphics pGuiGraphics, float pPartialTick, int pMouseX, int pMouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, GUI_TEXTURE);
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
pGuiGraphics.blit(GUI_TEXTURE, x, y, 0, 0, imageWidth, imageHeight);
}
@Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float delta) {
renderBackground(guiGraphics, mouseX, mouseY, delta);
super.render(guiGraphics, mouseX, mouseY, delta);
renderTooltip(guiGraphics, mouseX, mouseY);
gravityWidget.setMessage(Component.literal(String.format("%.1f", menu.blockEntity.gravityStrength)));
rangeWidget.setMessage(Component.literal("" + menu.blockEntity.areaSize));
}
}

View File

@@ -10,6 +10,8 @@ import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import net.xevianlight.aphelion.Aphelion;
import java.awt.*;
public class ModMenuTypes {
public static final DeferredRegister<MenuType<?>> MENUS =
DeferredRegister.create(Registries.MENU, Aphelion.MOD_ID);
@@ -23,6 +25,9 @@ public class ModMenuTypes {
public static DeferredHolder<MenuType<?>,MenuType<VacuumArcFurnaceMenu>> VACUUM_ARC_FURNACE_MENU =
registerMenuType("vacuum_arc_furnace_menu", VacuumArcFurnaceMenu::new);
public static DeferredHolder<MenuType<?>,MenuType<GravityTestBlockMenu>> GRAVITY_TEST_BLOCK_MENU =
registerMenuType("gravity_test_block_menu", GravityTestBlockMenu::new);
private static <T extends AbstractContainerMenu>DeferredHolder<MenuType<?>, MenuType<T>> registerMenuType(String name,
IContainerFactory<T> factory) {
return MENUS.register(name, () -> IMenuTypeExtension.create(factory));

View File

@@ -13,9 +13,13 @@ import net.xevianlight.aphelion.core.saveddata.types.GravityData;
public class GravityService {
/// If i did this right, there SHOULDN'T be a way to break client/server separation with this...
/// you shouldn't be able to get the "ServerLevel" object from the Client side unless you're already
/// breaking that rule, in which case, go for it lmfao
public static void setGravityArea(ServerLevel level, BlockPos pos, float accel, int radius) {
GravitySavedData.get(level).setGravityRegion(pos, new GravityData(accel, radius));
}
public static void removeGravityArea(ServerLevel level, BlockPos pos) {
GravitySavedData.get(level).removeGravityRegion(pos);
}
public static float getGravityAccel(Level level, BlockPos pos) {
if (level.isClientSide) {