diff --git a/src/main/java/com/atsuishio/superbwarfare/client/ClientRenderHandler.java b/src/main/java/com/atsuishio/superbwarfare/client/ClientRenderHandler.java index 28106dd6d..4f7c9afd3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/ClientRenderHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/ClientRenderHandler.java @@ -58,6 +58,7 @@ public class ClientRenderHandler { event.registerBelowAll(HandsomeFrameOverlay.ID, new HandsomeFrameOverlay()); event.registerBelowAll(SpyglassRangeOverlay.ID, new SpyglassRangeOverlay()); event.registerBelowAll(HelicopterHudOverlay.ID, new HelicopterHudOverlay()); + event.registerBelowAll(AircraftOverlay.ID, new AircraftOverlay()); event.registerBelowAll(MortarInfoOverlay.ID, new MortarInfoOverlay()); } } \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/client/VehicleSoundInstance.java b/src/main/java/com/atsuishio/superbwarfare/client/VehicleSoundInstance.java index ff5667e73..10529daf3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/VehicleSoundInstance.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/VehicleSoundInstance.java @@ -119,7 +119,28 @@ public abstract class VehicleSoundInstance extends AbstractTickableSoundInstance @Override protected float getVolume(MobileVehicleEntity mobileVehicle) { - return (float) Mth.lerp(Mth.clamp(mobileVehicle.getDeltaMovement().length(), 0F, 0.3F), 0.0F, 0.3F); + return (float) Mth.lerp(Mth.clamp(mobileVehicle.getDeltaMovement().length(), 0F, 0.3F), 0.0F, 0.3F) * (mobileVehicle.onGround() ? 1 : 0.5f); + } + } + + public static class SwimSound extends VehicleSoundInstance { + public SwimSound(MobileVehicleEntity mobileVehicle) { + super(ModSounds.VEHICLE_SWIM.get(), Minecraft.getInstance(), mobileVehicle); + } + + @Override + protected boolean canPlay(MobileVehicleEntity mobileVehicle) { + return true; + } + + @Override + protected float getPitch(MobileVehicleEntity mobileVehicle) { + return 1; + } + + @Override + protected float getVolume(MobileVehicleEntity mobileVehicle) { + return (float) Mth.lerp(Mth.clamp(mobileVehicle.getDeltaMovement().horizontalDistance() * (mobileVehicle.isInWater() ? 1.2 : 0), 0F, 0.6F), 0.0F, 0.6F); } } } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/AircraftOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/AircraftOverlay.java new file mode 100644 index 000000000..4bdf39568 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/AircraftOverlay.java @@ -0,0 +1,236 @@ +package com.atsuishio.superbwarfare.client.overlay; + +import com.atsuishio.superbwarfare.Mod; +import com.atsuishio.superbwarfare.client.ClickHandler; +import com.atsuishio.superbwarfare.client.RenderHelper; +import com.atsuishio.superbwarfare.entity.vehicle.base.AircraftEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.Camera; +import net.minecraft.client.CameraType; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.LayeredDraw; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; +import org.joml.Math; +import org.joml.Matrix4f; +import org.joml.Vector4f; + +import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; + +@OnlyIn(Dist.CLIENT) +public class AircraftOverlay implements LayeredDraw.Layer { + + public static final ResourceLocation ID = Mod.loc("aircraft_hud"); + + private static float scopeScale = 1; + private static float lerpVy = 1; + private static float lerpPower = 1; + + @Override + public void render(GuiGraphics guiGraphics, @NotNull DeltaTracker deltaTracker) { + int screenWidth = guiGraphics.guiWidth(); + int screenHeight = guiGraphics.guiHeight(); + + Minecraft mc = Minecraft.getInstance(); + Player player = mc.player; + Camera camera = mc.gameRenderer.getMainCamera(); + Vec3 cameraPos = camera.getPosition(); + PoseStack poseStack = guiGraphics.pose(); + + var partialTick = deltaTracker.getGameTimeDeltaPartialTick(true); + + if (player == null) return; + + if (ClickHandler.isEditing) + return; + + if (player.getVehicle() instanceof AircraftEntity aircraftEntity && aircraftEntity instanceof MobileVehicleEntity mobileVehicle && aircraftEntity.isDriver(player) && player.getVehicle() instanceof WeaponVehicleEntity weaponVehicle) { + poseStack.pushPose(); + + RenderSystem.disableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.enableBlend(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + RenderSystem.setShaderColor(1, 1, 1, 1); + + scopeScale = Mth.lerp(partialTick, scopeScale, 1F); + float f = (float) Math.min(screenWidth, screenHeight); + float f1 = Math.min((float) screenWidth / f, (float) screenHeight / f) * scopeScale; + float i = Mth.floor(f * f1); + float j = Mth.floor(f * f1); + float k = ((screenWidth - i) / 2); + float l = ((screenHeight - j) / 2); + + if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) { + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/heli_base.png"), k, l, 0, 0.0F, i, j, i, j); + renderDriverAngle(guiGraphics, player, mobileVehicle, k, l, i, j, partialTick); + + preciseBlit(guiGraphics, Mod.loc("textures/screens/compass.png"), (float) screenWidth / 2 - 128, (float) 6, 128 + ((float) 64 / 45 * mobileVehicle.getYRot()), 0, 256, 16, 512, 16); + + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(-aircraftEntity.getRotZ(partialTick)), screenWidth / 2f, screenHeight / 2f, 0); + float pitch = aircraftEntity.getRotX(partialTick); + + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/heli_line.png"), (float) screenWidth / 2 - 128, (float) screenHeight / 2 - 512 - 5.475f * pitch, 0, 0, 256, 1024, 256, 1024); + poseStack.popPose(); + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(aircraftEntity.getRotZ(partialTick)), screenWidth / 2f, screenHeight / 2f - 56, 0); + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/roll_ind.png"), (float) screenWidth / 2 - 8, (float) screenHeight / 2 - 88, 0, 0, 16, 16, 16, 16); + poseStack.popPose(); + + guiGraphics.blit(Mod.loc("textures/screens/helicopter/heli_power_ruler.png"), screenWidth / 2 + 100, screenHeight / 2 - 64, 0, 0, 64, 128, 64, 128); + + double height = mobileVehicle.position().distanceTo((Vec3.atLowerCornerOf(mobileVehicle.level().clip(new ClipContext(mobileVehicle.position(), mobileVehicle.position().add(new Vec3(0, -1, 0).scale(100)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.ANY, mobileVehicle)).getBlockPos()))); + double blockInWay = mobileVehicle.position().distanceTo((Vec3.atLowerCornerOf(mobileVehicle.level().clip(new ClipContext(mobileVehicle.position(), mobileVehicle.position().add(new Vec3(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y + 0.06, mobileVehicle.getDeltaMovement().z).normalize().scale(100)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.ANY, mobileVehicle)).getBlockPos()))); + + float power = aircraftEntity.getPower(); + lerpPower = Mth.lerp(0.001f * partialTick, lerpPower, power); + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/heli_power.png"), (float) screenWidth / 2 + 130f, ((float) screenHeight / 2 - 64 + 124 - power * 980), 0, 0, 4, power * 980, 4, power * 980); + lerpVy = (float) Mth.lerp(0.021f * partialTick, lerpVy, mobileVehicle.getDeltaMovement().y()); + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/heli_vy_move.png"), (float) screenWidth / 2 + 138, ((float) screenHeight / 2 - 3 - Math.max(lerpVy * 20, -24) * 2.5f), 0, 0, 8, 8, 8, 8); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(lerpVy * 20, "m/s")), + screenWidth / 2 + 146, (int) (screenHeight / 2 - 3 - Math.max(lerpVy * 20, -24) * 2.5), (lerpVy * 20 < -24 || ((lerpVy * 20 < -10 || (lerpVy * 20 < -1 && length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 100)) && height < 36) || (length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 40 && blockInWay < 72) ? -65536 : 0x66FF00), false); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(mobileVehicle.getY())), + screenWidth / 2 + 104, screenHeight / 2, 0x66FF00, false); + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/speed_frame.png"), (float) screenWidth / 2 - 144, (float) screenHeight / 2 - 6, 0, 0, 50, 18, 50, 18); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(FormatTool.format0D(length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72, "km/h")), + screenWidth / 2 - 140, screenHeight / 2, 0x66FF00, false); + +// if (mobileVehicle instanceof Ah6Entity ah6Entity) { +// if (weaponVehicle.getWeaponIndex(0) == 0) { +// double heat = 1 - ah6Entity.getEntityData().get(HEAT) / 100.0F; +// guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("20MM CANNON " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : aircraftEntity.getAmmoCount(player))), screenWidth / 2 - 160, screenHeight / 2 - 60, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); +// } else { +// guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("70MM ROCKET " + aircraftEntity.getAmmoCount(player)), screenWidth / 2 - 160, screenHeight / 2 - 60, 0x66FF00, false); +// } +// } + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("FLARE " + aircraftEntity.getDecoy()), screenWidth / 2 - 160, screenHeight / 2 - 50, 0x66FF00, false); + + if (lerpVy * 20 < -24) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("SINK RATE,PULL UP!"), + screenWidth / 2 - 53, screenHeight / 2 + 24, -65536, false); + } else if (((lerpVy * 20 < -10 || (lerpVy * 20 < -1 && length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 100)) && height < 36) + || (length(mobileVehicle.getDeltaMovement().x, mobileVehicle.getDeltaMovement().y, mobileVehicle.getDeltaMovement().z) * 72 > 40 && blockInWay < 72)) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("TERRAIN TERRAIN"), + screenWidth / 2 - 42, screenHeight / 2 + 24, -65536, false); + } + + if (mobileVehicle.getEnergy() < 0.02 * mobileVehicle.getMaxEnergy()) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("NO POWER!"), + screenWidth / 2 - 144, screenHeight / 2 + 14, -65536, false); + } else if (mobileVehicle.getEnergy() < 0.2 * mobileVehicle.getMaxEnergy()) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("LOW POWER"), + screenWidth / 2 - 144, screenHeight / 2 + 14, 0xFF6B00, false); + } + + } + + Matrix4f transform = getVehicleTransform(mobileVehicle, partialTick); + float x0 = 0f; + float y0 = 0.65f; + float z0 = 0.8f; + + Vector4f worldPosition = transformPosition(transform, x0, y0, z0); + + float fovAdjust2 = (float) (Minecraft.getInstance().options.fov().get() / 30) - 1; + double zoom = 0.96 * 3 + 0.06 * fovAdjust2; + + Vec3 pos = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z).add(mobileVehicle.getViewVector(partialTick).scale(192)); + Vec3 lookAngle = player.getLookAngle().normalize().scale(pos.distanceTo(cameraPos) * (1 - 1.0 / zoom)); + + var cPos = cameraPos.add(lookAngle); + + Vec3 p = RenderHelper.worldToScreen(new Vec3(worldPosition.x, worldPosition.y, worldPosition.z).add(mobileVehicle.getViewVector(partialTick).scale(192)), ClientEventHandler.zoomVehicle ? cPos : cameraPos); + + if (p != null) { + poseStack.pushPose(); + float x = (float) p.x; + float y = (float) p.y; + + if (mc.options.getCameraType() == CameraType.FIRST_PERSON) { + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/crosshair_ind.png"), x - 8, y - 8, 0, 0, 16, 16, 16, 16); + renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + } else if (mc.options.getCameraType() == CameraType.THIRD_PERSON_BACK) { + poseStack.pushPose(); + poseStack.rotateAround(Axis.ZP.rotationDegrees(aircraftEntity.getRotZ(partialTick)), x, y, 0); + preciseBlit(guiGraphics, Mod.loc("textures/screens/drone.png"), x - 8, y - 8, 0, 0, 16, 16, 16, 16); + renderKillIndicator(guiGraphics, x - 7.5f + (float) (2 * (Math.random() - 0.5f)), y - 7.5f + (float) (2 * (Math.random() - 0.5f))); + + poseStack.pushPose(); + + poseStack.translate(x, y, 0); + poseStack.scale(0.75f, 0.75f, 1); + +// if (mobileVehicle instanceof Ah6Entity ah6Entity) { +// if (weaponVehicle.getWeaponIndex(0) == 0) { +// double heat = ah6Entity.getEntityData().get(HEAT) / 100.0F; +// guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("20MM CANNON " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : aircraftEntity.getAmmoCount(player))), 25, -9, Mth.hsvToRgb(0F, (float) heat, 1.0F), false); +// } else { +// guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("70MM ROCKET " + aircraftEntity.getAmmoCount(player)), 25, -9, -1, false); +// } +// } + + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("FLARE " + aircraftEntity.getDecoy()), 25, 1, -1, false); + poseStack.popPose(); + poseStack.popPose(); + } + poseStack.popPose(); + } + + poseStack.popPose(); + } else { + scopeScale = 0.7f; + } + } + + private static void renderKillIndicator(GuiGraphics guiGraphics, float posX, float posY) { + VehicleHudOverlay.renderKillIndicator3P(guiGraphics, posX, posY); + } + + private static void renderDriverAngle(GuiGraphics guiGraphics, Player player, Entity heli, float k, float l, float i, float j, float ticks) { + float diffY = Mth.wrapDegrees(Mth.lerp(ticks, player.yHeadRotO, player.getYHeadRot()) - Mth.lerp(ticks, heli.yRotO, heli.getYRot())) * 0.35f; + float diffX = Mth.wrapDegrees(Mth.lerp(ticks, player.xRotO, player.getXRot()) - Mth.lerp(ticks, heli.xRotO, heli.getXRot())) * 0.072f; + + preciseBlit(guiGraphics, Mod.loc("textures/screens/helicopter/heli_driver_angle.png"), k + diffY, l + diffX, 0, 0.0F, i, j, i, j); + } + + public static Matrix4f getVehicleTransform(VehicleEntity vehicle, float partialTicks) { + Matrix4f transform = new Matrix4f(); + transform.translate((float) Mth.lerp(partialTicks, vehicle.xo, vehicle.getX()), (float) Mth.lerp(partialTicks, vehicle.yo + 1.45, vehicle.getY() + 1.45), (float) Mth.lerp(partialTicks, vehicle.zo, vehicle.getZ())); + transform.rotate(Axis.YP.rotationDegrees(-vehicle.getYRot())); + transform.rotate(Axis.XP.rotationDegrees(vehicle.getXRot())); + transform.rotate(Axis.ZP.rotationDegrees(vehicle.getRoll())); + return transform; + } + + public static Vector4f transformPosition(Matrix4f transform, float x, float y, float z) { + return transform.transform(new Vector4f(x, y, z, 1)); + } + + public static double length(double x, double y, double z) { + return Math.sqrt(x * x + y * y + z * z); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/A10Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/A10Entity.java index 0757678d4..54280463a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/A10Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/A10Entity.java @@ -6,26 +6,31 @@ import com.atsuishio.superbwarfare.config.server.VehicleConfig; import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity; import com.atsuishio.superbwarfare.entity.projectile.MelonBombEntity; import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity; -import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity; -import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; -import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.*; import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.HeliRocketWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.SmallCannonShellWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.init.ModTags; -import com.atsuishio.superbwarfare.tools.CustomExplosion; -import com.atsuishio.superbwarfare.tools.EntityFindUtil; -import com.atsuishio.superbwarfare.tools.FormatTool; -import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.network.message.receive.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.*; import com.mojang.math.Axis; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +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.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.Entity; @@ -35,8 +40,10 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; import org.jetbrains.annotations.NotNull; import org.joml.Math; import org.joml.Matrix4f; @@ -46,12 +53,17 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; -public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity { +import java.util.Comparator; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity, WeaponVehicleEntity, AircraftEntity { + public static final EntityDataAccessor LOADED_ROCKET = SynchedEntityData.defineId(A10Entity.class, EntityDataSerializers.INT); private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); private float yRotSync; private boolean fly; private int flyTime; - + public int fireIndex; public A10Entity(EntityType type, Level world) { super(type, world); @@ -62,6 +74,25 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity return 0.5f; } + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new SmallCannonShellWeapon() + .damage(VehicleConfig.BMP_2_CANNON_DAMAGE.get()) + .explosionDamage(VehicleConfig.BMP_2_CANNON_EXPLOSION_DAMAGE.get().floatValue()) + .explosionRadius(VehicleConfig.BMP_2_CANNON_EXPLOSION_RADIUS.get().floatValue()) + .sound(ModSounds.INTO_CANNON.get()) + .icon(Mod.loc("textures/screens/vehicle_weapon/cannon_20mm.png")), + new HeliRocketWeapon() + .damage(VehicleConfig.AH_6_ROCKET_DAMAGE.get()) + .explosionDamage(VehicleConfig.AH_6_ROCKET_EXPLOSION_DAMAGE.get()) + .explosionRadius(VehicleConfig.AH_6_ROCKET_EXPLOSION_RADIUS.get()) + .sound(ModSounds.INTO_MISSILE.get()), + } + }; + } + @Override public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { return new ThirdPersonCameraPosition(17, 3, 0); @@ -70,16 +101,19 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); + builder.define(LOADED_ROCKET, 0); } @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); + compound.putInt("LoadedRocket", this.entityData.get(LOADED_ROCKET)); } @Override public void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); + this.entityData.set(LOADED_ROCKET, compound.getInt("LoadedRocket")); } @Override @@ -146,10 +180,55 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity } } - this.terrainCompact(5f, 5f); + if (this.level() instanceof ServerLevel) { + if (reloadCoolDown > 0) { + reloadCoolDown--; + } + handleAmmo(); + } + + if (this.getFirstPassenger() instanceof Player player && fireInputDown) { + if (this.getWeaponIndex(0) == 0) { + if ((this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFire) { + vehicleShoot(player, 0); + } + } else { + if (this.entityData.get(AMMO) > 0) { + vehicleShoot(player, 0); + } + } + } + + this.terrainCompact(4f, 4f); this.refreshDimensions(); } + private void handleAmmo() { + if (!(this.getFirstPassenger() instanceof Player player)) return; + + int ammoCount = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return Ammo.HEAVY.get(stack) > 0; + } + return false; + }).mapToInt(Ammo.HEAVY::get).sum() + countItem(ModItems.SMALL_SHELL.get()); + + if ((hasItem(ModItems.ROCKET_70.get()) || InventoryTool.hasCreativeAmmoBox(player)) && reloadCoolDown == 0 && this.getEntityData().get(LOADED_ROCKET) < 28) { + this.entityData.set(LOADED_ROCKET, this.getEntityData().get(LOADED_ROCKET) + 1); + reloadCoolDown = 15; + if (!InventoryTool.hasCreativeAmmoBox(player)) { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.ROCKET_70.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + this.level().playSound(null, this, ModSounds.MISSILE_RELOAD.get(), this.getSoundSource(), 1, 1); + } + + if (this.getWeaponIndex(0) == 0) { + this.entityData.set(AMMO, ammoCount); + } else { + this.entityData.set(AMMO, this.getEntityData().get(LOADED_ROCKET)); + } + } + @Override public void travel() { Entity passenger = this.getFirstPassenger(); @@ -435,4 +514,163 @@ public class A10Entity extends ContainerMobileVehicleEntity implements GeoEntity public boolean allowFreeCam() { return true; } + + @Override + public void vehicleShoot(Player player, int type) { + Matrix4f transform = getVehicleTransform(1); + + if (getWeaponIndex(0) == 0) { + if (this.cannotFire) return; + + boolean hasCreativeAmmo = (getFirstPassenger() instanceof Player pPlayer && InventoryTool.hasCreativeAmmoBox(pPlayer)) || hasItem(ModItems.CREATIVE_AMMO_BOX.get()); + + Vector4f worldPosition = transformPosition(transform, 0.1321625f, -0.56446875f, 7.85210625f); + + if (this.entityData.get(AMMO) > 0 || hasCreativeAmmo) { + var entityToSpawn = ((SmallCannonShellWeapon) getWeapon(0)).create(player); + + entityToSpawn.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + entityToSpawn.shoot(getLookAngle().x, getLookAngle().y - 0.01, getLookAngle().z, 20, 0.5f); + level().addFreshEntity(entityToSpawn); + + sendParticle((ServerLevel) this.level(), ParticleTypes.LARGE_SMOKE, worldPosition.x, worldPosition.y, worldPosition.z, 1, 0, 0, 0, 0, false); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, this.getOnPos(), ModSounds.HPJ_11_FIRE_3P.get(), SoundSource.PLAYERS, 6, random.nextFloat() * 0.05f + 1); + serverPlayer.level().playSound(null, this.getOnPos(), ModSounds.HPJ_11_FAR.get(), SoundSource.PLAYERS, 12, random.nextFloat() * 0.05f + 1); + serverPlayer.level().playSound(null, this.getOnPos(), ModSounds.HPJ_11_VERYFAR.get(), SoundSource.PLAYERS, 24, random.nextFloat() * 0.05f + 1); + } + } + + if (!hasCreativeAmmo) { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.SMALL_SHELL.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + + } + + Level level = player.level(); + final Vec3 center = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + + for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(5), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 5, 12, this.getX(), this.getEyeY(), this.getZ())); + } + } + + this.entityData.set(HEAT, this.entityData.get(HEAT) + 2); + + + } else if (getWeaponIndex(0) == 1 && this.getEntityData().get(LOADED_ROCKET) > 0) { + var heliRocketEntity = ((HeliRocketWeapon) getWeapon(0)).create(player); + + Vector4f worldPosition; + Vector4f worldPosition2; + Vec3 shootAngle; + + if (fireIndex == 0) { + worldPosition = transformPosition(transform, -6.63f, -0.55f, 1.83f); + worldPosition2 = transformPosition(transform, -6.61f, -0.55f, 2.83f); + fireIndex = 1; + } else if (fireIndex == 1) { + worldPosition = transformPosition(transform, -5.28f, -1.76f, 1.87f); + worldPosition2 = transformPosition(transform, -5.27f, -1.76f, 2.87f); + fireIndex = 2; + } else if (fireIndex == 2) { + worldPosition = transformPosition(transform, 5.28f, -1.76f, 1.87f); + worldPosition2 = transformPosition(transform, 5.27f, -1.76f, 2.87f); + fireIndex = 3; + } else { + worldPosition = transformPosition(transform, 6.63f, -0.55f, 1.83f); + worldPosition2 = transformPosition(transform, 6.61f, -0.55f, 2.83f); + fireIndex = 0; + } + + shootAngle = new Vec3(worldPosition.x, worldPosition.y, worldPosition.z).vectorTo(new Vec3(worldPosition2.x, worldPosition2.y, worldPosition2.z)).normalize(); + + heliRocketEntity.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + heliRocketEntity.shoot(shootAngle.x, shootAngle.y - 0.01, shootAngle.z, 8, 0.5f); + player.level().addFreshEntity(heliRocketEntity); + + this.level().playSound(null, BlockPos.containing(new Vec3(worldPosition.x, worldPosition.y, worldPosition.z)), ModSounds.HELICOPTER_ROCKET_FIRE_3P.get(), SoundSource.PLAYERS, 5, 1); + + this.entityData.set(LOADED_ROCKET, this.getEntityData().get(LOADED_ROCKET) - 1); + + Level level = player.level(); + final Vec3 center = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + + for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(5), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 5, 12, this.getX(), this.getEyeY(), this.getZ())); + } + } + + reloadCoolDown = 15; + } + } + + @Override + public int mainGunRpm(Player player) { + return 0; + } + + @Override + public boolean canShoot(Player player) { + if (getWeaponIndex(0) == 0) { + return false; + } else if (getWeaponIndex(0) == 1) { + return this.entityData.get(AMMO) > 0; + } + return false; + } + + @Override + public int getAmmoCount(Player player) { + return this.entityData.get(AMMO); + } + + @Override + public boolean banHand(Player player) { + return true; + } + + @Override + public boolean hidePassenger(Entity entity) { + return false; + } + + @Override + public int zoomFov() { + return 3; + } + + @Override + public int getWeaponHeat(Player player) { + return entityData.get(HEAT); + } + + @Override + public float getRotX(float tickDelta) { + return this.getPitch(tickDelta); + } + + @Override + public float getRotY(float tickDelta) { + return this.getYaw(tickDelta); + } + + @Override + public float getRotZ(float tickDelta) { + return this.getRoll(tickDelta); + } + + @Override + public float getPower() { + return this.entityData.get(POWER); + } + + @Override + public int getDecoy() { + return this.entityData.get(DECOY_COUNT); + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java index 52ade33e8..b0539663b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java @@ -295,10 +295,6 @@ public class SpeedboatEntity extends ContainerMobileVehicleEntity implements Geo this.consumeEnergy(VehicleConfig.SPEEDBOAT_ENERGY_COST.get()); } - if (level().isClientSide) { - level().playLocalSound(this.getX(), this.getY() + this.getBbHeight() * 0.5, this.getZ(), this.getEngineSound(), this.getSoundSource(), Math.min((this.forwardInputDown || this.backInputDown ? 7.5f : 5f) * 2 * Mth.abs(this.entityData.get(POWER)), 0.25f), (random.nextFloat() * 0.1f + 1f), false); - } - this.entityData.set(POWER, this.entityData.get(POWER) * 0.96f); this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * 0.8f); @@ -327,6 +323,11 @@ public class SpeedboatEntity extends ContainerMobileVehicleEntity implements Geo return ModSounds.BOAT_ENGINE.get(); } + @Override + public float getEngineSoundVolume() { + return (Mth.abs(entityData.get(POWER)) - 0.01f) * 2f; + } + @Override @ParametersAreNonnullByDefault protected void positionRider(Entity passenger, MoveFunction callback) { diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AirEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AirEntity.java new file mode 100644 index 000000000..8784518f9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AirEntity.java @@ -0,0 +1,14 @@ +package com.atsuishio.superbwarfare.entity.vehicle.base; + +public interface AirEntity extends ArmedVehicleEntity { + + float getRotX(float tickDelta); + + float getRotY(float tickDelta); + + float getRotZ(float tickDelta); + + float getPower(); + + int getDecoy(); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AircraftEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AircraftEntity.java new file mode 100644 index 000000000..acebe6298 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/AircraftEntity.java @@ -0,0 +1,5 @@ +package com.atsuishio.superbwarfare.entity.vehicle.base; + +public interface AircraftEntity extends AirEntity { + +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/HelicopterEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/HelicopterEntity.java index 7ca4c4ebe..2ae0420d7 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/HelicopterEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/HelicopterEntity.java @@ -1,14 +1,5 @@ package com.atsuishio.superbwarfare.entity.vehicle.base; -public interface HelicopterEntity extends ArmedVehicleEntity { +public interface HelicopterEntity extends AirEntity { - float getRotX(float tickDelta); - - float getRotY(float tickDelta); - - float getRotZ(float tickDelta); - - float getPower(); - - int getDecoy(); } diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java index 9d028014e..30d2da25b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java @@ -19,6 +19,7 @@ public class ClientSoundHandler { if (event.getLevel().isClientSide) { if (event.getEntity() instanceof MobileVehicleEntity mobileVehicle) { Minecraft.getInstance().getSoundManager().play(new VehicleSoundInstance.EngineSound(mobileVehicle, mobileVehicle.getEngineSound())); + Minecraft.getInstance().getSoundManager().play(new VehicleSoundInstance.SwimSound(mobileVehicle)); } if (event.getEntity() instanceof MobileVehicleEntity mobileVehicle && mobileVehicle instanceof TrackEntity) { Minecraft.getInstance().getSoundManager().play(new VehicleSoundInstance.TrackSound(mobileVehicle)); diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java b/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java index c15b1b01b..303361684 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModSounds.java @@ -444,6 +444,7 @@ public class ModSounds { public static final DeferredHolder ROCKET_FLY = REGISTRY.register("rocket_fly", () -> SoundEvent.createVariableRangeEvent(Mod.loc("rocket_fly"))); public static final DeferredHolder SHELL_FLY = REGISTRY.register("shell_fly", () -> SoundEvent.createVariableRangeEvent(Mod.loc("shell_fly"))); public static final DeferredHolder ROCKET_ENGINE = REGISTRY.register("rocket_engine", () -> SoundEvent.createVariableRangeEvent(Mod.loc("rocket_engine"))); + public static final DeferredHolder VEHICLE_SWIM = REGISTRY.register("vehicle_swim", () -> SoundEvent.createVariableRangeEvent(Mod.loc("vehicle_swim"))); public static final DeferredHolder A_10_ENGINE = REGISTRY.register("a10_engine", () -> SoundEvent.createVariableRangeEvent(Mod.loc("a10_engine"))); } diff --git a/src/main/resources/assets/superbwarfare/lang/en_us.json b/src/main/resources/assets/superbwarfare/lang/en_us.json index 821e48331..66278f4ef 100644 --- a/src/main/resources/assets/superbwarfare/lang/en_us.json +++ b/src/main/resources/assets/superbwarfare/lang/en_us.json @@ -449,6 +449,7 @@ "entity.superbwarfare.swarm_drone": "Swarm Drone", "entity.superbwarfare.smoke_decoy": "Smoke", "entity.superbwarfare.hpj_11": "H/PJ-11 CIWS", + "entity.superbwarfare.a_10a": "A-10 Thunderbolt II", "key.categories.superbwarfare": "Superb Warfare", "key.superbwarfare.hold_zoom": "Zoom (Hold)", diff --git a/src/main/resources/assets/superbwarfare/lang/zh_cn.json b/src/main/resources/assets/superbwarfare/lang/zh_cn.json index 8142222b3..93c526715 100644 --- a/src/main/resources/assets/superbwarfare/lang/zh_cn.json +++ b/src/main/resources/assets/superbwarfare/lang/zh_cn.json @@ -448,6 +448,7 @@ "entity.superbwarfare.swarm_drone": "蜂群无人机", "entity.superbwarfare.smoke_decoy": "烟雾", "entity.superbwarfare.hpj_11": "H/PJ-11近防炮", + "entity.superbwarfare.a_10a": "A-10“雷电Ⅱ”攻击机", "key.categories.superbwarfare": "卓越前线", "key.superbwarfare.hold_zoom": "瞄准(按住)", diff --git a/src/main/resources/assets/superbwarfare/sounds.json b/src/main/resources/assets/superbwarfare/sounds.json index 4bcd476f2..7ad6cb168 100644 --- a/src/main/resources/assets/superbwarfare/sounds.json +++ b/src/main/resources/assets/superbwarfare/sounds.json @@ -2427,8 +2427,9 @@ "boat_engine": { "sounds": [ { - "name": "superbwarfare:speedboat/engine", - "stream": false + "attenuation_distance": 48, + "stream": false, + "name": "superbwarfare:speedboat/engine" } ] }, @@ -3100,6 +3101,15 @@ } ] }, + "vehicle_swim": { + "sounds": [ + { + "attenuation_distance": 48, + "stream": true, + "name": "superbwarfare:vehicle_swim" + } + ] + }, "a10_engine": { "sounds": [ { diff --git a/src/main/resources/assets/superbwarfare/sounds/speedboat/engine.ogg b/src/main/resources/assets/superbwarfare/sounds/speedboat/engine.ogg index b20383a23..ec5098cdc 100644 Binary files a/src/main/resources/assets/superbwarfare/sounds/speedboat/engine.ogg and b/src/main/resources/assets/superbwarfare/sounds/speedboat/engine.ogg differ diff --git a/src/main/resources/assets/superbwarfare/sounds/vehicle_swim.ogg b/src/main/resources/assets/superbwarfare/sounds/vehicle_swim.ogg new file mode 100644 index 000000000..4567df376 Binary files /dev/null and b/src/main/resources/assets/superbwarfare/sounds/vehicle_swim.ogg differ