Plane update 1

This commit is contained in:
2026-02-19 10:35:18 +01:00
parent 372212847f
commit 8a35e0a455
3 changed files with 199 additions and 268 deletions

View File

@@ -55,12 +55,12 @@ public class HitterEntity extends PathAwareEntity implements Arrestable{
ItemStack book = new ItemStack(Items.WRITTEN_BOOK); ItemStack book = new ItemStack(Items.WRITTEN_BOOK);
NbtCompound nbt = book.getOrCreateNbt(); NbtCompound nbt = book.getOrCreateNbt();
nbt.putString("title", "Hitler's will"); nbt.putString("title", "MeinCrampft");
nbt.putString("author", "Hitler"); nbt.putString("author", "Hitler");
// Pages need to be JSON text components // Pages need to be JSON text components
NbtList pages = new NbtList(); NbtList pages = new NbtList();
pages.add(NbtString.of("{\"text\":\"Hitler's will\\n - Kill all jews\\n - Kill all players\"}")); pages.add(NbtString.of("{\"text\":\"MeinCrampft\\n - Kill all jews\\n - Kill all players\"}"));
pages.add(NbtString.of("{\"text\":\"die\"}")); pages.add(NbtString.of("{\"text\":\"die\"}"));
nbt.put("pages", pages); nbt.put("pages", pages);

View File

@@ -1,41 +1,27 @@
package dev.tggamesyt.szar; package dev.tggamesyt.szar;
import dev.tggamesyt.szar.PlaneAnimation;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.entity.*; import net.minecraft.entity.*;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import static dev.tggamesyt.szar.Szar.ANIMATION_TIMINGS;
import static dev.tggamesyt.szar.Szar.ANIMATION_TIMINGS_SECONDS;
public class PlaneEntity extends Entity { public class PlaneEntity extends Entity {
/* -------- DATA TRACKER -------- */ private static final TrackedData<Float> ENGINE_TARGET =
DataTracker.registerData(PlaneEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Boolean> ENGINE_ON = private PlaneAnimation currentServerAnimation = null;
DataTracker.registerData(PlaneEntity.class, TrackedDataHandlerRegistry.BOOLEAN); private float enginePower = 0f;
private double lastY;
private static final TrackedData<Boolean> IS_FLYING =
DataTracker.registerData(PlaneEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
// PlaneEntity.java (CLIENT SIDE ONLY FIELDS)
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
private PlaneAnimation currentAnimation; private PlaneAnimation currentAnimation;
@@ -45,54 +31,200 @@ public class PlaneEntity extends Entity {
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
private boolean looping; private boolean looping;
// --- SERVER STATE --- public PlaneEntity(EntityType<? extends PlaneEntity> type, World world) {
private PlaneAnimation currentServerAnimation = null; super(type, world);
private int animationTick = 0; this.noClip = false;
private boolean hadPassengerLastTick = false; this.setNoGravity(false); // FORCE gravity ON
private boolean wasFlyingLastTick = false; }
@Override
protected void initDataTracker() {
this.dataTracker.startTracking(ENGINE_TARGET, 0f);
}
@Override
public boolean isCollidable() {
return false;
}
@Override
public boolean canHit() {
return true;
}
public float getEngineTarget() {
return dataTracker.get(ENGINE_TARGET);
}
public void setEngineTarget(float value) {
dataTracker.set(ENGINE_TARGET, MathHelper.clamp(value, 0f, 1f));
}
public float getEnginePower() {
return enginePower;
}
@Override
public void tick() {
super.tick();
PlayerEntity player = getControllingPassenger();
if (player == null) {
Vec3d velocity = getVelocity();
// Apply gravity even without pilot
velocity = velocity.add(0, -0.04, 0);
velocity = velocity.multiply(0.98);
setVelocity(velocity);
move(MovementType.SELF, velocity);
return;
}
/* --------------------------------
CONTROLLER (AircraftEntity logic)
-------------------------------- */
// YAW
setYaw(getYaw() - player.sidewaysSpeed * 4.0f);
// PITCH (only in air)
if (!isOnGround()) {
setPitch(getPitch() - player.forwardSpeed * 2.5f);
}
// Stabilizer (small auto leveling)
setPitch(getPitch() * 0.98f);
/* --------------------------------
THROTTLE (AirplaneEntity logic)
-------------------------------- */
if (player.jumping) {
setEngineTarget(getEngineTarget() + 0.02f);
}
if (player.isSneaking()) {
setEngineTarget(getEngineTarget() - 0.02f);
}
// Smooth engine reaction
enginePower += (getEngineTarget() - enginePower) * 0.05f;
/* --------------------------------
PHYSICS (STABLE VERSION)
-------------------------------- */
Vec3d forward = getRotationVector().normalize();
Vec3d velocity = getVelocity();
/* ---------- REALIGN VELOCITY ---------- */
/* Prevents internal momentum stacking */
double speed = velocity.length();
if (speed > 0.001) {
// Stronger forward locking
double alignment = 0.25; // was 0.08
Vec3d newDir = velocity.normalize().lerp(forward, alignment).normalize();
velocity = newDir.multiply(speed);
}
/* ---------- THRUST ---------- */
double thrust = Math.pow(enginePower, 2.0) * 0.08;
velocity = velocity.add(forward.multiply(thrust));
/* ---------- GLIDE ---------- */
double diffY = lastY - getY();
if (lastY != 0.0 && diffY != 0.0) {
velocity = velocity.add(
forward.multiply(diffY * 0.04 * (1.0 - Math.abs(forward.y)))
);
}
lastY = getY();
/* ---------- DYNAMIC GRAVITY ---------- */
double horizontalSpeed = velocity.length() * (1.0 - Math.abs(forward.y));
double gravityFactor = Math.max(0.0, 1.0 - horizontalSpeed * 1.5);
// ALWAYS apply — do not check hasNoGravity()
velocity = velocity.add(0, -0.04 * gravityFactor, 0);
/* ---------- DRAG ---------- */
velocity = velocity.multiply(0.98);
/* ---------- MAX SPEED CLAMP ---------- */
double maxSpeed = 1.5;
if (velocity.length() > maxSpeed) {
velocity = velocity.normalize().multiply(maxSpeed);
}
setVelocity(velocity);
move(MovementType.SELF, velocity);
/* --------------------------------
ANIMATION STATE SYNC
-------------------------------- */
boolean hasPassenger = getControllingPassenger() != null;
if (!hasPassenger) {
playServerAnimation(null);
}
else if (enginePower < 0.05f) {
playServerAnimation(PlaneAnimation.START_ENGINE);
}
else if (isOnGround()) {
playServerAnimation(PlaneAnimation.LAND_STARTED);
}
else {
playServerAnimation(PlaneAnimation.FLYING);
}
}
@Override
protected void readCustomDataFromNbt(NbtCompound nbt) {
if (nbt.contains("EngineTarget")) {
setEngineTarget(nbt.getFloat("EngineTarget"));
}
}
@Override
protected void writeCustomDataToNbt(NbtCompound nbt) {
nbt.putFloat("EngineTarget", getEngineTarget());
}
@Nullable
public PlayerEntity getControllingPassenger() {
Entity passenger = getFirstPassenger();
return passenger instanceof PlayerEntity p ? p : null;
}
@Override
protected boolean canAddPassenger(Entity passenger) {
return passenger instanceof PlayerEntity && getPassengerList().isEmpty();
}
@Override
public void updatePassengerPosition(Entity passenger, PositionUpdater updater) {
passenger.setPosition(getX(), getY() + 0.8, getZ());
}
private void playServerAnimation(PlaneAnimation anim) { private void playServerAnimation(PlaneAnimation anim) {
if (this.currentServerAnimation == anim) return; if (this.currentServerAnimation == anim) return;
this.currentServerAnimation = anim; this.currentServerAnimation = anim;
Szar.playPlaneAnimation(anim, this.getId()); Szar.playPlaneAnimation(anim, this.getId());
} }
private boolean isAboveGround(double distance) {
return !this.getWorld().isSpaceEmpty(
this,
this.getBoundingBox().offset(0, -distance, 0)
);
}
public PlaneEntity(EntityType<? extends PlaneEntity> type, World world) {
super(type, world);
this.noClip = false;
}
/* -------- DATA -------- */
@Override
protected void initDataTracker() {
this.dataTracker.startTracking(ENGINE_ON, false);
this.dataTracker.startTracking(IS_FLYING, false);
}
public boolean isEngineOn() {
return dataTracker.get(ENGINE_ON);
}
public void setEngineOn(boolean value) {
dataTracker.set(ENGINE_ON, value);
}
public boolean isFlying() {
return dataTracker.get(IS_FLYING);
}
public void setFlying(boolean value) {
dataTracker.set(IS_FLYING, value);
}
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public void playAnimation(PlaneAnimation anim, boolean looping) { public void playAnimation(PlaneAnimation anim, boolean looping) {
this.currentAnimation = anim; this.currentAnimation = anim;
@@ -112,213 +244,12 @@ public class PlaneEntity extends Entity {
return currentAnimation; return currentAnimation;
} }
@Environment(EnvType.CLIENT)
public float getAnimationTime(float tickDelta) {
if (currentAnimation == null) return 0;
float time = (this.age + tickDelta) - animationStartTick;
if (looping) {
return time % ANIMATION_TIMINGS_SECONDS.getOrDefault(currentAnimation, -1f);
}
return Math.min(time, ANIMATION_TIMINGS_SECONDS.getOrDefault(currentAnimation, -1f));
}
/* -------- SAVE / LOAD -------- */
@Override
protected void readCustomDataFromNbt(NbtCompound nbt) {
setEngineOn(nbt.getBoolean("EngineOn"));
setFlying(nbt.getBoolean("IsFlying"));
}
@Override
protected void writeCustomDataToNbt(NbtCompound nbt) {
nbt.putBoolean("EngineOn", isEngineOn());
nbt.putBoolean("IsFlying", isFlying());
}
/* -------- TICK -------- */
@Override
public void tick() {
super.tick();
if (getWorld().isClient) return;
PlayerEntity player = getControllingPassenger();
boolean hasPassenger = player != null;
// Tick the current animation
if (currentServerAnimation != null) {
animationTick++;
int duration = ANIMATION_TIMINGS.getOrDefault(currentServerAnimation, -1);
// If it's a non-looping animation and finished, clear it
if (duration != -1 && animationTick >= duration) {
currentServerAnimation = null;
animationTick = 0;
}
}
/* --------------------------------
LANDING / GRAVITY CHECK
-------------------------------- */
boolean nearGround = isAboveGround(1.5);
if (!nearGround && isFlying()) {
setFlying(false);
setNoGravity(false);
playServerAnimation(PlaneAnimation.LANDING);
}
/* --------------------------------
PASSENGER STATE CHANGES
-------------------------------- */
if (!hadPassengerLastTick && hasPassenger) {
setEngineOn(true);
playServerAnimation(PlaneAnimation.START_ENGINE);
}
if (hadPassengerLastTick && !hasPassenger) {
setEngineOn(false);
setFlying(false);
setNoGravity(false);
playServerAnimation(PlaneAnimation.STOP_ENGINE);
currentServerAnimation = null; // allow full stop
}
hadPassengerLastTick = hasPassenger;
/* --------------------------------
IDLE (NO PASSENGER)
-------------------------------- */
if (!hasPassenger) {
setVelocity(getVelocity().multiply(0.9));
move(MovementType.SELF, getVelocity());
return;
}
/* --------------------------------
ENGINE RUNNING (ON GROUND)
-------------------------------- */
if (isEngineOn() && !isFlying()) {
playServerAnimation(PlaneAnimation.LAND_STARTED);
}
/* --------------------------------
FLIGHT TAKEOFF
-------------------------------- */
boolean nearGroundForTakeoff = isAboveGround(1.5);
boolean wantsTakeoff = player.jumping;
if (!isFlying()) {
if (wantsTakeoff && nearGroundForTakeoff) {
// Start engine if not on yet
if (!isEngineOn()) {
setEngineOn(true);
playServerAnimation(PlaneAnimation.START_ENGINE);
}
// Play lift up if not already lifting
if (currentServerAnimation != PlaneAnimation.LIFT_UP) {
playServerAnimation(PlaneAnimation.LIFT_UP);
animationTick = 0;
}
}
// If lift-up animation finished, start flying
if (currentServerAnimation == PlaneAnimation.LIFT_UP) {
int liftUpDuration = ANIMATION_TIMINGS.getOrDefault(PlaneAnimation.LIFT_UP, 10);
if (animationTick >= liftUpDuration) {
setFlying(true);
setNoGravity(true);
playServerAnimation(PlaneAnimation.FLYING);
}
}
} else {
// Already flying, handle in-air movement
setNoGravity(true);
playServerAnimation(PlaneAnimation.FLYING); // ensure looping
}
/* --------------------------------
FLIGHT PHYSICS
-------------------------------- */
setYaw(player.getYaw());
setPitch(player.getPitch());
prevYaw = getYaw();
float forward = player.forwardSpeed;
float sideways = player.sidewaysSpeed;
float speed = isFlying() ? 0.4f : 0.15f;
Vec3d forwardDir = Vec3d.fromPolar(0, getYaw());
Vec3d velocity = forwardDir.multiply(forward * speed);
setYaw(getYaw() + sideways * 3.0f);
if (isFlying() && player.isSneaking()) {
velocity = velocity.add(0, -0.06, 0);
}
setVelocity(getVelocity().add(velocity).multiply(0.98));
move(MovementType.SELF, getVelocity());
wasFlyingLastTick = isFlying();
}
@Override @Override
public ActionResult interact(PlayerEntity player, Hand hand) { public ActionResult interact(PlayerEntity player, Hand hand) {
player.startRiding(this); if (!this.getWorld().isClient) {
player.startRiding(this);
}
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }
@Override
protected boolean canAddPassenger(Entity passenger) {
return passenger instanceof PlayerEntity && this.getPassengerList().isEmpty();
}
@Override
public void updatePassengerPosition(Entity passenger, PositionUpdater positionUpdater) {
if (this.hasPassenger(passenger)) {
passenger.setPosition(
this.getX(),
this.getY() + 0.8, // seat height
this.getZ() - 1.0
);
}
}
@Nullable
public PlayerEntity getControllingPassenger() {
Entity passenger = this.getFirstPassenger();
return passenger instanceof PlayerEntity player ? player : null;
}
@Override
public void updateTrackedPosition(double x, double y, double z) {
super.updateTrackedPosition(x, y, z);
this.prevYaw = this.getYaw();
}
public static DefaultAttributeContainer.Builder createAttributes() {
return MobEntity.createMobAttributes()
.add(EntityAttributes.GENERIC_MAX_HEALTH, 1.0)
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 1.0)
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 1.0);
}
@Override
public boolean canHit() {
return true;
}
@Override
public boolean isPushable() {
return true;
}
} }

View File

@@ -652,7 +652,7 @@ public class Szar implements ModInitializer {
public static final EntityType<AtomEntity> AtomEntityType = public static final EntityType<AtomEntity> AtomEntityType =
Registry.register( Registry.register(
Registries.ENTITY_TYPE, Registries.ENTITY_TYPE,
new Identifier(MOD_ID, "atom"), new Identifier(MOD_ID, "nuke"),
FabricEntityTypeBuilder.create() FabricEntityTypeBuilder.create()
.entityFactory(AtomEntity::new) .entityFactory(AtomEntity::new)
.dimensions(EntityDimensions.fixed(1.0F, 1.6F)) .dimensions(EntityDimensions.fixed(1.0F, 1.6F))
@@ -918,7 +918,7 @@ public class Szar implements ModInitializer {
); );
public static final Item ATOM = Registry.register( public static final Item ATOM = Registry.register(
Registries.ITEM, Registries.ITEM,
new Identifier(MOD_ID, "atom"), new Identifier(MOD_ID, "nuke"),
new AtomItem( new AtomItem(
new Item.Settings() new Item.Settings()
) )