superb-warfare/src/main/java/com/atsuishio/superbwarfare/entity/MortarEntity.java

285 lines
11 KiB
Java

package com.atsuishio.superbwarfare.entity;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.component.ModDataComponents;
import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity;
import com.atsuishio.superbwarfare.init.ModEntities;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.item.common.ammo.MortarShell;
import com.atsuishio.superbwarfare.tools.RangeTool;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.arguments.EntityAnchorArgument;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.items.ItemHandlerHelper;
import org.jetbrains.annotations.NotNull;
import org.joml.Math;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.*;
import software.bernie.geckolib.util.GeckoLibUtil;
public class MortarEntity extends VehicleEntity implements GeoEntity {
public static final EntityDataAccessor<Integer> FIRE_TIME = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<Float> PITCH = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.FLOAT);
public static final EntityDataAccessor<Float> YAW = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.FLOAT);
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public MortarEntity(EntityType<MortarEntity> type, Level level) {
super(type, level);
}
public MortarEntity(Level level, float yRot) {
super(ModEntities.MORTAR.get(), level);
this.setYRot(yRot);
this.entityData.set(YAW, yRot);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(FIRE_TIME, 0)
.define(PITCH, -70f)
.define(YAW, this.getYRot());
}
@Override
public boolean canBeCollidedWith() {
return false;
}
@Override
public boolean isPickable() {
return super.isPickable();
}
@Override
public double getEyeY() {
return 0.2F;
}
@Override
public boolean sendFireStarParticleOnHurt() {
return false;
}
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
compound.putFloat("Pitch", this.entityData.get(PITCH));
compound.putFloat("Yaw", this.entityData.get(YAW));
}
@Override
public void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
if (compound.contains("Pitch")) {
this.entityData.set(PITCH, compound.getFloat("Pitch"));
}
if (compound.contains("Yaw")) {
this.entityData.set(YAW, compound.getFloat("Yaw"));
}
}
@Override
public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) {
ItemStack stack = player.getMainHandItem();
if (stack.getItem() instanceof MortarShell shell && !player.isShiftKeyDown() && this.entityData.get(FIRE_TIME) == 0) {
this.entityData.set(FIRE_TIME, 25);
if (!player.isCreative()) {
stack.shrink(1);
}
if (!this.level().isClientSide()) {
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), ModSounds.MORTAR_LOAD.get(), SoundSource.PLAYERS, 1f, 1f);
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), ModSounds.MORTAR_FIRE.get(), SoundSource.PLAYERS, 8f, 1f);
this.level().playSound(null, this.getX(), this.getY(), this.getZ(), ModSounds.MORTAR_DISTANT.get(), SoundSource.PLAYERS, 32f, 1f);
}
Mod.queueServerWork(20, () -> {
Level level = this.level();
if (level instanceof ServerLevel server) {
MortarShellEntity entityToSpawn = shell.createShell(player, level, stack);
entityToSpawn.setPos(this.getX(), this.getY() + this.getEyeY(), this.getZ());
entityToSpawn.shoot(this.getLookAngle().x, this.getLookAngle().y, this.getLookAngle().z, 11.4f, (float) 0.1);
level.addFreshEntity(entityToSpawn);
server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, (this.getX() + 3 * this.getLookAngle().x), (this.getY() + 0.1 + 3 * this.getLookAngle().y), (this.getZ() + 3 * this.getLookAngle().z), 8, 0.4, 0.4, 0.4,
0.007);
server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, this.getX(), this.getY(), this.getZ(), 50, 2, 0.02, 2, 0.0005);
}
});
}
if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get()) {
if (setTarget(player.getMainHandItem())) {
player.swing(InteractionHand.MAIN_HAND);
return InteractionResult.SUCCESS;
} else {
player.displayClientMessage(Component.translatable("tips.superbwarfare.mortar.warn").withStyle(ChatFormatting.RED), true);
return InteractionResult.FAIL;
}
}
if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get()) {
if (setTarget(player.getOffhandItem())) {
player.swing(InteractionHand.OFF_HAND);
return InteractionResult.SUCCESS;
} else {
player.displayClientMessage(Component.translatable("tips.superbwarfare.mortar.warn").withStyle(ChatFormatting.RED), true);
return InteractionResult.FAIL;
}
}
if (player.isShiftKeyDown()) {
if (stack.getItem() == ModItems.CROWBAR.get()) {
this.discard();
ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.MORTAR_DEPLOYER.get()));
return InteractionResult.SUCCESS;
}
entityData.set(YAW, player.getYRot());
}
return InteractionResult.SUCCESS;
}
public boolean setTarget(ItemStack stack) {
var parameters = stack.get(ModDataComponents.FIRING_PARAMETERS);
if (parameters == null) return false;
var pos = parameters.pos();
double targetX = pos.getX();
double targetY = pos.getY();
double targetZ = pos.getZ();
var isDepressed = parameters.isDepressed();
if (!RangeTool.canReach(11.4, 0.146, this.getEyePosition(), new Vec3(targetX, targetY, targetZ), 20, 89, isDepressed)) {
return false;
}
this.look(new Vec3(targetX, targetY, targetZ));
entityData.set(PITCH, (float) -RangeTool.calculateAngle(
11.4, 0.146,
this.getEyePosition(),
new Vec3(targetX, targetY, targetZ),
parameters.isDepressed()
));
return true;
}
private void look(Vec3 pTarget) {
Vec3 vec3 = EntityAnchorArgument.Anchor.EYES.apply(this);
double d0 = (pTarget.x - vec3.x) * 0.2;
double d2 = (pTarget.z - vec3.z) * 0.2;
entityData.set(YAW, Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F));
}
@Override
public @NotNull Vec3 getDeltaMovement() {
return new Vec3(0, Math.min(super.getDeltaMovement().y, 0), 0);
}
@Override
public void baseTick() {
super.baseTick();
if (this.entityData.get(FIRE_TIME) > 0) {
this.entityData.set(FIRE_TIME, this.entityData.get(FIRE_TIME) - 1);
}
this.move(MoverType.SELF, this.getDeltaMovement());
if (this.onGround()) {
this.setDeltaMovement(Vec3.ZERO);
} else {
this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.04, 0.0));
}
}
@Override
public void handleClientSync() {
if (isControlledByLocalInstance()) {
interpolationSteps = 0;
syncPacketPositionCodec(getX(), getY(), getZ());
}
if (interpolationSteps <= 0) {
return;
}
double interpolatedYaw = Mth.wrapDegrees(serverYRot - (double) getYRot());
setYRot(getYRot() + (float) interpolatedYaw / (float) interpolationSteps);
setXRot(getXRot() + (float) (serverXRot - (double) getXRot()) / (float) interpolationSteps);
setRot(getYRot(), getXRot());
}
@Override
public void lerpTo(double x, double y, double z, float yaw, float pitch, int interpolationSteps) {
serverYRot = yaw;
serverXRot = pitch;
this.interpolationSteps = 10;
}
@Override
public void travel() {
float diffY = Mth.wrapDegrees(entityData.get(YAW) - this.getYRot());
float diffX = Mth.wrapDegrees(entityData.get(PITCH) - this.getXRot());
this.setYRot(this.getYRot() + Mth.clamp(0.5f * diffY, -20f, 20f));
this.setXRot(Mth.clamp(this.getXRot() + Mth.clamp(0.5f * diffX, -20f, 20f), -89, -20));
}
private PlayState movementPredicate(AnimationState<MortarEntity> event) {
if (this.entityData.get(FIRE_TIME) > 0) {
return event.setAndContinue(RawAnimation.begin().thenLoop("animation.mortar.fire"));
}
return event.setAndContinue(RawAnimation.begin().thenLoop("animation.mortar.idle"));
}
@Override
public void destroy() {
if (this.level() instanceof ServerLevel level) {
var x = this.getX();
var y = this.getY();
var z = this.getZ();
level.explode(null, x, y, z, 0, Level.ExplosionInteraction.NONE);
ItemEntity mortar = new ItemEntity(level, x, (y + 1), z, new ItemStack(ModItems.MORTAR_DEPLOYER.get()));
mortar.setPickUpDelay(10);
level.addFreshEntity(mortar);
}
super.destroy();
}
@Override
public float getMaxHealth() {
return 100;
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar data) {
data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate));
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.cache;
}
}