6 Commits

Author SHA1 Message Date
TechnoDraconic
3154d32d79 changed mixins to affect ALL entities (might cause bugs) and fixed fall damage 2026-02-08 13:36:26 -08:00
XevianLight
aaa55b087f Merge remote-tracking branch 'origin/gravity-system' into gravity-system 2026-02-07 17:04:20 -07:00
XevianLight
d9bd26e8a0 GravitySavedData now reads from Planet jsons for default values 2026-02-07 17:03:05 -07:00
TechnoDraconic
010fc7307f added some generated files to git 2026-02-07 15:43:53 -08:00
TechnoDraconic
9356c43ea7 added gravity test block with gui and debug renderer 2026-02-06 22:22:10 -08:00
TechnoDraconic
fa41966de4 added gravity 2026-02-05 00:44:15 -08:00
39 changed files with 1078 additions and 76 deletions

View File

@@ -1,11 +1,12 @@
// 1.21.1 2026-01-28T08:47:15.3186366 Loot Tables // 1.21.1 2026-02-06T10:36:07.5023829 Loot Tables
// 1.21.1 2026-01-26T19:04:46.4976369 Loot Tables
69d8318ddba171526d1fabb87d9d93548ed8598e data/aphelion/loot_table/blocks/arc_furnace_casing.json 69d8318ddba171526d1fabb87d9d93548ed8598e data/aphelion/loot_table/blocks/arc_furnace_casing.json
05f08985e601d30116f67e2f07b48b03b40cdca6 data/aphelion/loot_table/blocks/block_steel.json 05f08985e601d30116f67e2f07b48b03b40cdca6 data/aphelion/loot_table/blocks/block_steel.json
ff43a9c3741faf10b1e156a7a74d5cfb035cc118 data/aphelion/loot_table/blocks/dimension_changer.json ff43a9c3741faf10b1e156a7a74d5cfb035cc118 data/aphelion/loot_table/blocks/dimension_changer.json
b63130d9c10485676303d729807b6fcaac080294 data/aphelion/loot_table/blocks/electric_arc_furnace.json b63130d9c10485676303d729807b6fcaac080294 data/aphelion/loot_table/blocks/electric_arc_furnace.json
afb6519a03415b8e0d5bafc9fadb70905a398046 data/aphelion/loot_table/blocks/oxygen_test_block.json 086c97543700ccc2f815da4e6c29f11159766889 data/aphelion/loot_table/blocks/gravity_test_block.json
b9cfe672ead8e2673a7b2f5c4cec831e7e8e7040 data/aphelion/loot_table/blocks/launch_pad.json b9cfe672ead8e2673a7b2f5c4cec831e7e8e7040 data/aphelion/loot_table/blocks/launch_pad.json
afb6519a03415b8e0d5bafc9fadb70905a398046 data/aphelion/loot_table/blocks/oxygen_test_block.json
2c6748b2cfb5b78e0cc95a2f3583d4e50cb4c964 data/aphelion/loot_table/blocks/rocket_assemblerblock.json
1ab50c99e9f478840b9d003fd56ebdcab12fbbce data/aphelion/loot_table/blocks/test_block.json 1ab50c99e9f478840b9d003fd56ebdcab12fbbce data/aphelion/loot_table/blocks/test_block.json
7d8eeb99a1bc942a6e2cf292b21fd4534062b5ab data/aphelion/loot_table/blocks/vacuum_arc_furnace_controller.json 7d8eeb99a1bc942a6e2cf292b21fd4534062b5ab data/aphelion/loot_table/blocks/vacuum_arc_furnace_controller.json
797bf9839d79e08b4832c9eaf3cb303b0471ed0c data/aphelion/loot_table/blocks/vaf_dummy_block.json 797bf9839d79e08b4832c9eaf3cb303b0471ed0c data/aphelion/loot_table/blocks/vaf_dummy_block.json

View File

@@ -1,19 +1,21 @@
// 1.21.1 2026-01-28T08:47:15.3176368 Block States: aphelion // 1.21.1 2026-02-06T10:36:07.5013847 Block States: aphelion
// 1.21.1 2026-01-26T20:40:43.8251623 Block States: aphelion
851ff42f7b21dec86107c8e0cefb3934ae4ebc08 assets/aphelion/blockstates/block_steel.json 851ff42f7b21dec86107c8e0cefb3934ae4ebc08 assets/aphelion/blockstates/block_steel.json
30b9c0efd7aaadb5412d98e4568f98b3632adbb9 assets/aphelion/blockstates/dimension_changer.json 30b9c0efd7aaadb5412d98e4568f98b3632adbb9 assets/aphelion/blockstates/dimension_changer.json
cb4287104006c80c8396b290ab5258df65d62cef assets/aphelion/blockstates/electric_arc_furnace.json cb4287104006c80c8396b290ab5258df65d62cef assets/aphelion/blockstates/electric_arc_furnace.json
1975ab6c73f76642f8b6cfed00e0739b4ea5775f assets/aphelion/blockstates/gravity_test_block.json
28131a570d3666b7f323de4ad8a69e52ceec92e2 assets/aphelion/blockstates/oxygen_test_block.json 28131a570d3666b7f323de4ad8a69e52ceec92e2 assets/aphelion/blockstates/oxygen_test_block.json
b86c50fddcf6c8c6c19cb748529239d5962a3ede assets/aphelion/blockstates/test_block.json b86c50fddcf6c8c6c19cb748529239d5962a3ede assets/aphelion/blockstates/test_block.json
a810b97f4dace35d026f28d96cb9c47c93600d75 assets/aphelion/models/block/block_steel.json a810b97f4dace35d026f28d96cb9c47c93600d75 assets/aphelion/models/block/block_steel.json
2d3592b7ab7132908709243e97540151e0fb762e assets/aphelion/models/block/dimension_changer.json 2d3592b7ab7132908709243e97540151e0fb762e assets/aphelion/models/block/dimension_changer.json
5f7e8674070f31a63875b5d6147153bfa0eef61a assets/aphelion/models/block/electric_arc_furnace.json 5f7e8674070f31a63875b5d6147153bfa0eef61a assets/aphelion/models/block/electric_arc_furnace.json
ad49034f318c6bc14a4844cf598c6999296aa8a0 assets/aphelion/models/block/gravity_test_block.json
746f23f150a01524ad03cbd1eb822bfbb7cf453b assets/aphelion/models/block/oxygen_test_block.json 746f23f150a01524ad03cbd1eb822bfbb7cf453b assets/aphelion/models/block/oxygen_test_block.json
e0971228b4a1c4bc9dbab58a7dacdc3ae6037e02 assets/aphelion/models/block/test_block.json e0971228b4a1c4bc9dbab58a7dacdc3ae6037e02 assets/aphelion/models/block/test_block.json
cdc831b0f1c462be64825fd34bd446e5b95afac6 assets/aphelion/models/item/arc_furnace_casing.json cdc831b0f1c462be64825fd34bd446e5b95afac6 assets/aphelion/models/item/arc_furnace_casing.json
3599f9037eb2f66de1765318b97ab564c3eae92f assets/aphelion/models/item/block_steel.json 3599f9037eb2f66de1765318b97ab564c3eae92f assets/aphelion/models/item/block_steel.json
db0ec473a016ce05c258cde18a217d47a9ea8324 assets/aphelion/models/item/dimension_changer.json db0ec473a016ce05c258cde18a217d47a9ea8324 assets/aphelion/models/item/dimension_changer.json
279080c06ada87f54fd0a7b885b256dbe25a946a assets/aphelion/models/item/electric_arc_furnace.json 279080c06ada87f54fd0a7b885b256dbe25a946a assets/aphelion/models/item/electric_arc_furnace.json
8de1f7597e1fa82c5603a88040ad935aa1cb9b29 assets/aphelion/models/item/gravity_test_block.json
24cf60e70f7d9450b0e70cf017662e80971bae17 assets/aphelion/models/item/oxygen_test_block.json 24cf60e70f7d9450b0e70cf017662e80971bae17 assets/aphelion/models/item/oxygen_test_block.json
74418ef1cf678e72e7534924274688ef5a68af0e assets/aphelion/models/item/test_block.json 74418ef1cf678e72e7534924274688ef5a68af0e assets/aphelion/models/item/test_block.json
88ca3602517e99f7feaed57eddfc96965a25761c assets/aphelion/models/item/vacuum_arc_furnace_controller.json 88ca3602517e99f7feaed57eddfc96965a25761c assets/aphelion/models/item/vacuum_arc_furnace_controller.json

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "aphelion:block/gravity_test_block"
}
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "aphelion:block/gravity_test_block"
}
}

View File

@@ -0,0 +1,3 @@
{
"parent": "aphelion:block/gravity_test_block"
}

View File

@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "aphelion:gravity_test_block"
}
],
"rolls": 1.0
}
],
"random_sequence": "aphelion:blocks/gravity_test_block"
}

View File

@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "minecraft:air"
}
],
"rolls": 1.0
}
],
"random_sequence": "aphelion:blocks/rocket_assemblerblock"
}

View File

@@ -24,10 +24,7 @@ import net.xevianlight.aphelion.fluid.BaseFluidType;
import net.xevianlight.aphelion.fluid.ModFluidTypes; import net.xevianlight.aphelion.fluid.ModFluidTypes;
import net.xevianlight.aphelion.fluid.ModFluids; import net.xevianlight.aphelion.fluid.ModFluids;
import net.xevianlight.aphelion.recipe.ModRecipes; import net.xevianlight.aphelion.recipe.ModRecipes;
import net.xevianlight.aphelion.screen.ElectricArcFurnaceScreen; import net.xevianlight.aphelion.screen.*;
import net.xevianlight.aphelion.screen.ModMenuTypes;
import net.xevianlight.aphelion.screen.TestBlockScreen;
import net.xevianlight.aphelion.screen.VacuumArcFurnaceScreen;
import org.slf4j.Logger; import org.slf4j.Logger;
import net.xevianlight.aphelion.entites.vehicles.RocketRenderer; 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.TEST_BLOCK_MENU.get(), TestBlockScreen::new);
event.register(ModMenuTypes.ELECTRIC_ARC_FURNACE_MENU.get(), ElectricArcFurnaceScreen::new); event.register(ModMenuTypes.ELECTRIC_ARC_FURNACE_MENU.get(), ElectricArcFurnaceScreen::new);
event.register(ModMenuTypes.VACUUM_ARC_FURNACE_MENU.get(), VacuumArcFurnaceScreen::new); event.register(ModMenuTypes.VACUUM_ARC_FURNACE_MENU.get(), VacuumArcFurnaceScreen::new);
event.register(ModMenuTypes.GRAVITY_TEST_BLOCK_MENU.get(), GravityTestBlockScreen::new);
} }
@SubscribeEvent @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 // If in debug mode, renders a model made from the blocks
// that are currently returned by toBlockPositions(OxygenTestBlockEntity). // that are currently returned by toBlockPositions(OxygenTestBlockEntity).
public void render(OxygenTestBlockEntity be, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) { 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! // This bit's debug only, folks!
if (!Minecraft.getInstance().gui.getDebugOverlay().showDebugScreen()) return; 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 net.xevianlight.aphelion.Aphelion;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import java.util.Collection;
@EventBusSubscriber(modid = Aphelion.MOD_ID, value = Dist.CLIENT) @EventBusSubscriber(modid = Aphelion.MOD_ID, value = Dist.CLIENT)
public final class OxygenDebugRender { public final class OxygenDebugRender {
@@ -56,63 +58,9 @@ public final class OxygenDebugRender {
MultiBufferSource.BufferSource bufferSource = mc.renderBuffers().bufferSource(); MultiBufferSource.BufferSource bufferSource = mc.renderBuffers().bufferSource();
VertexConsumer vc = bufferSource.getBuffer(OXYGEN_FILL); VertexConsumer vc = bufferSource.getBuffer(OXYGEN_FILL);
// Render surface faces only (fast + pretty) DebugRenderUtils.drawBlockArea(poseStack, vc, ClientOxygenCache.OXYGEN);
for (long l : ClientOxygenCache.OXYGEN) {
BlockPos p = BlockPos.of(l);
drawSurfaceFaces(poseStack, vc, p);
}
poseStack.popPose(); poseStack.popPose();
bufferSource.endBatch(OXYGEN_FILL); 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( BLOCK_ENTITIES.register("rocket_assembler_block_entity", () -> BlockEntityType.Builder.of(
RocketAssemblerBlockEntity::new, ModBlocks.ROCKET_ASSEMBLER_BLOCK.get()).build(null) 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.Aphelion;
import net.xevianlight.aphelion.block.custom.*; import net.xevianlight.aphelion.block.custom.*;
import net.xevianlight.aphelion.block.dummy.VAFMultiblockDummyBlock; import net.xevianlight.aphelion.block.dummy.VAFMultiblockDummyBlock;
import net.xevianlight.aphelion.block.entity.custom.GravityTestBlockEntity;
public class ModBlocks { public class ModBlocks {
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(Aphelion.MOD_ID); 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> 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> 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> 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> 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> 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> 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> 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())); // 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

@@ -32,12 +32,18 @@ import java.util.List;
*/ */
public class GravitySavedData extends SavedData { public class GravitySavedData extends SavedData {
private Level level;
private final Long2IntOpenHashMap gravityData = new Long2IntOpenHashMap(); private final Long2IntOpenHashMap gravityData = new Long2IntOpenHashMap();
private static final String NAME = "aphelion_gravity"; private static final String NAME = "aphelion_gravity";
public static GravitySavedData create() { public static GravitySavedData create(Level level) {
return new GravitySavedData(); return new GravitySavedData(level);
}
public GravitySavedData(Level level) {
this.level = level;
} }
@Override @Override
@@ -60,18 +66,18 @@ public class GravitySavedData extends SavedData {
return tag; return tag;
} }
public static GravitySavedData load(CompoundTag tag, HolderLookup.Provider lookupProvider) { public static GravitySavedData load(CompoundTag tag, HolderLookup.Provider lookupProvider, Level level) {
GravitySavedData data = create(); GravitySavedData data = new GravitySavedData(level);
if (!tag.contains("Position", Tag.TAG_LONG_ARRAY) || !tag.contains("Value", Tag.TAG_INT_ARRAY)) { return data; } if (!tag.contains("Position", Tag.TAG_LONG_ARRAY) || !tag.contains("Value", Tag.TAG_INT_ARRAY)) {
return data;
}
long[] positions = tag.getLongArray("Position"); long[] positions = tag.getLongArray("Position");
int[] values = tag.getIntArray("Value"); int[] values = tag.getIntArray("Value");
int length = Math.min(positions.length, values.length); int length = Math.min(positions.length, values.length);
data.gravityData.ensureCapacity(length); data.gravityData.ensureCapacity(length);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
data.gravityData.put(positions[i], values[i]); data.gravityData.put(positions[i], values[i]);
} }
@@ -81,7 +87,7 @@ public class GravitySavedData extends SavedData {
private static final int ABSENT = Integer.MIN_VALUE; private static final int ABSENT = Integer.MIN_VALUE;
public @Nullable GravityData getGravityRegionData (Level level, BlockPos center) { public @Nullable GravityData getGravityRegionData (BlockPos center) {
GravityData data = GravityData.unpack(gravityData.getOrDefault(center.asLong(), ABSENT)); GravityData data = GravityData.unpack(gravityData.getOrDefault(center.asLong(), ABSENT));
return data.pack() == ABSENT ? null : data; return data.pack() == ABSENT ? null : data;
} }
@@ -94,6 +100,9 @@ public class GravitySavedData extends SavedData {
gravityData.put(pos.asLong(), data.pack()); gravityData.put(pos.asLong(), data.pack());
} }
public Long2IntOpenHashMap _debug_getGravityData() {
return gravityData;
}
/** /**
@@ -115,7 +124,7 @@ public class GravitySavedData extends SavedData {
* Returns the strongest acceleration among all gravity regions that overlap this block position * Returns the strongest acceleration among all gravity regions that overlap this block position
*/ */
public float getGravityMax (BlockPos pos) { public float getGravityMax (BlockPos pos) {
float max = 0; float max = -1;
List<GravityData> regions = getGravityRegions(pos); List<GravityData> regions = getGravityRegions(pos);
@@ -124,6 +133,10 @@ public class GravitySavedData extends SavedData {
if (accel > max) max = accel; if (accel > max) max = accel;
} }
if (max == -1) {
max = defaultGravity(this.level);
}
return max; return max;
} }
@@ -158,7 +171,10 @@ public class GravitySavedData extends SavedData {
public static GravitySavedData get(ServerLevel level) { public static GravitySavedData get(ServerLevel level) {
return level.getDataStorage().computeIfAbsent( return level.getDataStorage().computeIfAbsent(
new Factory<>(GravitySavedData::create, GravitySavedData::load), new Factory<>(
() -> new GravitySavedData(level),
(tag, provider) -> GravitySavedData.load(tag, provider, level)
),
NAME NAME
); );
} }

View File

@@ -4,7 +4,8 @@ public class GravityData {
private float accel; private float accel;
private float radius; private float radius;
public static final float DEFAULT_GRAVITY = 9.80665f; // 1G public static final float ONE_G = 9.80665f;
public static final float DEFAULT_GRAVITY = ONE_G; // 1G
public static final float GRAVITY_PRECISION = 100.0f; public static final float GRAVITY_PRECISION = 100.0f;
public static final float RADIUS_PRECISION = 100.0f; public static final float RADIUS_PRECISION = 100.0f;
public static final float MAX_RADIUS = Short.MAX_VALUE / RADIUS_PRECISION; public static final float MAX_RADIUS = Short.MAX_VALUE / RADIUS_PRECISION;

View File

@@ -26,6 +26,8 @@ public class ModBlockLootTableProvider extends BlockLootSubProvider {
dropSelf(ModBlocks.OXYGEN_TEST_BLOCK.get()); dropSelf(ModBlocks.OXYGEN_TEST_BLOCK.get());
dropOther(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), ItemStack.EMPTY.getItem()); dropOther(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), ItemStack.EMPTY.getItem());
dropSelf(ModBlocks.LAUNCH_PAD.get()); dropSelf(ModBlocks.LAUNCH_PAD.get());
dropSelf(ModBlocks.GRAVITY_TEST_BLOCK.get());
dropSelf(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get());
} }
@Override @Override

View File

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

View File

@@ -13,10 +13,14 @@ import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity; import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity; import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.network.ClientPlayerStateUpdateHandler;
import net.xevianlight.aphelion.network.RocketPayloadHandlers; import net.xevianlight.aphelion.network.RocketPayloadHandlers;
import net.xevianlight.aphelion.network.PartitionPayloadHandler; 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.PartitionPayload;
import net.xevianlight.aphelion.network.packet.RocketLaunchPayload; import net.xevianlight.aphelion.network.packet.RocketLaunchPayload;
import net.xevianlight.aphelion.network.packet.UpdateGravityTestBlockPacket;
@EventBusSubscriber(modid = Aphelion.MOD_ID) @EventBusSubscriber(modid = Aphelion.MOD_ID)
public class ModBusEvents { public class ModBusEvents {
@@ -49,5 +53,16 @@ public class ModBusEvents {
RocketPayloadHandlers::handleRocketLaunch RocketPayloadHandlers::handleRocketLaunch
); );
registrar.playToClient(
ClientPlayerStateUpdatePacket.TYPE,
ClientPlayerStateUpdatePacket.STREAM_CODEC,
ClientPlayerStateUpdateHandler::handleDataOnMain
);
registrar.playToServer(
UpdateGravityTestBlockPacket.TYPE,
UpdateGravityTestBlockPacket.STREAM_CODEC,
UpdateGravityTestBlockHandler::handleDataOnMain
);
} }
} }

View File

@@ -0,0 +1,67 @@
package net.xevianlight.aphelion.mixins.common;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.attachment.AttachmentHolder;
import net.xevianlight.aphelion.systems.GravityService;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import org.spongepowered.asm.util.Locals;
import java.io.ObjectOutputStream;
@Mixin(Entity.class)
public abstract class EntityMixin extends AttachmentHolder {
@Shadow
public float fallDistance;
// @At("RETURN") injects at all points IMMEDIATELY before a "return" opcode.
// Immediately before means IMMEDIATELY BEFORE,
// so even in a method like:
//
// return gravity;
//
// What's ACTUALLY happening is:
//
// $value = gravity;
// return $value;
//
// So, when we inject, we get:
//
// $value = gravity;
// [RETURN INJECT POINT]
// return $value;
//
// so we get to edit $value.
@Inject(method = "getGravity", at = @At("RETURN"), cancellable = true)
public void aphelion$getGravity(CallbackInfoReturnable<Double> cir) {
cir.setReturnValue(cir.getReturnValue() * GravityService.getGravityFactor((Entity) (Object) this));
}
// Should only break if the code that increases fall distance is moved outside Entity$checkFallDamage.
@WrapMethod(method = "checkFallDamage")
public void aphelion$checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos, Operation<Void> original) {
float prevFallDistance = this.fallDistance;
original.call(y, onGround, state, pos);
float newFallDistance = this.fallDistance;
if (newFallDistance > prevFallDistance && newFallDistance > 0) {
float fallDistanceGained = newFallDistance - prevFallDistance;
this.fallDistance = prevFallDistance + (fallDistanceGained * Math.min(GravityService.getGravityFactor((Entity) (Object) this), 1));
}
}
}

View File

@@ -5,6 +5,8 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.xevianlight.aphelion.systems.GravityService;
import net.xevianlight.aphelion.systems.OxygenService; import net.xevianlight.aphelion.systems.OxygenService;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -26,4 +28,10 @@ public abstract class LivingEntityMixin extends Entity {
OxygenService.entityTick(level, entity); OxygenService.entityTick(level, entity);
} }
} }
@Inject(method = "travel", at = @At("HEAD"))
public void aphelion$travel(Vec3 travelVector, CallbackInfo ci) {
// temporarily disabled in favor of aphelion$getGravity mixin
//if (this.isControlledByLocalInstance()) GravityService.onEntityTravel(level(), (LivingEntity) (Object) this);
}
} }

View File

@@ -0,0 +1,42 @@
package net.xevianlight.aphelion.network;
import net.minecraft.world.entity.player.Player;
import net.xevianlight.aphelion.core.saveddata.types.GravityData;
import net.xevianlight.aphelion.systems.GravityService;
import net.xevianlight.aphelion.systems.OxygenService;
/// Read-only player state object; updated by a server packet every so often
public record ClientPlayerState(boolean oxygen, float gravity, float temperature) {
// Default player state
private static ClientPlayerState localData = new ClientPlayerState(true, GravityData.DEFAULT_GRAVITY * 0.5f, 50f);
public static void updateState(ClientPlayerState newData) {
onStateUpdate(localData, newData);
localData = newData;
}
public static ClientPlayerState getServerStateOf(Player player) {
return new ClientPlayerState(OxygenService.hasOxygen(player), GravityService.getGravityAccel(player), 50f);
}
/// For things like playing SFX, VFX, etc. etc.
public static void onStateUpdate(ClientPlayerState oldData, ClientPlayerState newData) {
// TODO: add sfx
if (!oldData.oxygen() && newData.oxygen()) {
// On oxygen gained
}
if (oldData.oxygen() && !newData.oxygen()) {
// On oxygen removed
}
if (newData.gravity() - 0.25f > oldData.gravity()) {
// On gravity increased by > 0.25
}
if (oldData.gravity() - 0.25f > newData.gravity()) {
// On gravity decreased by > 0.25
}
}
public static ClientPlayerState getLocalData() {
return localData;
}
}

View File

@@ -0,0 +1,11 @@
package net.xevianlight.aphelion.network;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.xevianlight.aphelion.network.packet.ClientPlayerStateUpdatePacket;
public class ClientPlayerStateUpdateHandler {
public static void handleDataOnMain(ClientPlayerStateUpdatePacket packet, IPayloadContext context) {
context.enqueueWork(() -> ClientPlayerState.updateState(new ClientPlayerState(packet.oxygen(), packet.gravity(), packet.temp())));
}
}

View File

@@ -2,12 +2,16 @@ package net.xevianlight.aphelion.network;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.event.tick.ServerTickEvent;
import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.PacketDistributor;
import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.entites.vehicles.RocketEntity; import net.xevianlight.aphelion.entites.vehicles.RocketEntity;
import net.xevianlight.aphelion.network.packet.ClientPlayerStateUpdatePacket;
import net.xevianlight.aphelion.network.packet.RocketLaunchPayload; import net.xevianlight.aphelion.network.packet.RocketLaunchPayload;
import net.xevianlight.aphelion.client.AphelionClient; import net.xevianlight.aphelion.client.AphelionClient;
@@ -27,4 +31,17 @@ public final class KeyNetwork {
PacketDistributor.sendToServer(new RocketLaunchPayload(rocket.getId())); PacketDistributor.sendToServer(new RocketLaunchPayload(rocket.getId()));
} }
} }
@SubscribeEvent
public static void onServerTick(ServerTickEvent.Post event) {
int FREQ = 4;
for (ServerPlayer p : event.getServer().getPlayerList().getPlayers()) {
if (p.tickCount % FREQ == 0) {
ClientPlayerState state = ClientPlayerState.getServerStateOf(p);
PacketDistributor.sendToPlayer(p, new ClientPlayerStateUpdatePacket(state.oxygen(), state.gravity(), state.temperature()));
}
}
}
} }

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,29 @@
package net.xevianlight.aphelion.network.packet;
import io.netty.buffer.ByteBuf;
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 ClientPlayerStateUpdatePacket(boolean oxygen, float gravity, float temp) implements CustomPacketPayload {
public static final CustomPacketPayload.Type<ClientPlayerStateUpdatePacket> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Aphelion.MOD_ID, "player_state_update"));
public static final StreamCodec<ByteBuf, ClientPlayerStateUpdatePacket> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.BOOL,
ClientPlayerStateUpdatePacket::oxygen,
ByteBufCodecs.FLOAT,
ClientPlayerStateUpdatePacket::gravity,
ByteBufCodecs.FLOAT,
ClientPlayerStateUpdatePacket::temp,
ClientPlayerStateUpdatePacket::new
);
@Override
public CustomPacketPayload.Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

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

View File

@@ -0,0 +1,79 @@
package net.xevianlight.aphelion.systems;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.xevianlight.aphelion.network.ClientPlayerState;
import net.xevianlight.aphelion.core.saveddata.GravitySavedData;
import net.xevianlight.aphelion.core.saveddata.types.GravityData;
public class GravityService {
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) {
// Pull from the client data b/c we can't access the server's saved data
return ClientPlayerState.getLocalData().gravity();
}
// TODO: maybe change this based on how stuff pans out
var gravity = GravitySavedData.get((ServerLevel) level).getGravityMax(pos);
return gravity;
}
public static float getGravityAccel(Entity entity) {
// Not sure if this is at the entity's feet, head, or the middle... research later
// Blockpos is from entity's feet ~Xev
BlockPos entityBlockPos = BlockPos.containing(entity.getX(), entity.getY(), entity.getZ());
return getGravityAccel(entity.level(), entityBlockPos);
}
public static float getGravityFactor(Entity entity) {
float gravityAccelReal = getGravityAccel(entity);
// How many times normal gravity you're experiencing.
// "normal gravity" varies across different entities. Thankfully, minecraft slaps a "protected" status
// on LivingEntity.getGravity(), so i graciously get to go fuck myself and not care.
// Players are 0.08 units/second/travel() of gravity (from what i've gathered)
return gravityAccelReal / GravityData.ONE_G;
}
/// Called by LivingEntity$travel mixin
public static void onEntityTravel(Level level, LivingEntity entity) {
if (
entity.isFallFlying() || entity.isInLiquid() ||
entity.isUnderWater() ||
entity.hasEffect(MobEffects.SLOW_FALLING)
) return;
float gravityAccelReal = getGravityAccel(entity);
// How many times normal gravity you're experiencing.
// "normal gravity" varies across different entities. Thankfully, minecraft slaps a "protected" status
// on LivingEntity.getGravity(), so i graciously get to go fuck myself and not care.
// Players are 0.08 units/second/travel() of gravity (from what i've gathered)
float gravityFactor = gravityAccelReal / GravityData.ONE_G;
// NOTE: this might cause certain entities to fly into the stratosphere at ultra low gravity,
// seeing as this isn't the same for all entities.
// Thankfully, though, this should have no effect on anything at default gravity.
float baseGameGravityAccel = 0.08f;
float translatedAccel = baseGameGravityAccel * gravityFactor;
Vec3 currentVelocity = entity.getDeltaMovement();
// add baseGameGravity to cancel normal gravity, then subtract the new gravity
if (translatedAccel > 0) entity.setDeltaMovement(currentVelocity.x(), currentVelocity.y() + (baseGameGravityAccel - translatedAccel), currentVelocity.z());
else entity.setDeltaMovement(currentVelocity.x(), currentVelocity.y() + baseGameGravityAccel, currentVelocity.z());
}
}

View File

@@ -4,6 +4,7 @@
"package": "net.xevianlight.aphelion.mixins", "package": "net.xevianlight.aphelion.mixins",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"common.EntityMixin",
"common.LivingEntityMixin" "common.LivingEntityMixin"
], ],
"client": [ "client": [

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -2,6 +2,6 @@
"dimension": "minecraft:overworld", "dimension": "minecraft:overworld",
"orbit_distance": 1, "orbit_distance": 1,
"star_system": "aphelon:sol", "star_system": "aphelon:sol",
"gravity": 1, "gravity": 9.8,
"oxygen": false "oxygen": false
} }