mirror of
https://github.com/XevianLight/Aphelion.git
synced 2026-05-11 10:00:54 +01:00
added gravity
This commit is contained in:
@@ -115,7 +115,7 @@ public class GravitySavedData extends SavedData {
|
||||
* Returns the strongest acceleration among all gravity regions that overlap this block position
|
||||
*/
|
||||
public float getGravityMax (BlockPos pos) {
|
||||
float max = 0;
|
||||
float max = -1;
|
||||
|
||||
List<GravityData> regions = getGravityRegions(pos);
|
||||
|
||||
@@ -124,6 +124,10 @@ public class GravitySavedData extends SavedData {
|
||||
if (accel > max) max = accel;
|
||||
}
|
||||
|
||||
if (max == -1) {
|
||||
max = GravityData.DEFAULT_GRAVITY;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ public class GravityData {
|
||||
private float accel;
|
||||
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 RADIUS_PRECISION = 100.0f;
|
||||
public static final float MAX_RADIUS = Short.MAX_VALUE / RADIUS_PRECISION;
|
||||
|
||||
@@ -13,8 +13,10 @@ import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
|
||||
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
|
||||
import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity;
|
||||
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.packet.ClientPlayerStateUpdatePacket;
|
||||
import net.xevianlight.aphelion.network.packet.PartitionPayload;
|
||||
import net.xevianlight.aphelion.network.packet.RocketLaunchPayload;
|
||||
|
||||
@@ -49,5 +51,11 @@ public class ModBusEvents {
|
||||
RocketPayloadHandlers::handleRocketLaunch
|
||||
);
|
||||
|
||||
registrar.playToClient(
|
||||
ClientPlayerStateUpdatePacket.TYPE,
|
||||
ClientPlayerStateUpdatePacket.STREAM_CODEC,
|
||||
ClientPlayerStateUpdateHandler::handleDataOnMain
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
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 org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -26,4 +28,9 @@ public abstract class LivingEntityMixin extends Entity {
|
||||
OxygenService.entityTick(level, entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "travel", at = @At("HEAD"))
|
||||
public void aphelion$travel(Vec3 travelVector, CallbackInfo ci) {
|
||||
if (this.isControlledByLocalInstance()) GravityService.onEntityTravel(level(), (LivingEntity) (Object) this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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())));
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,16 @@ package net.xevianlight.aphelion.network;
|
||||
|
||||
|
||||
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.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
import net.xevianlight.aphelion.Aphelion;
|
||||
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.client.AphelionClient;
|
||||
@@ -27,4 +31,17 @@ public final class KeyNetwork {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
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 {
|
||||
|
||||
/// 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 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);
|
||||
}
|
||||
|
||||
/// 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user