From 89c9e52abfb3be5816c1fae1df399e15695ea728 Mon Sep 17 00:00:00 2001 From: Light_Quanta Date: Sat, 29 Mar 2025 01:16:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=89=80=E6=9C=89=E5=AE=9E?= =?UTF-8?q?=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../b69ee8a2655365569b979911c0440daa8c470ac2 | 5 +- .../superbwarfare/models/item/defuser.json | 6 + .../superbwarfare/models/item/drone.json | 6 + .../models/item/mortar_deployer.json | 6 + .../com/atsuishio/superbwarfare/ModUtils.java | 1 + .../superbwarfare/client/RenderHelper.java | 10 +- .../superbwarfare/client/gui/RangeHelper.java | 149 +++ .../layer/projectile/CannonShellLayer.java | 27 + .../layer/projectile/GunGrenadeLayer.java | 27 + .../layer/projectile/HeliRocketLayer.java | 27 + .../layer/projectile/JavelinMissleLayer.java | 27 + .../ProjectileEntityInsideLayer.java | 30 + .../projectile/ProjectileEntityLayer.java | 35 + .../layer/projectile/RpgRocketLayer.java | 27 + .../projectile/SmallCannonShellLayer.java | 27 + .../layer/projectile/WgMissileLayer.java | 27 + .../layer/vehicle/AnnihilatorGlowLayer.java | 29 + .../layer/vehicle/AnnihilatorLayer.java | 28 + .../layer/vehicle/AnnihilatorLedLayer.java | 28 + .../vehicle/AnnihilatorLedLightLayer.java | 28 + .../layer/vehicle/AnnihilatorPowerLayer.java | 33 + .../vehicle/AnnihilatorPowerLightLayer.java | 33 + .../client/layer/vehicle/Bmp2Layer.java | 28 + .../layer/vehicle/LaserTowerLaserLayer.java | 28 + .../layer/vehicle/LaserTowerPowerLayer.java | 31 + .../client/layer/vehicle/Lav150Layer.java | 28 + .../client/layer/vehicle/Mk42Layer.java | 28 + .../client/layer/vehicle/Mle1934Layer.java | 27 + .../client/layer/vehicle/MortarLayer.java | 28 + .../layer/vehicle/SpeedBoatHeatLayer.java | 35 + .../client/layer/vehicle/SpeedBoatLayer.java | 28 + .../layer/vehicle/SpeedBoatPowerLayer.java | 29 + .../client/layer/vehicle/Yx100GlowLayer.java | 29 + .../client/model/entity/Ah6Model.java | 43 + .../client/model/entity/AnnihilatorModel.java | 88 ++ .../client/model/entity/Bmp2Model.java | 37 + .../client/model/entity/C4Model.java | 30 + .../model/entity/CannonShellEntityModel.java | 32 + .../client/model/entity/ClaymoreModel.java | 30 + .../client/model/entity/DroneModel.java | 23 + .../client/model/entity/GunGrenadeModel.java | 34 + .../model/entity/HandGrenadeEntityModel.java | 24 + .../client/model/entity/HeliRocketModel.java | 24 + .../model/entity/JavelinMissileModel.java | 24 + .../client/model/entity/LaserTowerModel.java | 50 + .../client/model/entity/Lav150Model.java | 37 + .../client/model/entity/Mk42Model.java | 52 + .../client/model/entity/Mle1934Model.java | 49 + .../client/model/entity/MortarModel.java | 40 + .../model/entity/MortarShellEntityModel.java | 24 + .../model/entity/ProjectileEntityModel.java | 53 ++ .../model/entity/RgoGrenadeEntityModel.java | 24 + .../client/model/entity/RpgRocketModel.java | 24 + .../client/model/entity/SenpaiModel.java | 24 + .../model/entity/SmallCannonShellModel.java | 34 + .../client/model/entity/SpeedboatModel.java | 38 + .../entity/TaserBulletProjectileModel.java | 24 + .../client/model/entity/Tom6Model.java | 25 + .../client/model/entity/WgMissileModel.java | 24 + .../client/model/entity/WheelChairModel.java | 25 + .../client/model/entity/Yx100Model.java | 37 + .../client/model/item/LungeMineModel.java | 34 + .../entity/AbstractLaserEntityRenderer.java | 1 + .../client/renderer/entity/Ah6Renderer.java | 61 ++ .../renderer/entity/AnnihilatorRenderer.java | 54 ++ .../client/renderer/entity/Bmp2Renderer.java | 246 +++++ .../client/renderer/entity/C4Renderer.java | 44 + .../renderer/entity/CannonShellRenderer.java | 50 + .../renderer/entity/ClaymoreRenderer.java | 53 ++ .../client/renderer/entity/DroneRenderer.java | 156 +++ .../entity/FlareDecoyEntityRenderer.java | 57 ++ .../renderer/entity/GunGrenadeRenderer.java | 50 + .../renderer/entity/HandGrenadeRenderer.java | 47 + .../renderer/entity/HeliRocketRenderer.java | 49 + .../entity/JavelinMissileRenderer.java | 49 + .../renderer/entity/LaserTowerRenderer.java | 59 ++ .../renderer/entity/Lav150Renderer.java | 142 +++ .../entity/MelonBombEntityRenderer.java | 42 + .../client/renderer/entity/Mk42Renderer.java | 50 + .../renderer/entity/Mle1934Renderer.java | 50 + .../renderer/entity/MortarRenderer.java | 55 ++ .../renderer/entity/MortarShellRenderer.java | 47 + .../entity/ProjectileEntityRenderer.java | 56 ++ .../renderer/entity/RgoGrenadeRenderer.java | 47 + .../renderer/entity/RpgRocketRenderer.java | 49 + .../renderer/entity/SenpaiRenderer.java | 37 + .../entity/SmallCannonShellRenderer.java | 44 + .../renderer/entity/SpeedboatRenderer.java | 124 +++ .../entity/TaserBulletProjectileRenderer.java | 47 + .../client/renderer/entity/Tom6Renderer.java | 59 ++ .../renderer/entity/WgMissileRenderer.java | 49 + .../renderer/entity/WheelChairRenderer.java | 66 ++ .../client/renderer/entity/Yx100Renderer.java | 260 +++++ .../renderer/item/LungeMineRenderer.java | 116 +++ .../superbwarfare/command/ConfigCommand.java | 1 + .../compat/jade/SbwJadePlugin.java | 5 +- .../compat/jade/providers/C4InfoProvider.java | 31 +- .../component/ModDataComponents.java | 6 - .../datagen/ModItemModelProvider.java | 9 +- .../superbwarfare/entity/ClaymoreEntity.java | 275 ++++++ .../superbwarfare/entity/MortarEntity.java | 293 ++++++ .../superbwarfare/entity/SenpaiEntity.java | 197 ++++ .../entity/projectile/C4Entity.java | 402 ++++++++ .../entity/projectile/CannonShellEntity.java | 391 ++++++++ .../projectile/FastThrowableProjectile.java | 58 ++ .../entity/projectile/FlareDecoyEntity.java | 71 ++ .../entity/projectile/GunGrenadeEntity.java | 178 ++++ .../entity/projectile/HandGrenadeEntity.java | 160 ++++ .../entity/projectile/HeliRocketEntity.java | 168 ++++ .../projectile/JavelinMissileEntity.java | 331 +++++++ .../entity/projectile/MelonBombEntity.java | 63 ++ .../entity/projectile/MortarShellEntity.java | 271 ++++++ .../entity/projectile/RgoGrenadeEntity.java | 147 +++ .../entity/projectile/RpgRocketEntity.java | 182 ++++ .../projectile/SmallCannonShellEntity.java | 180 ++++ .../entity/projectile/TaserBulletEntity.java | 141 +++ .../entity/projectile/WgMissileEntity.java | 195 ++++ .../entity/vehicle/Ah6Entity.java | 776 +++++++++++++++ .../entity/vehicle/AnnihilatorEntity.java | 632 +++++++++++++ .../entity/vehicle/Bmp2Entity.java | 692 ++++++++++++++ .../entity/vehicle/DroneEntity.java | 658 +++++++++++++ .../entity/vehicle/LaserTowerEntity.java | 372 ++++++++ .../entity/vehicle/Lav150Entity.java | 605 ++++++++++++ .../entity/vehicle/Mk42Entity.java | 416 ++++++++ .../entity/vehicle/Mle1934Entity.java | 519 ++++++++++ .../entity/vehicle/SpeedboatEntity.java | 562 +++++++++++ .../entity/vehicle/Tom6Entity.java | 375 ++++++++ .../entity/vehicle/WheelChairEntity.java | 335 +++++++ .../entity/vehicle/Yx100Entity.java | 893 ++++++++++++++++++ .../entity/vehicle/base/VehicleEntity.java | 12 +- .../vehicle/weapon/CannonShellWeapon.java | 24 +- .../vehicle/weapon/HeliRocketWeapon.java | 9 +- .../weapon/SmallCannonShellWeapon.java | 10 +- .../vehicle/weapon/WgMissileWeapon.java | 9 +- .../superbwarfare/init/ModEntities.java | 172 ++-- .../init/ModEntityRenderers.java | 63 +- .../superbwarfare/init/ModItems.java | 49 +- .../atsuishio/superbwarfare/init/ModTabs.java | 17 +- .../atsuishio/superbwarfare/item/C4Bomb.java | 93 ++ .../superbwarfare/item/ClaymoreMine.java | 77 ++ .../item/ContainerBlockItem.java | 24 +- .../atsuishio/superbwarfare/item/Defuser.java | 73 ++ .../superbwarfare/item/Detonator.java | 54 ++ .../atsuishio/superbwarfare/item/Drone.java | 93 ++ .../superbwarfare/item/HandGrenade.java | 113 +++ .../superbwarfare/item/LungeMine.java | 151 +++ .../atsuishio/superbwarfare/item/Monitor.java | 181 ++++ .../superbwarfare/item/MortarDeployer.java | 115 +++ .../superbwarfare/item/RgoGrenade.java | 113 +++ .../item/common/ammo/MortarShell.java | 15 +- .../item/common/ammo/Rocket.java | 19 +- .../message/ClientMotionSyncMessage.java | 1 + .../superbwarfare/tools/CustomExplosion.java | 4 +- .../superbwarfare/tools/EntityFindUtil.java | 10 + .../superbwarfare/tools/GunsTool.java | 7 +- .../superbwarfare/tools/ProjectileTool.java | 58 ++ .../resources/META-INF/accesstransformer.cfg | 3 +- .../assets/superbwarfare/lang/en_us.json | 9 +- .../assets/superbwarfare/lang/zh_cn.json | 9 +- 159 files changed, 16206 insertions(+), 229 deletions(-) create mode 100644 src/generated/resources/assets/superbwarfare/models/item/defuser.json create mode 100644 src/generated/resources/assets/superbwarfare/models/item/drone.json create mode 100644 src/generated/resources/assets/superbwarfare/models/item/mortar_deployer.json create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/gui/RangeHelper.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/CannonShellLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/GunGrenadeLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/HeliRocketLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/JavelinMissleLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityInsideLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/RpgRocketLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/SmallCannonShellLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/WgMissileLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorGlowLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLightLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLightLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Bmp2Layer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerLaserLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerPowerLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Lav150Layer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mk42Layer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mle1934Layer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/MortarLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatHeatLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatPowerLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Yx100GlowLayer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Ah6Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/AnnihilatorModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Bmp2Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/C4Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/CannonShellEntityModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/ClaymoreModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/DroneModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/GunGrenadeModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/HandGrenadeEntityModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/HeliRocketModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/JavelinMissileModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/LaserTowerModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Lav150Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mk42Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mle1934Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarShellEntityModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/ProjectileEntityModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/RgoGrenadeEntityModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/RpgRocketModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/SenpaiModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/SmallCannonShellModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/SpeedboatModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/TaserBulletProjectileModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Tom6Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/WgMissileModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/WheelChairModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/Yx100Model.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/item/LungeMineModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Ah6Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AnnihilatorRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Bmp2Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/C4Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/CannonShellRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ClaymoreRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/DroneRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/FlareDecoyEntityRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/GunGrenadeRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HandGrenadeRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HeliRocketRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/JavelinMissileRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/LaserTowerRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Lav150Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MelonBombEntityRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mk42Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mle1934Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarShellRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ProjectileEntityRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RgoGrenadeRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RpgRocketRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SenpaiRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmallCannonShellRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SpeedboatRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/TaserBulletProjectileRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Tom6Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WgMissileRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WheelChairRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Yx100Renderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/item/LungeMineRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/ClaymoreEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/MortarEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/SenpaiEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/C4Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/MelonBombEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Tom6Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/WheelChairEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/C4Bomb.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/ClaymoreMine.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/Defuser.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/Detonator.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/Drone.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/HandGrenade.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/LungeMine.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/Monitor.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/MortarDeployer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/item/RgoGrenade.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/tools/ProjectileTool.java diff --git a/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 b/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 index 4e50491f0..981fba75a 100644 --- a/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 +++ b/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 @@ -1,4 +1,4 @@ -// 1.21.1 2025-03-27T19:46:28.6502692 Item Models: superbwarfare +// 1.21.1 2025-03-29T00:41:26.2074689 Item Models: superbwarfare 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/aa_12_blueprint.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/ak_12_blueprint.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/ak_47_blueprint.json @@ -21,8 +21,10 @@ a52a7f9dc18d5af69903c2249239c15cb6d38c8e assets/superbwarfare/models/item/coal_p fc892b610a110980dbc6f8e2c080672b5dc06e99 assets/superbwarfare/models/item/copper_plate.json 7e43d8e9c4b8589f7665c46d4b67de645949cc6b assets/superbwarfare/models/item/creative_charging_station.json b0296c3d68f3b5ae4945b46384fa20a1ff32cac5 assets/superbwarfare/models/item/crowbar.json +d81b738e17048945459ff8b59f8f83e872171473 assets/superbwarfare/models/item/defuser.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/devotion_blueprint.json 6f4a829dc159f1740f52265d01730ecb6a840d81 assets/superbwarfare/models/item/dog_tag.json +dd455cf29eed0ef5eb5e90ef3d7140cb8de61efe assets/superbwarfare/models/item/drone.json 831ce33c5a4c90b71a42515f42f16d4c1a946c50 assets/superbwarfare/models/item/empty_perk.json 2419503d8b597c92684d1921895a12fca33fec69 assets/superbwarfare/models/item/epic_material_pack.json b6f96946b54f44fdd2d8b809945b8d1ae5e776e2 assets/superbwarfare/models/item/firing_parameters.json @@ -65,6 +67,7 @@ a5cf666a970906ba6ac0af9a4d5d52dd0e093dec assets/superbwarfare/models/item/mle_19 db96dbb75327701d7901c2de48a539bda9fe31c4 assets/superbwarfare/models/item/mortar_barrel.json 3922427d3921d3de7195614780ee8f57dfc0ee6f assets/superbwarfare/models/item/mortar_base_plate.json ac9c6bc308bd741ada7f19d808d0c0722fceb976 assets/superbwarfare/models/item/mortar_bipod.json +9baf936f4340d41a0b5581857313240627b00386 assets/superbwarfare/models/item/mortar_deployer.json 41381cc65305bbfc1324a08b580125073d198e11 assets/superbwarfare/models/item/mortar_shell.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/mosin_nagant_blueprint.json 4de8d6e0cddd28963febd35e9b66334a41a25d4c assets/superbwarfare/models/item/motor.json diff --git a/src/generated/resources/assets/superbwarfare/models/item/defuser.json b/src/generated/resources/assets/superbwarfare/models/item/defuser.json new file mode 100644 index 000000000..e50a885f8 --- /dev/null +++ b/src/generated/resources/assets/superbwarfare/models/item/defuser.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "superbwarfare:item/defuser" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/superbwarfare/models/item/drone.json b/src/generated/resources/assets/superbwarfare/models/item/drone.json new file mode 100644 index 000000000..1a28b4d3f --- /dev/null +++ b/src/generated/resources/assets/superbwarfare/models/item/drone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "superbwarfare:item/drone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/superbwarfare/models/item/mortar_deployer.json b/src/generated/resources/assets/superbwarfare/models/item/mortar_deployer.json new file mode 100644 index 000000000..2317598c6 --- /dev/null +++ b/src/generated/resources/assets/superbwarfare/models/item/mortar_deployer.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "superbwarfare:item/mortar_deployer" + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java index 58e43efe1..9a63bc49f 100644 --- a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java +++ b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java @@ -57,6 +57,7 @@ public class ModUtils { // bus.addListener(this::onCommonSetup); // bus.addListener(this::onClientSetup); + bus.addListener(ModItems::registerDispenserBehavior); bus.addListener(NetworkRegistry::register); diff --git a/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java b/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java index f3ba05452..e44ed3d7f 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/RenderHelper.java @@ -217,7 +217,7 @@ public class RenderHelper { float blitOffset, float minU, float maxU, float minV, float maxV, - float red, float green, float blue, float alpha + int color ) { RenderSystem.setShaderTexture(0, atlasLocation); RenderSystem.setShader(GameRenderer::getPositionTexColorShader); @@ -226,16 +226,16 @@ public class RenderHelper { BufferBuilder bufferbuilder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR); bufferbuilder.addVertex(matrix4f, x1, y1, blitOffset) .setUv(minU, minV) - .setColor(red, green, blue, alpha); + .setColor(color); bufferbuilder.addVertex(matrix4f, x1, y2, blitOffset) .setUv(minU, maxV) - .setColor(red, green, blue, alpha); + .setColor(color); bufferbuilder.addVertex(matrix4f, x2, y2, blitOffset) .setUv(maxU, maxV) - .setColor(red, green, blue, alpha); + .setColor(color); bufferbuilder.addVertex(matrix4f, x2, y1, blitOffset) .setUv(maxU, minV) - .setColor(red, green, blue, alpha); + .setColor(color); BufferUploader.drawWithShader(bufferbuilder.buildOrThrow()); RenderSystem.disableBlend(); } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/gui/RangeHelper.java b/src/main/java/com/atsuishio/superbwarfare/client/gui/RangeHelper.java new file mode 100644 index 000000000..1b979a1d8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/gui/RangeHelper.java @@ -0,0 +1,149 @@ +package com.atsuishio.superbwarfare.client.gui; + +import net.minecraft.world.phys.Vec3; + +public class RangeHelper { + + public static final int MAX_RANGE = 1145; + + /** + * 计算迫击炮理论水平射程 + * + * @param thetaDegrees 发射角度(以度为单位),需要根据实际情况修改 + */ + public static double getRange(double thetaDegrees) { + double initialVelocity = 11.4; // 初始速度 11.4 m/s + double thetaRadians = Math.toRadians(thetaDegrees); // 将角度转换为弧度 + double gravity = 0.146; // 重力加速度 + double velocityDecay = 0.99; // 速度衰减系数 + + // 计算射程 + return calculateRange(initialVelocity, thetaRadians, gravity, velocityDecay); + } + + public static double calculateRange(double initialVelocity, double theta, double gravity, double velocityDecay) { + double vx = initialVelocity * Math.cos(theta); // 水平速度 + double vy = initialVelocity * Math.sin(theta); // 垂直速度 + + double x = 0.0; // 水平位置 + double y = 1.0; // 垂直位置 + + // 当炮弹还未触地时,继续计算飞行轨迹 + while (y >= 0) { + // 更新位置 + x += vx; + y += vy; + + // 更新速度 + vx *= velocityDecay; + vy = vy * velocityDecay - gravity; + + // 如果炮弹触地,则跳出循环 + if (y < 0) { + break; + } + } + + // 返回最终水平距离 + return x; + } + + public static double calculateRangeWithDeltaY(double initialVelocity, double theta, double gravity, double velocityDecay, double deltaY) { + double vx = initialVelocity * Math.cos(theta); // 水平速度 + double vy = initialVelocity * Math.sin(theta); // 垂直速度 + + double range = 0.0; // 水平距离 + double y = 1.0; // 垂直位置 + + double commonRange = calculateRange(initialVelocity, theta, gravity, velocityDecay); + + // 当炮弹还未触地时,继续计算飞行轨迹 + while (range < commonRange / 2 || (range >= commonRange / 2 && y >= deltaY)) { + // 更新位置 + range += vx; + y += vy; + + // 更新速度 + vx *= velocityDecay; + vy = vy * velocityDecay - gravity; + + if (range >= commonRange / 2 && y < deltaY) { + break; + } + } + + // 返回最终水平距离 + return range; + } + + public static boolean canReachTarget(double initialVelocity, double gravity, double velocityDecay, Vec3 startPos, Vec3 targetPos, double[] angles) { + if (startPos.equals(targetPos)) { + return false; + } + + double startX = startPos.x; + double startY = startPos.y; + double startZ = startPos.z; + + double targetX = targetPos.x; + double targetY = targetPos.y; + double targetZ = targetPos.z; + + double distanceXZ = Math.sqrt(Math.pow(targetX - startX, 2) + Math.pow(targetZ - startZ, 2)); + if (distanceXZ > MAX_RANGE) { + return false; + } + + double theta = calculateLaunchAngle(initialVelocity, gravity, velocityDecay, distanceXZ, targetY - startY); + + if (theta < 20 || theta > 90) { + return false; + } + + angles[0] = Math.atan2(targetZ, targetX); // 水平角度 + angles[1] = theta; // 炮口抬升角度 + return true; + } + + public static double calculateLaunchAngle(double initialVelocity, double gravity, double velocityDecay, double distanceXZ, double targetY) { + double left = 20; // 最小角度 + double right = 30; // 最大角度 + double tolerance = 0.5; // 允许的误差范围 + + // 在 20 到 30 之间搜索 + while (right - left > tolerance) { + double mid = (left + right) / 2; + double radian = Math.toRadians(mid); + double range = calculateRangeWithDeltaY(initialVelocity, radian, gravity, velocityDecay, targetY); + + if (Math.abs(range - distanceXZ) < tolerance * 8) { + return mid; + } else if (range < distanceXZ) { + left = mid; + } else { + right = mid; + } + } + + // 如果在 20 到 30 之间没有找到合适的角度,则在 30 到 90 之间搜索 + left = 30; + right = 90; + + while (right - left > tolerance) { + double mid = (left + right) / 2; + double radian = Math.toRadians(mid); + double range = calculateRangeWithDeltaY(initialVelocity, radian, gravity, velocityDecay, targetY); + + if (Math.abs(range - distanceXZ) < tolerance * 8) { + return mid; + } else if (range < distanceXZ) { + right = mid; + } else { + left = mid; + } + } + + // 如果仍然没有找到合适的角度,则返回 -1 + return -1; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/CannonShellLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/CannonShellLayer.java new file mode 100644 index 000000000..10bd8b7d2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/CannonShellLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.CannonShellEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class CannonShellLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/cannon_shell_e.png"); + + public CannonShellLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, CannonShellEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/GunGrenadeLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/GunGrenadeLayer.java new file mode 100644 index 000000000..d6ddb971b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/GunGrenadeLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class GunGrenadeLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/cannon_shell_e.png"); + + public GunGrenadeLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, GunGrenadeEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/HeliRocketLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/HeliRocketLayer.java new file mode 100644 index 000000000..2170d525b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/HeliRocketLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.HeliRocketEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class HeliRocketLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/rpg_rocket_e.png"); + + public HeliRocketLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, HeliRocketEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/JavelinMissleLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/JavelinMissleLayer.java new file mode 100644 index 000000000..c9b6edff5 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/JavelinMissleLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.JavelinMissileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class JavelinMissleLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/rpg_rocket_e.png"); + + public JavelinMissleLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, JavelinMissileEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityInsideLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityInsideLayer.java new file mode 100644 index 000000000..2c77f99c2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityInsideLayer.java @@ -0,0 +1,30 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class ProjectileEntityInsideLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/projectile_entity_inside.png"); + + public ProjectileEntityInsideLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, ProjectileEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), + partialTick, packedLight, OverlayTexture.NO_OVERLAY, + FastColor.ARGB32.color((int) (0.2f * 255), 255, 255, 255)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityLayer.java new file mode 100644 index 000000000..130b865cc --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/ProjectileEntityLayer.java @@ -0,0 +1,35 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class ProjectileEntityLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/projectile_entity.png"); + + public ProjectileEntityLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, ProjectileEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + + float r = animatable.getEntityData().get(ProjectileEntity.COLOR_R); + float g = animatable.getEntityData().get(ProjectileEntity.COLOR_G); + float b = animatable.getEntityData().get(ProjectileEntity.COLOR_B); + + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, + bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, + FastColor.ARGB32.color((int) (0.8 * 255), (int) (r * 255), (int) (g * 255), (int) (b * 255))); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/RpgRocketLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/RpgRocketLayer.java new file mode 100644 index 000000000..abf6328e7 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/RpgRocketLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class RpgRocketLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/rpg_rocket_e.png"); + + public RpgRocketLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, RpgRocketEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/SmallCannonShellLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/SmallCannonShellLayer.java new file mode 100644 index 000000000..b3db4b0fd --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/SmallCannonShellLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class SmallCannonShellLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/cannon_shell_e.png"); + + public SmallCannonShellLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, SmallCannonShellEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/WgMissileLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/WgMissileLayer.java new file mode 100644 index 000000000..bdf516ad3 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/projectile/WgMissileLayer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.projectile; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.WgMissileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class WgMissileLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/rpg_rocket_e.png"); + + public WgMissileLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, WgMissileEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorGlowLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorGlowLayer.java new file mode 100644 index 000000000..3e4b4f2e4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorGlowLayer.java @@ -0,0 +1,29 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.ModRenderTypes; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class AnnihilatorGlowLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/annihilator_glow_e.png"); + + public AnnihilatorGlowLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, AnnihilatorEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = ModRenderTypes.LASER.apply(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLayer.java new file mode 100644 index 000000000..c6e6dc9ae --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class AnnihilatorLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/annihilator_e.png"); + + public AnnihilatorLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, AnnihilatorEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.energySwirl(LAYER, 1, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLayer.java new file mode 100644 index 000000000..e84e903f9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class AnnihilatorLedLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/annihilator_led.png"); + + public AnnihilatorLedLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, AnnihilatorEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.entityTranslucent(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLightLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLightLayer.java new file mode 100644 index 000000000..b8f158a23 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorLedLightLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class AnnihilatorLedLightLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/annihilator_led.png"); + + public AnnihilatorLedLightLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, AnnihilatorEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLayer.java new file mode 100644 index 000000000..d8c30fe10 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLayer.java @@ -0,0 +1,33 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class AnnihilatorPowerLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/annihilator_power.png"); + + public AnnihilatorPowerLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, AnnihilatorEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.entityTranslucent(LAYER); + float red = 1 - Mth.clamp(2.5f * animatable.getEnergy() / animatable.getMaxEnergy(), 0, 1); + float green = Mth.clamp(2.5f * animatable.getEnergy() / animatable.getMaxEnergy(), 0, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, + FastColor.ARGB32.color(255, (int) (red * 255), (int) (green * 255), 0)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLightLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLightLayer.java new file mode 100644 index 000000000..597aa49ee --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/AnnihilatorPowerLightLayer.java @@ -0,0 +1,33 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class AnnihilatorPowerLightLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/annihilator_power.png"); + + public AnnihilatorPowerLightLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, AnnihilatorEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + float red = 1 - Mth.clamp(2.5f * animatable.getEnergy() / animatable.getMaxEnergy(), 0, 1); + float green = Mth.clamp(2.5f * animatable.getEnergy() / animatable.getMaxEnergy(), 0, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, + FastColor.ARGB32.color(255, (int) (red * 255), (int) (green * 255), 0)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Bmp2Layer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Bmp2Layer.java new file mode 100644 index 000000000..8e9606e08 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Bmp2Layer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class Bmp2Layer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/speedboat_e.png"); + + public Bmp2Layer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, Bmp2Entity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.energySwirl(LAYER, 1, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerLaserLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerLaserLayer.java new file mode 100644 index 000000000..49e768a79 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerLaserLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class LaserTowerLaserLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/laser_tower_laser.png"); + + public LaserTowerLaserLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, LaserTowerEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.energySwirl(LAYER, 1, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerPowerLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerPowerLayer.java new file mode 100644 index 000000000..8bb6d778f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/LaserTowerPowerLayer.java @@ -0,0 +1,31 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +import static com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity.ACTIVE; + +public class LaserTowerPowerLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/laser_tower_e.png"); + + public LaserTowerPowerLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, LaserTowerEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + if (animatable.getEnergy() <= 0 || !animatable.getEntityData().get(ACTIVE)) return; + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Lav150Layer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Lav150Layer.java new file mode 100644 index 000000000..838b793a4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Lav150Layer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Lav150Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class Lav150Layer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/speedboat_e.png"); + + public Lav150Layer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, Lav150Entity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.energySwirl(LAYER, 1, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mk42Layer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mk42Layer.java new file mode 100644 index 000000000..f33518ec9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mk42Layer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Mk42Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class Mk42Layer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/sherman_e.png"); + + public Mk42Layer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, Mk42Entity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mle1934Layer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mle1934Layer.java new file mode 100644 index 000000000..70addf2f5 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Mle1934Layer.java @@ -0,0 +1,27 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Mle1934Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class Mle1934Layer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/sherman_e.png"); + + public Mle1934Layer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, Mle1934Entity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/MortarLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/MortarLayer.java new file mode 100644 index 000000000..c43d287bd --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/MortarLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class MortarLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/mortar_e.png"); + + public MortarLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, MortarEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatHeatLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatHeatLayer.java new file mode 100644 index 000000000..045418d18 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatHeatLayer.java @@ -0,0 +1,35 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +import static com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity.HEAT; + +public class SpeedBoatHeatLayer extends GeoRenderLayer { + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/speedboat_heat.png"); + + public SpeedBoatHeatLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, SpeedboatEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.eyes(LAYER); + float heat = animatable.getEntityData().get(HEAT) < 20 ? 0 : animatable.getEntityData().get(HEAT) - 20; + int heatColor = (int) (heat / 80); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, + FastColor.ARGB32.color(255, heatColor, heatColor, heatColor) + ); + } +} + diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatLayer.java new file mode 100644 index 000000000..5221fabc3 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class SpeedBoatLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/speedboat_e.png"); + + public SpeedBoatLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, SpeedboatEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.energySwirl(LAYER, 1, 1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatPowerLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatPowerLayer.java new file mode 100644 index 000000000..f0a923a29 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/SpeedBoatPowerLayer.java @@ -0,0 +1,29 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class SpeedBoatPowerLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/speedboat_power.png"); + + public SpeedBoatPowerLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, SpeedboatEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + if (animatable.getEnergy() <= 0) return; + RenderType glowRenderType = RenderType.eyes(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Yx100GlowLayer.java b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Yx100GlowLayer.java new file mode 100644 index 000000000..7d1dc2ac6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/layer/vehicle/Yx100GlowLayer.java @@ -0,0 +1,29 @@ +package com.atsuishio.superbwarfare.client.layer.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.ModRenderTypes; +import com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class Yx100GlowLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/yx_100_glow.png"); + + public Yx100GlowLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, Yx100Entity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = ModRenderTypes.LASER.apply(LAYER); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Ah6Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Ah6Model.java new file mode 100644 index 000000000..82e994cde --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Ah6Model.java @@ -0,0 +1,43 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Ah6Entity; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.model.GeoModel; + +public class Ah6Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Ah6Entity entity) { + return null; +// return ModUtils.loc("animations/wheel_chair.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Ah6Entity entity) { + Player player = Minecraft.getInstance().player; + + int distance = 0; + + if (player != null) { + distance = (int) player.position().distanceTo(entity.position()); + } + + if (distance < 32) { + return ModUtils.loc("geo/ah_6.geo.json"); + } else if (distance < 64) { + return ModUtils.loc("geo/ah_6.lod1.geo.json"); + } else if (distance < 96) { + return ModUtils.loc("geo/ah_6.lod2.geo.json"); + } else { + return ModUtils.loc("geo/ah_6.lod3.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(Ah6Entity entity) { + return ModUtils.loc("textures/entity/ah_6.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/AnnihilatorModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/AnnihilatorModel.java new file mode 100644 index 000000000..03e412dd2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/AnnihilatorModel.java @@ -0,0 +1,88 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.constant.DataTickets; +import software.bernie.geckolib.model.GeoModel; +import software.bernie.geckolib.model.data.EntityModelData; + +import static com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity.*; + +public class AnnihilatorModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(AnnihilatorEntity entity) { + return ModUtils.loc("animations/annihilator.animation.json"); + } + + @Override + public ResourceLocation getModelResource(AnnihilatorEntity entity) { + Player player = Minecraft.getInstance().player; + + int distance = 0; + + if (player != null) { + distance = (int) player.position().distanceTo(entity.position()); + } + + if (distance < 64) { + return ModUtils.loc("geo/annihilator.geo.json"); + } else { + return ModUtils.loc("geo/annihilator.lod1.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(AnnihilatorEntity entity) { + return ModUtils.loc("textures/entity/annihilator.png"); + } + + @Override + public void setCustomAnimations(AnnihilatorEntity animatable, long instanceId, AnimationState animationState) { + GeoBone bone = getAnimationProcessor().getBone("PaoGuan"); + EntityModelData entityData = animationState.getData(DataTickets.ENTITY_MODEL_DATA); + bone.setRotX((entityData.headPitch()) * Mth.DEG_TO_RAD); + + GeoBone laserLeft = getAnimationProcessor().getBone("laser1"); + GeoBone laserMiddle = getAnimationProcessor().getBone("laser2"); + GeoBone laserRight = getAnimationProcessor().getBone("laser3"); + + laserLeft.setScaleZ(animatable.getEntityData().get(LASER_LEFT_LENGTH) + 0.5f); + laserMiddle.setScaleZ(animatable.getEntityData().get(LASER_MIDDLE_LENGTH) + 0.5f); + laserRight.setScaleZ(animatable.getEntityData().get(LASER_RIGHT_LENGTH) + 0.5f); + + GeoBone ledGreen = getAnimationProcessor().getBone("ledgreen"); + GeoBone ledGreen2 = getAnimationProcessor().getBone("ledgreen2"); + GeoBone ledGreen3 = getAnimationProcessor().getBone("ledgreen3"); + GeoBone ledGreen4 = getAnimationProcessor().getBone("ledgreen4"); + GeoBone ledGreen5 = getAnimationProcessor().getBone("ledgreen5"); + + GeoBone ledRed = getAnimationProcessor().getBone("ledred"); + GeoBone ledRed2 = getAnimationProcessor().getBone("ledred2"); + GeoBone ledRed3 = getAnimationProcessor().getBone("ledred3"); + GeoBone ledRed4 = getAnimationProcessor().getBone("ledred4"); + GeoBone ledRed5 = getAnimationProcessor().getBone("ledred5"); + + float coolDown = animatable.getEntityData().get(COOL_DOWN); + boolean cantShoot = animatable.getEnergy() < VehicleConfig.ANNIHILATOR_SHOOT_COST.get(); + + ledGreen.setHidden(coolDown > 80 || cantShoot); + ledGreen2.setHidden(coolDown > 60 || cantShoot); + ledGreen3.setHidden(coolDown > 40 || cantShoot); + ledGreen4.setHidden(coolDown > 20 || cantShoot); + ledGreen5.setHidden(coolDown > 0 || cantShoot); + + ledRed.setHidden(!ledGreen.isHidden()); + ledRed2.setHidden(!ledGreen2.isHidden()); + ledRed3.setHidden(!ledGreen3.isHidden()); + ledRed4.setHidden(!ledGreen4.isHidden()); + ledRed5.setHidden(!ledGreen5.isHidden()); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Bmp2Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Bmp2Model.java new file mode 100644 index 000000000..53933102b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Bmp2Model.java @@ -0,0 +1,37 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class Bmp2Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Bmp2Entity entity) { + return ModUtils.loc("animations/lav.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Bmp2Entity entity) { + return ModUtils.loc("geo/bmp2.geo.json"); +// Player player = Minecraft.getInstance().player; +// +// int distance = 0; +// +// if (player != null) { +// distance = (int) player.position().distanceTo(entity.position()); +// } +// +// if (distance < 32) { +// return ModUtils.loc("geo/Bmp2.geo.json"); +// } else { +// return ModUtils.loc("geo/speedboat.lod1.geo.json"); +// } + } + + @Override + public ResourceLocation getTextureResource(Bmp2Entity entity) { + return ModUtils.loc("textures/entity/bmp2.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/C4Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/C4Model.java new file mode 100644 index 000000000..7d290d5f8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/C4Model.java @@ -0,0 +1,30 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +import java.util.UUID; + +public class C4Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(C4Entity entity) { + return ModUtils.loc("animations/c4.animation.json"); + } + + @Override + public ResourceLocation getModelResource(C4Entity entity) { + return ModUtils.loc("geo/c4.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(C4Entity entity) { + UUID uuid = entity.getUUID(); + if (uuid.getLeastSignificantBits() % 114 == 0) { + return ModUtils.loc("textures/item/c4_alter.png"); + } + return ModUtils.loc("textures/item/c4.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/CannonShellEntityModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/CannonShellEntityModel.java new file mode 100644 index 000000000..937b1d2c8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/CannonShellEntityModel.java @@ -0,0 +1,32 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.CannonShellEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.model.GeoModel; + +public class CannonShellEntityModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(CannonShellEntity entity) { + return ModUtils.loc("animations/cannon_shell.animation.json"); + } + + @Override + public ResourceLocation getModelResource(CannonShellEntity entity) { + return ModUtils.loc("geo/cannon_shell.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(CannonShellEntity entity) { + return ModUtils.loc("textures/entity/cannon_shell.png"); + } + + @Override + public void setCustomAnimations(CannonShellEntity animatable, long instanceId, AnimationState animationState) { + GeoBone bone = getAnimationProcessor().getBone("bone"); + bone.setHidden(animatable.tickCount <= 1); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ClaymoreModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ClaymoreModel.java new file mode 100644 index 000000000..59397b8e2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ClaymoreModel.java @@ -0,0 +1,30 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.ClaymoreEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +import java.util.UUID; + +public class ClaymoreModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(ClaymoreEntity entity) { + return ModUtils.loc("animations/claymore.animation.json"); + } + + @Override + public ResourceLocation getModelResource(ClaymoreEntity entity) { + return ModUtils.loc("geo/claymore.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(ClaymoreEntity entity) { + UUID uuid = entity.getUUID(); + if (uuid.getLeastSignificantBits() % 514 == 0) { + return ModUtils.loc("textures/entity/claymore_alter.png"); + } + return ModUtils.loc("textures/entity/claymore.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/DroneModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/DroneModel.java new file mode 100644 index 000000000..f57960447 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/DroneModel.java @@ -0,0 +1,23 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class DroneModel extends GeoModel { + @Override + public ResourceLocation getAnimationResource(DroneEntity entity) { + return ModUtils.loc("animations/drone.animation.json"); + } + + @Override + public ResourceLocation getModelResource(DroneEntity entity) { + return ModUtils.loc("geo/drone.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(DroneEntity entity) { + return ModUtils.loc("textures/entity/drone.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/GunGrenadeModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/GunGrenadeModel.java new file mode 100644 index 000000000..63eb60096 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/GunGrenadeModel.java @@ -0,0 +1,34 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.model.GeoModel; + +public class GunGrenadeModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(GunGrenadeEntity entity) { + return ModUtils.loc("animations/cannon_shell.animation.json"); + } + + @Override + public ResourceLocation getModelResource(GunGrenadeEntity entity) { + return ModUtils.loc("geo/cannon_shell.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(GunGrenadeEntity entity) { + return ModUtils.loc("textures/entity/cannon_shell.png"); + } + + @Override + public void setCustomAnimations(GunGrenadeEntity animatable, long instanceId, AnimationState animationState) { + GeoBone bone = getAnimationProcessor().getBone("bone"); + bone.setScaleX(0.2f); + bone.setScaleY(0.2f); + bone.setScaleZ(0.2f); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/HandGrenadeEntityModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/HandGrenadeEntityModel.java new file mode 100644 index 000000000..1a77ba6df --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/HandGrenadeEntityModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.HandGrenadeEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class HandGrenadeEntityModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(HandGrenadeEntity entity) { + return null; + } + + @Override + public ResourceLocation getModelResource(HandGrenadeEntity entity) { + return ModUtils.loc("geo/hand_grenade.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(HandGrenadeEntity entity) { + return ModUtils.loc("textures/entity/hand_grenade.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/HeliRocketModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/HeliRocketModel.java new file mode 100644 index 000000000..bce2d6280 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/HeliRocketModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.HeliRocketEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class HeliRocketModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(HeliRocketEntity entity) { + return ModUtils.loc("animations/rpg_rocket.animation.json"); + } + + @Override + public ResourceLocation getModelResource(HeliRocketEntity entity) { + return ModUtils.loc("geo/heli_rocket.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(HeliRocketEntity entity) { + return ModUtils.loc("textures/entity/heli_rocket.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/JavelinMissileModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/JavelinMissileModel.java new file mode 100644 index 000000000..e0be95d98 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/JavelinMissileModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.JavelinMissileEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class JavelinMissileModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(JavelinMissileEntity entity) { + return ModUtils.loc("animations/javelin_missile.animation.json"); + } + + @Override + public ResourceLocation getModelResource(JavelinMissileEntity entity) { + return ModUtils.loc("geo/javelin_missile.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(JavelinMissileEntity entity) { + return ModUtils.loc("textures/entity/javelin_missile.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/LaserTowerModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/LaserTowerModel.java new file mode 100644 index 000000000..a2f192d90 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/LaserTowerModel.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.model.GeoModel; + +import static com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity.LASER_LENGTH; + +public class LaserTowerModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(LaserTowerEntity entity) { + return ModUtils.loc("animations/laser_tower.animation.json"); + } + + @Override + public ResourceLocation getModelResource(LaserTowerEntity entity) { + Player player = Minecraft.getInstance().player; + + int distance = 0; + + if (player != null) { + distance = (int) player.position().distanceTo(entity.position()); + } + + if (distance < 24 || player.isScoping()) { + return ModUtils.loc("geo/laser_tower.geo.json"); + } else if (distance < 48) { + return ModUtils.loc("geo/laser_tower.lod1.geo.json"); + } else { + return ModUtils.loc("geo/laser_tower.lod2.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(LaserTowerEntity entity) { + return ModUtils.loc("textures/entity/laser_tower.png"); + } + + @Override + public void setCustomAnimations(LaserTowerEntity animatable, long instanceId, AnimationState animationState) { + GeoBone laser = getAnimationProcessor().getBone("laser"); + laser.setScaleZ(10 * animatable.getEntityData().get(LASER_LENGTH)); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Lav150Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Lav150Model.java new file mode 100644 index 000000000..d5c2b2766 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Lav150Model.java @@ -0,0 +1,37 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Lav150Entity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class Lav150Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Lav150Entity entity) { + return ModUtils.loc("animations/lav.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Lav150Entity entity) { + return ModUtils.loc("geo/lav150.geo.json"); +// Player player = Minecraft.getInstance().player; +// +// int distance = 0; +// +// if (player != null) { +// distance = (int) player.position().distanceTo(entity.position()); +// } +// +// if (distance < 32) { +// return ModUtils.loc("geo/lav150.geo.json"); +// } else { +// return ModUtils.loc("geo/speedboat.lod1.geo.json"); +// } + } + + @Override + public ResourceLocation getTextureResource(Lav150Entity entity) { + return ModUtils.loc("textures/entity/lav150.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mk42Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mk42Model.java new file mode 100644 index 000000000..c3e9cbaf2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mk42Model.java @@ -0,0 +1,52 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Mk42Entity; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.constant.DataTickets; +import software.bernie.geckolib.model.GeoModel; +import software.bernie.geckolib.model.data.EntityModelData; + +public class Mk42Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Mk42Entity entity) { + return ModUtils.loc("animations/mk_42.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Mk42Entity entity) { + Player player = Minecraft.getInstance().player; + + int distance = 0; + + if (player != null) { + distance = (int) player.position().distanceTo(entity.position()); + } + + if (distance < 32) { + return ModUtils.loc("geo/sherman.geo.json"); + } else if (distance < 64) { + return ModUtils.loc("geo/sherman_lod1.geo.json"); + } else { + return ModUtils.loc("geo/sherman_lod2.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(Mk42Entity entity) { + return ModUtils.loc("textures/entity/mk42.png"); + } + + @Override + public void setCustomAnimations(Mk42Entity animatable, long instanceId, AnimationState animationState) { + GeoBone bone = getAnimationProcessor().getBone("maingun"); + EntityModelData entityData = animationState.getData(DataTickets.ENTITY_MODEL_DATA); + bone.setRotX((entityData.headPitch()) * Mth.DEG_TO_RAD); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mle1934Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mle1934Model.java new file mode 100644 index 000000000..a83ad703a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Mle1934Model.java @@ -0,0 +1,49 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Mle1934Entity; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.constant.DataTickets; +import software.bernie.geckolib.model.GeoModel; +import software.bernie.geckolib.model.data.EntityModelData; + +public class Mle1934Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Mle1934Entity entity) { + return ModUtils.loc("animations/mle1934.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Mle1934Entity entity) { + Player player = Minecraft.getInstance().player; + + int distance = 0; + if (player != null) { + distance = (int) player.position().distanceTo(entity.position()); + } + + if (distance < 32) { + return ModUtils.loc("geo/mle1934.geo.json"); + } else { + return ModUtils.loc("geo/mle1934_lod1.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(Mle1934Entity entity) { + return ModUtils.loc("textures/entity/mle1934.png"); + } + + @Override + public void setCustomAnimations(Mle1934Entity animatable, long instanceId, AnimationState animationState) { + GeoBone barrel = getAnimationProcessor().getBone("barrel"); + EntityModelData entityData = animationState.getData(DataTickets.ENTITY_MODEL_DATA); + barrel.setRotX((entityData.headPitch()) * Mth.DEG_TO_RAD); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarModel.java new file mode 100644 index 000000000..b86b1208f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarModel.java @@ -0,0 +1,40 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.constant.DataTickets; +import software.bernie.geckolib.model.GeoModel; +import software.bernie.geckolib.model.data.EntityModelData; + +public class MortarModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(MortarEntity entity) { + return ModUtils.loc("animations/mortar.animation.json"); + } + + @Override + public ResourceLocation getModelResource(MortarEntity entity) { + return ModUtils.loc("geo/mortar.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(MortarEntity entity) { + return ModUtils.loc("textures/entity/mortar.png"); + } + + @Override + public void setCustomAnimations(MortarEntity animatable, long instanceId, AnimationState animationState) { + GeoBone head = getAnimationProcessor().getBone("paoguan"); + GeoBone jiaojia = getAnimationProcessor().getBone("jiaojia"); + if (head != null) { + EntityModelData entityData = animationState.getData(DataTickets.ENTITY_MODEL_DATA); + head.setRotX((entityData.headPitch()) * Mth.DEG_TO_RAD); + jiaojia.setRotX(-2 * ((entityData.headPitch() - (10 - entityData.headPitch() * 0.1f)) * Mth.DEG_TO_RAD)); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarShellEntityModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarShellEntityModel.java new file mode 100644 index 000000000..53f4e6c52 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/MortarShellEntityModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class MortarShellEntityModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(MortarShellEntity entity) { + return null; + } + + @Override + public ResourceLocation getModelResource(MortarShellEntity entity) { + return ModUtils.loc("geo/mortar_shell.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(MortarShellEntity entity) { + return ModUtils.loc("textures/entity/mortar.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ProjectileEntityModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ProjectileEntityModel.java new file mode 100644 index 000000000..b64c6a783 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/ProjectileEntityModel.java @@ -0,0 +1,53 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.model.GeoModel; + +public class ProjectileEntityModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(ProjectileEntity entity) { + return null; + } + + @Override + public ResourceLocation getModelResource(ProjectileEntity entity) { + Player player = Minecraft.getInstance().player; + if (player == null) { + return ModUtils.loc("geo/projectile_entity2.geo.json"); + } + + if ((ClientEventHandler.zoom && !player.getMainHandItem().is(ModItems.MINIGUN.get())) + || player.getMainHandItem().is(ModItems.GLOCK_17.get()) + || player.getMainHandItem().is(ModItems.GLOCK_18.get()) + || player.getMainHandItem().is(ModItems.BOCEK.get()) + || (player.getVehicle() instanceof ArmedVehicleEntity)) { + return ModUtils.loc("geo/projectile_entity.geo.json"); + } else { + return ModUtils.loc("geo/projectile_entity2.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(ProjectileEntity entity) { + return ModUtils.loc("textures/entity/empty.png"); + } + + @Override + public void setCustomAnimations(ProjectileEntity animatable, long instanceId, AnimationState animationState) { + GeoBone bone = getAnimationProcessor().getBone("bone"); + Player player = Minecraft.getInstance().player; + if (player != null) { + bone.setHidden(animatable.position().distanceTo(player.position()) < 3 || animatable.tickCount < 1); + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/RgoGrenadeEntityModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/RgoGrenadeEntityModel.java new file mode 100644 index 000000000..8f44fc7f4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/RgoGrenadeEntityModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.RgoGrenadeEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class RgoGrenadeEntityModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(RgoGrenadeEntity entity) { + return null; + } + + @Override + public ResourceLocation getModelResource(RgoGrenadeEntity entity) { + return ModUtils.loc("geo/rgo_grenade.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(RgoGrenadeEntity entity) { + return ModUtils.loc("textures/item/rgo_grenade.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/RpgRocketModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/RpgRocketModel.java new file mode 100644 index 000000000..b845ae496 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/RpgRocketModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class RpgRocketModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(RpgRocketEntity entity) { + return ModUtils.loc("animations/rpg_rocket.animation.json"); + } + + @Override + public ResourceLocation getModelResource(RpgRocketEntity entity) { + return ModUtils.loc("geo/rpg_rocket.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(RpgRocketEntity entity) { + return ModUtils.loc("textures/entity/rpg_rocket.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SenpaiModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SenpaiModel.java new file mode 100644 index 000000000..79b456a7a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SenpaiModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.SenpaiEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class SenpaiModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(SenpaiEntity entity) { + return ModUtils.loc("animations/senpai.animation.json"); + } + + @Override + public ResourceLocation getModelResource(SenpaiEntity entity) { + return ModUtils.loc("geo/senpai.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(SenpaiEntity entity) { + return ModUtils.loc("textures/entity/senpai.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SmallCannonShellModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SmallCannonShellModel.java new file mode 100644 index 000000000..5f56a520d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SmallCannonShellModel.java @@ -0,0 +1,34 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.model.GeoModel; + +public class SmallCannonShellModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(SmallCannonShellEntity entity) { + return ModUtils.loc("animations/cannon_shell.animation.json"); + } + + @Override + public ResourceLocation getModelResource(SmallCannonShellEntity entity) { + return ModUtils.loc("geo/cannon_shell.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(SmallCannonShellEntity entity) { + return ModUtils.loc("textures/entity/cannon_shell.png"); + } + + @Override + public void setCustomAnimations(SmallCannonShellEntity animatable, long instanceId, AnimationState animationState) { + GeoBone bone = getAnimationProcessor().getBone("bone"); + bone.setScaleX(0.17f); + bone.setScaleY(0.17f); + bone.setScaleZ(0.17f); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SpeedboatModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SpeedboatModel.java new file mode 100644 index 000000000..46dde8e33 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SpeedboatModel.java @@ -0,0 +1,38 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.model.GeoModel; + +public class SpeedboatModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(SpeedboatEntity entity) { + return ModUtils.loc("animations/speedboat.animation.json"); + } + + @Override + public ResourceLocation getModelResource(SpeedboatEntity entity) { + Player player = Minecraft.getInstance().player; + + int distance = 0; + + if (player != null) { + distance = (int) player.position().distanceTo(entity.position()); + } + + if (distance < 32) { + return ModUtils.loc("geo/speedboat.geo.json"); + } else { + return ModUtils.loc("geo/speedboat.lod1.geo.json"); + } + } + + @Override + public ResourceLocation getTextureResource(SpeedboatEntity entity) { + return ModUtils.loc("textures/entity/speedboat.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/TaserBulletProjectileModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/TaserBulletProjectileModel.java new file mode 100644 index 000000000..4cbe34bf6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/TaserBulletProjectileModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.TaserBulletEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class TaserBulletProjectileModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(TaserBulletEntity entity) { + return null; + } + + @Override + public ResourceLocation getModelResource(TaserBulletEntity entity) { + return ModUtils.loc("geo/taser_rod.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(TaserBulletEntity entity) { + return ModUtils.loc("textures/entity/taser_rod.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Tom6Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Tom6Model.java new file mode 100644 index 000000000..97d61dd88 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Tom6Model.java @@ -0,0 +1,25 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Tom6Entity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class Tom6Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Tom6Entity entity) { + return null; +// return ModUtils.loc("animations/wheel_chair.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Tom6Entity entity) { + return ModUtils.loc("geo/tom_6.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(Tom6Entity entity) { + return ModUtils.loc("textures/entity/tom_6.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/WgMissileModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/WgMissileModel.java new file mode 100644 index 000000000..711a18950 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/WgMissileModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.WgMissileEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class WgMissileModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(WgMissileEntity entity) { + return ModUtils.loc("animations/javelin_missile.animation.json"); + } + + @Override + public ResourceLocation getModelResource(WgMissileEntity entity) { + return ModUtils.loc("geo/wg_missile.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(WgMissileEntity entity) { + return ModUtils.loc("textures/entity/javelin_missile.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/WheelChairModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/WheelChairModel.java new file mode 100644 index 000000000..22f09743d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/WheelChairModel.java @@ -0,0 +1,25 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.WheelChairEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class WheelChairModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(WheelChairEntity entity) { + return null; +// return ModUtils.loc("animations/wheel_chair.animation.json"); + } + + @Override + public ResourceLocation getModelResource(WheelChairEntity entity) { + return ModUtils.loc("geo/wheel_chair.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(WheelChairEntity entity) { + return ModUtils.loc("textures/entity/wheel_chair.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Yx100Model.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Yx100Model.java new file mode 100644 index 000000000..754ccfe9a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/Yx100Model.java @@ -0,0 +1,37 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class Yx100Model extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(Yx100Entity entity) { + return ModUtils.loc("animations/yx_100.animation.json"); + } + + @Override + public ResourceLocation getModelResource(Yx100Entity entity) { + return ModUtils.loc("geo/yx_100.geo.json"); +// Player player = Minecraft.getInstance().player; +// +// int distance = 0; +// +// if (player != null) { +// distance = (int) player.position().distanceTo(entity.position()); +// } +// +// if (distance < 32) { +// return ModUtils.loc("geo/Yx100.geo.json"); +// } else { +// return ModUtils.loc("geo/speedboat.lod1.geo.json"); +// } + } + + @Override + public ResourceLocation getTextureResource(Yx100Entity entity) { + return ModUtils.loc("textures/entity/yx_100.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/item/LungeMineModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/item/LungeMineModel.java new file mode 100644 index 000000000..0e6014700 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/item/LungeMineModel.java @@ -0,0 +1,34 @@ +package com.atsuishio.superbwarfare.client.model.item; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.item.LungeMine; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.model.GeoModel; + +public class LungeMineModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(LungeMine animatable) { + return ModUtils.loc("animations/lunge_mine.animation.json"); + } + + @Override + public ResourceLocation getModelResource(LungeMine animatable) { + return ModUtils.loc("geo/lunge_mine.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(LungeMine animatable) { + return ModUtils.loc("textures/item/lunge_mine.png"); + } + + @Override + public void setCustomAnimations(LungeMine animatable, long instanceId, AnimationState animationState) { + GeoBone camera = getAnimationProcessor().getBone("camera"); + ClientEventHandler.shake(Mth.RAD_TO_DEG * camera.getRotX(), Mth.RAD_TO_DEG * camera.getRotY(), Mth.RAD_TO_DEG * camera.getRotZ()); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AbstractLaserEntityRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AbstractLaserEntityRenderer.java index 3a421a8d2..236f60928 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AbstractLaserEntityRenderer.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AbstractLaserEntityRenderer.java @@ -156,6 +156,7 @@ public abstract class AbstractLaserEntityRenderer } protected void drawVertex(Matrix4f matrix, Matrix3f normals, VertexConsumer vertexBuilder, float offsetX, float offsetY, float offsetZ, float textureX, float textureY, int packedLightIn) { + // TODO drawVertex // vertexBuilder.addVertex(matrix, offsetX, offsetY, offsetZ).setColor(1F, 1F, 1F, 1F).setUv(textureX, textureY).setOverlay(OverlayTexture.NO_OVERLAY).setLight(packedLightIn).setNormal(normals, 0.0F, 1.0F, 0.0F).endVertex(); } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Ah6Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Ah6Renderer.java new file mode 100644 index 000000000..c84b603f9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Ah6Renderer.java @@ -0,0 +1,61 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.Ah6Model; +import com.atsuishio.superbwarfare.entity.vehicle.Ah6Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class Ah6Renderer extends GeoEntityRenderer { + + public Ah6Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Ah6Model()); + this.shadowRadius = 0.5f; + } + + @Override + public RenderType getRenderType(Ah6Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Ah6Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Ah6Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, @NotNull MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + Vec3 root = new Vec3(0, 1.45, 0); + poseStack.rotateAround(Axis.YP.rotationDegrees(-entityYaw), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot())), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll())), (float) root.x, (float) root.y, (float) root.z); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, Ah6Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (name.equals("propeller")) { + bone.setRotY(Mth.lerp(partialTick, animatable.propellerRotO, animatable.getPropellerRot())); + } + if (name.equals("tailPropeller")) { + bone.setRotX(-6 * Mth.lerp(partialTick, animatable.propellerRotO, animatable.getPropellerRot())); + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AnnihilatorRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AnnihilatorRenderer.java new file mode 100644 index 000000000..fe8351797 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/AnnihilatorRenderer.java @@ -0,0 +1,54 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.*; +import com.atsuishio.superbwarfare.client.model.entity.AnnihilatorModel; +import com.atsuishio.superbwarfare.entity.vehicle.AnnihilatorEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class AnnihilatorRenderer extends GeoEntityRenderer { + + public AnnihilatorRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new AnnihilatorModel()); + this.addRenderLayer(new AnnihilatorLayer(this)); + this.addRenderLayer(new AnnihilatorGlowLayer(this)); + this.addRenderLayer(new AnnihilatorPowerLayer(this)); + this.addRenderLayer(new AnnihilatorPowerLightLayer(this)); + this.addRenderLayer(new AnnihilatorLedLayer(this)); + this.addRenderLayer(new AnnihilatorLedLightLayer(this)); + } + + @Override + public RenderType getRenderType(AnnihilatorEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, AnnihilatorEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(AnnihilatorEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(AnnihilatorEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Bmp2Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Bmp2Renderer.java new file mode 100644 index 000000000..25f41e4c1 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Bmp2Renderer.java @@ -0,0 +1,246 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.Bmp2Layer; +import com.atsuishio.superbwarfare.client.model.entity.Bmp2Model; +import com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.YAW; + +public class Bmp2Renderer extends GeoEntityRenderer { + + public Bmp2Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Bmp2Model()); + this.addRenderLayer(new Bmp2Layer(this)); + } + + @Override + public RenderType getRenderType(Bmp2Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Bmp2Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Bmp2Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + poseStack.mulPose(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + poseStack.mulPose(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, Bmp2Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + for (int i = 0; i < 8; i++) { + if (name.equals("wheelL" + i)) { + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.leftWheelRotO, animatable.getLeftWheelRot())); + } + if (name.equals("wheelR" + i)) { + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); + } + } + + if (name.equals("cannon")) { + + Player player = Minecraft.getInstance().player; + bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player); + + bone.setRotY(Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * Mth.DEG_TO_RAD); + } + + if (name.equals("barrel")) { + + float a = animatable.getTurretYaw(partialTick); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setRotX( + -Mth.lerp(partialTick, animatable.turretXRotO, animatable.getTurretXRot()) * Mth.DEG_TO_RAD + - r * animatable.getPitch(partialTick) * Mth.DEG_TO_RAD + - r2 * animatable.getRoll(partialTick) * Mth.DEG_TO_RAD + ); + } + + if (name.equals("flare")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + if (name.equals("flare2")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + + if (name.equals("base")) { + + Player player = Minecraft.getInstance().player; + bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player); + + float a = animatable.getEntityData().get(YAW); + float r = (Mth.abs(a) - 90f) / 90f; + + bone.setPosZ(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 0.125f); + bone.setRotX(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 0.06f); + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setPosX(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 0.125f); + bone.setRotZ(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 0.2f); + } + + for (int i = 0; i < 51; i++) { + float tO = animatable.leftTrackO + 2 * i; + float t = animatable.getLeftTrack() + 2 * i; + + while (t >= 100) { + t -= 100; + } + while (t <= 0) { + t += 100; + } + while (tO >= 100) { + tO -= 100; + } + while (tO <= 0) { + tO += 100; + } + + float tO2 = animatable.rightTrackO + 2 * i; + float t2 = animatable.getRightTrack() + 2 * i; + + while (t2 >= 100) { + t2 -= 100; + } + while (t2 <= 0) { + t2 += 100; + } + while (tO2 >= 100) { + tO2 -= 100; + } + while (tO2 <= 0) { + tO2 += 100; + } + + if (name.equals("trackL" + i)) { + bone.setPosY(Mth.lerp(partialTick, getBoneMoveY(tO), getBoneMoveY(t))); + bone.setPosZ(Mth.lerp(partialTick, getBoneMoveZ(tO), getBoneMoveZ(t))); + } + + if (name.equals("trackR" + i)) { + bone.setPosY(Mth.lerp(partialTick, getBoneMoveY(tO2), getBoneMoveY(t2))); + bone.setPosZ(Mth.lerp(partialTick, getBoneMoveZ(tO2), getBoneMoveZ(t2))); + } + + if (name.equals("trackLRot" + i)) { + bone.setRotX(-Mth.lerp(partialTick, getBoneRotX(tO), getBoneRotX(t)) * Mth.DEG_TO_RAD); + } + + if (name.equals("trackRRot" + i)) { + bone.setRotX(-Mth.lerp(partialTick, getBoneRotX(tO2), getBoneRotX(t2)) * Mth.DEG_TO_RAD); + } + + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + public float getBoneRotX(float t) { + if (t <= 37.6667) return 0F; + if (t <= 38.5833) return Mth.lerp((t - 37.6667F) / (38.5833F - 37.6667F), 0F, -45F); + if (t <= 39.75) return -45F; + if (t <= 40.6667) return Mth.lerp((t - 39.75F) / (40.6667F - 39.75F), -45F, -90F); + if (t <= 41.6667) return -90F; + if (t <= 42.5) return -90F; + if (t <= 43.5) return Mth.lerp(t - 42.5F, -90F, -135F); + if (t <= 44.5833) return -135F; + if (t <= 45.0833) return Mth.lerp((t - 44.5833F) / (45.0833F - 44.5833F), -135F, -150F); + if (t <= 52.25) return -150F; + if (t <= 52.75) return Mth.lerp((t - 52.25F) / (52.75F - 52.25F), -150F, -180F); + if (t <= 84.3333) return -180F; + if (t <= 84.9167) return Mth.lerp((t - 84.3333F) / (84.9167F - 84.3333F), -180F, -210F); + if (t <= 92.5833) return -210F; + if (t <= 93.4167) return Mth.lerp((t - 92.5833F) / (93.4167F - 92.5833F), -210F, -220F); + if (t <= 94.25) return -220F; + if (t <= 94.9167) return Mth.lerp((t - 94.25F) / (94.9167F - 94.25F), -220F, -243.33F); + if (t <= 95.75) return Mth.lerp((t - 94.9167F) / (95.75F - 94.9167F), -243.33F, -270F); + if (t <= 96.8333) return -270F; + if (t <= 97.5833) return Mth.lerp((t - 96.8333F) / (97.5833F - 96.8333F), -270F, -315F); + if (t <= 98.8333) return -315F; + if (t <= 99.5833) return Mth.lerp((t - 98.8333F) / (99.5833F - 98.8333F), -315F, -360F); + + return 0F; + } + + public float getBoneMoveY(float t) { + if (t <= 37.6667) return 0F; + if (t <= 38.5833) return Mth.lerp((t - 37.6667F) / (38.5833F - 37.6667F), 0F, -1.8F); + if (t <= 40.3333) return Mth.lerp((t - 38.5833F) / (40.3333F - 38.5833F), -1.8F, -4.1F); + if (t <= 42.9167) return Mth.lerp((t - 40.3333F) / (42.9167F - 40.3333F), -4.1F, -10.3F); + if (t <= 44.25) return Mth.lerp((t - 42.9167F) / (44.25F - 42.9167F), -10.3F, -12.9F); + if (t <= 52.4167) return Mth.lerp((t - 44.25F) / (52.4167F - 44.25F), -12.9F, -23.96F); + if (t <= 84.5833) return -23.96F; + if (t <= 93) return Mth.lerp((t - 84.5833F) / (93F - 84.5833F), -23.96F, -12.93F); + if (t <= 95.25) return Mth.lerp((t - 93F) / (95.25F - 93F), -12.93F, -10.085F); + if (t <= 97.5) return Mth.lerp((t - 95.25F) / (97.5F - 95.25F), -10.085F, -4.585F); + if (t <= 98.8333) return Mth.lerp((t - 97.5F) / (98.8333F - 97.5F), -4.585F, -1.165F); + if (t <= 99.25) return Mth.lerp((t - 98.8333F) / (99.25F - 98.8333F), -1.165F, -0.25F); + + return Mth.lerp((t - 99.25F) / (100F - 99.25F), -0.25F, 0F); + } + + public float getBoneMoveZ(float t) { + if (t <= 37.6667) return Mth.lerp(t / (37.6667F - 0F), 0F, 111.6F); + if (t <= 38.5833) return Mth.lerp((t - 37.6667F) / (38.5833F - 37.6667F), 111.6F, 113.25F); + if (t <= 40.3333) return Mth.lerp((t - 38.5833F) / (40.3333F - 38.5833F), 113.25F, 116F); + if (t <= 42.9167) return 116F; + if (t <= 44.25) return Mth.lerp((t - 42.9167F) / (44.25F - 42.9167F), 116F, 113.5F); + if (t <= 52.4167) return Mth.lerp((t - 44.25F) / (52.4167F - 44.25F), 113.5F, 96.25F); + if (t <= 84.5833) return Mth.lerp((t - 52.4167F) / (84.5833F - 52.4167F), 96.25F, 14.095F); + if (t <= 93) return Mth.lerp((t - 84.5833F) / (93F - 84.5833F), 14.095F, -3.565F); + if (t <= 95.25) return Mth.lerp((t - 93F) / (95.25F - 93F), -3.565F, -6.35F); + if (t <= 97.5) return Mth.lerp((t - 95.25F) / (97.5F - 95.25F), -6.35F, -6.39F); + if (t <= 98.8333) return Mth.lerp((t - 97.5F) / (98.8333F - 97.5F), -6.39F, -3.03F); + if (t <= 99.25) return Mth.lerp((t - 98.8333F) / (99.25F - 98.8333F), -3.03F, -1.95F); + + return Mth.lerp((t - 99.25F) / (100F - 99.25F), -1.95F, 0F); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/C4Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/C4Renderer.java new file mode 100644 index 000000000..2a15440ee --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/C4Renderer.java @@ -0,0 +1,44 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.C4Model; +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class C4Renderer extends GeoEntityRenderer { + + public C4Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new C4Model()); + this.shadowRadius = 0f; + } + + @Override + public RenderType getRenderType(C4Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, C4Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 0.5f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, 15, packedOverlay, color); + } + + @Override + public void render(C4Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-entityYaw)); + poseStack.mulPose(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()) + 90)); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/CannonShellRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/CannonShellRenderer.java new file mode 100644 index 000000000..9622b9ffa --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/CannonShellRenderer.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.CannonShellLayer; +import com.atsuishio.superbwarfare.client.model.entity.CannonShellEntityModel; +import com.atsuishio.superbwarfare.entity.projectile.CannonShellEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class CannonShellRenderer extends GeoEntityRenderer { + public CannonShellRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new CannonShellEntityModel()); + this.addRenderLayer(new CannonShellLayer(this)); + this.shadowRadius = 0f; + } + + @Override + public RenderType getRenderType(CannonShellEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, CannonShellEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(CannonShellEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(CannonShellEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ClaymoreRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ClaymoreRenderer.java new file mode 100644 index 000000000..639a56b66 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ClaymoreRenderer.java @@ -0,0 +1,53 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.ClaymoreModel; +import com.atsuishio.superbwarfare.entity.ClaymoreEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class ClaymoreRenderer extends GeoEntityRenderer { + + public ClaymoreRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new ClaymoreModel()); + this.shadowRadius = 0f; + } + + @Override + public RenderType getRenderType(ClaymoreEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, ClaymoreEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 0.5f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(ClaymoreEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(ClaymoreEntity entityLivingBaseIn) { + return 0.0F; + } + + @Override + public boolean shouldShowName(ClaymoreEntity animatable) { + return false; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/DroneRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/DroneRenderer.java new file mode 100644 index 000000000..db6d94da8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/DroneRenderer.java @@ -0,0 +1,156 @@ + +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.DroneModel; +import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity; +import com.atsuishio.superbwarfare.entity.projectile.RgoGrenadeEntity; +import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity; +import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +import static com.atsuishio.superbwarfare.entity.vehicle.DroneEntity.KAMIKAZE_MODE; +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.AMMO; + +public class DroneRenderer extends GeoEntityRenderer { + public DroneRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new DroneModel()); + this.shadowRadius = 0.2f; + } + + @Override + public RenderType getRenderType(DroneEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, DroneEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(DroneEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-entityIn.getYaw(partialTicks))); + poseStack.mulPose(Axis.XP.rotationDegrees(entityIn.getBodyPitch(partialTicks))); + poseStack.mulPose(Axis.ZP.rotationDegrees(entityIn.getRoll(partialTicks))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + + Player player = Minecraft.getInstance().player; + if (player != null) { + ItemStack stack = player.getMainHandItem(); + var tag = NBTTool.getTag(stack); + DroneEntity drone = EntityFindUtil.findDrone(player.level(), tag.getString("LinkedDrone")); + + if (!(stack.is(ModItems.MONITOR.get()) && tag.getBoolean("Using") && tag.getBoolean("Linked") && drone != null && drone.getUUID() == entityIn.getUUID())) { + if (entityIn.getEntityData().get(KAMIKAZE_MODE) == 1) { + Entity entity = new MortarShellEntity(ModEntities.MORTAR_SHELL.get(), entityIn.level()); + entityRenderDispatcher.render(entity, 0, 0.03, 0.25, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + } + + if (entityIn.getEntityData().get(KAMIKAZE_MODE) == 3) { + Entity entity = new RpgRocketEntity(ModEntities.RPG_ROCKET.get(), entityIn.level()); + entityRenderDispatcher.render(entity, 0, -0.03, -1.8, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + } + + for (int i = 0; i < entityIn.getEntityData().get(AMMO); i++) { + double yOffset = 0; + double xOffset = 0; + + if (i == 0) { + yOffset = 0.2; + xOffset = 0.1; + } + if (i == 1) { + yOffset = 0.2; + xOffset = -0.1; + } + if (i == 2) { + yOffset = -0.05; + xOffset = 0.1; + } + if (i == 3) { + yOffset = -0.05; + xOffset = -0.1; + } + if (i == 4) { + yOffset = -0.3; + xOffset = 0.1; + } + if (i == 5) { + yOffset = -0.3; + xOffset = -0.1; + } + + + poseStack.pushPose(); + poseStack.mulPose(Axis.XP.rotationDegrees(90)); + poseStack.scale(0.35f, 0.35f, 0.35f); + Entity entity = new RgoGrenadeEntity(ModEntities.RGO_GRENADE.get(), entityIn.level()); + entityRenderDispatcher.render(entity, xOffset, yOffset, 0, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + } + } + + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, DroneEntity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (!animatable.onGround()) { + if (name.equals("wingFL")) { + bone.setRotY((System.currentTimeMillis() % 36000000) / 12f); + } + if (name.equals("wingFR")) { + bone.setRotY((System.currentTimeMillis() % 36000000) / 12f); + } + if (name.equals("wingBL")) { + bone.setRotY((System.currentTimeMillis() % 36000000) / 12f); + } + if (name.equals("wingBR")) { + bone.setRotY((System.currentTimeMillis() % 36000000) / 12f); + } + } + + if (name.equals("c4")) { + bone.setHidden(animatable.getEntityData().get(KAMIKAZE_MODE) != 2); + + } + + +// Player player = Minecraft.getInstance().player; +// if (player != null && animatable.getEntityData().get(KAMIKAZE_MODE) == 2 && name.equals("c4")) { +// ItemStack stack = player.getMainHandItem(); +// DroneEntity drone = EntityFindUtil.findDrone(player.level(), stack.getOrCreateTag().getString("LinkedDrone")); +// +// if (!(stack.is(ModItems.MONITOR.get()) && stack.getOrCreateTag().getBoolean("Using") && stack.getOrCreateTag().getBoolean("Linked") && drone != null && drone.getUUID() == animatable.getUUID())) { +// bone.setHidden(true); +// } else { +// bone.setHidden(false); +// } +// } + + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/FlareDecoyEntityRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/FlareDecoyEntityRenderer.java new file mode 100644 index 000000000..63f94d041 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/FlareDecoyEntityRenderer.java @@ -0,0 +1,57 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.FlareDecoyEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix3f; +import org.joml.Matrix4f; + +public class FlareDecoyEntityRenderer extends EntityRenderer { + public FlareDecoyEntityRenderer(EntityRendererProvider.Context pContext) { + super(pContext); + } + + protected int getBlockLightLevel(@NotNull FlareDecoyEntity pEntity, @NotNull BlockPos pPos) { + return 15; + } + + public void render(@NotNull FlareDecoyEntity pEntity, float pEntityYaw, float pPartialTicks, PoseStack pMatrixStack, MultiBufferSource pBuffer, int pPackedLight) { + pMatrixStack.pushPose(); + pMatrixStack.scale(1.0F, 1.0F, 1.0F); + pMatrixStack.mulPose(this.entityRenderDispatcher.cameraOrientation()); + pMatrixStack.mulPose(Axis.YP.rotationDegrees(180.0F)); + PoseStack.Pose $$6 = pMatrixStack.last(); + Matrix4f $$7 = $$6.pose(); + Matrix3f $$8 = $$6.normal(); + VertexConsumer $$9 = pBuffer.getBuffer(RenderType.entityCutoutNoCull(texture(pEntity))); + vertex($$9, $$7, $$8, pPackedLight, 0.0F, 0, 0, 1); + vertex($$9, $$7, $$8, pPackedLight, 1.0F, 0, 1, 1); + vertex($$9, $$7, $$8, pPackedLight, 1.0F, 1, 1, 0); + vertex($$9, $$7, $$8, pPackedLight, 0.0F, 1, 0, 0); + pMatrixStack.popPose(); + super.render(pEntity, pEntityYaw, pPartialTicks, pMatrixStack, pBuffer, pPackedLight); + } + + private static void vertex(VertexConsumer pConsumer, Matrix4f pPose, Matrix3f pNormal, int pLightmapUV, float pX, float pY, int pU, int pV) { + // TODO vertex + // pConsumer.vertex(pPose, pX - 0.5F, pY - 0.25F, 0.0F).color(255, 255, 255, 255).uv((float)pU, (float)pV).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(pLightmapUV).normal(pNormal, 0.0F, 1.0F, 0.0F).endVertex(); + } + + private static ResourceLocation texture(Entity entity) { + return ModUtils.loc("textures/particle/fire_star_" + (entity.tickCount % 8 + 1) + ".png"); + } + + public ResourceLocation getTextureLocation(FlareDecoyEntity pEntity) { + return texture(pEntity); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/GunGrenadeRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/GunGrenadeRenderer.java new file mode 100644 index 000000000..ec9eadefd --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/GunGrenadeRenderer.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.GunGrenadeLayer; +import com.atsuishio.superbwarfare.client.model.entity.GunGrenadeModel; +import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class GunGrenadeRenderer extends GeoEntityRenderer { + public GunGrenadeRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new GunGrenadeModel()); + this.addRenderLayer(new GunGrenadeLayer(this)); + this.shadowRadius = 0f; + } + + @Override + public RenderType getRenderType(GunGrenadeEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, GunGrenadeEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(GunGrenadeEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(GunGrenadeEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HandGrenadeRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HandGrenadeRenderer.java new file mode 100644 index 000000000..8acc97041 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HandGrenadeRenderer.java @@ -0,0 +1,47 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.HandGrenadeEntityModel; +import com.atsuishio.superbwarfare.entity.projectile.HandGrenadeEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class HandGrenadeRenderer extends GeoEntityRenderer { + public HandGrenadeRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new HandGrenadeEntityModel()); + } + + @Override + public RenderType getRenderType(HandGrenadeEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, HandGrenadeEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(HandGrenadeEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(HandGrenadeEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HeliRocketRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HeliRocketRenderer.java new file mode 100644 index 000000000..bf2bb4abb --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/HeliRocketRenderer.java @@ -0,0 +1,49 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.HeliRocketLayer; +import com.atsuishio.superbwarfare.client.model.entity.HeliRocketModel; +import com.atsuishio.superbwarfare.entity.projectile.HeliRocketEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class HeliRocketRenderer extends GeoEntityRenderer { + public HeliRocketRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new HeliRocketModel()); + this.addRenderLayer(new HeliRocketLayer(this)); + } + + @Override + public RenderType getRenderType(HeliRocketEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, HeliRocketEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(HeliRocketEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(HeliRocketEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/JavelinMissileRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/JavelinMissileRenderer.java new file mode 100644 index 000000000..cd1b9940b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/JavelinMissileRenderer.java @@ -0,0 +1,49 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.JavelinMissleLayer; +import com.atsuishio.superbwarfare.client.model.entity.JavelinMissileModel; +import com.atsuishio.superbwarfare.entity.projectile.JavelinMissileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class JavelinMissileRenderer extends GeoEntityRenderer { + public JavelinMissileRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new JavelinMissileModel()); + this.addRenderLayer(new JavelinMissleLayer(this)); + } + + @Override + public RenderType getRenderType(JavelinMissileEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, JavelinMissileEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(JavelinMissileEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(JavelinMissileEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/LaserTowerRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/LaserTowerRenderer.java new file mode 100644 index 000000000..3d2e0a9a7 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/LaserTowerRenderer.java @@ -0,0 +1,59 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.LaserTowerLaserLayer; +import com.atsuishio.superbwarfare.client.layer.vehicle.LaserTowerPowerLayer; +import com.atsuishio.superbwarfare.client.model.entity.LaserTowerModel; +import com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class LaserTowerRenderer extends GeoEntityRenderer { + + public LaserTowerRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new LaserTowerModel()); + this.addRenderLayer(new LaserTowerPowerLayer(this)); + this.addRenderLayer(new LaserTowerLaserLayer(this)); + } + + @Override + public RenderType getRenderType(LaserTowerEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, LaserTowerEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(@NotNull LaserTowerEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, LaserTowerEntity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (name.equals("turret")) { + bone.setRotY(-Mth.lerp(partialTick, animatable.yRotO, animatable.getYRot()) * Mth.DEG_TO_RAD); + } + if (name.equals("barrel")) { + bone.setRotX(-Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()) * Mth.DEG_TO_RAD); + } + + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Lav150Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Lav150Renderer.java new file mode 100644 index 000000000..bfaa3ec6c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Lav150Renderer.java @@ -0,0 +1,142 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.Lav150Layer; +import com.atsuishio.superbwarfare.client.model.entity.Lav150Model; +import com.atsuishio.superbwarfare.entity.vehicle.Lav150Entity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.YAW; + +public class Lav150Renderer extends GeoEntityRenderer { + + public Lav150Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Lav150Model()); + this.addRenderLayer(new Lav150Layer(this)); + } + + @Override + public RenderType getRenderType(Lav150Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Lav150Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Lav150Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + poseStack.mulPose(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + poseStack.mulPose(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, Lav150Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (name.equals("wheel1")) { + bone.setRotY(Mth.lerp(partialTick, animatable.rudderRotO, animatable.getRudderRot())); + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.leftWheelRotO, animatable.getLeftWheelRot())); + } + if (name.equals("wheel2")) { + bone.setRotY(Mth.lerp(partialTick, animatable.rudderRotO, animatable.getRudderRot())); + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); + } + if (name.equals("wheel3")) { + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); + } + if (name.equals("wheel4")) { + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.leftWheelRotO, animatable.getLeftWheelRot())); + } + + if (name.equals("base")) { + + Player player = Minecraft.getInstance().player; + bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player); + + float a = animatable.getEntityData().get(YAW); + float r = (Mth.abs(a) - 90f) / 90f; + + bone.setPosZ(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 0.2f); + bone.setRotX(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 0.3f); + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setPosX(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 0.15f); + bone.setRotZ(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 0.5f); + } + + if (name.equals("cannon")) { + + Player player = Minecraft.getInstance().player; + bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player); + + bone.setRotY(Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * Mth.DEG_TO_RAD); + } + if (name.equals("barrel")) { + + float a = animatable.getTurretYaw(partialTick); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setRotX( + -Mth.lerp(partialTick, animatable.turretXRotO, animatable.getTurretXRot()) * Mth.DEG_TO_RAD + - r * animatable.getPitch(partialTick) * Mth.DEG_TO_RAD + - r2 * animatable.getRoll(partialTick) * Mth.DEG_TO_RAD + ); + } + if (name.equals("flare")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + if (name.equals("flare2")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + protected float getDeathMaxRotation(Lav150Entity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MelonBombEntityRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MelonBombEntityRenderer.java new file mode 100644 index 000000000..beefc931b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MelonBombEntityRenderer.java @@ -0,0 +1,42 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.entity.projectile.MelonBombEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.client.renderer.entity.TntMinecartRenderer; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Blocks; +import org.jetbrains.annotations.NotNull; + +public class MelonBombEntityRenderer extends EntityRenderer { + + private final BlockRenderDispatcher blockRenderer; + + public MelonBombEntityRenderer(EntityRendererProvider.Context context) { + super(context); + this.shadowRadius = 0.2f; + this.blockRenderer = context.getBlockRenderDispatcher(); + } + + @Override + public void render(@NotNull MelonBombEntity entity, float entityYaw, float partialTicks, PoseStack matrixStack, MultiBufferSource buffer, int packedLight) { + matrixStack.pushPose(); + matrixStack.translate(0.0, 0.5, 0.0); + matrixStack.mulPose(Axis.YP.rotationDegrees(-90.0f)); + matrixStack.translate(-0.5, -0.5, 0.5); + matrixStack.mulPose(Axis.YP.rotationDegrees(90.0f)); + TntMinecartRenderer.renderWhiteSolidBlock(this.blockRenderer, Blocks.MELON.defaultBlockState(), matrixStack, buffer, packedLight, false); + matrixStack.popPose(); + super.render(entity, entityYaw, partialTicks, matrixStack, buffer, packedLight); + } + + @Override + public @NotNull ResourceLocation getTextureLocation(@NotNull MelonBombEntity entity) { + return TextureAtlas.LOCATION_BLOCKS; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mk42Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mk42Renderer.java new file mode 100644 index 000000000..de64220e8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mk42Renderer.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.Mk42Layer; +import com.atsuishio.superbwarfare.client.model.entity.Mk42Model; +import com.atsuishio.superbwarfare.entity.vehicle.Mk42Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class Mk42Renderer extends GeoEntityRenderer { + + public Mk42Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Mk42Model()); + this.shadowRadius = 2f; + this.addRenderLayer(new Mk42Layer(this)); + } + + @Override + public RenderType getRenderType(Mk42Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Mk42Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Mk42Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(Mk42Entity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mle1934Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mle1934Renderer.java new file mode 100644 index 000000000..3127a63d6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Mle1934Renderer.java @@ -0,0 +1,50 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.Mle1934Layer; +import com.atsuishio.superbwarfare.client.model.entity.Mle1934Model; +import com.atsuishio.superbwarfare.entity.vehicle.Mle1934Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class Mle1934Renderer extends GeoEntityRenderer { + + public Mle1934Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Mle1934Model()); + this.shadowRadius = 2f; + this.addRenderLayer(new Mle1934Layer(this)); + } + + @Override + public RenderType getRenderType(Mle1934Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Mle1934Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Mle1934Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(Mle1934Entity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarRenderer.java new file mode 100644 index 000000000..c5abe6d28 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarRenderer.java @@ -0,0 +1,55 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.MortarLayer; +import com.atsuishio.superbwarfare.client.model.entity.MortarModel; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class MortarRenderer extends GeoEntityRenderer { + + public MortarRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new MortarModel()); + this.shadowRadius = 0f; + this.addRenderLayer(new MortarLayer(this)); + } + + @Override + public RenderType getRenderType(MortarEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, MortarEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(MortarEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(MortarEntity entityLivingBaseIn) { + return 0.0F; + } + + @Override + public boolean shouldShowName(MortarEntity animatable) { + return animatable.hasCustomName(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarShellRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarShellRenderer.java new file mode 100644 index 000000000..f1f0d375b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/MortarShellRenderer.java @@ -0,0 +1,47 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.MortarShellEntityModel; +import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class MortarShellRenderer extends GeoEntityRenderer { + public MortarShellRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new MortarShellEntityModel()); + } + + @Override + public RenderType getRenderType(MortarShellEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, MortarShellEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(MortarShellEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(MortarShellEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ProjectileEntityRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ProjectileEntityRenderer.java new file mode 100644 index 000000000..202b4645e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/ProjectileEntityRenderer.java @@ -0,0 +1,56 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.ProjectileEntityInsideLayer; +import com.atsuishio.superbwarfare.client.layer.projectile.ProjectileEntityLayer; +import com.atsuishio.superbwarfare.client.model.entity.ProjectileEntityModel; +import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class ProjectileEntityRenderer extends GeoEntityRenderer { + public ProjectileEntityRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new ProjectileEntityModel()); + this.shadowRadius = 0f; + this.addRenderLayer(new ProjectileEntityLayer(this)); + this.addRenderLayer(new ProjectileEntityInsideLayer(this)); + } + + @Override + public RenderType getRenderType(ProjectileEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, ProjectileEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + if (entity.tickCount > 1) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + } + + @Override + public void render(ProjectileEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + if (entityIn.tickCount > 1) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + } + + @Override + protected float getDeathMaxRotation(ProjectileEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RgoGrenadeRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RgoGrenadeRenderer.java new file mode 100644 index 000000000..0d96fdb10 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RgoGrenadeRenderer.java @@ -0,0 +1,47 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.RgoGrenadeEntityModel; +import com.atsuishio.superbwarfare.entity.projectile.RgoGrenadeEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class RgoGrenadeRenderer extends GeoEntityRenderer { + public RgoGrenadeRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new RgoGrenadeEntityModel()); + } + + @Override + public RenderType getRenderType(RgoGrenadeEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, RgoGrenadeEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(RgoGrenadeEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(RgoGrenadeEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RpgRocketRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RpgRocketRenderer.java new file mode 100644 index 000000000..7b5819623 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/RpgRocketRenderer.java @@ -0,0 +1,49 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.RpgRocketLayer; +import com.atsuishio.superbwarfare.client.model.entity.RpgRocketModel; +import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class RpgRocketRenderer extends GeoEntityRenderer { + public RpgRocketRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new RpgRocketModel()); + this.addRenderLayer(new RpgRocketLayer(this)); + } + + @Override + public RenderType getRenderType(RpgRocketEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, RpgRocketEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(RpgRocketEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(RpgRocketEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SenpaiRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SenpaiRenderer.java new file mode 100644 index 000000000..5814f99b2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SenpaiRenderer.java @@ -0,0 +1,37 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.SenpaiModel; +import com.atsuishio.superbwarfare.entity.SenpaiEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class SenpaiRenderer extends GeoEntityRenderer { + public SenpaiRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new SenpaiModel()); + this.shadowRadius = 0.5f; + } + + @Override + public RenderType getRenderType(SenpaiEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, SenpaiEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + protected float getDeathMaxRotation(SenpaiEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmallCannonShellRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmallCannonShellRenderer.java new file mode 100644 index 000000000..11a624b60 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SmallCannonShellRenderer.java @@ -0,0 +1,44 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.SmallCannonShellLayer; +import com.atsuishio.superbwarfare.client.model.entity.SmallCannonShellModel; +import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class SmallCannonShellRenderer extends GeoEntityRenderer { + public SmallCannonShellRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new SmallCannonShellModel()); + this.addRenderLayer(new SmallCannonShellLayer(this)); + } + + @Override + public RenderType getRenderType(SmallCannonShellEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, SmallCannonShellEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(SmallCannonShellEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SpeedboatRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SpeedboatRenderer.java new file mode 100644 index 000000000..faaccec2e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SpeedboatRenderer.java @@ -0,0 +1,124 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.SpeedBoatHeatLayer; +import com.atsuishio.superbwarfare.client.layer.vehicle.SpeedBoatLayer; +import com.atsuishio.superbwarfare.client.layer.vehicle.SpeedBoatPowerLayer; +import com.atsuishio.superbwarfare.client.model.entity.SpeedboatModel; +import com.atsuishio.superbwarfare.entity.vehicle.SpeedboatEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.YAW; + +public class SpeedboatRenderer extends GeoEntityRenderer { + + public SpeedboatRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new SpeedboatModel()); + this.addRenderLayer(new SpeedBoatLayer(this)); + this.addRenderLayer(new SpeedBoatPowerLayer(this)); + this.addRenderLayer(new SpeedBoatHeatLayer(this)); + } + + @Override + public RenderType getRenderType(SpeedboatEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, SpeedboatEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(SpeedboatEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + Vec3 root = new Vec3(0, 0.9, 0); + poseStack.rotateAround(Axis.YP.rotationDegrees(-entityYaw), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot())), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll())), (float) root.x, (float) root.y, (float) root.z); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, SpeedboatEntity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (name.equals("root")) { + float a = animatable.getEntityData().get(YAW); + float r = (Mth.abs(a) - 90f) / 90f; + + bone.setPosZ(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 0.125f); + bone.setRotX(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 0.5f); + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setPosX(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 0.125f); + bone.setRotZ(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 0.75f); + } + + if (name.equals("Rotor")) { + bone.setRotZ(Mth.lerp(partialTick, animatable.rotorRotO, animatable.getRotorRot())); + } + if (name.equals("duo")) { + bone.setRotY(Mth.lerp(partialTick, animatable.rudderRotO, animatable.getRudderRot())); + } + if (name.equals("paota")) { + bone.setRotY(Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * Mth.DEG_TO_RAD); + } + if (name.equals("gun")) { + + float a = animatable.getTurretYaw(partialTick); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setRotX( + -Mth.lerp(partialTick, animatable.turretXRotO, animatable.getTurretXRot()) * Mth.DEG_TO_RAD + - r * animatable.getPitch(partialTick) * Mth.DEG_TO_RAD + - r2 * animatable.getRoll(partialTick) * Mth.DEG_TO_RAD + ); + } + if (name.equals("flare")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + protected float getDeathMaxRotation(SpeedboatEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/TaserBulletProjectileRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/TaserBulletProjectileRenderer.java new file mode 100644 index 000000000..ce7b18ec0 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/TaserBulletProjectileRenderer.java @@ -0,0 +1,47 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.TaserBulletProjectileModel; +import com.atsuishio.superbwarfare.entity.projectile.TaserBulletEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class TaserBulletProjectileRenderer extends GeoEntityRenderer { + public TaserBulletProjectileRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new TaserBulletProjectileModel()); + } + + @Override + public RenderType getRenderType(TaserBulletEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, TaserBulletEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(TaserBulletEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(TaserBulletEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Tom6Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Tom6Renderer.java new file mode 100644 index 000000000..96cf092e6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Tom6Renderer.java @@ -0,0 +1,59 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.Tom6Model; +import com.atsuishio.superbwarfare.entity.vehicle.Tom6Entity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +import static com.atsuishio.superbwarfare.entity.vehicle.Tom6Entity.MELON; + +public class Tom6Renderer extends GeoEntityRenderer { + + public Tom6Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Tom6Model()); + this.shadowRadius = 0.5f; + } + + @Override + public RenderType getRenderType(Tom6Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Tom6Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Tom6Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + Vec3 root = new Vec3(0, 0.5, 0); + poseStack.rotateAround(Axis.YP.rotationDegrees(-entityYaw), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot())), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll())), (float) root.x, (float) root.y, (float) root.z); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, Tom6Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (name.equals("melon")) { + bone.setHidden(!animatable.getEntityData().get(MELON)); + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WgMissileRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WgMissileRenderer.java new file mode 100644 index 000000000..7df72b1db --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WgMissileRenderer.java @@ -0,0 +1,49 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.projectile.WgMissileLayer; +import com.atsuishio.superbwarfare.client.model.entity.WgMissileModel; +import com.atsuishio.superbwarfare.entity.projectile.WgMissileEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class WgMissileRenderer extends GeoEntityRenderer { + public WgMissileRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new WgMissileModel()); + this.addRenderLayer(new WgMissileLayer(this)); + } + + @Override + public RenderType getRenderType(WgMissileEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, WgMissileEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(WgMissileEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()) - 90)); + poseStack.mulPose(Axis.ZP.rotationDegrees(90 + Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(WgMissileEntity entityLivingBaseIn) { + return 0.0F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WheelChairRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WheelChairRenderer.java new file mode 100644 index 000000000..04c35472f --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/WheelChairRenderer.java @@ -0,0 +1,66 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.WheelChairModel; +import com.atsuishio.superbwarfare.entity.vehicle.WheelChairEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class WheelChairRenderer extends GeoEntityRenderer { + + public WheelChairRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new WheelChairModel()); + this.shadowRadius = 0.5f; + } + + @Override + public RenderType getRenderType(WheelChairEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, WheelChairEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(WheelChairEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + Vec3 root = new Vec3(0, 0.4, 0); + poseStack.rotateAround(Axis.YP.rotationDegrees(-entityYaw), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot())), (float) root.x, (float) root.y, (float) root.z); + poseStack.rotateAround(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll())), (float) root.x, (float) root.y, (float) root.z); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, WheelChairEntity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + if (name.equals("w_rb")) { + bone.setRotX(Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); + } + if (name.equals("w_lb")) { + bone.setRotX(Mth.lerp(partialTick, animatable.leftWheelRotO, animatable.getLeftWheelRot())); + } + if (name.equals("w_rr")) { + bone.setRotX(4 * Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); + } + if (name.equals("w_lr")) { + bone.setRotX(4 * Mth.lerp(partialTick, animatable.leftWheelRotO, animatable.getLeftWheelRot())); + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Yx100Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Yx100Renderer.java new file mode 100644 index 000000000..b47455cef --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Yx100Renderer.java @@ -0,0 +1,260 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.layer.vehicle.Yx100GlowLayer; +import com.atsuishio.superbwarfare.client.model.entity.Yx100Model; +import com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +import static com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity.YAW; + +public class Yx100Renderer extends GeoEntityRenderer { + + public Yx100Renderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new Yx100Model()); + this.addRenderLayer(new Yx100GlowLayer(this)); + } + + @Override + public RenderType getRenderType(Yx100Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, Yx100Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + float scale = 1f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + @Override + public void render(Yx100Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + poseStack.mulPose(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + poseStack.mulPose(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.prevRoll, entityIn.getRoll()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + public void renderRecursively(PoseStack poseStack, Yx100Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) { + String name = bone.getName(); + for (int i = 0; i < 8; i++) { + if (name.equals("wheelL" + i)) { + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.leftWheelRotO, animatable.getLeftWheelRot())); + } + if (name.equals("wheelR" + i)) { + bone.setRotX(1.5f * Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); + } + } + + if (name.equals("turret")) { + bone.setRotY(Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * Mth.DEG_TO_RAD); + } + + if (name.equals("barrel")) { + float a = animatable.getTurretYaw(partialTick); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setRotX( + -Mth.lerp(partialTick, animatable.turretXRotO, animatable.getTurretXRot()) * Mth.DEG_TO_RAD + - r * animatable.getPitch(partialTick) * Mth.DEG_TO_RAD + - r2 * animatable.getRoll(partialTick) * Mth.DEG_TO_RAD + ); + } + + if (name.equals("jiqiang")) { + bone.setRotY(Mth.lerp(partialTick, animatable.gunYRotO, animatable.getGunYRot()) * Mth.DEG_TO_RAD - Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * Mth.DEG_TO_RAD); + } + if (name.equals("qiangguan")) { + float a = animatable.getTurretYaw(partialTick); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setRotX(Mth.clamp( + -Mth.lerp(partialTick, animatable.gunXRotO, animatable.getGunXRot()) * Mth.DEG_TO_RAD + - r * animatable.getPitch(partialTick) * Mth.DEG_TO_RAD + - r2 * animatable.getRoll(partialTick) * Mth.DEG_TO_RAD, + -10 * Mth.DEG_TO_RAD, 60 * Mth.DEG_TO_RAD) + ); + } + + if (name.equals("flare")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + if (name.equals("flare2")) { + bone.setRotZ((float) (0.5 * (Math.random() - 0.5))); + } + + if (name.equals("leida") && animatable.getEnergy() > 0) { + bone.setRotY((System.currentTimeMillis() % 36000000) / 300f); + } + + if (name.equals("base")) { + + Player player = Minecraft.getInstance().player; + bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player); + + float a = animatable.getEntityData().get(YAW); + float r = (Mth.abs(a) - 90f) / 90f; + + bone.setPosZ(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 1.75f); + bone.setRotX(r * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD); + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + bone.setPosX(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * 1f); + bone.setRotZ(r2 * Mth.lerp(partialTick, (float) animatable.recoilShakeO, (float) animatable.getRecoilShake()) * Mth.DEG_TO_RAD * 1.5f); + } + + for (int i = 0; i < 41; i++) { + float tO = animatable.leftTrackO + 2 * i; + float t = animatable.getLeftTrack() + 2 * i; + + while (t >= 80) { + t -= 80; + } + while (t <= 0) { + t += 80; + } + while (tO >= 80) { + tO -= 80; + } + while (tO <= 0) { + tO += 80; + } + + float tO2 = animatable.rightTrackO + 2 * i; + float t2 = animatable.getRightTrack() + 2 * i; + + while (t2 >= 80) { + t2 -= 80; + } + while (t2 <= 0) { + t2 += 80; + } + while (tO2 >= 80) { + tO2 -= 80; + } + while (tO2 <= 0) { + tO2 += 80; + } + + if (name.equals("trackL" + i)) { + bone.setPosY(Mth.lerp(partialTick, getBoneMoveY(tO), getBoneMoveY(t))); + bone.setPosZ(Mth.lerp(partialTick, getBoneMoveZ(tO), getBoneMoveZ(t))); + } + + if (name.equals("trackR" + i)) { + bone.setPosY(Mth.lerp(partialTick, getBoneMoveY(tO2), getBoneMoveY(t2))); + bone.setPosZ(Mth.lerp(partialTick, getBoneMoveZ(tO2), getBoneMoveZ(t2))); + } + + if (name.equals("trackLRot" + i)) { + bone.setRotX(-Mth.lerp(partialTick, getBoneRotX(tO), getBoneRotX(t)) * Mth.DEG_TO_RAD); + } + + if (name.equals("trackRRot" + i)) { + bone.setRotX(-Mth.lerp(partialTick, getBoneRotX(tO2), getBoneRotX(t2)) * Mth.DEG_TO_RAD); + } + + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); + } + + public float getBoneRotX(float t) { + if (t <= 32.5833) return 0F; + if (t <= 33.5833) return Mth.lerp(t - 32.5833F, 0F, -45F); + if (t <= 34.5833) return Mth.lerp(t - 33.5833F, -45F, -90F); + if (t <= 36.8333) return Mth.lerp((t - 34.5833F) / (36.8333F - 34.5833F), -90F, -150F); + if (t <= 40.5833) return -150F; + if (t <= 41.0833) return Mth.lerp((t - 40.5833F) / (41.0833F - 40.5833F), -150F, -180F); + if (t <= 70) return -180F; + if (t <= 71) return Mth.lerp(t - 70F, -180F, -210F); + if (t <= 74.25) return -210F; + if (t <= 76.5) return Mth.lerp((t - 74.25F) / (76.5F - 74.25F), -210F, -270F); + if (t <= 77.5) return Mth.lerp(t - 76.5F, -270F, -315F); + if (t <= 79.75) return Mth.lerp((t - 77.5F) / (79.75F - 77.5F), -315F, -360F); + + return 0F; + } + + public float getBoneMoveY(float t) { + if (t <= 32.5833) return 0F; + if (t <= 33.0833) return Mth.lerp((t - 32.5833F) / (33.0833F - 32.5833F), 0F, -1F); + if (t <= 34.0833) return Mth.lerp(t - 33.0833F, -1F, -2.5F); + if (t <= 35.5833) return Mth.lerp((t - 34.0833F) / (35.5833F - 34.0833F), -2.5F, -7.5F); + if (t <= 36.8333) return Mth.lerp((t - 35.5833F) / (36.8333F - 35.5833F), -7.5F, -12.25F); + if (t <= 41.0833) return Mth.lerp((t - 36.8333F) / (41.0833F - 36.8333F), -12.25F, -20.9F); + if (t <= 70) return -20.9F; + if (t <= 74.25) return Mth.lerp((t - 70F) / (74.25F - 70F), -20.9F, -12.25F); + if (t <= 76) return Mth.lerp((t - 74.25F) / (76F - 74.25F), -12.25F, -7.5F); + if (t <= 77.75) return Mth.lerp((t - 76F) / (77.75F - 76F), -7.5F, -2F); + if (t <= 79.25) return Mth.lerp((t - 77.75F) / (79.25F - 77.75F), -2F, -0.3F); + + return Mth.lerp((t - 79.25F) / (80F - 79.25F), -0.3F, 0F); + } + + public float getBoneMoveZ(float t) { + if (t <= 32.5833) return Mth.lerp(t / (32.5833F - 0F), 0F, 135.6F); + if (t <= 33.0833) return Mth.lerp((t - 32.5833F) / (33.0833F - 32.5833F), 135.6F, 137.75F); + if (t <= 34.0833) return Mth.lerp(t - 33.0833F, 137.75F, 140.25F); + if (t <= 35.5833) return 140.25F; + if (t <= 36.8333) return Mth.lerp((t - 35.5833F) / (36.8333F - 35.5833F), 140.25F, 137.25F); + if (t <= 41.0833) return Mth.lerp((t - 36.8333F) / (41.0833F - 36.8333F), 137.25F, 121.5F); + if (t <= 70) return Mth.lerp((t - 41.0833F) / (70F - 41.0833F), 121.5F, 11.5F); + if (t <= 74.25) return Mth.lerp((t - 70F) / (74.25F - 70F), 11.5F, -3.75F); + if (t <= 76) return Mth.lerp((t - 74.25F) / (76F - 74.25F), -3.75F, -10F); + if (t <= 77.75) return Mth.lerp((t - 76F) / (77.75F - 76F), -10F, -8.25F); + if (t <= 79.25) return Mth.lerp((t - 77.75F) / (79.25F - 77.75F), -8.25F, -4.12F); + + return Mth.lerp((t - 79.25F) / (80F - 79.25F), -4.12F, 0F); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/item/LungeMineRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/item/LungeMineRenderer.java new file mode 100644 index 000000000..b0b0fc821 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/item/LungeMineRenderer.java @@ -0,0 +1,116 @@ +package com.atsuishio.superbwarfare.client.renderer.item; + +import com.atsuishio.superbwarfare.client.AnimationHelper; +import com.atsuishio.superbwarfare.client.model.item.LungeMineModel; +import com.atsuishio.superbwarfare.item.LungeMine; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.PlayerModel; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.player.PlayerRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.cache.object.GeoBone; +import software.bernie.geckolib.renderer.GeoItemRenderer; +import software.bernie.geckolib.util.RenderUtil; + +import java.util.HashSet; +import java.util.Set; + +public class LungeMineRenderer extends GeoItemRenderer { + + public LungeMineRenderer() { + super(new LungeMineModel()); + } + + @Override + public RenderType getRenderType(LungeMine animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + private static final float SCALE_RECIPROCAL = 1.0f / 16.0f; + protected boolean renderArms = false; + protected MultiBufferSource currentBuffer; + protected RenderType renderType; + public ItemDisplayContext transformType; + protected LungeMine animatable; + private final Set hiddenBones = new HashSet<>(); + + @Override + public void renderByItem(ItemStack stack, ItemDisplayContext transformType, PoseStack matrixStack, MultiBufferSource bufferIn, int combinedLightIn, int p_239207_6_) { + this.transformType = transformType; + if (this.animatable != null) + this.animatable.getTransformType(transformType); + super.renderByItem(stack, transformType, matrixStack, bufferIn, combinedLightIn, p_239207_6_); + } + + @Override + public void actuallyRender(PoseStack matrixStackIn, LungeMine animatable, BakedGeoModel model, RenderType type, MultiBufferSource renderTypeBuffer, VertexConsumer vertexBuilder, boolean isRenderer, float partialTicks, int packedLightIn, + int packedOverlayIn, int color) { + this.currentBuffer = renderTypeBuffer; + this.renderType = type; + this.animatable = animatable; + super.actuallyRender(matrixStackIn, animatable, model, type, renderTypeBuffer, vertexBuilder, isRenderer, partialTicks, packedLightIn, packedOverlayIn, color); + if (this.renderArms) { + this.renderArms = false; + } + } + + @Override + public void renderRecursively(PoseStack stack, LungeMine animatable, GeoBone bone, RenderType type, MultiBufferSource buffer, VertexConsumer bufferIn, boolean isReRender, float partialTick, int packedLightIn, int packedOverlayIn, int color) { + Minecraft mc = Minecraft.getInstance(); + String name = bone.getName(); + boolean renderingArms = false; + if (name.equals("Lefthand") || name.equals("Righthand")) { + bone.setHidden(true); + renderingArms = true; + } else { + bone.setHidden(this.hiddenBones.contains(name)); + } + + if (this.transformType.firstPerson() && renderingArms) { + AbstractClientPlayer localPlayer = mc.player; + + if (localPlayer == null) { + return; + } + + PlayerRenderer playerRenderer = (PlayerRenderer) mc.getEntityRenderDispatcher().getRenderer(localPlayer); + PlayerModel model = playerRenderer.getModel(); + stack.pushPose(); + RenderUtil.translateMatrixToBone(stack, bone); + RenderUtil.translateToPivotPoint(stack, bone); + RenderUtil.rotateMatrixAroundBone(stack, bone); + RenderUtil.scaleMatrixForBone(stack, bone); + RenderUtil.translateAwayFromPivotPoint(stack, bone); + ResourceLocation loc = localPlayer.getSkin().texture(); + VertexConsumer armBuilder = this.currentBuffer.getBuffer(RenderType.entitySolid(loc)); + VertexConsumer sleeveBuilder = this.currentBuffer.getBuffer(RenderType.entityTranslucent(loc)); + if (name.equals("Lefthand")) { + stack.translate(-1.0f * SCALE_RECIPROCAL, 2.0f * SCALE_RECIPROCAL, 0.0f); + AnimationHelper.renderPartOverBone2(model.leftArm, bone, stack, armBuilder, packedLightIn, OverlayTexture.NO_OVERLAY, 1); + AnimationHelper.renderPartOverBone2(model.leftSleeve, bone, stack, sleeveBuilder, packedLightIn, OverlayTexture.NO_OVERLAY, 1); + } else { + stack.translate(SCALE_RECIPROCAL, 2.0f * SCALE_RECIPROCAL, 0.0f); + AnimationHelper.renderPartOverBone2(model.rightArm, bone, stack, armBuilder, packedLightIn, OverlayTexture.NO_OVERLAY, 1); + AnimationHelper.renderPartOverBone2(model.rightSleeve, bone, stack, sleeveBuilder, packedLightIn, OverlayTexture.NO_OVERLAY, 1); + } + + this.currentBuffer.getBuffer(this.renderType); + stack.popPose(); + } + super.renderRecursively(stack, animatable, bone, type, buffer, bufferIn, isReRender, partialTick, packedLightIn, packedOverlayIn, color); + } + + @Override + public ResourceLocation getTextureLocation(LungeMine instance) { + return super.getTextureLocation(instance); + } +} + diff --git a/src/main/java/com/atsuishio/superbwarfare/command/ConfigCommand.java b/src/main/java/com/atsuishio/superbwarfare/command/ConfigCommand.java index bc6915967..0d5f0e1d0 100644 --- a/src/main/java/com/atsuishio/superbwarfare/command/ConfigCommand.java +++ b/src/main/java/com/atsuishio/superbwarfare/command/ConfigCommand.java @@ -16,6 +16,7 @@ public class ConfigCommand { .then(Commands.literal("explosionDestroy").requires(s -> s.hasPermission(2)).then(Commands.argument("value", BoolArgumentType.bool()).executes(context -> { var value = BoolArgumentType.getBool(context, "value"); ExplosionConfig.EXPLOSION_DESTROY.set(value); + ExplosionConfig.EXPLOSION_DESTROY.save(); context.getSource().sendSuccess(() -> Component.translatable(value ? "commands.config.explosion_destroy.enabled" : "commands.config.explosion_destroy.disabled"), true); return 0; diff --git a/src/main/java/com/atsuishio/superbwarfare/compat/jade/SbwJadePlugin.java b/src/main/java/com/atsuishio/superbwarfare/compat/jade/SbwJadePlugin.java index 6f00068f5..918581da7 100644 --- a/src/main/java/com/atsuishio/superbwarfare/compat/jade/SbwJadePlugin.java +++ b/src/main/java/com/atsuishio/superbwarfare/compat/jade/SbwJadePlugin.java @@ -1,8 +1,10 @@ package com.atsuishio.superbwarfare.compat.jade; import com.atsuishio.superbwarfare.block.ContainerBlock; +import com.atsuishio.superbwarfare.compat.jade.providers.C4InfoProvider; import com.atsuishio.superbwarfare.compat.jade.providers.ContainerEntityProvider; import com.atsuishio.superbwarfare.compat.jade.providers.VehicleHealthProvider; +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import snownee.jade.api.IWailaClientRegistration; import snownee.jade.api.IWailaCommonRegistration; @@ -19,8 +21,7 @@ public class SbwJadePlugin implements IWailaPlugin { @Override public void registerClient(IWailaClientRegistration registration) { registration.registerEntityComponent(VehicleHealthProvider.INSTANCE, VehicleEntity.class); - // TODO C4 -// registration.registerEntityComponent(C4InfoProvider.INSTANCE, C4Entity.class); + registration.registerEntityComponent(C4InfoProvider.INSTANCE, C4Entity.class); registration.registerBlockComponent(ContainerEntityProvider.INSTANCE, ContainerBlock.class); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/compat/jade/providers/C4InfoProvider.java b/src/main/java/com/atsuishio/superbwarfare/compat/jade/providers/C4InfoProvider.java index c8c718217..0a7e16725 100644 --- a/src/main/java/com/atsuishio/superbwarfare/compat/jade/providers/C4InfoProvider.java +++ b/src/main/java/com/atsuishio/superbwarfare/compat/jade/providers/C4InfoProvider.java @@ -1,6 +1,10 @@ package com.atsuishio.superbwarfare.compat.jade.providers; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import snownee.jade.api.EntityAccessor; import snownee.jade.api.IEntityComponentProvider; @@ -13,20 +17,19 @@ public enum C4InfoProvider implements IEntityComponentProvider { private static final ResourceLocation ID = ModUtils.loc("c4_info"); public void appendTooltip(ITooltip tooltip, EntityAccessor accessor, IPluginConfig config) { - // TODO C4 Info -// var c4 = (C4Entity) accessor.getEntity(); -// -// if (c4.getEntityData().get(C4Entity.IS_CONTROLLABLE)) { -// // 遥控 -// tooltip.add(Component.translatable("des.jade_plugin_superbwarfare.c4.remote_control").withStyle(ChatFormatting.YELLOW)); -// } else { -// // 定时 -// var timeLeft = ExplosionConfig.C4_EXPLOSION_COUNTDOWN.get() - c4.tickCount; -// tooltip.add(Component.translatable( -// "des.jade_plugin_superbwarfare.c4.time_left", -// String.format("%.2f", timeLeft / 20.0) -// ).withStyle(ChatFormatting.YELLOW)); -// } + var c4 = (C4Entity) accessor.getEntity(); + + if (c4.getEntityData().get(C4Entity.IS_CONTROLLABLE)) { + // 遥控 + tooltip.add(Component.translatable("des.jade_plugin_superbwarfare.c4.remote_control").withStyle(ChatFormatting.YELLOW)); + } else { + // 定时 + var timeLeft = ExplosionConfig.C4_EXPLOSION_COUNTDOWN.get() - c4.tickCount; + tooltip.add(Component.translatable( + "des.jade_plugin_superbwarfare.c4.time_left", + String.format("%.2f", timeLeft / 20.0) + ).withStyle(ChatFormatting.YELLOW)); + } } public ResourceLocation getUid() { diff --git a/src/main/java/com/atsuishio/superbwarfare/component/ModDataComponents.java b/src/main/java/com/atsuishio/superbwarfare/component/ModDataComponents.java index 7138b7fba..fdbad44c8 100644 --- a/src/main/java/com/atsuishio/superbwarfare/component/ModDataComponents.java +++ b/src/main/java/com/atsuishio/superbwarfare/component/ModDataComponents.java @@ -8,7 +8,6 @@ import com.mojang.serialization.Codec; import net.minecraft.core.BlockPos; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.neoforged.bus.api.IEventBus; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; @@ -40,11 +39,6 @@ public class ModDataComponents { builder -> builder.persistent(AmmoBoxInfo.CODEC) ); - public static final DeferredHolder, DataComponentType> GUN_DATA = register( - "gun_data", - builder -> builder.persistent(CompoundTag.CODEC) - ); - private static DeferredHolder, DataComponentType> register(String name, UnaryOperator> builderOperator) { return DATA_COMPONENT_TYPES.register(name, () -> builderOperator.apply(DataComponentType.builder()).build()); } diff --git a/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java b/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java index df1a254eb..6e4bfbe7f 100644 --- a/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java +++ b/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java @@ -33,15 +33,13 @@ public class ModItemModelProvider extends ItemModelProvider { simpleItem(ModItems.LARGE_MOTOR); simpleItem(ModItems.WHEEL); simpleItem(ModItems.TRACK); - // TODO drone -// simpleItem(ModItems.DRONE); + simpleItem(ModItems.DRONE); simpleItem(ModItems.LIGHT_ARMAMENT_MODULE); simpleItem(ModItems.MEDIUM_ARMAMENT_MODULE); simpleItem(ModItems.HEAVY_ARMAMENT_MODULE); simpleItem(ModItems.TARGET_DEPLOYER); - // TODO mortar -// simpleItem(ModItems.MORTAR_DEPLOYER); + simpleItem(ModItems.MORTAR_DEPLOYER); simpleItem(ModItems.MORTAR_BARREL); simpleItem(ModItems.MORTAR_BASE_PLATE); simpleItem(ModItems.MORTAR_BIPOD); @@ -71,8 +69,7 @@ public class ModItemModelProvider extends ItemModelProvider { simpleItem(ModItems.RAW_SILVER); simpleItem(ModItems.SILVER_INGOT); handheldItem(ModItems.CROWBAR); - // TODO defuser -// handheldItem(ModItems.DEFUSER); + handheldItem(ModItems.DEFUSER); simpleItem(ModItems.FIRING_PARAMETERS); simpleItem(ModItems.BEAM_TEST); simpleItem(ModItems.HANDGUN_AMMO); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/ClaymoreEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/ClaymoreEntity.java new file mode 100644 index 000000000..8edb978f9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/ClaymoreEntity.java @@ -0,0 +1,275 @@ +package com.atsuishio.superbwarfare.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.init.*; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +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.server.players.OldUsersConverter; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.ThrownPotion; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.items.ItemHandlerHelper; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.Nullable; +import java.util.Comparator; +import java.util.Optional; +import java.util.UUID; + +public class ClaymoreEntity extends Entity implements GeoEntity, OwnableEntity { + + protected static final EntityDataAccessor> OWNER_UUID = SynchedEntityData.defineId(ClaymoreEntity.class, EntityDataSerializers.OPTIONAL_UUID); + protected static final EntityDataAccessor LAST_ATTACKER_UUID = SynchedEntityData.defineId(ClaymoreEntity.class, EntityDataSerializers.STRING); + public static final EntityDataAccessor HEALTH = SynchedEntityData.defineId(ClaymoreEntity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public ClaymoreEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public ClaymoreEntity(LivingEntity owner, Level level) { + super(ModEntities.CLAYMORE.get(), level); + this.setOwnerUUID(owner.getUUID()); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(OWNER_UUID, Optional.empty()) + .define(LAST_ATTACKER_UUID, "undefined") + .define(HEALTH, 10f); + } + + @Override + public boolean isPickable() { + return !this.isRemoved(); + } + + @Override + public boolean hurt(DamageSource source, float amount) { + if (source.getDirectEntity() instanceof ThrownPotion || source.getDirectEntity() instanceof AreaEffectCloud) + return false; + if (source.is(DamageTypes.FALL)) + return false; + if (source.is(DamageTypes.CACTUS)) + return false; + if (source.is(DamageTypes.DROWN)) + return false; + if (source.is(DamageTypes.DRAGON_BREATH)) + return false; + if (source.is(DamageTypes.WITHER)) + return false; + if (source.is(DamageTypes.WITHER_SKULL)) + return false; + if (source.is(ModDamageTypes.CUSTOM_EXPLOSION) || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.PROJECTILE_BOOM)) { + amount *= 0.2f; + } + + if (source.getEntity() != null) { + this.entityData.set(LAST_ATTACKER_UUID, source.getEntity().getStringUUID()); + } + + if (this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ModParticleTypes.FIRE_STAR.get(), this.getX(), this.getY() + 0.2, this.getZ(), 2, 0.02, 0.02, 0.02, 0.1, false); + } + this.level().playSound(null, this.getOnPos(), ModSounds.HIT.get(), SoundSource.PLAYERS, 1, 1); + this.entityData.set(HEALTH, this.entityData.get(HEALTH) - amount); + + return super.hurt(source, amount); + } + + public void setOwnerUUID(@Nullable UUID pUuid) { + this.entityData.set(OWNER_UUID, Optional.ofNullable(pUuid)); + } + + @Nullable + public UUID getOwnerUUID() { + return this.entityData.get(OWNER_UUID).orElse(null); + } + + public boolean isOwnedBy(LivingEntity pEntity) { + return pEntity == this.getOwner(); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + compound.putFloat("Health", this.entityData.get(HEALTH)); + compound.putString("LastAttacker", this.entityData.get(LAST_ATTACKER_UUID)); + if (this.getOwnerUUID() != null) { + compound.putUUID("Owner", this.getOwnerUUID()); + } + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + if (compound.contains("Health")) { + this.entityData.set(HEALTH, compound.getFloat("Health")); + } + + if (compound.contains("LastAttacker")) { + this.entityData.set(LAST_ATTACKER_UUID, compound.getString("LastAttacker")); + } + + UUID uuid; + if (compound.hasUUID("Owner")) { + uuid = compound.getUUID("Owner"); + } else { + String s = compound.getString("Owner"); + + assert this.getServer() != null; + uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s); + } + + if (uuid != null) { + try { + this.setOwnerUUID(uuid); + } catch (Throwable ignored) { + } + } + } + + @Override + public InteractionResult interact(Player player, InteractionHand hand) { + if (this.isOwnedBy(player) && player.isShiftKeyDown()) { + if (!this.level().isClientSide()) { + this.discard(); + } + + if (!player.getAbilities().instabuild) { + ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.CLAYMORE_MINE.get())); + } + } + + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + + @Override + public void tick() { + super.tick(); + var level = this.level(); + var x = this.getX(); + var y = this.getY(); + var z = this.getZ(); + + if (this.tickCount >= 12000) { + if (!this.level().isClientSide()) this.discard(); + } + + if (this.tickCount >= 40) { + final Vec3 center = new Vec3(x + 1.5 * this.getLookAngle().x, y + 1.5 * this.getLookAngle().y, z + 1.5 * this.getLookAngle().z); + for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(2.5 / 2d), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + var condition = this.getOwner() != target + && (target instanceof LivingEntity || target instanceof VehicleEntity) + && !(target instanceof TargetEntity) + && !(target instanceof Player player && (player.isCreative() || player.isSpectator())) + && (this.getOwner() != null && !this.getOwner().isAlliedTo(target) || target.getTeam() == null || target.getTeam().getName().equals("TDM")) + && !target.isShiftKeyDown(); + if (!condition) continue; + + if (!level.isClientSide()) { + if (!this.level().isClientSide()) { + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + this.discard(); + } + + ModUtils.queueServerWork(1, () -> { + if (!level.isClientSide()) { + triggerExplode(); + } + }); + break; + } + } + + this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.03, 0.0)); + + if (!this.level().noCollision(this.getBoundingBox())) { + this.moveTowardsClosestSpace(this.getX(), (this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0, this.getZ()); + } + + this.move(MoverType.SELF, this.getDeltaMovement()); + float f = 0.98F; + if (this.onGround()) { + BlockPos pos = this.getBlockPosBelowThatAffectsMyMovement(); + f = this.level().getBlockState(pos).getFriction(this.level(), pos, this) * 0.98F; + } + + this.setDeltaMovement(this.getDeltaMovement().multiply(f, 0.98, f)); + if (this.onGround()) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, -0.9, 1.0)); + } + + if (this.entityData.get(HEALTH) <= 0) { + destroy(); + } + + this.refreshDimensions(); + } + + public void destroy() { + if (level() instanceof ServerLevel) { + Entity attacker = EntityFindUtil.findEntity(this.level(), this.entityData.get(LAST_ATTACKER_UUID)); + CustomExplosion explosion = new CustomExplosion(this.level(), attacker == null ? this : attacker, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), attacker == null ? this : attacker, attacker == null ? this : attacker), 25.0f, + this.getX(), this.getY(), this.getZ(), 5f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + this.discard(); + } + } + + private void triggerExplode() { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeMineDamage(this.level().registryAccess(), this.getOwner()), 140f, + this.getX(), this.getEyeY(), this.getZ(), 4f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + } + + @Override + public @NotNull EntityDimensions getDimensions(@NotNull Pose p_33597_) { + return super.getDimensions(p_33597_).scale((float) 0.5); + } + + @Override + public boolean isPushable() { + return true; + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/MortarEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/MortarEntity.java new file mode 100644 index 000000000..e00584805 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/MortarEntity.java @@ -0,0 +1,293 @@ +package com.atsuishio.superbwarfare.entity; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.gui.RangeHelper; +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.NBTTool; +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 FIRE_TIME = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor PITCH = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor YAW = SynchedEntityData.defineId(MortarEntity.class, EntityDataSerializers.FLOAT); + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public MortarEntity(EntityType 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; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @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); + } + ModUtils.queueServerWork(20, () -> { + Level level = this.level(); + if (level instanceof ServerLevel server) { + MortarShellEntity entityToSpawn = shell.createShell(player, level, stack); + entityToSpawn.setPos(this.getX(), 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 tag = NBTTool.getTag(stack); + double targetX = tag.getDouble("TargetX"); + double targetY = tag.getDouble("TargetY"); + double targetZ = tag.getDouble("TargetZ"); + + this.look(new Vec3(targetX, targetY, targetZ)); + + double[] angles = new double[2]; + boolean flag = RangeHelper.canReachTarget(11.4, 0.146, 0.99, + new Vec3(this.getX(), this.getEyeY(), this.getZ()), + new Vec3(targetX, targetY, targetZ), + angles); + + if (flag) { + entityData.set(PITCH, (float) -angles[1]); + } + + return flag; + } + + 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 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); + this.discard(); + } + } + + @Override + public float getMaxHealth() { + return 100; + } + + public String getSyncedAnimation() { + return null; + } + + public void setAnimation(String animation) { + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/SenpaiEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/SenpaiEntity.java new file mode 100644 index 000000000..ce3aeffb9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/SenpaiEntity.java @@ -0,0 +1,197 @@ +package com.atsuishio.superbwarfare.entity; + +import com.atsuishio.superbwarfare.init.ModSounds; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.ai.goal.FloatGoal; +import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; +import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; +import net.minecraft.world.entity.ai.goal.RandomStrollGoal; +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class SenpaiEntity extends Monster implements GeoEntity { + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public SenpaiEntity(EntityType type, Level world) { + super(type, world); + xpReward = 40; + setNoAi(false); + } + + @Override + public double getEyeY() { + return 1.75F; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.4, false) { + // TODO what is this? +// @Override +// protected double getAttackReachSqr(LivingEntity entity) { +// return this.mob.getBbWidth() * this.mob.getBbWidth() + entity.getBbWidth(); +// } + }); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this).setAlertOthers()); + this.goalSelector.addGoal(3, new RandomLookAroundGoal(this)); + this.goalSelector.addGoal(4, new FloatGoal(this)); + this.goalSelector.addGoal(5, new RandomStrollGoal(this, 0.8)); + this.targetSelector.addGoal(6, new NearestAttackableTargetGoal<>(this, Player.class, false, false)); + } + + + // TODO mob type +// @Override +// public MobType getMobType() { +// return MobType.ILLAGER; +// } + + + @Override + @ParametersAreNonnullByDefault + protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { + super.dropCustomDeathLoot(level, damageSource, recentlyHit); + + double random = Math.random(); + if (random < 0.01) { + this.spawnAtLocation(new ItemStack(Items.ENCHANTED_GOLDEN_APPLE)); + } else if (random < 0.2) { + this.spawnAtLocation(new ItemStack(Items.GOLDEN_APPLE)); + } else { + this.spawnAtLocation(new ItemStack(Items.APPLE)); + } + } + + @Override + public SoundEvent getAmbientSound() { + return ModSounds.IDLE.get(); + } + + @Override + @ParametersAreNonnullByDefault + public void playStepSound(BlockPos pos, BlockState blockIn) { + this.playSound(ModSounds.STEP.get(), 0.25f, 1); + } + + @Override + public SoundEvent getHurtSound(@NotNull DamageSource ds) { + return ModSounds.OUCH.get(); + } + + @Override + public SoundEvent getDeathSound() { + return ModSounds.GROWL.get(); + } + + @Override + public void addAdditionalSaveData(@NotNull CompoundTag compound) { + super.addAdditionalSaveData(compound); + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag compound) { + super.readAdditionalSaveData(compound); + } + + @Override + public void baseTick() { + super.baseTick(); + this.refreshDimensions(); + } + + @Override + protected @NotNull EntityDimensions getDefaultDimensions(@NotNull Pose pose) { + return super.getDefaultDimensions(pose).scale(1); + } + + @Override + public void aiStep() { + super.aiStep(); + this.updateSwingTime(); + } + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.23) + .add(Attributes.MAX_HEALTH, 24) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 5) + .add(Attributes.FOLLOW_RANGE, 64) + .add(Attributes.KNOCKBACK_RESISTANCE, 0.5); + } + + private PlayState movementPredicate(AnimationState event) { + if ((event.isMoving() || !(event.getLimbSwingAmount() > -0.15F && event.getLimbSwingAmount() < 0.15F)) && !this.isAggressive()) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.senpai.walk")); + } + if (this.isDeadOrDying()) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.senpai.die")); + } + if (this.isAggressive() && event.isMoving()) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.senpai.run")); + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.senpai.idle")); + } + + @Override + public void die(@NotNull DamageSource source) { + super.die(source); + } + + @Override + protected void tickDeath() { + ++this.deathTime; + if (this.deathTime == 540) { + this.remove(RemovalReason.KILLED); + this.dropExperience(null); + } + } + + public String getSyncedAnimation() { + return null; + } + + public void setAnimation(String animation) { + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 4, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/C4Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/C4Entity.java new file mode 100644 index 000000000..a209dc3c4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/C4Entity.java @@ -0,0 +1,402 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.sounds.SoundEvent; +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.*; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +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.*; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.items.ItemHandlerHelper; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import static com.atsuishio.superbwarfare.item.C4Bomb.TAG_CONTROL; + +public class C4Entity extends Projectile implements GeoEntity { + + protected static final EntityDataAccessor LAST_ATTACKER_UUID = SynchedEntityData.defineId(C4Entity.class, EntityDataSerializers.STRING); + protected static final EntityDataAccessor TARGET_UUID = SynchedEntityData.defineId(C4Entity.class, EntityDataSerializers.STRING); + public static final EntityDataAccessor IS_CONTROLLABLE = SynchedEntityData.defineId(C4Entity.class, EntityDataSerializers.BOOLEAN); + + public static final int DEFAULT_DEFUSE_PROGRESS = 100; + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + protected boolean inGround; + protected boolean onEntity; + @Nullable + private BlockState lastState; + + public C4Entity(EntityType type, Level level) { + super(type, level); + } + + public C4Entity(LivingEntity owner, Level level) { + super(ModEntities.C_4.get(), level); + this.setOwner(owner); + } + + public C4Entity(LivingEntity owner, Level level, boolean isControllable) { + super(ModEntities.C_4.get(), level); + this.setOwner(owner); + this.entityData.set(IS_CONTROLLABLE, isControllable); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(LAST_ATTACKER_UUID, "undefined"); + builder.define(TARGET_UUID, "undefined"); + builder.define(IS_CONTROLLABLE, false); + } + + @Override + public void addAdditionalSaveData(@NotNull CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putString("Target", this.entityData.get(TARGET_UUID)); + compound.putString("LastAttacker", this.entityData.get(LAST_ATTACKER_UUID)); + compound.putBoolean("IsControllable", this.entityData.get(IS_CONTROLLABLE)); + + if (this.lastState != null) { + compound.put("InBlockState", NbtUtils.writeBlockState(this.lastState)); + } + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag compound) { + super.readAdditionalSaveData(compound); + if (compound.contains("LastAttacker")) { + this.entityData.set(LAST_ATTACKER_UUID, compound.getString("LastAttacker")); + } + + if (compound.contains("Target")) { + this.entityData.set(TARGET_UUID, compound.getString("Target")); + } + + if (compound.contains("InBlockState", 10)) { + this.lastState = NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), compound.getCompound("InBlockState")); + } + + if (compound.contains("IsControllable")) { + this.entityData.set(IS_CONTROLLABLE, compound.getBoolean("IsControllable")); + } + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResult interact(Player player, InteractionHand hand) { + if (this.getOwner() == player && player.isShiftKeyDown()) { + if (!this.level().isClientSide()) { + this.discard(); + } + + if (!player.getAbilities().instabuild) { + ItemHandlerHelper.giveItemToPlayer(player, this.getItemStack()); + } + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + return InteractionResult.PASS; + } + + @Override + public void tick() { + super.tick(); + + if (!this.entityData.get(IS_CONTROLLABLE)) { + if (this.tickCount >= ExplosionConfig.C4_EXPLOSION_COUNTDOWN.get()) { + this.explode(); + } + + int countdown = ExplosionConfig.C4_EXPLOSION_COUNTDOWN.get(); + if (countdown - tickCount > 39 && tickCount % ((20 * (countdown - tickCount)) / countdown + 1) == 0) { + this.level().playSound(null, this.getOnPos(), ModSounds.C4_BEEP.get(), SoundSource.PLAYERS, 1, 1); + } + + if (tickCount == countdown - 39) { + this.level().playSound(null, this.getOnPos(), ModSounds.C4_FINAL.get(), SoundSource.PLAYERS, 2, 1); + } + } + + Vec3 motion = this.getDeltaMovement(); + if (this.xRotO == 0.0F && this.yRotO == 0.0F && !this.inGround) { + double d0 = motion.horizontalDistance(); + this.setYRot((float) (Mth.atan2(motion.x, motion.z) * (double) (180F / (float) Math.PI))); + this.setXRot((float) (Mth.atan2(motion.y, d0) * (double) (180F / (float) Math.PI))); + this.yRotO = this.getYRot(); + this.xRotO = this.getXRot(); + } + + BlockPos blockpos = this.blockPosition(); + BlockState blockstate = this.level().getBlockState(blockpos); + if (!blockstate.isAir()) { + VoxelShape voxelshape = blockstate.getCollisionShape(this.level(), blockpos); + if (!voxelshape.isEmpty()) { + Vec3 vec31 = this.position(); + + for (AABB aabb : voxelshape.toAabbs()) { + if (aabb.move(blockpos).contains(vec31)) { + this.inGround = true; + break; + } + } + } + } + + if (this.inGround) { + if (this.lastState != blockstate && this.shouldFall()) { + this.startFalling(); + } + } else if (!this.onEntity) { + Vec3 position = this.position(); + Vec3 nextPosition = position.add(motion); + HitResult hitresult = this.level().clip(new ClipContext(position, nextPosition, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)); + if (hitresult.getType() != HitResult.Type.MISS) { + nextPosition = hitresult.getLocation(); + } + + while (!this.isRemoved()) { + EntityHitResult entityhitresult = this.findHitEntity(position, nextPosition); + if (entityhitresult != null) { + hitresult = entityhitresult; + } + + if (hitresult != null && hitresult.getType() != HitResult.Type.MISS) { + this.onHit(hitresult); + this.hasImpulse = true; + break; + } + + if (entityhitresult == null) { + break; + } + + hitresult = null; + } + + if (this.isRemoved()) { + return; + } + + motion = this.getDeltaMovement(); + double pX = motion.x; + double pY = motion.y; + double pZ = motion.z; + + double nX = this.getX() + pX; + double nY = this.getY() + pY; + double nZ = this.getZ() + pZ; + + this.updateRotation(); + + float f = 0.99F; + if (this.isInWater()) { + for (int j = 0; j < 4; ++j) { + this.level().addParticle(ParticleTypes.BUBBLE, nX - pX * 0.25D, nY - pY * 0.25D, nZ - pZ * 0.25D, pX, pY, pZ); + } + + f = this.getWaterInertia(); + } + + this.setDeltaMovement(motion.scale(f)); + if (!this.isNoGravity()) { + Vec3 vec34 = this.getDeltaMovement(); + this.setDeltaMovement(vec34.x, vec34.y - (double) 0.05F, vec34.z); + } + + this.setPos(nX, nY, nZ); + this.checkInsideBlocks(); + } else { + Entity target = EntityFindUtil.findEntity(level(), entityData.get(TARGET_UUID)); + if (target != null) { + this.setPos(target.getX(), target.getY() + target.getBbHeight(), target.getZ()); + } else { + this.onEntity = false; + } + } + + this.refreshDimensions(); + } + + private boolean shouldFall() { + return this.inGround && this.level().noCollision((new AABB(this.position(), this.position())).inflate(0.06D)); + } + + private void startFalling() { + this.inGround = false; + Vec3 vec3 = this.getDeltaMovement(); + this.setDeltaMovement(vec3.multiply(this.random.nextFloat() * 0.2F, this.random.nextFloat() * 0.2F, this.random.nextFloat() * 0.2F)); + } + + @Override + @ParametersAreNonnullByDefault + public void move(MoverType pType, Vec3 pPos) { + super.move(pType, pPos); + if (pType != MoverType.SELF && this.shouldFall()) { + this.startFalling(); + } + } + + public void look(Vec3 pTarget) { + double d0 = pTarget.x; + double d1 = pTarget.y; + double d2 = pTarget.z; + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + setXRot(Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875)))); + setYHeadRot(getYRot()); + this.xRotO = getXRot(); + this.yRotO = getYRot(); + } + + @Override + protected void updateRotation() { + if (getDeltaMovement().length() > 0.05 && !inGround && !onEntity) { + super.updateRotation(); + } + } + + @Nullable + protected EntityHitResult findHitEntity(Vec3 pStartVec, Vec3 pEndVec) { + return ProjectileUtil.getEntityHitResult(this.level(), this, pStartVec, pEndVec, this.getBoundingBox().expandTowards(this.getDeltaMovement()).inflate(1.0D), this::canHitEntity); + } + + @Override + protected void onHit(HitResult pResult) { + switch (pResult.getType()) { + case BLOCK: + this.onHitBlock((BlockHitResult) pResult); + break; + case ENTITY: + this.onHitEntity((EntityHitResult) pResult); + break; + default: + break; + } + } + + @Override + protected void onHitEntity(@NotNull EntityHitResult pResult) { + super.onHitEntity(pResult); + Entity entity = pResult.getEntity(); + if (tickCount < 2 || entity == this.getVehicle() || entity instanceof C4Entity) return; + this.entityData.set(TARGET_UUID, entity.getStringUUID()); + this.onEntity = true; + this.setDeltaMovement(this.getDeltaMovement().multiply(0, 0, 0)); + this.setXRot(-90); + this.xRotO = this.getXRot(); + } + + @Override + protected void onHitBlock(BlockHitResult pResult) { + this.lastState = this.level().getBlockState(pResult.getBlockPos()); + super.onHitBlock(pResult); + Vec3 vec3 = pResult.getLocation().subtract(this.getX(), this.getY(), this.getZ()); + this.setDeltaMovement(vec3); + Vec3 vec31 = vec3.normalize().scale(0.05F); + this.setPosRaw(this.getX() - vec31.x, this.getY() - vec31.y, this.getZ() - vec31.z); + + this.look(Vec3.atLowerCornerOf(pResult.getDirection().getNormal())); + this.setYRot((float) (pResult.getDirection().get2DDataValue() * 90)); + + BlockPos resultPos = pResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + SoundEvent event = state.getBlock().getSoundType(state, this.level(), resultPos, this).getBreakSound(); + double speed = this.getDeltaMovement().length(); + if (speed > 0.1) { + this.level().playSound(null, pResult.getLocation().x, pResult.getLocation().y, pResult.getLocation().z, event, SoundSource.AMBIENT, 1.0F, 1.0F); + } + this.inGround = true; + } + + public void explode() { + Vec3 pos = position(); + + if (onEntity) { + Entity target = EntityFindUtil.findEntity(level(), entityData.get(TARGET_UUID)); + if (target != null) { + pos = target.position(); + } + } + + CustomExplosion explosion = new CustomExplosion(level(), this, + ModDamageTypes.causeProjectileBoomDamage(level().registryAccess(), this, this.getOwner()), ExplosionConfig.C4_EXPLOSION_DAMAGE.get(), + pos.x, pos.y, pos.z, ExplosionConfig.C4_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(level(), explosion); + ParticleTool.spawnHugeExplosionParticles(level(), position()); + explosion.finalizeExplosion(false); + + this.discard(); + } + + @Override + public @NotNull EntityDimensions getDimensions(@NotNull Pose pPose) { + return super.getDimensions(pPose).scale((float) 0.5); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + protected float getWaterInertia() { + return 0.6F; + } + + @Override + public boolean isPickable() { + return true; + } + + public ItemStack getItemStack() { + ItemStack stack = new ItemStack(ModItems.C4_BOMB.get()); + if (this.getEntityData().get(IS_CONTROLLABLE)) { + NBTTool.setBoolean(stack, TAG_CONTROL, true); + } + return stack; + } + + public void defuse() { + this.discard(); + ItemEntity entity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), this.getItemStack()); + if (!this.level().isClientSide) { + this.level().addFreshEntity(entity); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java new file mode 100644 index 000000000..169915b9a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/CannonShellEntity.java @@ -0,0 +1,391 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.init.*; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.network.message.ClientMotionSyncMessage; +import com.atsuishio.superbwarfare.tools.ChunkLoadTool; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +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.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.HashSet; +import java.util.Set; + +public class CannonShellEntity extends FastThrowableProjectile implements GeoEntity { + + public static final EntityDataAccessor ANIMATION = SynchedEntityData.defineId(CannonShellEntity.class, EntityDataSerializers.STRING); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public String animationProcedure = "empty"; + private float damage = 0; + private float radius = 0; + private float explosionDamage = 0; + private float fireProbability = 0; + private int fireTime = 0; + private int durability = 40; + private boolean firstHit = true; + public Set loadedChunks = new HashSet<>(); + + public CannonShellEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public CannonShellEntity(LivingEntity entity, Level world, float damage, float radius, float explosionDamage, float fireProbability, int fireTime) { + super(ModEntities.CANNON_SHELL.get(), entity, world); + this.damage = damage; + this.radius = radius; + this.explosionDamage = explosionDamage; + this.fireProbability = fireProbability; + this.fireTime = fireTime; + } + + public CannonShellEntity durability(int durability) { + this.durability = durability; + return this; + } + + @Override + public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { + super.addAdditionalSaveData(pCompound); + + pCompound.putFloat("Damage", this.damage); + pCompound.putFloat("ExplosionDamage", this.explosionDamage); + pCompound.putFloat("Radius", this.radius); + pCompound.putFloat("FireProbability", this.fireProbability); + pCompound.putInt("FireTime", this.fireTime); + pCompound.putInt("Durability", this.durability); + + ListTag listTag = new ListTag(); + for (long chunkPos : this.loadedChunks) { + CompoundTag tag = new CompoundTag(); + tag.putLong("Pos", chunkPos); + listTag.add(tag); + } + pCompound.put("Chunks", listTag); + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { + super.readAdditionalSaveData(pCompound); + + if (pCompound.contains("Damage")) { + this.damage = pCompound.getFloat("Damage"); + } + + if (pCompound.contains("ExplosionDamage")) { + this.explosionDamage = pCompound.getFloat("ExplosionDamage"); + } + + if (pCompound.contains("Radius")) { + this.radius = pCompound.getFloat("Radius"); + } + + if (pCompound.contains("FireProbability")) { + this.fireProbability = pCompound.getFloat("FireProbability"); + } + + if (pCompound.contains("FireTime")) { + this.fireTime = pCompound.getInt("FireTime"); + } + + if (pCompound.contains("Durability")) { + this.durability = pCompound.getInt("Durability"); + } + + if (pCompound.contains("Chunks")) { + ListTag listTag = pCompound.getList("Chunks", 10); + for (int i = 0; i < listTag.size(); i++) { + CompoundTag tag = listTag.getCompound(i); + this.loadedChunks.add(tag.getLong("Pos")); + } + } + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.HE_5_INCHES.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + public void onHitEntity(@NotNull EntityHitResult entityHitResult) { + if (this.level() instanceof ServerLevel) { + Entity entity = entityHitResult.getEntity(); + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), this.damage); + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + ParticleTool.cannonHitParticles(this.level(), this.position(), this); + causeExplode(entity); + if (entity instanceof VehicleEntity) { + this.discard(); + } + + } + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + if (this.level() instanceof ServerLevel) { + int x = blockHitResult.getBlockPos().getX(); + int y = blockHitResult.getBlockPos().getY(); + int z = blockHitResult.getBlockPos().getZ(); + + BlockState blockState = this.level().getBlockState(BlockPos.containing(x, y, z)); + if (blockState.is(Blocks.BEDROCK) || blockState.is(Blocks.BARRIER)) { + this.discard(); + causeExplodeBlock(blockHitResult); + return; + } + + float hardness = this.level().getBlockState(BlockPos.containing(x, y, z)).getBlock().defaultDestroyTime(); + this.durability -= (int) hardness; + + if (ExplosionConfig.EXPLOSION_DESTROY.get() && hardness != -1 && hardness <= 50) { + BlockPos blockPos = BlockPos.containing(x, y, z); + Block.dropResources(this.level().getBlockState(blockPos), this.level(), BlockPos.containing(x, y, z), null); + this.level().destroyBlock(blockPos, true); + } + + if (blockState.is(ModBlocks.SANDBAG.get()) || blockState.is(Blocks.NETHERITE_BLOCK)) { + this.durability -= 10; + } + + if (blockState.is(Blocks.IRON_BLOCK) || blockState.is(Blocks.COPPER_BLOCK)) { + this.durability -= 5; + } + + if (blockState.is(Blocks.GOLD_BLOCK)) { + this.durability -= 3; + } + + if (this.durability <= 0) { + causeExplodeBlock(blockHitResult); + } else { + if (ExplosionConfig.EXPLOSION_DESTROY.get()) { + if (this.firstHit) { + ParticleTool.cannonHitParticles(this.level(), this.position(), this); + causeExplodeBlock(blockHitResult); + this.firstHit = false; + } + } + apExplode(blockHitResult); + } + } + } + + @Override + public void tick() { + super.tick(); + if (this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.001, true); + + // 更新需要加载的区块 + ChunkLoadTool.updateLoadedChunks(serverLevel, this, this.loadedChunks); + } + if (this.tickCount > 600 || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.radius, 1.25f); + } + this.discard(); + } + } + + @Override + public void syncMotion() { + if (!this.level().isClientSide) { + PacketDistributor.sendToAllPlayers(new ClientMotionSyncMessage(this)); + } + } + + private void causeExplode(Entity entity) { + if (Math.random() > fireProbability) { + fireTime = 0; + } + + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), + this, + this.getOwner()), + explosionDamage, + entity.getX(), + entity.getY() + 0.5 * entity.getBbHeight(), + entity.getZ(), + radius, + ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP). + setDamageMultiplier(1).setFireTime(fireTime); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + + if (radius > 7) { + ParticleTool.spawnHugeExplosionParticles(this.level(), new Vec3(entity.getX(), + entity.getY() + 0.5 * entity.getBbHeight(), + entity.getZ())); + } else { + ParticleTool.spawnMediumExplosionParticles(this.level(), new Vec3(entity.getX(), + entity.getY() + 0.5 * entity.getBbHeight(), + entity.getZ())); + } + } + + private void causeExplodeBlock(HitResult result) { + if (Math.random() > fireProbability) { + fireTime = 0; + } + + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), + this, + this.getOwner()), + explosionDamage, + this.getX(), + this.getY() + 0.5 * this.getBbHeight(), + this.getZ(), + radius, + ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP). + setDamageMultiplier(1).setFireTime(fireTime); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + + if (radius > 7) { + ParticleTool.spawnHugeExplosionParticles(this.level(), result.getLocation()); + } else { + ParticleTool.spawnMediumExplosionParticles(this.level(), result.getLocation()); + } + this.discard(); + } + + private void apExplode(HitResult result) { + if (Math.random() > fireProbability) { + fireTime = 0; + } + + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), + this, + this.getOwner()), + explosionDamage, + result.getLocation().x + 5 * getDeltaMovement().normalize().x, + result.getLocation().y + 5 * getDeltaMovement().normalize().y, + result.getLocation().z + 5 * getDeltaMovement().normalize().z, + radius, + ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP). + setDamageMultiplier(1).setFireTime(fireTime); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + + if (radius > 7) { + ParticleTool.spawnHugeExplosionParticles(this.level(), result.getLocation()); + } else { + ParticleTool.spawnMediumExplosionParticles(this.level(), result.getLocation()); + } + this.discard(); + } + + private PlayState movementPredicate(AnimationState event) { + if (this.animationProcedure.equals("empty")) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.cannon_shell.idle")); + } + return PlayState.STOP; + } + + private PlayState procedurePredicate(AnimationState event) { + if (!animationProcedure.equals("empty") && event.getController().getAnimationState() == AnimationController.State.STOPPED) { + event.getController().setAnimation(RawAnimation.begin().thenPlay(this.animationProcedure)); + if (event.getController().getAnimationState() == AnimationController.State.STOPPED) { + this.animationProcedure = "empty"; + event.getController().forceAnimationReset(); + } + } else if (animationProcedure.equals("empty")) { + return PlayState.STOP; + } + return PlayState.CONTINUE; + } + + @Override + protected double getDefaultGravity() { + return 0.05F; + } + + public void setAnimation(String animation) { + this.entityData.set(ANIMATION, animation); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + data.add(new AnimationController<>(this, "procedure", 0, this::procedurePredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public void onRemovedFromLevel() { + if (this.level() instanceof ServerLevel serverLevel) { + ChunkLoadTool.unloadAllChunks(serverLevel, this, this.loadedChunks); + } + super.onRemovedFromLevel(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java new file mode 100644 index 000000000..6daf5c7e4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FastThrowableProjectile.java @@ -0,0 +1,58 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.network.message.ClientMotionSyncMessage; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.ThrowableItemProjectile; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.entity.IEntityWithComplexSpawn; +import net.neoforged.neoforge.network.PacketDistributor; + +public abstract class FastThrowableProjectile extends ThrowableItemProjectile implements CustomSyncMotionEntity, IEntityWithComplexSpawn { + + public FastThrowableProjectile(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public FastThrowableProjectile(EntityType pEntityType, double pX, double pY, double pZ, Level pLevel) { + super(pEntityType, pX, pY, pZ, pLevel); + } + + public FastThrowableProjectile(EntityType pEntityType, LivingEntity pShooter, Level pLevel) { + super(pEntityType, pShooter, pLevel); + } + + @Override + public void tick() { + super.tick(); + this.syncMotion(); + } + + @Override + public void syncMotion() { + if (this.level().isClientSide) return; + if (!shouldSyncMotion()) return; + + if (this.tickCount % this.getType().updateInterval() == 0) { + PacketDistributor.sendToAllPlayers(new ClientMotionSyncMessage(this)); + } + } + + public boolean shouldSyncMotion() { + return false; + } + + @Override + public void writeSpawnData(RegistryFriendlyByteBuf buffer) { + var motion = this.getDeltaMovement(); + buffer.writeFloat((float) motion.x); + buffer.writeFloat((float) motion.y); + buffer.writeFloat((float) motion.z); + } + + @Override + public void readSpawnData(RegistryFriendlyByteBuf additionalData) { + this.setDeltaMovement(additionalData.readFloat(), additionalData.readFloat(), additionalData.readFloat()); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java new file mode 100644 index 000000000..38919d257 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/FlareDecoyEntity.java @@ -0,0 +1,71 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; + +public class FlareDecoyEntity extends Entity { + + public FlareDecoyEntity(EntityType type, Level world) { + super(type, world); + } + + public FlareDecoyEntity(LivingEntity entity, Level level) { + super(ModEntities.FLARE_DECOY.get(), level); + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { + } + + @Override + protected void addAdditionalSaveData(@NotNull CompoundTag compoundTag) { + } + + @Override + protected void defineSynchedData(SynchedEntityData.@NotNull Builder builder) { + } + + @Override + public void tick() { + super.tick(); + this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.02, 0.0)); + this.move(MoverType.SELF, this.getDeltaMovement()); + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.END_ROD, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.02, true); + ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.02, true); + } + if (this.tickCount > 200 || this.isInWater() || this.onGround()) { + this.discard(); + } + } + + public void decoyShoot(Entity entity, Vec3 shootVec, float pVelocity, float pInaccuracy) { + Vec3 vec3 = shootVec.normalize().add(this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy), this.random.triangle(0.0, 0.0172275 * (double) pInaccuracy)).scale((double) pVelocity); + this.setDeltaMovement(entity.getDeltaMovement().scale(0.75).add(vec3)); + double d0 = vec3.horizontalDistance(); + this.setYRot((float) (Mth.atan2(vec3.x, vec3.z) * 57.2957763671875)); + this.setXRot((float) (Mth.atan2(vec3.y, d0) * 57.2957763671875)); + this.yRotO = this.getYRot(); + this.xRotO = this.getXRot(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java new file mode 100644 index 000000000..909c5035a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/GunGrenadeEntity.java @@ -0,0 +1,178 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +public class GunGrenadeEntity extends FastThrowableProjectile implements GeoEntity { + + private float monsterMultiplier = 0.0f; + private float damage = 40.0f; + private float explosionDamage = 80f; + private float explosionRadius = 5f; + private boolean charged = false; + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public GunGrenadeEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public GunGrenadeEntity(LivingEntity entity, Level level, float damage, float explosionDamage, float explosionRadius) { + super(ModEntities.GUN_GRENADE.get(), entity, level); + this.damage = damage; + this.explosionDamage = explosionDamage; + this.explosionRadius = explosionRadius; + } + + public void setDamage(float damage) { + this.damage = damage; + } + + public void setExplosionDamage(float explosionDamage) { + this.explosionDamage = explosionDamage; + } + + public void setExplosionRadius(float explosionRadius) { + this.explosionRadius = explosionRadius; + } + + public void setCharged(boolean charged) { + this.charged = charged; + } + + public void setMonsterMultiplier(float monsterMultiplier) { + this.monsterMultiplier = monsterMultiplier; + } + + public void charged(boolean charged) { + this.charged = charged; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.GRENADE_40MM.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + float damageMultiplier = 1 + this.monsterMultiplier; + Entity entity = result.getEntity(); + + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + if (charged) { + damage *= 1.25f; + } + + if (entity instanceof Monster monster) { + monster.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), 1.2f * this.damage * damageMultiplier); + } else { + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), damage); + } + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.tickCount > 0) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + entity, this.explosionDamage, this.explosionRadius, this.monsterMultiplier); + } + } + + this.discard(); + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + BlockPos resultPos = blockHitResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockHitResult.getDirection()); + } + + if (this.tickCount > 0) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius, this.monsterMultiplier); + } + } + + this.discard(); + } + + @Override + public void tick() { + super.tick(); + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.02, true); + } + + if (this.tickCount > 200 || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius, this.monsterMultiplier); + } + this.discard(); + } + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java new file mode 100644 index 000000000..5fdc04d08 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HandGrenadeEntity.java @@ -0,0 +1,160 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +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.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +public class HandGrenadeEntity extends FastThrowableProjectile implements GeoEntity { + + private int fuse = 100; + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public HandGrenadeEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public HandGrenadeEntity(EntityType type, double x, double y, double z, Level world) { + super(type, x, y, z, world); + this.noCulling = true; + } + + public HandGrenadeEntity(LivingEntity entity, Level level, int fuse) { + super(ModEntities.HAND_GRENADE.get(), entity, level); + this.fuse = fuse; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.HAND_GRENADE.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHit(HitResult result) { + switch (result.getType()) { + case BLOCK: + BlockHitResult blockResult = (BlockHitResult) result; + BlockPos resultPos = blockResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + SoundEvent event = state.getBlock().getSoundType(state, this.level(), resultPos, this).getBreakSound(); + double speed = this.getDeltaMovement().length(); + if (speed > 0.1) { + this.level().playSound(null, result.getLocation().x, result.getLocation().y, result.getLocation().z, event, SoundSource.AMBIENT, 1.0F, 1.0F); + } + this.bounce(blockResult.getDirection()); + + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockResult.getDirection()); + } + + break; + case ENTITY: + EntityHitResult entityResult = (EntityHitResult) result; + Entity entity = entityResult.getEntity(); + if (entity == this.getOwner() || entity == this.getVehicle()) return; + double speed_e = this.getDeltaMovement().length(); + if (speed_e > 0.1) { + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + entity.hurt(entity.damageSources().thrown(this, this.getOwner()), 1.0F); + } + this.bounce(Direction.getNearest(this.getDeltaMovement().x(), this.getDeltaMovement().y(), this.getDeltaMovement().z()).getOpposite()); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.25, 1.0, 0.25)); + break; + default: + break; + } + } + + private void bounce(Direction direction) { + switch (direction.getAxis()) { + case X: + this.setDeltaMovement(this.getDeltaMovement().multiply(-0.5, 0.75, 0.75)); + break; + case Y: + this.setDeltaMovement(this.getDeltaMovement().multiply(0.75, -0.25, 0.75)); + if (this.getDeltaMovement().y() < this.getGravity()) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1, 0, 1)); + } + break; + case Z: + this.setDeltaMovement(this.getDeltaMovement().multiply(0.75, 0.75, -0.5)); + break; + } + } + + @Override + public void tick() { + super.tick(); + --this.fuse; + + if (this.fuse <= 0) { + this.discard(); + if (!this.level().isClientSide) { + ProjectileTool.causeCustomExplode(this, ExplosionConfig.M67_GRENADE_EXPLOSION_DAMAGE.get(), ExplosionConfig.M67_GRENADE_EXPLOSION_RADIUS.get(), 1.2f); + } + } + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.01, true); + } + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + protected double getDefaultGravity() { + return 0.07F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java new file mode 100644 index 000000000..8e9223975 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/HeliRocketEntity.java @@ -0,0 +1,168 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.ThrowableItemProjectile; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.Nullable; + +public class HeliRocketEntity extends FastThrowableProjectile implements GeoEntity { + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + private float damage = 140f; + private float explosionDamage = 60f; + private float explosionRadius = 5f; + + public HeliRocketEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public HeliRocketEntity(LivingEntity entity, Level level, float damage, float explosionDamage, float explosionRadius) { + super(ModEntities.HELI_ROCKET.get(), entity, level); + this.damage = damage; + this.explosionDamage = explosionDamage; + this.explosionRadius = explosionRadius; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.ROCKET.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + Entity entity = result.getEntity(); + if (entity == this.getOwner() || entity == this.getVehicle()) return; + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), this.damage); + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.tickCount > 1) { + if (this.level() instanceof ServerLevel) { + causeRocketExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + entity, this.explosionDamage, this.explosionRadius, 1); + } + } + + this.discard(); + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + if (this.tickCount > 1) { + if (this.level() instanceof ServerLevel) { + causeRocketExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius, 1); + } + } + + this.discard(); + } + + @Override + public void tick() { + super.tick(); + if (this.tickCount == 3) { + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, this.xo, this.yo, this.zo, 15, 0.8, 0.8, 0.8, 0.01, true); + ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, 10, 0.8, 0.8, 0.8, 0.01, true); + } + } + if (this.tickCount > 2) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1.025, 1.025, 1.025)); + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, 1, 0, 0, 0, 0, true); + } + } + + if (this.tickCount > 100 || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + causeRocketExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius, 1); + } + this.discard(); + } + } + + public static void causeRocketExplode(ThrowableItemProjectile projectile, @Nullable DamageSource source, Entity target, float damage, float radius, float damageMultiplier) { + CustomExplosion explosion = new CustomExplosion(projectile.level(), projectile, source, damage, + projectile.getX(), projectile.getY(), projectile.getZ(), radius, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(damageMultiplier); + explosion.explode(); + EventHooks.onExplosionStart(projectile.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(projectile.level(), projectile.position()); + projectile.discard(); + } + + private PlayState movementPredicate(AnimationState event) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.rpg.idle")); + } + + @Override + protected double getDefaultGravity() { + return 0.002f; + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java new file mode 100644 index 000000000..99fde47dd --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/JavelinMissileEntity.java @@ -0,0 +1,331 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +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.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.Pig; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.List; + +public class JavelinMissileEntity extends FastThrowableProjectile implements GeoEntity { + + public static final EntityDataAccessor TARGET_UUID = SynchedEntityData.defineId(JavelinMissileEntity.class, EntityDataSerializers.STRING); + public static final EntityDataAccessor TOP = SynchedEntityData.defineId(JavelinMissileEntity.class, EntityDataSerializers.BOOLEAN); + public static final EntityDataAccessor TARGET_X = SynchedEntityData.defineId(JavelinMissileEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor TARGET_Y = SynchedEntityData.defineId(JavelinMissileEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor TARGET_Z = SynchedEntityData.defineId(JavelinMissileEntity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + private float monsterMultiplier = 0.0f; + private float damage = 500.0f; + private float explosion_damage = 140f; + private float explosion_radius = 6f; + private boolean distracted = false; + private int guide_type = 0; + + public JavelinMissileEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public JavelinMissileEntity(LivingEntity entity, Level level, float damage, float explosion_damage, float explosion_radius, int guide_type, Vec3 targetPos) { + super(ModEntities.JAVELIN_MISSILE.get(), entity, level); + this.damage = damage; + this.explosion_damage = explosion_damage; + this.explosion_radius = explosion_radius; + this.guide_type = guide_type; + this.entityData.set(TARGET_X, (float) targetPos.x); + this.entityData.set(TARGET_Y, (float) targetPos.y); + this.entityData.set(TARGET_Z, (float) targetPos.z); + } + + public void setMonsterMultiplier(float monsterMultiplier) { + this.monsterMultiplier = monsterMultiplier; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.JAVELIN_MISSILE.get(); + } + + public void setTargetUuid(String uuid) { + this.entityData.set(TARGET_UUID, uuid); + } + + public void setAttackMode(boolean mode) { + this.entityData.set(TOP, mode); + } + + @Override + protected void defineSynchedData(SynchedEntityData.@NotNull Builder builder) { + super.defineSynchedData(builder); + builder.define(TARGET_UUID, "none") + .define(TOP, false) + .define(TARGET_X, 0f) + .define(TARGET_Y, 0f) + .define(TARGET_Z, 0f); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + float damageMultiplier = 1 + this.monsterMultiplier; + Entity entity = result.getEntity(); + if (entity == this.getOwner() || entity == this.getVehicle()) return; + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + if (entity instanceof Monster monster) { + monster.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), (entityData.get(TOP) ? 1.3f : 1f) * this.damage * damageMultiplier); + } else { + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), (entityData.get(TOP) ? 1.3f : 1f) * this.damage); + } + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.tickCount > 1) { + if (this.level() instanceof ServerLevel) { + causeExplode(result); + } + } + + this.discard(); + } + + @Override + public boolean isNoGravity() { + return true; + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + BlockPos resultPos = blockHitResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockHitResult.getDirection()); + } + + if (this.tickCount > 1) { + if (this.level() instanceof ServerLevel) { + causeExplode(blockHitResult); + } + } + + this.discard(); + } + + @Override + public void tick() { + super.tick(); + Entity entity = EntityFindUtil.findEntity(this.level(), entityData.get(TARGET_UUID)); + List decoy = SeekTool.seekLivingEntities(this, this.level(), 48, 160); + + for (var e : decoy) { + if (e instanceof FlareDecoyEntity flareDecoy && !distracted) { + this.entityData.set(TARGET_UUID, flareDecoy.getStringUUID()); + distracted = true; + } + } + + if (guide_type == 0 || !entityData.get(TARGET_UUID).equals("none")) { + if (entity != null) { + if (entity.level() instanceof ServerLevel) { + this.entityData.set(TARGET_X, (float) entity.getX()); + this.entityData.set(TARGET_Y, (float) entity.getY() + 0.5f * entity.getBbHeight()); + this.entityData.set(TARGET_Z, (float) entity.getZ()); + if ((!entity.getPassengers().isEmpty() || entity instanceof VehicleEntity) && entity.tickCount % ((int) Math.max(0.04 * this.distanceTo(entity), 2)) == 0) { + entity.level().playSound(null, entity.getOnPos(), entity instanceof Pig ? SoundEvents.PIG_HURT : ModSounds.MISSILE_WARNING.get(), SoundSource.PLAYERS, 2, 1f); + } + } + } + + + double px = this.getX(); + double ex = this.entityData.get(TARGET_X); + double pz = this.getZ(); + double ez = this.entityData.get(TARGET_Z); + boolean dir = Math.sqrt(Math.pow(px - ex, 2) + Math.pow(pz - ez, 2)) < 30; + Vec3 targetPos = new Vec3(this.entityData.get(TARGET_X), this.entityData.get(TARGET_Y) + (entity instanceof EnderDragon ? -3 : 0), this.entityData.get(TARGET_Z)); + if (entity != null) { + Vec3 toVec = getEyePosition().vectorTo(targetPos.add(entity.getDeltaMovement().scale(0.5))).normalize(); + if (this.tickCount > 3) { + if (entityData.get(TOP)) { + if (!dir) { + Vec3 targetTopPos = new Vec3(this.entityData.get(TARGET_X), this.entityData.get(TARGET_Y) + Mth.clamp(5 * this.tickCount, 0, 90), this.entityData.get(TARGET_Z)); + Vec3 toTopVec = getEyePosition().vectorTo(targetTopPos).normalize(); + setDeltaMovement(getDeltaMovement().add(toTopVec.scale(0.5))); + } else { + boolean lostTarget = this.getY() < entity.getY(); + if (!lostTarget) { + setDeltaMovement(getDeltaMovement().add(toVec.scale(1)).scale(0.87)); + } + } + } else { + boolean lostTarget = (VectorTool.calculateAngle(getDeltaMovement(), toVec) > 80); + if (!lostTarget) { + setDeltaMovement(getDeltaMovement().add(toVec.scale(1)).scale(0.87)); + } + } + } + } + } else if (guide_type == 1) { + double px = this.getX(); + double ex = this.entityData.get(TARGET_X); + double pz = this.getZ(); + double ez = this.entityData.get(TARGET_Z); + boolean dir = Math.sqrt(Math.pow(px - ex, 2) + Math.pow(pz - ez, 2)) < 30; + Vec3 targetPos = new Vec3(this.entityData.get(TARGET_X), this.entityData.get(TARGET_Y), this.entityData.get(TARGET_Z)); + Vec3 toVec = getEyePosition().vectorTo(targetPos).normalize(); + + if (this.tickCount > 3) { + if (entityData.get(TOP)) { + if (!dir) { + Vec3 targetTopPos = new Vec3(this.entityData.get(TARGET_X), this.entityData.get(TARGET_Y) + Mth.clamp(5 * this.tickCount, 0, 90), this.entityData.get(TARGET_Z)); + Vec3 toTopVec = getEyePosition().vectorTo(targetTopPos).normalize(); + setDeltaMovement(getDeltaMovement().add(toTopVec.scale(0.5))); + } else { + boolean lostTarget = this.getY() < this.entityData.get(TARGET_Y); + if (!lostTarget) { + setDeltaMovement(getDeltaMovement().add(toVec.scale(1)).scale(0.87)); + } + } + } else { + boolean lostTarget = (VectorTool.calculateAngle(getDeltaMovement(), toVec) > 80); + if (!lostTarget) { + setDeltaMovement(getDeltaMovement().add(toVec.scale(1)).scale(0.87)); + } + } + } + + } + + if (this.tickCount == 4) { + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, this.xo, this.yo, this.zo, 15, 0.8, 0.8, 0.8, 0.01, true); + ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, 10, 0.8, 0.8, 0.8, 0.01, true); + } + } + + if (this.tickCount > 4) { + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, 1, 0, 0, 0, 0, true); + } + } + + if (this.tickCount > 200 || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosion_damage, this.explosion_radius, this.monsterMultiplier); + } + this.discard(); + } + + // 控制速度 + if (this.getDeltaMovement().length() < 2.6) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1.06, 1.06, 1.06)); + } + + if (this.getDeltaMovement().length() > 2.9) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.9, 0.9, 0.9)); + } + + this.setDeltaMovement(this.getDeltaMovement().multiply(0.96, 0.96, 0.96)); + } + + private void causeExplode(HitResult result) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), + this, + this.getOwner()), + explosion_damage, + this.getX(), + this.getEyeY(), + this.getZ(), + explosion_radius, + ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP). + setDamageMultiplier(this.monsterMultiplier); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnSmallExplosionParticles(this.level(), result.getLocation()); + } + + private PlayState movementPredicate(AnimationState event) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.jvm.idle")); + } + + @Override + protected double getDefaultGravity() { + return 0F; + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public boolean shouldSyncMotion() { + return true; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MelonBombEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MelonBombEntity.java new file mode 100644 index 000000000..3754e6970 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MelonBombEntity.java @@ -0,0 +1,63 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.NotNull; + +public class MelonBombEntity extends FastThrowableProjectile { + + public MelonBombEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public MelonBombEntity(LivingEntity entity, Level level) { + super(ModEntities.MELON_BOMB.get(), entity, level); + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return Items.MELON; + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + ProjectileTool.causeCustomExplode(this, VehicleConfig.TOM_6_BOMB_EXPLOSION_DAMAGE.get(), VehicleConfig.TOM_6_BOMB_EXPLOSION_RADIUS.get().floatValue(), 1.5f); + this.discard(); + } + + @Override + public void tick() { + super.tick(); + if (tickCount > 600) { + this.discard(); + if (!this.level().isClientSide) { + ProjectileTool.causeCustomExplode(this, VehicleConfig.TOM_6_BOMB_EXPLOSION_DAMAGE.get(), VehicleConfig.TOM_6_BOMB_EXPLOSION_RADIUS.get().floatValue(), 1.5f); + } + } + } + + @Override + protected double getDefaultGravity() { + return 0.05F; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java new file mode 100644 index 000000000..fe7b393a9 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/MortarShellEntity.java @@ -0,0 +1,271 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.ChunkLoadTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import com.google.common.collect.Sets; +import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.AreaEffectCloud; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.Potions; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public class MortarShellEntity extends FastThrowableProjectile implements GeoEntity { + + private float damage = ExplosionConfig.MORTAR_SHELL_EXPLOSION_DAMAGE.get(); + private int life = 600; + private float radius = ExplosionConfig.MORTAR_SHELL_EXPLOSION_RADIUS.get(); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public Set loadedChunks = new HashSet<>(); + + private Potion potion = Potions.WATER.value(); + private final Set effects = Sets.newHashSet(); + + public MortarShellEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public MortarShellEntity(EntityType type, double x, double y, double z, Level world) { + super(type, x, y, z, world); + this.noCulling = true; + } + + public MortarShellEntity(LivingEntity entity, Level level) { + super(ModEntities.MORTAR_SHELL.get(), entity, level); + } + + public MortarShellEntity(LivingEntity entity, Level world, float damage) { + super(ModEntities.MORTAR_SHELL.get(), entity, world); + this.damage = damage; + } + + public MortarShellEntity(LivingEntity entity, Level world, float damage, float radius) { + super(ModEntities.MORTAR_SHELL.get(), entity, world); + this.damage = damage; + this.radius = radius; + } + + public void setEffectsFromItem(ItemStack stack) { + if (stack.is(ModItems.POTION_MORTAR_SHELL.get())) { + var data = stack.get(DataComponents.POTION_CONTENTS); + if (data != null) { + data.potion().ifPresent(p -> this.potion = p.value()); + Collection collection = data.customEffects(); + if (!collection.isEmpty()) { + for (MobEffectInstance mobeffectinstance : collection) { + this.effects.add(new MobEffectInstance(mobeffectinstance)); + } + } + } + } else if (stack.is(ModItems.MORTAR_SHELL.get())) { + this.potion = Potions.WATER.value(); + this.effects.clear(); + } + } + + @Override + public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { + super.addAdditionalSaveData(pCompound); + pCompound.putFloat("Damage", this.damage); + pCompound.putInt("Life", this.life); + pCompound.putFloat("Radius", this.radius); + + ListTag listTag = new ListTag(); + for (long chunkPos : this.loadedChunks) { + CompoundTag tag = new CompoundTag(); + tag.putLong("Pos", chunkPos); + listTag.add(tag); + } + pCompound.put("Chunks", listTag); + + if (this.potion != Potions.WATER.value()) { + pCompound.putString("Potion", Objects.requireNonNullElse(BuiltInRegistries.POTION.getKey(this.potion), "empty").toString()); + } + + if (!this.effects.isEmpty()) { + ListTag listtag = new ListTag(); + for (MobEffectInstance mobeffectinstance : this.effects) { + listtag.add(mobeffectinstance.save()); + } + pCompound.put("CustomPotionEffects", listtag); + } + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { + super.readAdditionalSaveData(pCompound); + if (pCompound.contains("Damage")) { + this.damage = pCompound.getFloat("Damage"); + } else { + this.damage = ExplosionConfig.MORTAR_SHELL_EXPLOSION_DAMAGE.get(); + } + + if (pCompound.contains("Life")) { + this.life = pCompound.getInt("Life"); + } else { + this.life = 600; + } + + if (pCompound.contains("Radius")) { + this.radius = pCompound.getFloat("Radius"); + } else { + this.radius = ExplosionConfig.MORTAR_SHELL_EXPLOSION_RADIUS.get(); + } + + if (pCompound.contains("Chunks")) { + ListTag listTag = pCompound.getList("Chunks", 10); + for (int i = 0; i < listTag.size(); i++) { + CompoundTag tag = listTag.getCompound(i); + this.loadedChunks.add(tag.getLong("Pos")); + } + } + + if (pCompound.contains("Potion", 8)) { + var tagName = pCompound.getString("Potion"); + this.potion = BuiltInRegistries.POTION.get(ResourceLocation.tryParse(tagName)); + } + + var listTag = pCompound.getList("CustomPotionEffects", 10); + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundtag = listTag.getCompound(i); + MobEffectInstance instance = MobEffectInstance.load(compoundtag); + if (instance != null) { + this.effects.add(instance); + } + } + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.MORTAR_SHELL.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + public void onHitEntity(@NotNull EntityHitResult entityHitResult) { + if (this.tickCount > 1) { + Entity entity = entityHitResult.getEntity(); + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), this.damage); + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, this.damage, this.radius); + this.createAreaCloud(this.level()); + } + this.discard(); + } + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + BlockPos resultPos = blockHitResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockHitResult.getDirection()); + } + if (!this.level().isClientSide() && this.level() instanceof ServerLevel) { + if (this.tickCount > 1) { + ProjectileTool.causeCustomExplode(this, this.damage, this.radius); + this.createAreaCloud(this.level()); + } + } + this.discard(); + } + + @Override + public void tick() { + super.tick(); + if (this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.001, true); + + // 更新需要加载的区块 + ChunkLoadTool.updateLoadedChunks(serverLevel, this, this.loadedChunks); + } + if (this.tickCount > this.life || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, this.damage, this.radius); + this.createAreaCloud(this.level()); + } + this.discard(); + } + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + protected double getDefaultGravity() { + return 0.146F; + } + + @Override + public void onRemovedFromLevel() { + if (this.level() instanceof ServerLevel serverLevel) { + ChunkLoadTool.unloadAllChunks(serverLevel, this, this.loadedChunks); + } + super.onRemovedFromLevel(); + } + + private void createAreaCloud(Level level) { + if (this.potion == Potions.WATER.value()) return; + + AreaEffectCloud cloud = new AreaEffectCloud(level, this.getX() + 0.75 * getDeltaMovement().x, this.getY() + 0.5 * getBbHeight() + 0.75 * getDeltaMovement().y, this.getZ() + 0.75 * getDeltaMovement().z); + + // TODO PotionContents +// cloud.setPotion(this.potion); + cloud.setDuration((int) this.damage); + cloud.setRadius(this.radius); + if (this.getOwner() instanceof LivingEntity living) { + cloud.setOwner(living); + } + level.addFreshEntity(cloud); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java new file mode 100644 index 000000000..3221ccd98 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RgoGrenadeEntity.java @@ -0,0 +1,147 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +public class RgoGrenadeEntity extends FastThrowableProjectile implements GeoEntity { + + private int fuse = 80; + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public RgoGrenadeEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public RgoGrenadeEntity(EntityType type, double x, double y, double z, Level world) { + super(type, x, y, z, world); + this.noCulling = true; + } + + public RgoGrenadeEntity(LivingEntity entity, Level level, int fuse) { + super(ModEntities.RGO_GRENADE.get(), entity, level); + this.fuse = fuse; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.RGO_GRENADE.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHit(@NotNull HitResult result) { + if (level() instanceof ServerLevel) { + switch (result.getType()) { + case BLOCK: + BlockHitResult blockResult = (BlockHitResult) result; + BlockPos resultPos = blockResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockResult.getDirection()); + } + ProjectileTool.causeCustomExplode(this, ExplosionConfig.RGO_GRENADE_EXPLOSION_DAMAGE.get(), ExplosionConfig.RGO_GRENADE_EXPLOSION_RADIUS.get(), 1.2f); + + break; + case ENTITY: + EntityHitResult entityResult = (EntityHitResult) result; + Entity entity = entityResult.getEntity(); + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + if (!(entity instanceof DroneEntity)) { + ProjectileTool.causeCustomExplode(this, ExplosionConfig.RGO_GRENADE_EXPLOSION_DAMAGE.get(), ExplosionConfig.RGO_GRENADE_EXPLOSION_RADIUS.get(), 1.2f); + } + break; + default: + break; + } + } + } + + @Override + public void tick() { + super.tick(); + --this.fuse; + + if (this.fuse <= 0) { + this.discard(); + if (!this.level().isClientSide) { + ProjectileTool.causeCustomExplode(this, ExplosionConfig.RGO_GRENADE_EXPLOSION_DAMAGE.get(), ExplosionConfig.RGO_GRENADE_EXPLOSION_RADIUS.get(), 1.2f); + } + } + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.01, true); + } + } + + @Override + protected double getDefaultGravity() { + return 0.07F; + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + public void droneShoot(Entity drone) { + Vec3 vec3 = (new Vec3(0.2 * drone.getDeltaMovement().x, 0.2 * drone.getDeltaMovement().y, 0.2 * drone.getDeltaMovement().z)); + this.setDeltaMovement(vec3); + double d0 = vec3.horizontalDistance(); + this.setYRot((float) (Mth.atan2(vec3.x, vec3.z) * (double) (180F / (float) Math.PI))); + this.setXRot((float) (Mth.atan2(vec3.y, d0) * (double) (180F / (float) Math.PI))); + this.yRotO = this.getYRot(); + this.xRotO = this.getXRot(); + } + +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java new file mode 100644 index 000000000..9bb11df28 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/RpgRocketEntity.java @@ -0,0 +1,182 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.projectile.ThrowableItemProjectile; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +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 RpgRocketEntity extends FastThrowableProjectile implements GeoEntity { + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + private float monsterMultiplier = 0.0f; + private float damage = 250f; + + private float explosionRadius = 1; + + public RpgRocketEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public RpgRocketEntity(EntityType pEntityType, double pX, double pY, double pZ, Level pLevel) { + super(pEntityType, pX, pY, pZ, pLevel); + this.noCulling = true; + } + + public RpgRocketEntity(LivingEntity entity, Level level, float damage) { + super(ModEntities.RPG_ROCKET.get(), entity, level); + this.damage = damage; + } + + public void setExplosionRadius(float explosionRadius) { + this.explosionRadius = explosionRadius; + } + + public void setDamage(float damage) { + this.damage = damage; + } + + + public void setMonsterMultiplier(float monsterMultiplier) { + this.monsterMultiplier = monsterMultiplier; + } + + // TOD AEP +// @Override +// public @NotNull Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.ROCKET.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + float damageMultiplier = 1 + this.monsterMultiplier; + Entity entity = result.getEntity(); + if (entity == this.getOwner() || entity == this.getVehicle()) return; + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + if (entity instanceof Monster monster) { + monster.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), 1.2f * this.damage * damageMultiplier); + } else { + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), this.damage); + } + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.tickCount > 1) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, ExplosionConfig.RPG_EXPLOSION_DAMAGE.get(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get() * explosionRadius, this.monsterMultiplier); + } + } + + this.discard(); + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + BlockPos resultPos = blockHitResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockHitResult.getDirection()); + } + + if (this.tickCount > 1) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, ExplosionConfig.RPG_EXPLOSION_DAMAGE.get(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get() * explosionRadius, this.monsterMultiplier); + } + } + + this.discard(); + } + + @Override + public void tick() { + super.tick(); + + if (this.tickCount == 3) { + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, this.xo, this.yo, this.zo, 15, 0.8, 0.8, 0.8, 0.01, true); + ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, 10, 0.8, 0.8, 0.8, 0.01, true); + } + } + if (this.tickCount > 2) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1.03, 1.03, 1.03)); + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, 1, 0, 0, 0, 0, true); + } + } + + if (this.tickCount > 100 || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + ProjectileTool.causeCustomExplode(this, ExplosionConfig.RPG_EXPLOSION_DAMAGE.get(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get() * explosionRadius, this.monsterMultiplier); + } + this.discard(); + } + } + + private PlayState movementPredicate(AnimationState event) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.rpg.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public boolean shouldSyncMotion() { + return true; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java new file mode 100644 index 000000000..01c880a65 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SmallCannonShellEntity.java @@ -0,0 +1,180 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.ProjectileTool; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +public class SmallCannonShellEntity extends FastThrowableProjectile implements GeoEntity { + + private float damage = 40.0f; + private float explosionDamage = 80f; + private float explosionRadius = 5f; + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public SmallCannonShellEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public SmallCannonShellEntity(LivingEntity entity, Level level, float damage, float explosionDamage, float explosionRadius) { + super(ModEntities.SMALL_CANNON_SHELL.get(), entity, level); + this.damage = damage; + this.explosionDamage = explosionDamage; + this.explosionRadius = explosionRadius; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.SMALL_SHELL.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + Entity entity = result.getEntity(); + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), damage); + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.tickCount > 0) { + if (this.level() instanceof ServerLevel) { + causeExplode(entity); + } + } + this.discard(); + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + BlockPos resultPos = blockHitResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockHitResult.getDirection()); + } + if (this.level() instanceof ServerLevel) { + causeExplodeBlock(blockHitResult); + } + this.discard(); + } + + private void causeExplode(Entity entity) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), + this, + this.getOwner()), + explosionDamage, + entity.getX(), + entity.getY() + 0.6 * entity.getBbHeight(), + entity.getZ(), + explosionRadius, + ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP). + setDamageMultiplier(1.25f); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnSmallExplosionParticles(this.level(), + new Vec3(entity.getX(), + entity.getEyeY(), + entity.getZ())); + } + + private void causeExplodeBlock(HitResult result) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), + this, + this.getOwner()), + explosionDamage, + result.getLocation().x, + result.getLocation().y, + result.getLocation().z, + explosionRadius, + ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP). + setDamageMultiplier(1.25f); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnSmallExplosionParticles(this.level(), result.getLocation()); + } + + @Override + public void tick() { + super.tick(); + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, + 1, 0, 0, 0, 0.02, true); + } + + if (onGround()) { + this.setDeltaMovement(0, 0, 0); + } + + if (this.tickCount > 200 || this.isInWater()) { + if (this.level() instanceof ServerLevel && !onGround()) { + ProjectileTool.causeCustomExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius, 1.25f); + } + this.discard(); + } + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java new file mode 100644 index 000000000..64a30571d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/TaserBulletEntity.java @@ -0,0 +1,141 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModMobEffects; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LightningBolt; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.entity.projectile.ItemSupplier; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BellBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +@OnlyIn(value = Dist.CLIENT, _interface = ItemSupplier.class) +public class TaserBulletEntity extends AbstractArrow implements GeoEntity { + + private float damage = 1f; + private int volt = 0; + private int wireLength = 0; + private boolean stop = false; + public static final ItemStack PROJECTILE_ITEM = new ItemStack(Items.AIR); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public TaserBulletEntity(LivingEntity entity, Level level, float damage, int volt, int wireLength) { + super(ModEntities.TASER_BULLET.get(), level); + this.damage = damage; + this.volt = volt; + this.wireLength = wireLength; + } + + public TaserBulletEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public void playerTouch(@NotNull Player pEntity) { + } + + @Override + protected @NotNull ItemStack getPickupItem() { + return PROJECTILE_ITEM; + } + + @Override + protected @NotNull ItemStack getDefaultPickupItem() { + return PROJECTILE_ITEM; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + Entity entity = result.getEntity(); + if (entity == this.getVehicle()) return; + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + if (entity instanceof LivingEntity living) { + entity.invulnerableTime = 0; + entity.hurt(ModDamageTypes.causeShockDamage(this.level().registryAccess(), this.getOwner()), this.damage); + if (living instanceof Player player && player.isCreative()) { + return; + } + if (!living.level().isClientSide()) { + if (living instanceof Creeper creeper && living.level() instanceof ServerLevel serverLevel) { + creeper.thunderHit(serverLevel, new LightningBolt(EntityType.LIGHTNING_BOLT, serverLevel)); + } else { + living.addEffect(new MobEffectInstance(ModMobEffects.SHOCK, 100 + volt * 30, volt), this.getOwner()); + } + } + } + this.discard(); + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + BlockPos resultPos = blockHitResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + if (state.getBlock() instanceof BellBlock bell) { + bell.attemptToRing(this.level(), resultPos, blockHitResult.getDirection()); + } + } + + @Override + public void tick() { + super.tick(); + + if (this.getOwner() != null && this.position().distanceTo(this.getOwner().position()) > 10 + 4 * wireLength && !stop) { + stop = true; + this.setDeltaMovement(new Vec3(0, 0, 0)); + } + + if (this.tickCount > 200) { + this.discard(); + } + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} + diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java new file mode 100644 index 000000000..f114f721e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java @@ -0,0 +1,195 @@ +package com.atsuishio.superbwarfare.entity.projectile; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.VectorTool; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.ThrowableItemProjectile; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.Nullable; + +public class WgMissileEntity extends FastThrowableProjectile implements GeoEntity { + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + private float damage = 250f; + private float explosionDamage = 200f; + private float explosionRadius = 10f; + + public WgMissileEntity(EntityType type, Level level) { + super(type, level); + this.noCulling = true; + } + + public WgMissileEntity(LivingEntity entity, Level level, float damage, float explosionDamage, float explosionRadius) { + super(ModEntities.WG_MISSILE.get(), entity, level); + this.damage = damage; + this.explosionDamage = explosionDamage; + this.explosionRadius = explosionRadius; + } + + // TODO AEP +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.WIRE_GUIDE_MISSILE.get(); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(EntityHitResult result) { + Entity entity = result.getEntity(); + if (this.tickCount < 1) return; + if (entity == this.getOwner() || entity == this.getVehicle()) return; + + if (this.getOwner() instanceof LivingEntity living) { + if (!living.level().isClientSide() && living instanceof ServerPlayer player) { + living.level().playSound(null, living.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 1, 1); + + PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5)); + } + } + + entity.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), this, this.getOwner()), this.damage); + + if (entity instanceof LivingEntity) { + entity.invulnerableTime = 0; + } + + if (this.tickCount > 2) { + if (this.level() instanceof ServerLevel) { + causeMissileExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + entity, this.explosionDamage, this.explosionRadius); + } + } + } + + @Override + public void onHitBlock(@NotNull BlockHitResult blockHitResult) { + super.onHitBlock(blockHitResult); + if (this.level() instanceof ServerLevel) { + causeMissileExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius); + } + } + + @Override + public void tick() { + super.tick(); + + if (this.tickCount == 1) { + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.CLOUD, this.xo, this.yo, this.zo, 15, 0.8, 0.8, 0.8, 0.01, true); + ParticleTool.sendParticle(serverLevel, ParticleTypes.CAMPFIRE_COSY_SMOKE, this.xo, this.yo, this.zo, 10, 0.8, 0.8, 0.8, 0.01, true); + } + } + if (this.tickCount > 2) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1.03, 1.03, 1.03)); + + if (!this.level().isClientSide() && this.level() instanceof ServerLevel serverLevel) { + ParticleTool.sendParticle(serverLevel, ParticleTypes.SMOKE, this.xo, this.yo, this.zo, 1, 0, 0, 0, 0, true); + } + } + + if (tickCount > 5 && this.getOwner() != null && getOwner().getVehicle() instanceof Bmp2Entity bmp2) { + Entity shooter = this.getOwner(); + Vec3 lookVec = bmp2.getBarrelVector(1).normalize(); + Vec3 toVec = shooter.getEyePosition().vectorTo(this.getEyePosition()).normalize(); + Vec3 addVec = lookVec.add(toVec.scale(-0.85)).normalize(); + double angle = Mth.abs((float) VectorTool.calculateAngle(lookVec, toVec)); + setDeltaMovement(getDeltaMovement().add(addVec.scale(Math.min(0.1 + 0.15 * angle + distanceTo(getOwner()) * 0.003, tickCount < 15 ? 0.04 : 0.4)))); + + // 控制速度 + if (this.getDeltaMovement().length() < 2.8) { + this.setDeltaMovement(this.getDeltaMovement().multiply(1.06, 1.06, 1.06)); + } + + if (this.getDeltaMovement().length() > 3) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.9, 0.9, 0.9)); + } + + this.setDeltaMovement(this.getDeltaMovement().multiply(0.96, 0.96, 0.96)); + } + + if (this.tickCount > 300 || this.isInWater()) { + if (this.level() instanceof ServerLevel) { + causeMissileExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius); + } + this.discard(); + } + } + + public static void causeMissileExplode(ThrowableItemProjectile projectile, @Nullable DamageSource source, Entity target, float damage, float radius) { + CustomExplosion explosion = new CustomExplosion(projectile.level(), projectile, source, damage, + target.getX(), target.getEyeY(), target.getZ(), radius, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1.25f); + explosion.explode(); + EventHooks.onExplosionStart(projectile.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(projectile.level(), projectile.position()); + projectile.discard(); + } + + private PlayState movementPredicate(AnimationState event) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.jvm.idle")); + } + + @Override + protected double getDefaultGravity() { + return 0; + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public boolean shouldSyncMotion() { + return true; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java new file mode 100644 index 000000000..3b72a511e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Ah6Entity.java @@ -0,0 +1,776 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.projectile.*; +import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.HelicopterEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.HeliRocketWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.ProjectileWeapon; +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.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.AmmoType; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.google.common.collect.Lists; +import com.mojang.math.Axis; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +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.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.vehicle.DismountHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +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; +import org.joml.Vector3f; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.ArrayList; +import java.util.Comparator; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class Ah6Entity extends ContainerMobileVehicleEntity implements GeoEntity, HelicopterEntity, WeaponVehicleEntity { + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public static final EntityDataAccessor PROPELLER_ROT = SynchedEntityData.defineId(Ah6Entity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor DECOY_COUNT = SynchedEntityData.defineId(Ah6Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor LOADED_ROCKET = SynchedEntityData.defineId(Ah6Entity.class, EntityDataSerializers.INT); + public boolean engineStart; + public boolean engineStartOver; + + public double velocity; + public int decoyReloadCoolDown; + public int fireIndex; + public int holdTick; + public int holdPowerTick; + + public Ah6Entity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + @Override + public float maxUpStep() { + return 1.1F; + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new ProjectileWeapon() + .damage(VehicleConfig.AH_6_CANNON_DAMAGE.get()) + .headShot(2) + .zoom(false) + .heBullet(1) + .bypassArmorRate(0.1f) + .sound(ModSounds.INTO_CANNON.get()) + .icon(ModUtils.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(7, 1, -2.7); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(LOADED_ROCKET, 0) + .define(PROPELLER_ROT, 0f) + .define(DECOY_COUNT, 6); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("LoadedRocket", this.entityData.get(LOADED_ROCKET)); + compound.putFloat("PropellerRot", this.entityData.get(PROPELLER_ROT)); + compound.putInt("DecoyCount", this.entityData.get(DECOY_COUNT)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(LOADED_ROCKET, compound.getInt("LoadedRocket")); + this.entityData.set(PROPELLER_ROT, compound.getFloat("PropellerRot")); + this.entityData.set(DECOY_COUNT, compound.getInt("DecoyCount")); + } + + // TODO addentitypacket + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.5f) + .multiply(0.2f, DamageTypes.ARROW) + .multiply(0.4f, DamageTypes.TRIDENT) + .multiply(0.4f, DamageTypes.MOB_ATTACK) + .multiply(0.4f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(0.4f, DamageTypes.MOB_PROJECTILE) + .multiply(0.4f, DamageTypes.PLAYER_ATTACK) + .multiply(4, DamageTypes.LAVA) + .multiply(4, DamageTypes.EXPLOSION) + .multiply(4, DamageTypes.PLAYER_EXPLOSION) + .multiply(0.8f, ModDamageTypes.CANNON_FIRE) + .multiply(0.16f, ModTags.DamageTypes.PROJECTILE) + .multiply(10, ModDamageTypes.VEHICLE_STRIKE) + .custom((source, damage) -> { + if (source.getDirectEntity() instanceof MelonBombEntity) { + return 2f * damage; + } + if (source.getDirectEntity() instanceof RgoGrenadeEntity) { + return 6f * damage; + } + if (source.getDirectEntity() instanceof HandGrenadeEntity) { + return 5f * damage; + } + if (source.getDirectEntity() instanceof MortarShellEntity) { + return 4f * damage; + } + return damage; + }) + + .reduce(2); + } + + @Override + public void baseTick() { + super.baseTick(); + + if (this.level() instanceof ServerLevel) { + if (reloadCoolDown > 0) { + reloadCoolDown--; + } + if (decoyReloadCoolDown > 0) { + decoyReloadCoolDown--; + } + handleAmmo(); + } + + if (this.onGround()) { + this.terrainCompat(2.7f, 2.7f); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.8, 1, 0.8)); + } else { + setZRot(getRoll() * (backInputDown ? 0.9f : 0.99f)); + float f = (float) Mth.clamp(0.9f - 0.015 * getDeltaMovement().length() + 0.02f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90, 0.01, 0.99); + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).scale((this.getXRot() < 0 ? -0.035 : (this.getXRot() > 0 ? 0.035 : 0)) * this.getDeltaMovement().length()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f, 0.95, f)); + } + + if (this.isInWater() && this.tickCount % 4 == 0 && getSubmergedHeight(this) > 0.5 * getBbHeight()) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 0.6, 0.6)); + this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), 1 + (float) (20 * ((lastTickSpeed - 0.4) * (lastTickSpeed - 0.4)))); + } + + releaseDecoy(); + lowHealthWarning(); + + 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 AmmoType.HEAVY.get(stack) > 0; + } + return false; + }).mapToInt(AmmoType.HEAVY::get).sum() + countItem(ModItems.HEAVY_AMMO.get()); + + if ((hasItem(ModItems.ROCKET_70.get()) || InventoryTool.hasCreativeAmmoBox(player)) && reloadCoolDown == 0 && this.getEntityData().get(LOADED_ROCKET) < 14) { + this.entityData.set(LOADED_ROCKET, this.getEntityData().get(LOADED_ROCKET) + 1); + reloadCoolDown = 25; + 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)); + } + } + + public void releaseDecoy() { + if (decoyInputDown) { + if (this.entityData.get(DECOY_COUNT) > 0 && this.level() instanceof ServerLevel) { + Entity passenger = getFirstPassenger(); + for (int i = 0; i < 4; i++) { + FlareDecoyEntity flareDecoyEntity = new FlareDecoyEntity((LivingEntity) passenger, this.level()); + flareDecoyEntity.setPos(this.getX() + this.getDeltaMovement().x, this.getY() + 0.5 + this.getDeltaMovement().y, this.getZ() + this.getDeltaMovement().z); + flareDecoyEntity.decoyShoot(this, this.getViewVector(1).yRot((45 + 90 * i) * Mth.DEG_TO_RAD), 0.8f, 8); + this.level().addFreshEntity(flareDecoyEntity); + } + this.level().playSound(null, this, ModSounds.DECOY_FIRE.get(), this.getSoundSource(), 1, 1); + if (this.getEntityData().get(DECOY_COUNT) == 6) { + decoyReloadCoolDown = 300; + } + this.getEntityData().set(DECOY_COUNT, this.getEntityData().get(DECOY_COUNT) - 1); + } + decoyInputDown = false; + } + if (this.entityData.get(DECOY_COUNT) < 6 && decoyReloadCoolDown == 0 && this.level() instanceof ServerLevel) { + this.entityData.set(DECOY_COUNT, this.entityData.get(DECOY_COUNT) + 1); + this.level().playSound(null, this, ModSounds.DECOY_RELOAD.get(), this.getSoundSource(), 1, 1); + decoyReloadCoolDown = 300; + } + } + + @Override + public void travel() { + Entity passenger = getFirstPassenger(); + Entity passenger2 = getNthEntity(1); + Entity passenger3 = getNthEntity(2); + Entity passenger4 = getNthEntity(3); + float diffX; + float diffY; + + + if (passenger == null) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + this.upInputDown = false; + this.downInputDown = false; + this.setZRot(this.roll * 0.98f); + this.setXRot(this.getXRot() * 0.98f); + if (passenger2 == null && passenger3 == null && passenger4 == null) { + this.entityData.set(POWER, this.entityData.get(POWER) * 0.99f); + } + } else if (passenger instanceof Player) { + diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(passenger.getYHeadRot() - this.getYRot())); + diffX = Math.clamp(-60f, 60f, Mth.wrapDegrees(passenger.getXRot() - this.getXRot())); + + if (rightInputDown) { + holdTick++; + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 2f * Math.min(holdTick, 7) * this.entityData.get(POWER)); + } else if (this.leftInputDown) { + holdTick++; + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 2f * Math.min(holdTick, 7) * this.entityData.get(POWER)); + } else { + holdTick = 0; + } + + this.setYRot(this.getYRot() + Mth.clamp((this.onGround() ? 0.1f : 2f) * diffY * this.entityData.get(PROPELLER_ROT), -10f, 10f)); + this.setXRot(Mth.clamp(this.getXRot() + ((this.onGround()) ? 0 : 1.5f) * diffX * this.entityData.get(PROPELLER_ROT), -80, 80)); + this.setZRot(this.getRoll() - this.entityData.get(DELTA_ROT) + (this.onGround() ? 0 : 0.25f) * diffY * this.entityData.get(PROPELLER_ROT)); + } + + if (this.level() instanceof ServerLevel) { + if (this.getEnergy() > 0) { + boolean up = upInputDown || forwardInputDown; + boolean down = this.downInputDown; + + if (!engineStart && up) { + engineStart = true; + this.level().playSound(null, this, ModSounds.HELICOPTER_ENGINE_START.get(), this.getSoundSource(), 3, 1); + } + + if (up && engineStartOver) { + holdPowerTick++; + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + 0.0007f * Math.min(holdPowerTick, 10), 0.12f)); + } + + if (engineStartOver) { + if (down) { + holdPowerTick++; + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - 0.001f * Math.min(holdPowerTick, 5), this.onGround() ? 0 : 0.025f)); + } else if (backInputDown) { + holdPowerTick++; + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - 0.001f * Math.min(holdPowerTick, 5), this.onGround() ? 0 : 0.052f)); + if (passenger != null) { + passenger.setXRot(0.8f * passenger.getXRot()); + } + } + } + + if (engineStart && !engineStartOver) { + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + 0.0012f, 0.045f)); + } + + if (!(up || down || backInputDown) && engineStartOver) { + if (this.getDeltaMovement().y() < 0) { + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + 0.0002f, 0.12f)); + } else { + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - (this.onGround() ? 0.00005f : 0.0002f), 0)); + } + holdPowerTick = 0; + } + } else { + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - 0.0001f, 0)); + this.forwardInputDown = false; + this.backInputDown = false; + engineStart = false; + engineStartOver = false; + } + } + + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * 0.9f); + this.entityData.set(PROPELLER_ROT, Mth.lerp(0.18f, this.entityData.get(PROPELLER_ROT), this.entityData.get(POWER))); + this.setPropellerRot(this.getPropellerRot() + 30 * this.entityData.get(PROPELLER_ROT)); + this.entityData.set(PROPELLER_ROT, this.entityData.get(PROPELLER_ROT) * 0.9995f); + + if (engineStart) { + this.consumeEnergy((int) (VehicleConfig.AH_6_MIN_ENERGY_COST.get() + this.entityData.get(POWER) * ((VehicleConfig.AH_6_MAX_ENERGY_COST.get() - VehicleConfig.AH_6_MIN_ENERGY_COST.get()) / 0.12))); + } + + setDeltaMovement(getDeltaMovement().add(0.0f, Math.min(Math.sin((90 - this.getXRot()) * Mth.DEG_TO_RAD), Math.sin((90 + this.getRoll()) * Mth.DEG_TO_RAD)) * this.entityData.get(POWER), 0.0f)); + + Vector3f direction = getRightDirection().mul(-Math.sin(this.getRoll() * Mth.DEG_TO_RAD) * this.entityData.get(PROPELLER_ROT)); + setDeltaMovement(getDeltaMovement().add(new Vec3(direction.x, direction.y, direction.z).scale(3))); + +// if (passenger instanceof Player player) { +// player.displayClientMessage(Component.literal(this.getRoll() + ""), true); +// } + + Vector3f directionZ = getForwardDirection().mul(-Math.cos((this.getXRot() + 90) * Mth.DEG_TO_RAD) * this.entityData.get(PROPELLER_ROT)); + setDeltaMovement(getDeltaMovement().add(new Vec3(directionZ.x, directionZ.y, directionZ.z).scale(3))); + + if (this.entityData.get(POWER) > 0.04f) { + engineStartOver = true; + } + + if (this.entityData.get(POWER) < 0.0004f) { + engineStart = false; + engineStartOver = false; + } + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.HELICOPTER_ENGINE.get(); + } + + protected void clampRotation(Entity entity) { + if (entity == getNthEntity(0) || entity == getNthEntity(1)) { + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, -80.0F, 80F); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getYRot()); + float f3 = Mth.clamp(f2, -80.0F, 80.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(this.getYRot()); + } else if (entity == getNthEntity(2)) { + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getYRot()); + float f3 = Mth.clamp(f2, 10.0F, 170.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(getYRot() + 90); + } else if (entity == getNthEntity(3)) { + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getYRot()); + float f3 = Mth.clamp(f2, -170.0F, -10.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(getYRot() - 90); + } + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + @Override + public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) { + // From Immersive_Aircraft + if (!this.hasPassenger(passenger)) { + return; + } + + Matrix4f transform = getVehicleTransform(1); + + float x = 0.6f; + float y = 1.2f - 1.45f; + float z = 1f; + y += (float) passenger.getVehicleAttachmentPoint(this).y; + + int i = this.getOrderedPassengers().indexOf(passenger); + + if (i == 0) { + Vector4f worldPosition = transformPosition(transform, x, y, z); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 1) { + Vector4f worldPosition = transformPosition(transform, -x, y, z); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 2) { + Vector4f worldPosition = transformPosition(transform, -1.4f, -1.05f, 0); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 3) { + Vector4f worldPosition = transformPosition(transform, 1.4f, -1.05f, 0); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } + + if (passenger != this.getFirstPassenger()) { + passenger.setXRot(passenger.getXRot() + (getXRot() - xRotO)); + } + + copyEntityData(passenger); + } + + public void copyEntityData(Entity entity) { + if (entity == getNthEntity(0) || entity == getNthEntity(1)) { + float f = Mth.wrapDegrees(entity.getYRot() - getYRot()); + float g = Mth.clamp(f, -105.0f, 105.0f); + entity.yRotO += g - f; + entity.setYRot(entity.getYRot() + g - f); + entity.setYHeadRot(entity.getYRot()); + entity.setYBodyRot(getYRot()); + } else if (entity == getNthEntity(2)) { + float f = Mth.wrapDegrees(entity.getYRot() - getYRot()); + float g = Mth.clamp(f, 10.0f, 170.0f); + entity.yRotO += g - f; + entity.setYRot(entity.getYRot() + g - f); + entity.setYHeadRot(entity.getYRot()); + entity.setYBodyRot(getYRot() + 90); + } else if (entity == getNthEntity(3)) { + float f = Mth.wrapDegrees(entity.getYRot() - getYRot()); + float g = Mth.clamp(f, -170.0f, -10.0f); + entity.yRotO += g - f; + entity.setYRot(entity.getYRot() + g - f); + entity.setYHeadRot(entity.getYRot()); + entity.setYBodyRot(getYRot() - 90); + } + } + + @Override + public Matrix4f getVehicleTransform(float ticks) { + Matrix4f transform = new Matrix4f(); + transform.translate((float) Mth.lerp(ticks, xo, getX()), (float) Mth.lerp(ticks, yo + 1.45f, getY() + 1.45f), (float) Mth.lerp(ticks, zo, getZ())); + transform.rotate(Axis.YP.rotationDegrees(-Mth.lerp(ticks, yRotO, getYRot()))); + transform.rotate(Axis.XP.rotationDegrees(Mth.lerp(ticks, xRotO, getXRot()))); + transform.rotate(Axis.ZP.rotationDegrees(Mth.lerp(ticks, prevRoll, getRoll()))); + return transform; + } + + @Override + public void destroy() { + if (this.crash) { + crashPassengers(); + } else { + explodePassengers(); + } + + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), this, getAttacker()), 300.0f, + this.getX(), this.getY(), this.getZ(), 8f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnHugeExplosionParticles(this.level(), this.position()); + } + this.discard(); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public float getMaxHealth() { + return VehicleConfig.AH_6_HP.get(); + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.AH_6_MAX_ENERGY.get(); + } + + @Override + public void vehicleShoot(Player player, int type) { + boolean hasCreativeAmmo = false; + for (int i = 0; i < getMaxPassengers() - 1; i++) { + if (getNthEntity(i) instanceof Player pPlayer && InventoryTool.hasCreativeAmmoBox(pPlayer)) { + hasCreativeAmmo = true; + } + } + + Matrix4f transform = getVehicleTransform(1); + float x; + float y; + float z; + + Vector4f worldPositionRight; + Vector4f worldPositionLeft; + + if (getWeaponIndex(0) == 0) { + if (this.cannotFire) return; + + x = 1.15f; + y = 0.62f - 1.45f; + z = 0.8f; + + worldPositionRight = transformPosition(transform, -x, y, z); + worldPositionLeft = transformPosition(transform, x, y, z); + + if (this.entityData.get(AMMO) > 0 || hasCreativeAmmo) { + ProjectileEntity projectileRight = ((ProjectileWeapon) getWeapon(0)).create(player); + + projectileRight.setPos(worldPositionRight.x, worldPositionRight.y, worldPositionRight.z); + projectileRight.shoot(player, this.getLookAngle().x, this.getLookAngle().y + 0.018, this.getLookAngle().z, 20, + (float) 0.2); + this.level().addFreshEntity(projectileRight); + sendParticle((ServerLevel) this.level(), ParticleTypes.LARGE_SMOKE, worldPositionRight.x, worldPositionRight.y, worldPositionRight.z, 1, 0, 0, 0, 0, false); + if (!InventoryTool.hasCreativeAmmoBox(player)) { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.HEAVY_AMMO.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + } + + if (this.entityData.get(AMMO) > 0 || hasCreativeAmmo) { + ProjectileEntity projectileLeft = ((ProjectileWeapon) getWeapon(0)).create(player); + + projectileLeft.setPos(worldPositionLeft.x, worldPositionLeft.y, worldPositionLeft.z); + projectileLeft.shoot(player, this.getLookAngle().x, this.getLookAngle().y + 0.018, this.getLookAngle().z, 20, + (float) 0.2); + this.level().addFreshEntity(projectileLeft); + sendParticle((ServerLevel) this.level(), ParticleTypes.LARGE_SMOKE, worldPositionLeft.x, worldPositionLeft.y, worldPositionLeft.z, 1, 0, 0, 0, 0, false); + + if (!hasCreativeAmmo) { + ItemStack ammoBox = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return AmmoType.HEAVY.get(stack) > 0; + } + return false; + }).findFirst().orElse(ItemStack.EMPTY); + + if (!ammoBox.isEmpty()) { + AmmoType.HEAVY.add(ammoBox, -1); + } else { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.HEAVY_AMMO.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + } + + } + + this.entityData.set(HEAT, this.entityData.get(HEAT) + 5); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.HELICOPTER_CANNON_FIRE_3P.get(), 4, 1); + serverPlayer.playSound(ModSounds.HELICOPTER_CANNON_FAR.get(), 12, 1); + serverPlayer.playSound(ModSounds.HELICOPTER_CANNON_VERYFAR.get(), 24, 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(6), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 4, 8, this.getX(), this.getEyeY(), this.getZ())); + } + } + } else if (getWeaponIndex(0) == 1 && this.getEntityData().get(LOADED_ROCKET) > 0) { + x = 1.7f; + y = 0.62f - 1.45f; + z = 0.8f; + + worldPositionRight = transformPosition(transform, -x, y, z); + worldPositionLeft = transformPosition(transform, x, y, z); + + var heliRocketEntity = ((HeliRocketWeapon) getWeapon(0)).create(player); + + if (fireIndex == 0) { + heliRocketEntity.setPos(worldPositionRight.x, worldPositionRight.y, worldPositionRight.z); + heliRocketEntity.shoot(this.getLookAngle().x, this.getLookAngle().y + 0.008, this.getLookAngle().z, 7, 0.25f); + player.level().addFreshEntity(heliRocketEntity); + fireIndex = 1; + } else if (fireIndex == 1) { + heliRocketEntity.setPos(worldPositionLeft.x, worldPositionLeft.y, worldPositionLeft.z); + heliRocketEntity.shoot(this.getLookAngle().x, this.getLookAngle().y + 0.008, this.getLookAngle().z, 7, 0.25f); + player.level().addFreshEntity(heliRocketEntity); + fireIndex = 0; + } + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.HELICOPTER_ROCKET_FIRE_3P.get(), 6, 1); + } + } + + this.entityData.set(LOADED_ROCKET, this.getEntityData().get(LOADED_ROCKET) - 1); + reloadCoolDown = 30; + + 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(6), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 5, 7, this.getX(), this.getEyeY(), this.getZ())); + } + } + } + } + + @Override + public @NotNull Vec3 getDismountLocationForPassenger(LivingEntity passenger) { + Vec3 vec3d = getDismountOffset(getBbWidth() * Mth.SQRT_OF_TWO, passenger.getBbWidth() * Mth.SQRT_OF_TWO); + double ox = getX() + vec3d.x; + int i = this.getOrderedPassengers().indexOf(passenger); + if (i == 0 || i == 2 || i == 3 || i == 4) { + ox = getX() - vec3d.x; + } + + double oz = getZ() + vec3d.z; + BlockPos exitPos = new BlockPos((int) ox, (int) getY(), (int) oz); + BlockPos floorPos = exitPos.below(); + if (!level().isWaterAt(floorPos)) { + ArrayList list = Lists.newArrayList(); + double exitHeight = level().getBlockFloorHeight(exitPos); + if (DismountHelper.isBlockFloorValid(exitHeight)) { + list.add(new Vec3(ox, (double) exitPos.getY() + exitHeight, oz)); + } + double floorHeight = level().getBlockFloorHeight(floorPos); + if (DismountHelper.isBlockFloorValid(floorHeight)) { + list.add(new Vec3(ox, (double) floorPos.getY() + floorHeight, oz)); + } + for (Pose entityPose : passenger.getDismountPoses()) { + for (Vec3 vec3d2 : list) { + if (!DismountHelper.canDismountTo(level(), vec3d2, passenger, entityPose)) continue; + passenger.setPose(entityPose); + return vec3d2; + } + } + } + + return super.getDismountLocationForPassenger(passenger); + } + + @Override + public int mainGunRpm(Player player) { + return 360; + } + + @Override + public boolean canShoot(Player player) { + if (getWeaponIndex(0) == 0) { + return (this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFire; + } 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 hidePassenger(Entity entity) { + return false; + } + + @Override + public int zoomFov() { + return 3; + } + + @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); + } + + public int getMaxPassengers() { + return 4; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/ah_6_icon.png"); + } + + @Override + public boolean allowFreeCam() { + return true; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java new file mode 100644 index 000000000..03c051ea1 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/AnnihilatorEntity.java @@ -0,0 +1,632 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import com.atsuishio.superbwarfare.entity.projectile.MelonBombEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.EnergyVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.LaserWeapon; +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.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.*; +import net.minecraft.ChatFormatting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +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.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.*; +import net.neoforged.neoforge.capabilities.Capabilities; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.NotNull; +import org.joml.Math; +import org.joml.Vector3d; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Comparator; + +public class AnnihilatorEntity extends EnergyVehicleEntity implements GeoEntity, CannonEntity { + + public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor LASER_LEFT_LENGTH = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor LASER_MIDDLE_LENGTH = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor LASER_RIGHT_LENGTH = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor PITCH = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor YAW = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor SHOOTER_UUID = SynchedEntityData.defineId(AnnihilatorEntity.class, EntityDataSerializers.STRING); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public Vec3 barrelLookAt; + + public AnnihilatorEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new LaserWeapon() + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(16, 1.3, 0); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(COOL_DOWN, 0) + .define(SHOOTER_UUID, "none") + .define(LASER_LEFT_LENGTH, 0f) + .define(LASER_MIDDLE_LENGTH, 0f) + .define(LASER_RIGHT_LENGTH, 0f) + .define(PITCH, 0f) + .define(YAW, 0f); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("CoolDown", this.entityData.get(COOL_DOWN)); + compound.putFloat("Pitch", this.entityData.get(PITCH)); + compound.putFloat("Yaw", this.entityData.get(YAW)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(COOL_DOWN, compound.getInt("CoolDown")); + this.entityData.set(PITCH, compound.getFloat("Pitch")); + this.entityData.set(YAW, compound.getFloat("Yaw")); + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + + if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { + setTarget(player.getOffhandItem()); + return InteractionResult.SUCCESS; + } + if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { + setTarget(player.getOffhandItem()); + return InteractionResult.SUCCESS; + } + + if (stack.is(ModItems.CROWBAR.get()) && !player.isCrouching()) { + if (this.entityData.get(COOL_DOWN) == 0) { + vehicleShoot(player, 0); + entityData.set(SHOOTER_UUID, player.getStringUUID()); + } + return InteractionResult.SUCCESS; + } + return super.interact(player, hand); + } + + public void setTarget(ItemStack stack) { + var tag = NBTTool.getTag(stack); + int targetX = tag.getInt("TargetX"); + int targetY = tag.getInt("TargetY"); + int targetZ = tag.getInt("TargetZ"); + this.look(new Vec3(targetX, targetY, targetZ)); + } + + private void look(Vec3 pTarget) { + float yRot = this.getYRot(); + if (yRot < 0) { + yRot += 360; + } + yRot = yRot + 90 % 360; + + var BarrelRoot = new Vector3d(4.95, 2.25, 0); + BarrelRoot.rotateY(-yRot * Mth.DEG_TO_RAD); + + Vec3 vec3 = new Vec3(this.getX() + BarrelRoot.x, this.getY() + BarrelRoot.y, this.getZ() + BarrelRoot.z); + + double d0 = pTarget.x - vec3.x; + double d1 = pTarget.y - vec3.y; + double d2 = pTarget.z - vec3.z; + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + entityData.set(YAW, Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F)); + entityData.set(PITCH, Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875)))); + } + + @Override + @ParametersAreNonnullByDefault + protected void positionRider(Entity pPassenger, MoveFunction pCallback) { + if (this.hasPassenger(pPassenger)) { + float f1 = (float) ((this.isRemoved() ? 0.009999999776482582 : this.getPassengerRidingPosition(pPassenger).y) + pPassenger.getVehicleAttachmentPoint(this).y); + Vec3 vec3 = (new Vec3(1, 0.0, 0.0)).yRot(-this.getYRot() * 0.017453292F - 1.5707964F); + pCallback.accept(pPassenger, this.getX() + vec3.x, this.getY() + (double) f1, this.getZ() + vec3.z); + } + } + + // TODO addEntityPacket + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public @NotNull Vec3 getPassengerRidingPosition(@NotNull Entity entity) { + return super.getPassengerRidingPosition(entity).add(0, 0.75, 0); + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.1f) + .immuneTo(DamageTypes.ARROW) + .immuneTo(DamageTypes.TRIDENT) + .immuneTo(DamageTypes.MOB_ATTACK) + .immuneTo(DamageTypes.MOB_ATTACK_NO_AGGRO) + .immuneTo(DamageTypes.MOB_PROJECTILE) + .immuneTo(DamageTypes.PLAYER_ATTACK) + .immuneTo(ModTags.DamageTypes.PROJECTILE) + .immuneTo(ModDamageTypes.VEHICLE_STRIKE) + .multiply(0.7f, DamageTypes.EXPLOSION) + .multiply(0.2f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(0.2f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.2f, ModDamageTypes.MINE) + .multiply(0.24f, ModDamageTypes.LUNGE_MINE) + .multiply(0.3f, ModDamageTypes.CANNON_FIRE) + .multiply(0.04f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .custom((source, damage) -> getSourceAngle(source, 3) * damage) + .custom((source, damage) -> { + if (source.getDirectEntity() instanceof C4Entity) { + return 10f * damage; + } + if (source.getDirectEntity() instanceof MelonBombEntity) { + return 8f * damage; + } + return damage; + }) + .reduce(12); + } + + @Override + public Vec3 getDeltaMovement() { + return new Vec3(0, Math.min(super.getDeltaMovement().y, 0), 0); + } + + @Override + public void baseTick() { + super.baseTick(); + + if (this.entityData.get(COOL_DOWN) > 0) { + this.entityData.set(COOL_DOWN, this.entityData.get(COOL_DOWN) - 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)); + } + + lowHealthWarning(); + + float delta = Math.abs(getYRot() - yRotO); + while (getYRot() > 180F) { + setYRot(getYRot() - 360F); + yRotO = getYRot() - delta; + } + while (getYRot() <= -180F) { + setYRot(getYRot() + 360F); + yRotO = delta + getYRot(); + } + + float yRot = this.getYRot(); + if (yRot < 0) { + yRot += 360; + } + yRot = yRot + 90 % 360; + + var BarrelRoot = new Vector3d(4.95, 2.25, 0); + BarrelRoot.rotateY(-yRot * Mth.DEG_TO_RAD); + + // 中间炮管transform origin(?)世界坐标 + Vec3 BarrelRootPos = new Vec3(this.getX() + BarrelRoot.x, this.getY() + BarrelRoot.y, this.getZ() + BarrelRoot.z); + + var leftPos = new Vector3d(16, 0, -2.703125); + leftPos.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + leftPos.rotateY(-yRot * Mth.DEG_TO_RAD); + + Vec3 BarrelLeftPos = new Vec3(BarrelRootPos.x + leftPos.x, BarrelRootPos.y + leftPos.y, BarrelRootPos.z + leftPos.z); + + var middlePos = new Vector3d(16, 0, 0); + middlePos.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + middlePos.rotateY(-yRot * Mth.DEG_TO_RAD); + + Vec3 BarrelMiddlePos = new Vec3(BarrelRootPos.x + middlePos.x, BarrelRootPos.y + middlePos.y, BarrelRootPos.z + middlePos.z); + + var rightPos = new Vector3d(16, 0, 2.703125); + rightPos.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + rightPos.rotateY(-yRot * Mth.DEG_TO_RAD); + + Vec3 BarrelRightPos = new Vec3(BarrelRootPos.x + rightPos.x, BarrelRootPos.y + rightPos.y, BarrelRootPos.z + rightPos.z); + + if (this.entityData.get(COOL_DOWN) > 88) { + this.entityData.set(LASER_LEFT_LENGTH, Math.min(laserLength(BarrelLeftPos, this), laserLengthEntity(BarrelLeftPos, this))); + this.entityData.set(LASER_MIDDLE_LENGTH, Math.min(laserLength(BarrelMiddlePos, this), laserLengthEntity(BarrelMiddlePos, this))); + this.entityData.set(LASER_RIGHT_LENGTH, Math.min(laserLength(BarrelRightPos, this), laserLengthEntity(BarrelRightPos, this))); + } + +// if (this.getPassengers().isEmpty()) { +// autoAim(); +// } else { +// travel(); +// } + if (this.entityData.get(COOL_DOWN) == 20) { + this.level().playSound(null, this.getOnPos(), ModSounds.ANNIHILATOR_RELOAD.get(), SoundSource.PLAYERS, 1, 1); + } + } + + @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 yRot, float xRot, int steps) { + serverYRot = yRot; + serverXRot = xRot; + this.interpolationSteps = 10; + } + + private float laserLength(Vec3 pos, Entity cannon) { + if (this.level() instanceof ServerLevel) { + BlockHitResult result = cannon.level().clip(new ClipContext(pos, pos.add(cannon.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, cannon)); + + Vec3 looking = Vec3.atLowerCornerOf(result.getBlockPos()); + Vec3 hitPos = result.getLocation(); + BlockPos _pos = BlockPos.containing(looking.x, looking.y, looking.z); + + float hardness = this.level().getBlockState(_pos).getBlock().defaultDestroyTime(); + + if (ExplosionConfig.EXPLOSION_DESTROY.get() && hardness != -1) { + Block.dropResources(this.level().getBlockState(_pos), this.level(), _pos, null); + this.level().destroyBlock(_pos, true); + } + + if (this.entityData.get(COOL_DOWN) > 98) { + laserExplosion(hitPos); + } + + if (this.getFirstPassenger() != null) { + this.level().explode(this.getFirstPassenger(), hitPos.x, hitPos.y, hitPos.z, 5, ExplosionConfig.EXPLOSION_DESTROY.get() ? Level.ExplosionInteraction.BLOCK : Level.ExplosionInteraction.NONE); + } else { + Entity shooter = EntityFindUtil.findEntity(this.level(), this.entityData.get(SHOOTER_UUID)); + this.level().explode(shooter, hitPos.x, hitPos.y, hitPos.z, 5, ExplosionConfig.EXPLOSION_DESTROY.get() ? Level.ExplosionInteraction.BLOCK : Level.ExplosionInteraction.NONE); + } + } + + return (float) pos.distanceTo((Vec3.atLowerCornerOf(cannon.level().clip( + new ClipContext(pos, pos.add(cannon.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, cannon)).getBlockPos()))); + } + + private float laserLengthEntity(Vec3 pos, Entity cannon) { + if (this.level() instanceof ServerLevel) { + double distance = 512 * 512; + HitResult hitResult = cannon.pick(512, 1.0f, false); + if (hitResult.getType() != HitResult.Type.MISS) { + distance = hitResult.getLocation().distanceToSqr(pos); + double blockReach = 5; + if (distance > blockReach * blockReach) { + Vec3 posB = hitResult.getLocation(); + hitResult = BlockHitResult.miss(posB, Direction.getNearest(pos.x, pos.y, pos.z), BlockPos.containing(posB)); + } + } + Vec3 viewVec = cannon.getViewVector(1.0F); + Vec3 toVec = pos.add(viewVec.x * 512, viewVec.y * 512, viewVec.z * 512); + AABB aabb = cannon.getBoundingBox().expandTowards(viewVec.scale(512)).inflate(1.0D, 1.0D, 1.0D); + EntityHitResult entityhitresult = ProjectileUtil.getEntityHitResult(cannon, pos, toVec, aabb, p -> !p.isSpectator(), distance); + if (entityhitresult != null) { + Vec3 targetPos = entityhitresult.getLocation(); + double distanceToTarget = pos.distanceToSqr(targetPos); + if (distanceToTarget > distance || distanceToTarget > 512 * 512) { + hitResult = BlockHitResult.miss(targetPos, Direction.getNearest(viewVec.x, viewVec.y, viewVec.z), BlockPos.containing(targetPos)); + } else if (distanceToTarget < distance) { + hitResult = entityhitresult; + } + if (hitResult.getType() == HitResult.Type.ENTITY) { + Entity passenger = this.getFirstPassenger(); + Entity target = ((EntityHitResult) hitResult).getEntity(); + + if (passenger != null) { + target.hurt(ModDamageTypes.causeLaserDamage(this.level().registryAccess(), this, passenger), (float) 200); + } else { + Entity shooter = EntityFindUtil.findEntity(this.level(), this.entityData.get(SHOOTER_UUID)); + target.hurt(ModDamageTypes.causeLaserDamage(this.level().registryAccess(), this, shooter), (float) 200); + + } + + target.invulnerableTime = 0; + if (this.entityData.get(COOL_DOWN) > 98) { + laserExplosion(targetPos); + } + return (float) pos.distanceTo(target.position()); + } + } + } + return 512; + } + + private void laserExplosion(Vec3 pos) { + Entity passenger = this.getFirstPassenger(); + + if (passenger != null) { + CustomExplosion explosion = new CustomExplosion(this.level(), passenger, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, passenger), 300f, + pos.x, pos.y, pos.z, 15f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnHugeExplosionParticles(this.level(), pos); + } else { + Entity shooter = EntityFindUtil.findEntity(this.level(), this.entityData.get(SHOOTER_UUID)); + CustomExplosion explosion = new CustomExplosion(this.level(), shooter, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, shooter), 300f, + pos.x, pos.y, pos.z, 15f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnHugeExplosionParticles(this.level(), pos); + } + } + + @Override + public void destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 600f, + this.getX(), this.getY(), this.getZ(), 15f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnHugeExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + @Override + public void vehicleShoot(Player player, int type) { + if (this.entityData.get(COOL_DOWN) > 0) { + return; + } + + if (!this.canConsume(VehicleConfig.ANNIHILATOR_SHOOT_COST.get())) { + player.displayClientMessage(Component.translatable("tips.superbwarfare.annihilator.energy_not_enough").withStyle(ChatFormatting.RED), true); + return; + } + + Level level = player.level(); + if (level instanceof ServerLevel) { + if (player instanceof ServerPlayer serverPlayer) { + SoundTool.playLocalSound(serverPlayer, ModSounds.ANNIHILATOR_FIRE_1P.get(), 1, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.ANNIHILATOR_FIRE_3P.get(), SoundSource.PLAYERS, 6, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.ANNIHILATOR_FAR.get(), SoundSource.PLAYERS, 16, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.ANNIHILATOR_VERYFAR.get(), SoundSource.PLAYERS, 32, 1); + } + + this.entityData.set(COOL_DOWN, 100); + this.consumeEnergy(VehicleConfig.ANNIHILATOR_SHOOT_COST.get()); + final Vec3 center = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(20), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(15, 15, 25, this.getX(), this.getEyeY(), this.getZ())); + } + } + } + } + + @Override + public void travel() { + Entity passenger = this.getFirstPassenger(); + if (this.getEnergy() <= 0) return; + + if (passenger instanceof LivingEntity entity) { + float yRot = this.getYRot(); + if (yRot < 0) { + yRot += 360; + } + yRot = yRot + 90 % 360; + + var BarrelRoot = new Vector3d(4.95, 2.25, 0); + BarrelRoot.rotateY(-yRot * Mth.DEG_TO_RAD); + + Vec3 barrelRootPos = new Vec3(this.getX() + BarrelRoot.x, this.getY() + BarrelRoot.y, this.getZ() + BarrelRoot.z); + + Vec3 passengersEyePos = new Vec3(entity.getX(), entity.getEyeY(), entity.getZ()); + + Entity lookingAt = TraceTool.findLookingEntity(entity, 512); + + if (lookingAt == null) { + HitResult result = entity.level().clip(new ClipContext(passengersEyePos, passengersEyePos.add(entity.getViewVector(1).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, entity)); + Vec3 blockHitPos = result.getLocation(); + barrelLookAt = new Vec3(blockHitPos.x - barrelRootPos.x, blockHitPos.y - barrelRootPos.y, blockHitPos.z - barrelRootPos.z); + } else { + barrelLookAt = new Vec3(lookingAt.getX() - barrelRootPos.x, lookingAt.getEyeY() - barrelRootPos.y, lookingAt.getZ() - barrelRootPos.z); + } + + float offset = (float) VectorTool.calculateAngle(entity.getViewVector(1), barrelLookAt); + + entityData.set(YAW, passenger.getYHeadRot()); + entityData.set(PITCH, Mth.clamp(passenger.getXRot() - offset, -45f, 5f)); + } + + float diffY = Mth.wrapDegrees(entityData.get(YAW) - this.getYRot()); + float diffX = Mth.wrapDegrees(entityData.get(PITCH) - this.getXRot()); + + turretTurnSound(diffX, diffY, 0.8f); + + this.setYRot(this.getYRot() + Mth.clamp(0.5f * diffY, -0.6f, 0.6f)); + this.setXRot(Mth.clamp(this.getXRot() + Mth.clamp(diffX, -0.8f, 0.8f), -45, 5f)); + } + + public void autoAim() { + if (this.getEnergy() <= 0) return; + + Entity target = SeekTool.seekLivingEntity(this, this.level(), 64, 30); + + if (target == null) return; + + float yRot = this.getYRot(); + if (yRot < 0) { + yRot += 360; + } + yRot = yRot + 90 % 360; + + var BarrelRoot = new Vector3d(4.95, 2.25, 0); + BarrelRoot.rotateY(-yRot * Mth.DEG_TO_RAD); + + Vec3 barrelRootPos = new Vec3(this.getX() + BarrelRoot.x, this.getY() + BarrelRoot.y, this.getZ() + BarrelRoot.z); + Vec3 targetVec = new Vec3(target.getX() - barrelRootPos.x, target.getEyeY() - barrelRootPos.y, target.getZ() - barrelRootPos.z).normalize(); + + double d0 = targetVec.x; + double d1 = targetVec.y; + double d2 = targetVec.z; + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + this.setXRot(Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875)))); + float targetY = Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F); + + float diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(targetY - this.getYRot())); + + this.setYRot(this.getYRot() + Mth.clamp(0.5f * diffY, -1f, 1f)); + this.setRot(this.getYRot(), this.getXRot()); + } + + protected void clampRotation(Entity entity) { + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, -45.0F, 5); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + private PlayState movementPredicate(AnimationState event) { + if (this.entityData.get(COOL_DOWN) > 85) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.annihilator.fire")); + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.annihilator.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.ANNIHILATOR_MAX_ENERGY.get(); + } + + @Override + public float getMaxHealth() { + return VehicleConfig.ANNIHILATOR_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + return 0; + } + + @Override + public boolean canShoot(Player player) { + return true; + } + + @Override + public int getAmmoCount(Player player) { + var cap = this.getCapability(Capabilities.EnergyStorage.ENTITY, null); + return (int) ((cap != null ? cap.getEnergyStored() : 0) * 100f / (float) this.getMaxEnergy()); + } + + @Override + public boolean hidePassenger(Entity entity) { + return true; + } + + @Override + public int zoomFov() { + return 5; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/annihilator_icon.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java new file mode 100644 index 000000000..06b712790 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java @@ -0,0 +1,692 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +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.LandArmorEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.ProjectileWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.SmallCannonShellWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.WgMissileWeapon; +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.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.AmmoType; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.mojang.math.Axis; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +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.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +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.Matrix4f; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Comparator; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class Bmp2Entity extends ContainerMobileVehicleEntity implements GeoEntity, LandArmorEntity, WeaponVehicleEntity { + public static final EntityDataAccessor CANNON_FIRE_TIME = SynchedEntityData.defineId(Bmp2Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor LOADED_MISSILE = SynchedEntityData.defineId(Bmp2Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor MISSILE_COUNT = SynchedEntityData.defineId(Bmp2Entity.class, EntityDataSerializers.INT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public int reloadCoolDown; + + + public Bmp2Entity(EntityType type, Level world) { + super(type, world); + } + + @Override + public float maxUpStep() { + return 2.25F; + } + + @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()) + .explosionRadius(VehicleConfig.BMP_2_CANNON_EXPLOSION_RADIUS.get().floatValue()) + .sound(ModSounds.INTO_MISSILE.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/cannon_30mm.png")), + new ProjectileWeapon() + .damage(9.5f) + .headShot(2) + .zoom(false) + .sound(ModSounds.INTO_CANNON.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/gun_7_62mm.png")), + new WgMissileWeapon() + .damage(ExplosionConfig.WIRE_GUIDE_MISSILE_DAMAGE.get()) + .explosionDamage(ExplosionConfig.WIRE_GUIDE_MISSILE_EXPLOSION_DAMAGE.get()) + .explosionRadius(ExplosionConfig.WIRE_GUIDE_MISSILE_EXPLOSION_RADIUS.get()) + .sound(ModSounds.INTO_MISSILE.get()), + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(3, 1, 0); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(CANNON_FIRE_TIME, 0) + .define(LOADED_MISSILE, 0) + .define(MISSILE_COUNT, 0); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("LoadedMissile", this.entityData.get(LOADED_MISSILE)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(LOADED_MISSILE, compound.getInt("LoadedMissile")); + } + + // TODO getAddEntityPacket + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.2f) + .multiply(1.5f, DamageTypes.ARROW) + .multiply(1.5f, DamageTypes.TRIDENT) + .multiply(2.5f, DamageTypes.MOB_ATTACK) + .multiply(2f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(1.5f, DamageTypes.MOB_PROJECTILE) + .multiply(12.5f, DamageTypes.LAVA) + .multiply(6f, DamageTypes.EXPLOSION) + .multiply(6f, DamageTypes.PLAYER_EXPLOSION) + .multiply(2f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(2f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.7f, ModDamageTypes.MINE) + .multiply(0.9f, ModDamageTypes.LUNGE_MINE) + .multiply(1.5f, ModDamageTypes.CANNON_FIRE) + .multiply(0.1f, ModTags.DamageTypes.PROJECTILE) + .multiply(0.7f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .multiply(8.5f, ModDamageTypes.VEHICLE_STRIKE) + .custom((source, damage) -> getSourceAngle(source, 0.4f) * damage) + .custom((source, damage) -> { + if (source.getDirectEntity() instanceof MelonBombEntity) { + return 2f * damage; + } + if (source.getDirectEntity() instanceof MortarShellEntity) { + return 3f * damage; + } + return damage; + }) + .reduce(8); + } + + @Override + @ParametersAreNonnullByDefault + protected void playStepSound(BlockPos pPos, BlockState pState) { + this.playSound(ModSounds.BMP_STEP.get(), Mth.abs(this.entityData.get(POWER)) * 8, random.nextFloat() * 0.15f + 1f); + } + + @Override + public double getSubmergedHeight(Entity entity) { + return super.getSubmergedHeight(entity); + } + + @Override + public void baseTick() { + super.baseTick(); + + if (getLeftTrack() < 0) { + setLeftTrack(100); + } + + if (getLeftTrack() > 100) { + setLeftTrack(0); + } + + if (getRightTrack() < 0) { + setRightTrack(100); + } + + if (getRightTrack() > 100) { + setRightTrack(0); + } + + + if (this.level() instanceof ServerLevel) { + if (reloadCoolDown > 0) { + reloadCoolDown--; + } + this.handleAmmo(); + } + + double fluidFloat; + fluidFloat = 0.052 * getSubmergedHeight(this); + this.setDeltaMovement(this.getDeltaMovement().add(0.0, fluidFloat, 0.0)); + + if (this.onGround()) { + float f0 = 0.54f + 0.25f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.05 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f0, 0.85, f0)); + } else if (this.isInWater()) { + float f1 = 0.61f + 0.08f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.04 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f1, 0.85, f1)); + } else { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.99, 0.95, 0.99)); + } + + if (this.level() instanceof ServerLevel serverLevel && this.isInWater() && this.getDeltaMovement().length() > 0.1) { + sendParticle(serverLevel, ParticleTypes.CLOUD, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 4 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + sendParticle(serverLevel, ParticleTypes.BUBBLE_COLUMN_UP, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 10 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + } + + collideBlock(); + if (this.getDeltaMovement().length() > 0.1) { + collideHardBlock(); + } + + turretAngle(15, 10); + this.terrainCompat(4f, 5f); + inertiaRotate(1); + + lowHealthWarning(); + 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 AmmoType.RIFLE.get(stack) > 0; + } + return false; + }).mapToInt(AmmoType.RIFLE::get).sum() + countItem(ModItems.RIFLE_AMMO.get()); + + if ((hasItem(ModItems.WIRE_GUIDE_MISSILE.get()) + || InventoryTool.hasCreativeAmmoBox(player)) + && this.reloadCoolDown <= 0 && this.getEntityData().get(LOADED_MISSILE) < 1) { + this.entityData.set(LOADED_MISSILE, this.getEntityData().get(LOADED_MISSILE) + 1); + this.reloadCoolDown = 160; + if (!InventoryTool.hasCreativeAmmoBox(player)) { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.WIRE_GUIDE_MISSILE.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + this.level().playSound(null, this, ModSounds.BMP_MISSILE_RELOAD.get(), this.getSoundSource(), 1, 1); + } + + if (getWeaponIndex(0) == 0) { + this.entityData.set(AMMO, countItem(ModItems.SMALL_SHELL.get())); + } else if (getWeaponIndex(0) == 1) { + this.entityData.set(AMMO, ammoCount); + } else { + this.entityData.set(AMMO, this.getEntityData().get(LOADED_MISSILE)); + } + + this.entityData.set(MISSILE_COUNT, countItem(ModItems.WIRE_GUIDE_MISSILE.get())); + } + + @Override + public void move(@NotNull MoverType movementType, @NotNull Vec3 movement) { + super.move(movementType, movement); + if (this.isInWater() && horizontalCollision) { + setDeltaMovement(this.getDeltaMovement().add(0, 0.07, 0)); + } + } + + @Override + public void vehicleShoot(Player player, int type) { + boolean hasCreativeAmmo = false; + for (int i = 0; i < getMaxPassengers() - 1; i++) { + if (getNthEntity(i) instanceof Player pPlayer && InventoryTool.hasCreativeAmmoBox(pPlayer)) { + hasCreativeAmmo = true; + } + } + + Matrix4f transform = getBarrelTransform(1); + if (getWeaponIndex(0) == 0) { + if (this.cannotFire) return; + float x = -0.45f; + float y = 0.4f; + float z = 4.2f; + + Vector4f worldPosition = transformPosition(transform, x, y, z); + var smallCannonShell = ((SmallCannonShellWeapon) getWeapon(0)).create(player); + + smallCannonShell.setPos(worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z); + smallCannonShell.shoot(getBarrelVector(1).x, getBarrelVector(1).y + 0.005f, getBarrelVector(1).z, 20, + 0.25f); + this.level().addFreshEntity(smallCannonShell); + + sendParticle((ServerLevel) this.level(), ParticleTypes.LARGE_SMOKE, worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z, 1, 0.02, 0.02, 0.02, 0, false); + + float pitch = this.entityData.get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - this.entityData.get(HEAT))); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.BMP_CANNON_FIRE_3P.get(), 4, pitch); + serverPlayer.playSound(ModSounds.LAV_CANNON_FAR.get(), 12, pitch); + serverPlayer.playSound(ModSounds.LAV_CANNON_VERYFAR.get(), 24, pitch); + } + } + + 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(4), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 5, 9, this.getX(), this.getEyeY(), this.getZ())); + } + } + + this.entityData.set(CANNON_RECOIL_TIME, 40); + this.entityData.set(YAW, getTurretYRot()); + + this.entityData.set(HEAT, this.entityData.get(HEAT) + 7); + this.entityData.set(FIRE_ANIM, 3); + + if (hasCreativeAmmo) return; + + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.SMALL_SHELL.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } else if (getWeaponIndex(0) == 1) { + if (this.cannotFireCoax) return; + float x = -0.2f; + float y = 0.3f; + float z = 1.2f; + + Vector4f worldPosition = transformPosition(transform, x, y, z); + + if (this.entityData.get(AMMO) > 0 || hasCreativeAmmo) { + var projectileRight = ((ProjectileWeapon) getWeapon(0)).create(player); + + projectileRight.bypassArmorRate(0.2f); + projectileRight.setPos(worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z); + projectileRight.shoot(player, getBarrelVector(1).x, getBarrelVector(1).y + 0.002f, getBarrelVector(1).z, 36, + 0.25f); + this.level().addFreshEntity(projectileRight); + + if (!hasCreativeAmmo) { + ItemStack ammoBox = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return AmmoType.RIFLE.get(stack) > 0; + } + return false; + }).findFirst().orElse(ItemStack.EMPTY); + + if (!ammoBox.isEmpty()) { + AmmoType.RIFLE.add(ammoBox, -1); + } else { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.RIFLE_AMMO.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + } + } + + this.entityData.set(COAX_HEAT, this.entityData.get(COAX_HEAT) + 3); + this.entityData.set(FIRE_ANIM, 2); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.M_60_FIRE_3P.get(), 3, 1); + serverPlayer.playSound(ModSounds.M_60_FAR.get(), 6, 1); + serverPlayer.playSound(ModSounds.M_60_VERYFAR.get(), 12, 1); + } + } + } else if (getWeaponIndex(0) == 2 && this.getEntityData().get(LOADED_MISSILE) > 0) { + Matrix4f transformT = getBarrelTransform(1); + Vector4f worldPosition = transformPosition(transformT, 0, 1, 0); + + var wgMissileEntity = ((WgMissileWeapon) getWeapon(0)).create(player); + + wgMissileEntity.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + wgMissileEntity.shoot(getBarrelVector(1).x, getBarrelVector(1).y, getBarrelVector(1).z, 2f, 0f); + player.level().addFreshEntity(wgMissileEntity); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.BMP_MISSILE_FIRE_3P.get(), 6, 1); + } + } + + this.entityData.set(LOADED_MISSILE, this.getEntityData().get(LOADED_MISSILE) - 1); + reloadCoolDown = 160; + } + } + + @Override + public void travel() { + Entity passenger0 = this.getFirstPassenger(); + + if (this.getEnergy() <= 0) return; + + if (passenger0 == null) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + this.entityData.set(POWER, 0f); + } + + if (forwardInputDown) { + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + (this.entityData.get(POWER) < 0 ? 0.016f : 0.0024f), 0.21f)); + } + + if (backInputDown) { + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - (this.entityData.get(POWER) > 0 ? 0.016f : 0.0024f), -0.16f)); + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } + } else { + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } + } + + if (this.forwardInputDown || this.backInputDown) { + this.consumeEnergy(VehicleConfig.BMP_2_ENERGY_COST.get()); + } + + this.entityData.set(POWER, this.entityData.get(POWER) * (upInputDown ? 0.5f : (rightInputDown || leftInputDown) ? 0.947f : 0.96f)); + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * (float) Math.max(0.76f - 0.1f * this.getDeltaMovement().horizontalDistance(), 0.3)); + + float angle = (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1)); + double s0; + + if (Mth.abs(angle) < 90) { + s0 = this.getDeltaMovement().horizontalDistance(); + } else { + s0 = -this.getDeltaMovement().horizontalDistance(); + } + + this.setLeftWheelRot((float) ((this.getLeftWheelRot() - 1.25 * s0) + Mth.clamp(0.75f * this.entityData.get(DELTA_ROT), -5f, 5f))); + this.setRightWheelRot((float) ((this.getRightWheelRot() - 1.25 * s0) - Mth.clamp(0.75f * this.entityData.get(DELTA_ROT), -5f, 5f))); + + setLeftTrack((float) ((getLeftTrack() - 1.9 * Math.PI * s0) + Mth.clamp(0.4f * Math.PI * this.entityData.get(DELTA_ROT), -5f, 5f))); + setRightTrack((float) ((getRightTrack() - 1.9 * Math.PI * s0) - Mth.clamp(0.4f * Math.PI * this.entityData.get(DELTA_ROT), -5f, 5f))); + + if (this.isInWater() || onGround()) { + this.setYRot((float) (this.getYRot() - (isInWater() && !onGround() ? 2.5 : 6) * entityData.get(DELTA_ROT))); + this.setDeltaMovement(this.getDeltaMovement().add(getViewVector(1).scale((!isInWater() && !onGround() ? 0.13f : (isInWater() && !onGround() ? 2 : 2.4f)) * this.entityData.get(POWER)))); + } + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.BMP_ENGINE.get(); + } + + @Override + public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) { + // From Immersive_Aircraft + if (!this.hasPassenger(passenger)) { + return; + } + + Matrix4f transform = getTurretTransform(1); + Matrix4f transformV = getVehicleTransform(1); + + int i = this.getSeatIndex(passenger); + + Vector4f worldPosition; + if (i == 0) { + worldPosition = transformPosition(transform, 0.36f, -0.25f, 0.56f); + } else { + worldPosition = transformPosition(transformV, 0, 1, 0); + } + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + + copyEntityData(passenger); + } + + public void copyEntityData(Entity entity) { + if (entity == getNthEntity(0)) { + entity.setYBodyRot(getBarrelYRot(1)); + } + } + + public int getMaxPassengers() { + return 5; + } + + public Vec3 driverZoomPos(float ticks) { + Matrix4f transform = getTurretTransform(ticks); + Vector4f worldPosition = transformPosition(transform, 0, 0, 0.75f); + return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); + } + + @Override + public Vec3 getBarrelVector(float pPartialTicks) { + Matrix4f transform = getBarrelTransform(pPartialTicks); + Vector4f rootPosition = transformPosition(transform, 0, 0, 0); + Vector4f targetPosition = transformPosition(transform, 0, 0, 1); + return new Vec3(rootPosition.x, rootPosition.y, rootPosition.z).vectorTo(new Vec3(targetPosition.x, targetPosition.y, targetPosition.z)); + } + + public Matrix4f getBarrelTransform(float ticks) { + Matrix4f transformT = getTurretTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0.3625f, 0.293125f, 1.18095f); + + transformT.translate(worldPosition.x, worldPosition.y, worldPosition.z); + + float a = getTurretYaw(ticks); + + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float x = Mth.lerp(ticks, turretXRotO, getTurretXRot()); + float xV = Mth.lerp(ticks, xRotO, getXRot()); + float z = Mth.lerp(ticks, prevRoll, getRoll()); + + transformT.rotate(Axis.XP.rotationDegrees(x + r * xV + r2 * z)); + return transformT; + } + + public Matrix4f getTurretTransform(float ticks) { + Matrix4f transformV = getVehicleTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0, 2.25f, -0.703125f); + + transformV.translate(worldPosition.x, worldPosition.y, worldPosition.z); + transformV.rotate(Axis.YP.rotationDegrees(Mth.lerp(ticks, turretYRotO, getTurretYRot()))); + return transformV; + } + + @Override + public void destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 80f, + this.getX(), this.getY(), this.getZ(), 5f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + protected void clampRotation(Entity entity) { + float a = getTurretYaw(1); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float min = -74f - r * getXRot() - r2 * getRoll(); + float max = 7.5f - r * getXRot() - r2 * getRoll(); + + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, min, max); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + entity.setYBodyRot(getBarrelYRot(1)); + } + + @Override + public void onPassengerTurned(Entity entity) { + this.clampRotation(entity); + } + + private PlayState firePredicate(AnimationState event) { + if (this.entityData.get(FIRE_ANIM) > 1 && getWeaponIndex(0) == 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lav.fire")); + } + + if (this.entityData.get(FIRE_ANIM) > 0 && getWeaponIndex(0) == 1) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lav.fire2")); + } + + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.lav.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::firePredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.BMP_2_MAX_ENERGY.get(); + } + + @Override + public float getMaxHealth() { + return VehicleConfig.BMP_2_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + if (getWeaponIndex(0) == 0) { + return 250; + } else if (getWeaponIndex(0) == 1) { + return 750; + } + return 250; + } + + @Override + public boolean canShoot(Player player) { + if (getWeaponIndex(0) == 0) { + return (this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFire; + } else if (getWeaponIndex(0) == 1) { + return (this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFireCoax; + } else if (getWeaponIndex(0) == 2) { + return (this.entityData.get(LOADED_MISSILE) > 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 true; + } + + @Override + public int zoomFov() { + return 3; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/bmp2_icon.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java new file mode 100644 index 000000000..89fcf197c --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/DroneEntity.java @@ -0,0 +1,658 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.projectile.*; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.item.Monitor; +import com.atsuishio.superbwarfare.item.common.ammo.MortarShell; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.NBTTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.ChatFormatting; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.AreaEffectCloud; +import net.minecraft.world.entity.Entity; +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.entity.projectile.Projectile; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.alchemy.Potion; +import net.minecraft.world.item.alchemy.Potions; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.items.ItemHandlerHelper; +import org.jetbrains.annotations.NotNull; +import org.joml.Math; +import org.joml.Vector3f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.Comparator; +import java.util.Objects; +import java.util.UUID; + +public class DroneEntity extends MobileVehicleEntity implements GeoEntity { + + public static final EntityDataAccessor LINKED = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.BOOLEAN); + public static final EntityDataAccessor CONTROLLER = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.STRING); + public static final EntityDataAccessor KAMIKAZE_MODE = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor DELTA_X_ROT = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.FLOAT); + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public static final float MAX_HEALTH = 5; + + public boolean fire; + public int collisionCoolDown; + public double lastTickSpeed; + public double lastTickVerticalSpeed; + public ItemStack currentItem = ItemStack.EMPTY; + + public float pitch; + public float pitchO; + + public int holdTickX; + public int holdTickY; + public int holdTickZ; + + public DroneEntity(EntityType type, Level world) { + super(type, world); + } + + public float getBodyPitch() { + return pitch; + } + + public void setBodyXRot(float rot) { + pitch = rot; + } + + public float getBodyPitch(float tickDelta) { + return Mth.lerp(0.6f * tickDelta, pitchO, getBodyPitch()); + } + + @Override + public boolean sendFireStarParticleOnHurt() { + return false; + } + + @Override + public boolean playHitSoundOnHurt() { + return false; + } + + @Override + public float getMaxHealth() { + return MAX_HEALTH; + } + + public DroneEntity(EntityType type, Level world, float moveX, float moveY, float moveZ) { + super(type, world); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(DELTA_X_ROT, 0f) + .define(CONTROLLER, "undefined") + .define(LINKED, false) + .define(KAMIKAZE_MODE, 0); + } + + // TODO addEntityPacket + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + + // @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public boolean causeFallDamage(float l, float d, DamageSource source) { + return false; + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putBoolean("Linked", this.entityData.get(LINKED)); + compound.putString("Controller", this.entityData.get(CONTROLLER)); + compound.putInt("Ammo", this.entityData.get(AMMO)); + compound.putInt("KamikazeMode", this.entityData.get(KAMIKAZE_MODE)); + + CompoundTag item = new CompoundTag(); + this.currentItem.save(level().registryAccess(), item); + compound.put("Item", item); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + if (compound.contains("Linked")) + this.entityData.set(LINKED, compound.getBoolean("Linked")); + if (compound.contains("Controller")) + this.entityData.set(CONTROLLER, compound.getString("Controller")); + if (compound.contains("Ammo")) + this.entityData.set(AMMO, compound.getInt("Ammo")); + if (compound.contains("KamikazeMode")) + this.entityData.set(KAMIKAZE_MODE, compound.getInt("KamikazeMode")); + if (compound.contains("Item")) + this.currentItem = ItemStack.parse(level().registryAccess(), compound.getCompound("Item")) + .orElse(ItemStack.EMPTY); + } + + @Override + public int maxRepairCoolDown() { + return -1; + } + + @Override + public void baseTick() { + pitchO = this.getBodyPitch(); + setBodyXRot(pitch * 0.9f); + + super.baseTick(); + + setZRot(getRoll() * 0.9f); + + lastTickSpeed = this.getDeltaMovement().length(); + lastTickVerticalSpeed = this.getDeltaMovement().y; + + if (collisionCoolDown > 0) { + collisionCoolDown--; + } + + Player controller = EntityFindUtil.findPlayer(this.level(), this.entityData.get(CONTROLLER)); + + if (!this.onGround()) { + if (controller != null) { + ItemStack stack = controller.getMainHandItem(); + var tag = NBTTool.getTag(stack); + if (stack.is(ModItems.MONITOR.get()) && tag.getBoolean("Using")) { + if (controller.level().isClientSide) { + controller.playSound(ModSounds.DRONE_SOUND.get(), 114, 1); + } + } else { + upInputDown = false; + downInputDown = false; + forwardInputDown = false; + backInputDown = false; + leftInputDown = false; + rightInputDown = false; + } + + if (tickCount % 5 == 0) { + controller.getInventory().items.stream().filter(pStack -> pStack.getItem() == ModItems.MONITOR.get()) + .forEach(pStack -> { + if (tag.getString(Monitor.LINKED_DRONE).equals(this.getStringUUID())) { + Monitor.getDronePos(pStack, this.position()); + } + }); + } + } + } + + if (this.isInWater()) { + this.hurt(new DamageSource(level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.EXPLOSION), controller), 0.25f + (float) (2 * lastTickSpeed)); + } + + if (this.fire) { + if (this.entityData.get(AMMO) > 0) { + this.entityData.set(AMMO, this.entityData.get(AMMO) - 1); + if (controller != null) { + droneDrop(controller); + } + } + if (this.entityData.get(KAMIKAZE_MODE) != 0) { + if (controller != null) { + if (controller.getMainHandItem().is(ModItems.MONITOR.get())) { + Monitor.disLink(controller.getMainHandItem(), controller); + } + this.hurt(new DamageSource(level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.EXPLOSION), controller), 10000); + } + + } + this.fire = false; + } + + this.refreshDimensions(); + } + + + private void droneDrop(Player player) { + Level level = player.level(); + if (!level.isClientSide()) { + RgoGrenadeEntity rgoGrenadeEntity = new RgoGrenadeEntity(player, level, 160); + rgoGrenadeEntity.setPos(this.getX(), this.getEyeY() - 0.09, this.getZ()); + rgoGrenadeEntity.droneShoot(this); + level.addFreshEntity(rgoGrenadeEntity); + } + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + if (stack.getItem() == ModItems.MONITOR.get()) { + var tag = NBTTool.getTag(stack); + if (!player.isCrouching()) { + if (!this.entityData.get(LINKED)) { + if (tag.getBoolean("Linked")) { + player.displayClientMessage(Component.translatable("tips.superbwarfare.monitor.already_linked").withStyle(ChatFormatting.RED), true); + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + + this.entityData.set(LINKED, true); + this.entityData.set(CONTROLLER, player.getStringUUID()); + + Monitor.link(stack, this.getStringUUID()); + player.displayClientMessage(Component.translatable("tips.superbwarfare.monitor.linked").withStyle(ChatFormatting.GREEN), true); + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), SoundEvents.ARROW_HIT_PLAYER, SoundSource.PLAYERS, 0.5F, 1); + } + } else { + player.displayClientMessage(Component.translatable("tips.superbwarfare.drone.already_linked").withStyle(ChatFormatting.RED), true); + } + } else { + if (this.entityData.get(LINKED)) { + if (!tag.getBoolean("Linked")) { + player.displayClientMessage(Component.translatable("tips.superbwarfare.drone.already_linked").withStyle(ChatFormatting.RED), true); + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + + this.entityData.set(CONTROLLER, "none"); + this.entityData.set(LINKED, false); + + Monitor.disLink(stack, player); + player.displayClientMessage(Component.translatable("tips.superbwarfare.monitor.unlinked").withStyle(ChatFormatting.RED), true); + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), SoundEvents.ARROW_HIT_PLAYER, SoundSource.PLAYERS, 0.5F, 1); + } + } + } + } else if (stack.is(ModItems.CROWBAR.get()) && player.isCrouching()) { + // 返还物品 + ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.DRONE.get())); + + // 返还普通弹药 + for (int index0 = 0; index0 < this.entityData.get(AMMO); index0++) { + ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.RGO_GRENADE.get())); + } + + // 返还神风弹药 + if (this.entityData.get(KAMIKAZE_MODE) != 0) { + ItemHandlerHelper.giveItemToPlayer(player, this.currentItem); + } + + player.getInventory().items.stream().filter(stack_ -> stack_.getItem() == ModItems.MONITOR.get()) + .forEach(itemStack -> { + if (NBTTool.getTag(itemStack).getString(Monitor.LINKED_DRONE).equals(this.getStringUUID())) { + Monitor.disLink(itemStack, player); + } + }); + + if (!this.level().isClientSide()) { + this.discard(); + } + } else if (stack.getItem() == ModItems.RGO_GRENADE.get() && this.entityData.get(KAMIKAZE_MODE) == 0) { + // 装载普通弹药 + if (this.entityData.get(AMMO) < 6) { + this.entityData.set(AMMO, this.entityData.get(AMMO) + 1); + if (!player.isCreative()) { + stack.shrink(1); + } + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1); + } + } + } else if (stack.getItem() instanceof MortarShell && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) { + // 迫击炮神风 + var copy = stack.copy(); + copy.setCount(1); + this.currentItem = copy; + + if (!player.isCreative()) { + stack.shrink(1); + } + this.entityData.set(KAMIKAZE_MODE, 1); + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1); + } + } else if (stack.getItem() == ModItems.C4_BOMB.get() && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) { + // C4神风 + this.currentItem = new ItemStack(stack.getItem(), 1); + + if (!player.isCreative()) { + stack.shrink(1); + } + this.entityData.set(KAMIKAZE_MODE, 2); + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1); + } + } else if (stack.getItem() == ModItems.ROCKET.get() && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) { + // RPG神风 + this.currentItem = new ItemStack(stack.getItem(), 1); + + if (!player.isCreative()) { + stack.shrink(1); + } + this.entityData.set(KAMIKAZE_MODE, 3); + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1); + } + } + + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + + @Override + public void travel() { + float diffX; + float diffY; + if (!this.onGround()) { + // left and right + if (rightInputDown) { + holdTickX++; + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.3f * Math.min(holdTickX, 5)); + } else if (this.leftInputDown) { + holdTickX++; + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.3f * Math.min(holdTickX, 5)); + } else { + holdTickX = 0; + } + + // forward and backward + if (forwardInputDown) { + holdTickZ++; + this.entityData.set(DELTA_X_ROT, this.entityData.get(DELTA_X_ROT) - 0.3f * Math.min(holdTickZ, 5)); + } else if (backInputDown) { + holdTickZ++; + this.entityData.set(DELTA_X_ROT, this.entityData.get(DELTA_X_ROT) + 0.3f * Math.min(holdTickZ, 5)); + } else { + holdTickZ = 0; + } + + this.setDeltaMovement(this.getDeltaMovement().multiply(0.94, 0.55, 0.94)); + } else { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.8, 1, 0.8)); + this.setZRot(this.roll * 0.7f); + this.setXRot(this.getXRot() * 0.7f); + this.setBodyXRot(this.getBodyPitch() * 0.7f); + } + + if (this.isInWater() && this.tickCount % 4 == 0) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 0.6, 0.6)); + this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), 26 + (float) (60 * ((lastTickSpeed - 0.4) * (lastTickSpeed - 0.4)))); + } + + boolean up = this.upInputDown; + boolean down = this.downInputDown; + + if (up) { + holdTickY++; + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + 0.06f * Math.min(holdTickY, 5), 0.9f)); + } else if (down) { + holdTickY++; + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - 0.06f * Math.min(holdTickY, 5), -0.9f)); + } else { + holdTickY = 0; + } + + this.entityData.set(POWER, this.entityData.get(POWER) * 0.7f); + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * 0.7f); + this.entityData.set(DELTA_X_ROT, this.entityData.get(DELTA_X_ROT) * 0.7f); + + this.setZRot(Mth.clamp(this.getRoll() - this.entityData.get(DELTA_ROT), -30, 30)); + this.setBodyXRot(Mth.clamp(this.getBodyPitch() - this.entityData.get(DELTA_X_ROT), -30, 30)); + + setDeltaMovement(getDeltaMovement().add(0.0f, Math.min(Math.sin((90 - this.getBodyPitch()) * Mth.DEG_TO_RAD), Math.sin((90 + this.getRoll()) * Mth.DEG_TO_RAD)) * this.entityData.get(POWER), 0.0f)); + + Vector3f direction = getRightDirection().mul(this.entityData.get(DELTA_ROT)); + setDeltaMovement(getDeltaMovement().add(new Vec3(direction.x, direction.y, direction.z).scale(0.04))); + + Vector3f directionZ = getForwardDirection().mul(-this.entityData.get(DELTA_X_ROT)); + setDeltaMovement(getDeltaMovement().add(new Vec3(directionZ.x, directionZ.y, directionZ.z).scale(0.04))); + + Player controller = EntityFindUtil.findPlayer(this.level(), this.entityData.get(CONTROLLER)); + if (controller != null) { + ItemStack stack = controller.getMainHandItem(); + if (stack.is(ModItems.MONITOR.get()) && NBTTool.getTag(stack).getBoolean("Using")) { + diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(controller.getYHeadRot() - this.getYRot())); + diffX = Math.clamp(-60f, 60f, Mth.wrapDegrees(controller.getXRot() - this.getXRot())); + this.setYRot(this.getYRot() + 0.5f * diffY); + this.setXRot(Mth.clamp(this.getXRot() + 0.5f * diffX, -10, 90)); + } + } + + float f = 0.7f; + AABB aabb = AABB.ofSize(this.getEyePosition(), f, 0.3, f); + var level = this.level(); + final Vec3 center = new Vec3(this.getX(), this.getY(), this.getZ()); + for (Entity target : level.getEntitiesOfClass(Entity.class, aabb, e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (this != target && target != null + && !(target instanceof ItemEntity || target instanceof Projectile || target instanceof ProjectileEntity || target instanceof LaserEntity || target instanceof FlareDecoyEntity || target instanceof AreaEffectCloud || target instanceof C4Entity)) { + hitEntityCrash(controller, target); + } + } + } + + public void hitEntityCrash(Player controller, Entity target) { + if (lastTickSpeed > 0.12) { + if (this.entityData.get(KAMIKAZE_MODE) != 0 && 20 * lastTickSpeed > this.getHealth()) { + if (this.entityData.get(KAMIKAZE_MODE) == 1) { + Entity mortarShell = new MortarShellEntity(controller, controller.level()); + target.hurt(ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), mortarShell, controller), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE.get()); + target.invulnerableTime = 0; + } else if (this.entityData.get(KAMIKAZE_MODE) == 2) { + Entity c4 = new C4Entity(controller, controller.level()); + target.hurt(ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), c4, controller), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE_C4.get()); + target.invulnerableTime = 0; + } else if (this.entityData.get(KAMIKAZE_MODE) == 3) { + Entity rpg = new RpgRocketEntity(controller, controller.level(), ExplosionConfig.RPG_EXPLOSION_DAMAGE.get()); + target.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), rpg, controller), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE_RPG.get()); + target.invulnerableTime = 0; + } + + if (controller != null && controller.getMainHandItem().is(ModItems.MONITOR.get())) { + Monitor.disLink(controller.getMainHandItem(), controller); + } + } + target.hurt(ModDamageTypes.causeDroneHitDamage(this.level().registryAccess(), this, controller), (float) (5 * lastTickSpeed)); + + this.hurt(new DamageSource(level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(DamageTypes.EXPLOSION), Objects.requireNonNullElse(controller, this)), (float) (((this.entityData.get(KAMIKAZE_MODE) != 0) ? 20 : 4) * lastTickSpeed)); + } + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.DRONE_SOUND.get(); + } + + @Override + public void move(@NotNull MoverType movementType, @NotNull Vec3 movement) { + super.move(movementType, movement); + Player controller = EntityFindUtil.findPlayer(this.level(), this.entityData.get(CONTROLLER)); + + if (lastTickSpeed < 0.2 || collisionCoolDown > 0) return; + + if ((verticalCollision) && Mth.abs((float) lastTickVerticalSpeed) > 1) { + this.hurt(ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), this, controller == null ? this : controller), (float) (20 * ((Mth.abs((float) lastTickVerticalSpeed) - 1) * (lastTickSpeed - 0.2) * (lastTickSpeed - 0.2)))); + collisionCoolDown = 4; + } + + if (this.horizontalCollision) { + this.hurt(ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), this, controller == null ? this : controller), (float) (10 * ((lastTickSpeed - 0.2) * (lastTickSpeed - 0.2)))); + collisionCoolDown = 4; + } + } + + @Override + public void destroy() { + // 无人机爆炸 + if (level() instanceof ServerLevel) { + level().explode(null, this.getX(), this.getY(), this.getZ(), 0, Level.ExplosionInteraction.NONE); + } + + // 神风自爆 + if (this.entityData.get(KAMIKAZE_MODE) != 0) { + kamikazeExplosion(this.entityData.get(KAMIKAZE_MODE)); + } + + // RGO投弹 + ItemStack rgoGrenade = new ItemStack(ModItems.RGO_GRENADE.get(), this.entityData.get(AMMO)); + if (this.level() instanceof ServerLevel level) { + ItemEntity itemEntity = new ItemEntity(level, this.getX(), this.getY(), this.getZ(), rgoGrenade); + itemEntity.setPickUpDelay(10); + level.addFreshEntity(itemEntity); + } + + Player controller = EntityFindUtil.findPlayer(this.level(), this.entityData.get(CONTROLLER)); + if (controller != null) { + if (controller.getMainHandItem().is(ModItems.MONITOR.get())) { + Monitor.disLink(controller.getMainHandItem(), controller); + } + } + + String id = this.entityData.get(CONTROLLER); + UUID uuid; + try { + uuid = UUID.fromString(id); + } catch (IllegalArgumentException ignored) { + this.discard(); + return; + } + + Player player = this.level().getPlayerByUUID(uuid); + if (player != null) { + player.getInventory().items.stream().filter(stack -> stack.getItem() == ModItems.MONITOR.get()) + .forEach(stack -> { + if (NBTTool.getTag(stack).getString(Monitor.LINKED_DRONE).equals(this.getStringUUID())) { + Monitor.disLink(stack, player); + } + }); + } + + this.discard(); + } + + private void kamikazeExplosion(int mode) { + Entity attacker = EntityFindUtil.findEntity(this.level(), this.entityData.get(LAST_ATTACKER_UUID)); + Player controller = EntityFindUtil.findPlayer(this.level(), this.entityData.get(CONTROLLER)); + + Entity mortarShell = new MortarShellEntity(controller, level()); + Entity c4 = new C4Entity(controller, level()); + Entity rpg = new RpgRocketEntity(controller, level(), ExplosionConfig.RPG_EXPLOSION_DAMAGE.get()); + + CustomExplosion explosion = switch (mode) { + case 1 -> new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), mortarShell, attacker), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_DAMAGE.get(), + this.getX(), this.getY(), this.getZ(), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + + case 2 -> new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), c4, attacker), ExplosionConfig.C4_EXPLOSION_DAMAGE.get(), + this.getX(), this.getY(), this.getZ(), ExplosionConfig.C4_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + + case 3 -> new CustomExplosion(this.level(), this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), rpg, attacker), ExplosionConfig.RPG_EXPLOSION_DAMAGE.get(), + this.getX(), this.getY(), this.getZ(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + + default -> null; + }; + + if (explosion == null) return; + + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + if (mode == 1) { + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + + if (this.currentItem.getItem() instanceof MortarShell) { + // TODO area cloud +// this.createAreaCloud(PotionUtils.getPotion(this.currentItem), this.level(), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_DAMAGE.get(), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_RADIUS.get()); + } + } + + if (mode == 2 || mode == 3) { + ParticleTool.spawnHugeExplosionParticles(this.level(), this.position()); + } + } + + // TODO potion + + private void createAreaCloud(Potion potion, Level level, int duration, float radius) { + if (potion == Potions.WATER.value()) return; + + AreaEffectCloud cloud = new AreaEffectCloud(level, this.getX() + 0.75 * getDeltaMovement().x, this.getY() + 0.5 * getBbHeight() + 0.75 * getDeltaMovement().y, this.getZ() + 0.75 * getDeltaMovement().z); + // TODO cloud potion + // cloud.setPotion(potion); + cloud.setDuration(duration); + cloud.setRadius(radius); + + Player controller = EntityFindUtil.findPlayer(this.level(), this.entityData.get(CONTROLLER)); + if (controller != null) { + cloud.setOwner(controller); + } + level.addFreshEntity(cloud); + } + + @Override + public boolean isNoGravity() { + return super.isNoGravity(); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public boolean canCrushEntities() { + return false; + } + + @Override + public void collideBlock() { + } + + @Override + public void collideHardBlock() { + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java new file mode 100644 index 000000000..f21af216e --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/LaserTowerEntity.java @@ -0,0 +1,372 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.TargetEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.EnergyVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.init.*; +import com.atsuishio.superbwarfare.item.ContainerBlockItem; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.VectorTool; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.OldUsersConverter; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.monster.Enemy; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Math; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimationState; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.Comparator; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.StreamSupport; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class LaserTowerEntity extends EnergyVehicleEntity implements GeoEntity, OwnableEntity { + + public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor TARGET_UUID = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.STRING); + public static final EntityDataAccessor ACTIVE = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.BOOLEAN); + public static final EntityDataAccessor> OWNER_UUID = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.OPTIONAL_UUID); + public static final EntityDataAccessor LASER_LENGTH = SynchedEntityData.defineId(LaserTowerEntity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public int changeTargetTimer = 60; + + + public LaserTowerEntity(EntityType type, Level world) { + super(type, world); + this.noCulling = true; + } + + public LaserTowerEntity(LivingEntity owner, Level level) { + super(ModEntities.LASER_TOWER.get(), level); + this.setOwnerUUID(owner.getUUID()); + } + + public boolean isOwnedBy(LivingEntity pEntity) { + return pEntity == this.getOwner(); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(TARGET_UUID, "none") + .define(OWNER_UUID, Optional.empty()) + .define(COOL_DOWN, 0) + .define(LASER_LENGTH, 0f) + .define(ACTIVE, false); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("CoolDown", this.entityData.get(COOL_DOWN)); + compound.putBoolean("Active", this.entityData.get(ACTIVE)); + if (this.getOwnerUUID() != null) { + compound.putUUID("Owner", this.getOwnerUUID()); + } + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(COOL_DOWN, compound.getInt("CoolDown")); + this.entityData.set(ACTIVE, compound.getBoolean("Active")); + + UUID uuid; + if (compound.hasUUID("Owner")) { + uuid = compound.getUUID("Owner"); + } else { + String s = compound.getString("Owner"); + + assert this.getServer() != null; + uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s); + } + + if (uuid != null) { + try { + this.setOwnerUUID(uuid); + } catch (Throwable ignored) { + } + } + } + + public void setOwnerUUID(@Nullable UUID pUuid) { + this.entityData.set(OWNER_UUID, Optional.ofNullable(pUuid)); + } + + @Nullable + public UUID getOwnerUUID() { + return this.entityData.get(OWNER_UUID).orElse(null); + } + + // TODO add entity packet + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + + // @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.1f, DamageTypes.ARROW) + .multiply(0.2f, DamageTypes.TRIDENT) + .multiply(0.2f, DamageTypes.MOB_ATTACK) + .multiply(0.2f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(0.4f, DamageTypes.MOB_PROJECTILE) + .multiply(0.4f, DamageTypes.PLAYER_ATTACK) + .multiply(1.5f, DamageTypes.EXPLOSION) + .multiply(1.5f, DamageTypes.PLAYER_EXPLOSION) + .multiply(0.5f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(0.5f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.5f, ModDamageTypes.MINE) + .multiply(0.5f, ModDamageTypes.LUNGE_MINE) + .multiply(0.6f, ModDamageTypes.CANNON_FIRE) + .multiply(0.5f, ModTags.DamageTypes.PROJECTILE) + .multiply(0.8f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .multiply(2f, ModDamageTypes.VEHICLE_STRIKE) + .reduce(1); + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + if (player.isCrouching()) { + if (stack.is(ModItems.CROWBAR.get()) && (getOwner() == null || player == getOwner())) { + ItemStack container = ContainerBlockItem.createInstance(this); + if (!player.addItem(container)) { + player.drop(container, false); + } + this.remove(RemovalReason.DISCARDED); + this.discard(); + return InteractionResult.SUCCESS; + } else if (!entityData.get(ACTIVE)) { + entityData.set(ACTIVE, true); + this.setOwnerUUID(player.getUUID()); + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), SoundEvents.ARROW_HIT_PLAYER, SoundSource.PLAYERS, 0.5F, 1); + } + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + } + return InteractionResult.sidedSuccess(this.level().isClientSide()); + } + + @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(COOL_DOWN) > 0) { + this.entityData.set(COOL_DOWN, this.entityData.get(COOL_DOWN) - 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)); + } + this.autoAim(); + } + + @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 destroy() { + Entity attacker = EntityFindUtil.findEntity(this.level(), this.entityData.get(LAST_ATTACKER_UUID)); + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), attacker, attacker), 10f, + this.getX(), this.getY(), this.getZ(), 3f, Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + this.discard(); + } + + public void autoAim() { + if (this.getEnergy() <= 0 || !entityData.get(ACTIVE)) { + return; + } + + if (entityData.get(TARGET_UUID).equals("none") && tickCount % 10 == 0) { + Entity naerestEntity = seekNearLivingEntity(72); + if (naerestEntity != null) { + entityData.set(TARGET_UUID, naerestEntity.getStringUUID()); + } + } + + Entity target = EntityFindUtil.findEntity(level(), entityData.get(TARGET_UUID)); + + if (target != null) { + if (target instanceof LivingEntity living && living.getHealth() <= 0) { + this.entityData.set(TARGET_UUID, "none"); + return; + } + if (target == this || target instanceof TargetEntity) { + this.entityData.set(TARGET_UUID, "none"); + return; + } + + Vec3 barrelRootPos = new Vec3(this.getX(), this.getY() + 1.390625f, this.getZ()); + Vec3 targetVec = barrelRootPos.vectorTo(target.getEyePosition()).normalize(); + + double d0 = targetVec.x; + double d1 = targetVec.y; + double d2 = targetVec.z; + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + this.setXRot(Mth.clamp(Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875))), -90, 40)); + float targetY = Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F); + + float diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(targetY - this.getYRot())); + + turretTurnSound(0, diffY, 1.1f); + + this.setYRot(this.getYRot() + Mth.clamp(0.5f * diffY, -60f, 60f)); + this.setRot(this.getYRot(), this.getXRot()); + + if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1) { + changeTargetTimer++; + } + + if (this.entityData.get(COOL_DOWN) == 0 && VectorTool.calculateAngle(getViewVector(1), targetVec) < 1 && checkNoClip(target)) { + this.entityData.set(COOL_DOWN, VehicleConfig.LASER_TOWER_COOLDOWN.get()); + + if (level() instanceof ServerLevel serverLevel) { + this.level().playSound(this, getOnPos(), ModSounds.LASER_TOWER_SHOOT.get(), SoundSource.PLAYERS, 2, random.nextFloat() * 0.1f + 1); + sendParticle(serverLevel, ParticleTypes.END_ROD, target.getX(), target.getEyeY(), target.getZ(), 12, 0, 0, 0, 0.05, true); + sendParticle(serverLevel, ParticleTypes.LAVA, target.getX(), target.getEyeY(), target.getZ(), 4, 0, 0, 0, 0.15, true); + } + + target.hurt(ModDamageTypes.causeLaserStaticDamage(this.level().registryAccess(), this, this.getOwner()), VehicleConfig.LASER_TOWER_DAMAGE.get()); + target.invulnerableTime = 0; + entityData.set(LASER_LENGTH, distanceTo(target)); + if (Math.random() < 0.25 && target instanceof LivingEntity living) { + living.setRemainingFireTicks(2); + } + if (!target.isAlive()) { + entityData.set(TARGET_UUID, "none"); + } + this.consumeEnergy(VehicleConfig.LASER_TOWER_SHOOT_COST.get()); + } + + } else { + entityData.set(TARGET_UUID, "none"); + } + + if (changeTargetTimer > 60) { + entityData.set(TARGET_UUID, "none"); + changeTargetTimer = 0; + } + } + + public Entity seekNearLivingEntity(double seekRange) { + return StreamSupport.stream(EntityFindUtil.getEntities(level()).getAll().spliterator(), false) + .filter(e -> { + // TODO 自定义目标列表 + if (e.distanceTo(this) <= seekRange && ((e instanceof LivingEntity living && living instanceof Enemy && living.getHealth() > 0) + )) { + return checkNoClip(e); + } + return false; + }).min(Comparator.comparingDouble(e -> e.distanceTo(this))).orElse(null); + } + + public boolean checkNoClip(Entity target) { + return level().clip(new ClipContext(this.getEyePosition(), target.getEyePosition(), + ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() != HitResult.Type.BLOCK; + } + + private PlayState movementPredicate(AnimationState event) { + if (this.entityData.get(COOL_DOWN) > 10) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lt.fire")); + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.lt.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.LASER_TOWER_MAX_ENERGY.get(); + } + + @Override + public float getMaxHealth() { + return VehicleConfig.LASER_TOWER_HP.get(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java new file mode 100644 index 000000000..6fdb784d8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Lav150Entity.java @@ -0,0 +1,605 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +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.LandArmorEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.ProjectileWeapon; +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.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.AmmoType; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.mojang.math.Axis; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +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; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Comparator; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class Lav150Entity extends ContainerMobileVehicleEntity implements GeoEntity, LandArmorEntity, WeaponVehicleEntity { + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public Lav150Entity(EntityType type, Level world) { + super(type, world); + } + + @Override + public float maxUpStep() { + return 1.5F; + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new SmallCannonShellWeapon() + .damage(VehicleConfig.LAV_150_CANNON_DAMAGE.get()) + .explosionDamage(VehicleConfig.LAV_150_CANNON_EXPLOSION_DAMAGE.get()) + .explosionRadius(VehicleConfig.LAV_150_CANNON_EXPLOSION_RADIUS.get().floatValue()) + .sound(ModSounds.INTO_MISSILE.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/cannon_20mm.png")), + new ProjectileWeapon() + .damage(9.5f) + .headShot(2) + .zoom(false) + .sound(ModSounds.INTO_CANNON.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/gun_7_62mm.png")), + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(2.75, 1, 0); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + } + + @Override + @ParametersAreNonnullByDefault + protected void playStepSound(BlockPos pPos, BlockState pState) { + this.playSound(ModSounds.BMP_STEP.get(), Mth.abs(this.entityData.get(POWER)) * 3, random.nextFloat() * 0.15f + 1.05f); + } + + // TODO add entity packet + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.2f) + .multiply(1.5f, DamageTypes.ARROW) + .multiply(1.5f, DamageTypes.TRIDENT) + .multiply(2.5f, DamageTypes.MOB_ATTACK) + .multiply(2f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(1.5f, DamageTypes.MOB_PROJECTILE) + .multiply(12.5f, DamageTypes.LAVA) + .multiply(6f, DamageTypes.EXPLOSION) + .multiply(6f, DamageTypes.PLAYER_EXPLOSION) + .multiply(2.4f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(2f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.75f, ModDamageTypes.MINE) + .multiply(1.5f, ModDamageTypes.CANNON_FIRE) + .multiply(0.25f, ModTags.DamageTypes.PROJECTILE) + .multiply(0.85f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .multiply(10f, ModDamageTypes.VEHICLE_STRIKE) + .custom((source, damage) -> getSourceAngle(source, 0.25f) * damage) + .custom((source, damage) -> { + if (source.getDirectEntity() instanceof MelonBombEntity) { + return 3f * damage; + } + if (source.getDirectEntity() instanceof MortarShellEntity) { + return 3f * damage; + } + return damage; + }) + .reduce(7); + } + + @Override + public void baseTick() { + turretYRotO = this.getTurretYRot(); + turretXRotO = this.getTurretXRot(); + rudderRotO = this.getRudderRot(); + leftWheelRotO = this.getLeftWheelRot(); + rightWheelRotO = this.getRightWheelRot(); + + super.baseTick(); + + if (this.level() instanceof ServerLevel) { + this.handleAmmo(); + } + + double fluidFloat; + fluidFloat = 0.052 * getSubmergedHeight(this); + this.setDeltaMovement(this.getDeltaMovement().add(0.0, fluidFloat, 0.0)); + + if (this.onGround()) { + float f0 = 0.54f + 0.25f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.05 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f0, 0.85, f0)); + + } else if (this.isInWater()) { + float f1 = 0.74f + 0.09f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.04 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f1, 0.85, f1)); + } else { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.99, 0.95, 0.99)); + } + + if (this.level() instanceof ServerLevel serverLevel && this.isInWater() && this.getDeltaMovement().length() > 0.1) { + sendParticle(serverLevel, ParticleTypes.CLOUD, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 4 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + sendParticle(serverLevel, ParticleTypes.BUBBLE_COLUMN_UP, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 10 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + } + + collideBlock(); + if (this.getDeltaMovement().length() > 0.125) { + collideHardBlock(); + } + + turretAngle(15, 12.5f); + lowHealthWarning(); + this.terrainCompat(2.7f, 3.61f); + inertiaRotate(1.25f); + + this.refreshDimensions(); + } + + private void handleAmmo() { + if (!(this.getFirstPassenger() instanceof Player)) return; + + int ammoCount = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return AmmoType.RIFLE.get(stack) > 0; + } + return false; + }).mapToInt(AmmoType.RIFLE::get).sum() + countItem(ModItems.RIFLE_AMMO.get()); + + if (getWeaponIndex(0) == 0) { + this.entityData.set(AMMO, countItem(ModItems.SMALL_SHELL.get())); + } else if (getWeaponIndex(0) == 1) { + this.entityData.set(AMMO, ammoCount); + } + } + + @Override + public void move(@NotNull MoverType movementType, @NotNull Vec3 movement) { + super.move(movementType, movement); + if (this.isInWater() && horizontalCollision) { + setDeltaMovement(this.getDeltaMovement().add(0, 0.07, 0)); + } + } + + @Override + public Vec3 getBarrelVector(float pPartialTicks) { + Matrix4f transform = getBarrelTransform(pPartialTicks); + Vector4f rootPosition = transformPosition(transform, 0, 0, 0); + Vector4f targetPosition = transformPosition(transform, 0, 0, 1); + return new Vec3(rootPosition.x, rootPosition.y, rootPosition.z).vectorTo(new Vec3(targetPosition.x, targetPosition.y, targetPosition.z)); + } + + @Override + public void vehicleShoot(Player player, int type) { + boolean hasCreativeAmmo = false; + for (int i = 0; i < getMaxPassengers() - 1; i++) { + if (getNthEntity(i) instanceof Player pPlayer && InventoryTool.hasCreativeAmmoBox(pPlayer)) { + hasCreativeAmmo = true; + } + } + + Matrix4f transform = getBarrelTransform(1); + if (getWeaponIndex(0) == 0) { + if (this.cannotFire) return; + float x = 0.0609375f; + float y = 0.0517f; + float z = 3.0927625f; + + Vector4f worldPosition = transformPosition(transform, x, y, z); + var smallCannonShell = ((SmallCannonShellWeapon) getWeapon(0)).create(player); + + smallCannonShell.setPos(worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z); + smallCannonShell.shoot(getBarrelVector(1).x, getBarrelVector(1).y + 0.005f, getBarrelVector(1).z, 20, + 0.25f); + this.level().addFreshEntity(smallCannonShell); + + sendParticle((ServerLevel) this.level(), ParticleTypes.LARGE_SMOKE, worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z, 1, 0.02, 0.02, 0.02, 0, false); + + float pitch = this.entityData.get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - this.entityData.get(HEAT))); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.LAV_CANNON_FIRE_3P.get(), 4, pitch); + serverPlayer.playSound(ModSounds.LAV_CANNON_FAR.get(), 12, pitch); + serverPlayer.playSound(ModSounds.LAV_CANNON_VERYFAR.get(), 24, pitch); + } + } + + 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(4), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 5, 9, this.getX(), this.getEyeY(), this.getZ())); + } + } + + this.entityData.set(CANNON_RECOIL_TIME, 40); + this.entityData.set(YAW, getTurretYRot()); + + this.entityData.set(HEAT, this.entityData.get(HEAT) + 7); + this.entityData.set(FIRE_ANIM, 3); + + if (hasCreativeAmmo) return; + + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.SMALL_SHELL.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + + } else if (getWeaponIndex(0) == 1) { + if (this.cannotFireCoax) return; + float x = 0.3f; + float y = 0.08f; + float z = 0.7f; + + Vector4f worldPosition = transformPosition(transform, x, y, z); + + if (this.entityData.get(AMMO) > 0 || hasCreativeAmmo) { + var projectile = ((ProjectileWeapon) getWeapon(0)).create(player); + + projectile.bypassArmorRate(0.2f); + projectile.setPos(worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z); + projectile.shoot(player, getBarrelVector(1).x, getBarrelVector(1).y + 0.002f, getBarrelVector(1).z, 36, + 0.25f); + this.level().addFreshEntity(projectile); + + if (!hasCreativeAmmo) { + ItemStack ammoBox = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return AmmoType.RIFLE.get(stack) > 0; + } + return false; + }).findFirst().orElse(ItemStack.EMPTY); + + if (!ammoBox.isEmpty()) { + AmmoType.RIFLE.add(ammoBox, -1); + } else { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.RIFLE_AMMO.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + } + } + + this.entityData.set(COAX_HEAT, this.entityData.get(COAX_HEAT) + 3); + this.entityData.set(FIRE_ANIM, 2); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.RPK_FIRE_3P.get(), 3, 1); + serverPlayer.playSound(ModSounds.RPK_FAR.get(), 6, 1); + serverPlayer.playSound(ModSounds.RPK_VERYFAR.get(), 12, 1); + } + } + } + } + + @Override + public void travel() { + Entity passenger0 = this.getFirstPassenger(); + + if (this.getEnergy() <= 0) return; + + if (passenger0 == null) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + this.entityData.set(POWER, 0f); + } + + if (forwardInputDown) { + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + (this.entityData.get(POWER) < 0 ? 0.012f : 0.0024f), 0.18f)); + } + + if (backInputDown) { + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - (this.entityData.get(POWER) > 0 ? 0.012f : 0.0024f), -0.13f)); + } + + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } + + if (this.forwardInputDown || this.backInputDown) { + this.consumeEnergy(VehicleConfig.LAV_150_ENERGY_COST.get()); + } + + this.entityData.set(POWER, this.entityData.get(POWER) * (upInputDown ? 0.5f : (rightInputDown || leftInputDown) ? 0.977f : 0.99f)); + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * (float) Math.max(0.76f - 0.1f * this.getDeltaMovement().horizontalDistance(), 0.3)); + + float angle = (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1)); + double s0; + + if (Mth.abs(angle) < 90) { + s0 = this.getDeltaMovement().horizontalDistance(); + } else { + s0 = -this.getDeltaMovement().horizontalDistance(); + } + + this.setLeftWheelRot((float) ((this.getLeftWheelRot() - 1.25 * s0) - this.getDeltaMovement().horizontalDistance() * Mth.clamp(1.5f * this.entityData.get(DELTA_ROT), -5f, 5f))); + this.setRightWheelRot((float) ((this.getRightWheelRot() - 1.25 * s0) + this.getDeltaMovement().horizontalDistance() * Mth.clamp(1.5f * this.entityData.get(DELTA_ROT), -5f, 5f))); + + this.setRudderRot(Mth.clamp(this.getRudderRot() - this.entityData.get(DELTA_ROT), -0.8f, 0.8f) * 0.75f); + + if (this.isInWater() || onGround()) { + this.setYRot((float) (this.getYRot() - Math.max((isInWater() && !onGround() ? 5 : 10) * this.getDeltaMovement().horizontalDistance(), 0) * this.getRudderRot() * (this.entityData.get(POWER) > 0 ? 1 : -1))); + this.setDeltaMovement(this.getDeltaMovement().add(getViewVector(1).scale((!isInWater() && !onGround() ? 0.05f : (isInWater() && !onGround() ? 0.3f : 1)) * this.entityData.get(POWER)))); + } + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.LAV_ENGINE.get(); + } + + @Override + public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) { + // From Immersive_Aircraft + if (!this.hasPassenger(passenger)) { + return; + } + + Matrix4f transform = getTurretTransform(1); + Matrix4f transformV = getVehicleTransform(1); + + int i = this.getSeatIndex(passenger); + + Vector4f worldPosition; + if (i == 0) { + worldPosition = transformPosition(transform, 0.36f, -0.65f, 0.56f); + } else { + worldPosition = transformPosition(transformV, 0, 1, 0); + } + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + + copyEntityData(passenger); + } + + public void copyEntityData(Entity entity) { + if (entity == getNthEntity(0)) { + entity.setYBodyRot(getBarrelYRot(1)); + } + } + + public int getMaxPassengers() { + return 5; + } + + public Vec3 driverZoomPos(float ticks) { + Matrix4f transform = getTurretTransform(ticks); + Vector4f worldPosition = transformPosition(transform, 0.3f, 0.75f, 0.56f); + return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); + } + + public Matrix4f getBarrelTransform(float ticks) { + Matrix4f transformT = getTurretTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0.0234375f, 0.33795f, 0.825f); + + transformT.translate(worldPosition.x, worldPosition.y, worldPosition.z); + + float a = getTurretYaw(ticks); + + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float x = Mth.lerp(ticks, turretXRotO, getTurretXRot()); + float xV = Mth.lerp(ticks, xRotO, getXRot()); + float z = Mth.lerp(ticks, prevRoll, getRoll()); + + transformT.rotate(Axis.XP.rotationDegrees(x + r * xV + r2 * z)); + return transformT; + } + + public Matrix4f getTurretTransform(float ticks) { + Matrix4f transformV = getVehicleTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0, 2.4003f, 0); + + transformV.translate(worldPosition.x, worldPosition.y, worldPosition.z); + transformV.rotate(Axis.YP.rotationDegrees(Mth.lerp(ticks, turretYRotO, getTurretYRot()))); + return transformV; + } + + @Override + public void destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 80f, + this.getX(), this.getY(), this.getZ(), 5f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + protected void clampRotation(Entity entity) { + float a = getTurretYaw(1); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float min = -32.5f - r * getXRot() - r2 * getRoll(); + float max = 15f - r * getXRot() - r2 * getRoll(); + + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, min, max); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + entity.setYBodyRot(getBarrelYRot(1)); + } + + @Override + public void onPassengerTurned(Entity entity) { + this.clampRotation(entity); + } + + private PlayState firePredicate(AnimationState event) { + if (this.entityData.get(FIRE_ANIM) > 1 && getWeaponIndex(0) == 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lav.fire")); + } + + if (this.entityData.get(FIRE_ANIM) > 0 && getWeaponIndex(0) == 1) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lav.fire2")); + } + + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.lav.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::firePredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.LAV_150_MAX_ENERGY.get(); + } + + @Override + public float getMaxHealth() { + return VehicleConfig.LAV_150_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + if (getWeaponIndex(0) == 0) { + return 300; + } else if (getWeaponIndex(0) == 1) { + return 600; + } + return 300; + } + + @Override + public boolean canShoot(Player player) { + if (getWeaponIndex(0) == 0) { + return (this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFire; + } else if (getWeaponIndex(0) == 1) { + return (this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFireCoax; + } + 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 true; + } + + @Override + public int zoomFov() { + return 3; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/lav150_icon.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java new file mode 100644 index 000000000..4538c15d4 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mk42Entity.java @@ -0,0 +1,416 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.CannonShellWeapon; +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.item.common.ammo.CannonShellItem; +import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.*; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +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.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +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 software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.Comparator; + +public class Mk42Entity extends VehicleEntity implements GeoEntity, CannonEntity { + + public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(Mk42Entity.class, EntityDataSerializers.INT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public static final EntityDataAccessor PITCH = SynchedEntityData.defineId(Mk42Entity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor YAW = SynchedEntityData.defineId(Mk42Entity.class, EntityDataSerializers.FLOAT); + + + public Mk42Entity(EntityType type, Level world) { + super(type, world); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(COOL_DOWN, 0) + .define(PITCH, 0F) + .define(YAW, 0F); + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new CannonShellWeapon() + .hitDamage(VehicleConfig.MK42_AP_DAMAGE.get()) + .explosionDamage(VehicleConfig.MK42_AP_EXPLOSION_DAMAGE.get()) + .explosionRadius(VehicleConfig.MK42_AP_EXPLOSION_RADIUS.get().floatValue()) + .durability(60) + .sound(ModSounds.CANNON_RELOAD.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/ap_shell.png")), + new CannonShellWeapon() + .hitDamage(VehicleConfig.MK42_HE_DAMAGE.get()) + .explosionDamage(VehicleConfig.MK42_HE_EXPLOSION_DAMAGE.get()) + .explosionRadius(VehicleConfig.MK42_HE_EXPLOSION_RADIUS.get().floatValue()) + .durability(1) + .fireProbability(0.18F) + .fireTime(2) + .sound(ModSounds.CANNON_RELOAD.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/he_shell.png")), + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(8, 1, 0); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("CoolDown", this.entityData.get(COOL_DOWN)); + compound.putFloat("Pitch", this.entityData.get(PITCH)); + compound.putFloat("Yaw", this.entityData.get(YAW)); + } + + @Override + protected void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(COOL_DOWN, compound.getInt("CoolDown")); + this.entityData.set(PITCH, compound.getFloat("Pitch")); + this.entityData.set(YAW, compound.getFloat("Yaw")); + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + + if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { + setTarget(player.getMainHandItem()); + return InteractionResult.SUCCESS; + } + if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { + setTarget(player.getOffhandItem()); + return InteractionResult.SUCCESS; + } + + if (stack.getItem() instanceof CannonShellItem) { + if (this.entityData.get(COOL_DOWN) == 0) { + var weaponType = stack.is(ModItems.AP_5_INCHES.get()) ? 0 : 1; + setWeaponIndex(0, weaponType); + vehicleShoot(player, 0); + } + return InteractionResult.SUCCESS; + } + return super.interact(player, hand); + } + + public void setTarget(ItemStack stack) { + var tag = NBTTool.getTag(stack); + int targetX = tag.getInt("TargetX"); + int targetY = tag.getInt("TargetY"); + int targetZ = tag.getInt("TargetZ"); + this.look(new Vec3(targetX, targetY, targetZ)); + } + + private void look(Vec3 pTarget) { + Vec3 vec3 = this.getEyePosition(); + double d0 = pTarget.x - vec3.x; + double d1 = pTarget.y - vec3.y; + double d2 = pTarget.z - vec3.z; + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + double distance = pTarget.distanceTo(vec3); + entityData.set(YAW, Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F)); + entityData.set(PITCH, Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875))) - (float) (distance * 0.008f)); + } + + @Override + public double getEyeY() { + return 2.16F; + } + + // TODO addEntityPacket + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + + @Override + public @NotNull Vec3 getPassengerRidingPosition(@NotNull Entity entity) { + return super.getPassengerRidingPosition(entity).add(0, -0.25, 0); + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.2f) + .multiply(1.5f, DamageTypes.ARROW) + .multiply(1.5f, DamageTypes.TRIDENT) + .multiply(2.5f, DamageTypes.MOB_ATTACK) + .multiply(2f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(1.5f, DamageTypes.MOB_PROJECTILE) + .multiply(12.5f, DamageTypes.LAVA) + .multiply(6f, DamageTypes.EXPLOSION) + .multiply(6f, DamageTypes.PLAYER_EXPLOSION) + .multiply(2.4f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(2f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.75f, ModDamageTypes.MINE) + .multiply(1.5f, ModDamageTypes.CANNON_FIRE) + .multiply(0.25f, ModTags.DamageTypes.PROJECTILE) + .multiply(0.85f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .multiply(10f, ModDamageTypes.VEHICLE_STRIKE) + .custom((source, damage) -> getSourceAngle(source, 1f) * damage) + .reduce(8); + } + + @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(COOL_DOWN) > 0) { + this.entityData.set(COOL_DOWN, this.entityData.get(COOL_DOWN) - 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)); + } + + lowHealthWarning(); + } + + @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 destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 100f, + this.getX(), this.getY(), this.getZ(), 7f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + @Override + public void vehicleShoot(Player player, int type) { + if (this.entityData.get(COOL_DOWN) > 0) return; + + Level level = player.level(); + if (level instanceof ServerLevel server) { + if (!InventoryTool.hasCreativeAmmoBox(player)) { + var ammo = getWeaponIndex(0) == 0 ? ModItems.AP_5_INCHES.get() : ModItems.HE_5_INCHES.get(); + var ammoCount = InventoryTool.countItem(player.getInventory().items, ammo); + + if (ammoCount <= 0) return; + InventoryTool.consumeItem(player.getInventory().items, ammo, 1); + } + + var entityToSpawn = ((CannonShellWeapon) getWeapon(0)).create(player); + + entityToSpawn.setPos(this.getX(), this.getEyeY(), this.getZ()); + entityToSpawn.shoot(this.getLookAngle().x, this.getLookAngle().y, this.getLookAngle().z, 15, 0.05f); + level.addFreshEntity(entityToSpawn); + + if (player instanceof ServerPlayer serverPlayer) { + SoundTool.playLocalSound(serverPlayer, ModSounds.MK_42_FIRE_1P.get(), 2, 1); + SoundTool.playLocalSound(serverPlayer, ModSounds.CANNON_RELOAD.get(), 2, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MK_42_FIRE_3P.get(), SoundSource.PLAYERS, 6, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MK_42_FAR.get(), SoundSource.PLAYERS, 16, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MK_42_VERYFAR.get(), SoundSource.PLAYERS, 32, 1); + } + + this.entityData.set(COOL_DOWN, 30); + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + 5 * this.getLookAngle().x, + this.getY(), + this.getZ() + 5 * this.getLookAngle().z, + 100, 7, 0.02, 7, 0.005); + + double x = this.getX() + 9 * this.getLookAngle().x; + double y = this.getEyeY() + 9 * this.getLookAngle().y; + double z = this.getZ() + 9 * this.getLookAngle().z; + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, x, y, z, 10, 0.4, 0.4, 0.4, 0.0075); + server.sendParticles(ParticleTypes.CLOUD, x, y, z, 10, 0.4, 0.4, 0.4, 0.0075); + + int count = 6; + + for (float i = 9.5f; i < 16; i += .5f) { + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + i * this.getLookAngle().x, + this.getEyeY() + i * this.getLookAngle().y, + this.getZ() + i * this.getLookAngle().z, + Mth.clamp(count--, 1, 5), 0.15, 0.15, 0.15, 0.0025); + } + + final Vec3 center = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + + for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(20), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(15, 15, 45, this.getX(), this.getEyeY(), this.getZ())); + } + } + } + } + + + @Override + public void travel() { + Entity passenger = this.getFirstPassenger(); + if (passenger != null) { + entityData.set(YAW, passenger.getYHeadRot()); + entityData.set(PITCH, passenger.getXRot() - 1.3f); + } + + float diffY = Mth.wrapDegrees(entityData.get(YAW) - this.getYRot()); + float diffX = Mth.wrapDegrees(entityData.get(PITCH) - this.getXRot()); + + turretTurnSound(diffX, diffY, 0.95f); + + this.setYRot(this.getYRot() + Mth.clamp(0.5f * diffY, -1.75f, 1.75f)); + this.setXRot(Mth.clamp(this.getXRot() + Mth.clamp(0.5f * diffX, -3f, 3f), -85, 16.3f)); + } + + protected void clampRotation(Entity entity) { + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, -85.0F, 16.3F); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + private PlayState movementPredicate(AnimationState event) { + if (this.entityData.get(COOL_DOWN) > 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.mk42.fire")); + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.mk42.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public float getMaxHealth() { + return VehicleConfig.MK42_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + return 0; + } + + @Override + public boolean canShoot(Player player) { + return true; + } + + @Override + public int getAmmoCount(Player player) { + var ammo = getWeaponIndex(0) == 0 ? ModItems.AP_5_INCHES.get() : ModItems.HE_5_INCHES.get(); + return InventoryTool.countItem(player.getInventory().items, ammo); + } + + @Override + public boolean hidePassenger(Entity entity) { + return true; + } + + @Override + public int zoomFov() { + return 5; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/sherman_icon.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java new file mode 100644 index 000000000..e48ffef50 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Mle1934Entity.java @@ -0,0 +1,519 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.CannonShellWeapon; +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.item.common.ammo.CannonShellItem; +import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.*; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +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.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +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.Vector3d; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Comparator; + +public class Mle1934Entity extends VehicleEntity implements GeoEntity, CannonEntity { + + public static final EntityDataAccessor COOL_DOWN = SynchedEntityData.defineId(Mle1934Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor TYPE = SynchedEntityData.defineId(Mle1934Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor PITCH = SynchedEntityData.defineId(Mle1934Entity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor YAW = SynchedEntityData.defineId(Mle1934Entity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public Mle1934Entity(EntityType type, Level world) { + super(type, world); + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new CannonShellWeapon() + .hitDamage(VehicleConfig.MLE1934_AP_DAMAGE.get()) + .explosionDamage(VehicleConfig.MLE1934_AP_EXPLOSION_DAMAGE.get()) + .explosionRadius(VehicleConfig.MLE1934_AP_EXPLOSION_RADIUS.get().floatValue()) + .durability(70) + .sound(ModSounds.CANNON_RELOAD.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/ap_shell.png")), + new CannonShellWeapon() + .hitDamage(VehicleConfig.MLE1934_HE_DAMAGE.get()) + .explosionDamage(VehicleConfig.MLE1934_HE_EXPLOSION_DAMAGE.get()) + .explosionRadius(VehicleConfig.MLE1934_HE_EXPLOSION_RADIUS.get().floatValue()) + .durability(1) + .fireProbability(0.24F) + .fireTime(5) + .sound(ModSounds.CANNON_RELOAD.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/he_shell.png")), + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(10, 1.3, 0); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(COOL_DOWN, 0) + .define(TYPE, 0) + .define(PITCH, 0f) + .define(YAW, 0f); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("CoolDown", this.entityData.get(COOL_DOWN)); + compound.putInt("Type", this.entityData.get(TYPE)); + compound.putFloat("Pitch", this.entityData.get(PITCH)); + compound.putFloat("Yaw", this.entityData.get(YAW)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(COOL_DOWN, compound.getInt("CoolDown")); + this.entityData.set(TYPE, compound.getInt("Type")); + this.entityData.set(PITCH, compound.getFloat("Pitch")); + this.entityData.set(YAW, compound.getFloat("Yaw")); + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + + if (player.getMainHandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { + setTarget(player.getMainHandItem()); + return InteractionResult.SUCCESS; + } + if (player.getOffhandItem().getItem() == ModItems.FIRING_PARAMETERS.get() && player.isCrouching()) { + setTarget(player.getOffhandItem()); + return InteractionResult.SUCCESS; + } + + if (stack.getItem() instanceof CannonShellItem) { + if (this.entityData.get(COOL_DOWN) == 0) { + var weaponType = stack.is(ModItems.AP_5_INCHES.get()) ? 0 : 1; + setWeaponIndex(0, weaponType); + vehicleShoot(player, 0); + } + return InteractionResult.SUCCESS; + } + return super.interact(player, hand); + } + + public void setTarget(ItemStack stack) { + var tag = NBTTool.getTag(stack); + int targetX = tag.getInt("TargetX"); + int targetY = tag.getInt("TargetY"); + int targetZ = tag.getInt("TargetZ"); + this.look(new Vec3(targetX, targetY, targetZ)); + } + + private void look(Vec3 pTarget) { + Vec3 vec3 = this.getEyePosition(); + double d0 = pTarget.x - vec3.x; + double d1 = pTarget.y - vec3.y; + double d2 = pTarget.z - vec3.z; + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + double distance = pTarget.distanceTo(vec3); + entityData.set(YAW, Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875) - 90.0F)); + entityData.set(PITCH, Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875))) - (float) (distance * 0.008f)); + } + + @Override + public double getEyeY() { + return 2.16F; + } + + // TODO add entity packet + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + + // @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + @ParametersAreNonnullByDefault + protected void positionRider(Entity pPassenger, MoveFunction pCallback) { + if (this.hasPassenger(pPassenger)) { + float f1 = (float) ((this.isRemoved() ? 0.009999999776482582 : this.getPassengerRidingPosition(this).y) + pPassenger.getVehicleAttachmentPoint(this).y); + Vec3 vec3 = (new Vec3(1, 0.0, 0.0)).yRot(-this.getYRot() * 0.017453292F - 1.5707964F); + pCallback.accept(pPassenger, this.getX() + vec3.x, this.getY() + (double) f1, this.getZ() + vec3.z); + } + } + + @Override + public @NotNull Vec3 getPassengerRidingPosition(@NotNull Entity entity) { + return super.getPassengerRidingPosition(entity).add(0, -0.075, 0); + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.2f) + .multiply(1.5f, DamageTypes.ARROW) + .multiply(1.5f, DamageTypes.TRIDENT) + .multiply(2.5f, DamageTypes.MOB_ATTACK) + .multiply(2f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(1.5f, DamageTypes.MOB_PROJECTILE) + .multiply(12.5f, DamageTypes.LAVA) + .multiply(6f, DamageTypes.EXPLOSION) + .multiply(6f, DamageTypes.PLAYER_EXPLOSION) + .multiply(2.4f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(2f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.75f, ModDamageTypes.MINE) + .multiply(1.5f, ModDamageTypes.CANNON_FIRE) + .multiply(0.25f, ModTags.DamageTypes.PROJECTILE) + .multiply(0.85f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .multiply(10f, ModDamageTypes.VEHICLE_STRIKE) + .custom((source, damage) -> getSourceAngle(source, 1f) * damage) + .reduce(8); + } + + @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(COOL_DOWN) > 0) { + this.entityData.set(COOL_DOWN, this.entityData.get(COOL_DOWN) - 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)); + } + + lowHealthWarning(); + } + + @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 destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 120f, + this.getX(), this.getY(), this.getZ(), 6f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + @Override + public void vehicleShoot(Player player, int type) { + if (this.entityData.get(COOL_DOWN) > 0) return; + + Level level = player.level(); + if (level instanceof ServerLevel server) { + int consumed; + if (InventoryTool.hasCreativeAmmoBox(player)) { + consumed = 2; + } else { + var ammo = getWeaponIndex(0) == 0 ? ModItems.AP_5_INCHES.get() : ModItems.HE_5_INCHES.get(); + var ammoCount = InventoryTool.countItem(player.getInventory().items, ammo); + + // 尝试消耗两发弹药 + if (ammoCount <= 0) return; + consumed = InventoryTool.consumeItem(player.getInventory().items, ammo, 2); + } + + boolean salvoShoot = consumed == 2; + + float yRot = this.getYRot(); + if (yRot < 0) { + yRot += 360; + } + yRot = yRot + 90 % 360; + + var leftPos = new Vector3d(0, 0, -0.45); + leftPos.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + leftPos.rotateY(-yRot * Mth.DEG_TO_RAD); + + // 左炮管 + var entityToSpawnLeft = ((CannonShellWeapon) getWeapon(0)).create(player); + + entityToSpawnLeft.setPos(this.getX() + leftPos.x, + this.getEyeY() - 0.2 + leftPos.y, + this.getZ() + leftPos.z); + entityToSpawnLeft.shoot(this.getLookAngle().x, this.getLookAngle().y, this.getLookAngle().z, 15, 0.05f); + level.addFreshEntity(entityToSpawnLeft); + + var leftPosP1 = new Vector3d(8, 0, -0.45); + leftPosP1.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + leftPosP1.rotateY(-yRot * Mth.DEG_TO_RAD); + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + leftPosP1.x, + this.getEyeY() - 0.2 + leftPosP1.y, + this.getZ() + leftPosP1.z, + 10, 0.4, 0.4, 0.4, 0.0075); + + server.sendParticles(ParticleTypes.CLOUD, + this.getX() + leftPosP1.x, + this.getEyeY() - 0.2 + leftPosP1.y, + this.getZ() + leftPosP1.z, + 10, 0.4, 0.4, 0.4, 0.0075); + + int count = 5; + + for (float i = 9.5f; i < 14; i += .5f) { + var leftPosP = new Vector3d(i, 0, -0.45); + leftPosP.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + leftPosP.rotateY(-yRot * Mth.DEG_TO_RAD); + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + leftPosP.x, + this.getEyeY() - 0.2 + leftPosP.y, + this.getZ() + leftPosP.z, + Mth.clamp(count--, 1, 5), 0.1, 0.1, 0.1, 0.002); + } + + // 右炮管 + if (salvoShoot) { + var rightPos = new Vector3d(0, 0, 0.45); + rightPos.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + rightPos.rotateY(-yRot * Mth.DEG_TO_RAD); + + var entityToSpawnRight = ((CannonShellWeapon) getWeapon(0)).create(player); + + entityToSpawnRight.setPos(this.getX() + rightPos.x, + this.getEyeY() - 0.2 + rightPos.y, + this.getZ() + rightPos.z); + entityToSpawnRight.shoot(this.getLookAngle().x, this.getLookAngle().y, this.getLookAngle().z, 15, 0.05f); + level.addFreshEntity(entityToSpawnRight); + + var rightPosP1 = new Vector3d(8, 0, 0.45); + rightPosP1.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + rightPosP1.rotateY(-yRot * Mth.DEG_TO_RAD); + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + rightPosP1.x, + this.getEyeY() - 0.2 + rightPosP1.y, + this.getZ() + rightPosP1.z, + 10, 0.4, 0.4, 0.4, 0.0075); + + server.sendParticles(ParticleTypes.CLOUD, + this.getX() + rightPosP1.x, + this.getEyeY() - 0.2 + rightPosP1.y, + this.getZ() + rightPosP1.z, + 10, 0.4, 0.4, 0.4, 0.0075); + + int countR = 5; + + for (float i = 9.5f; i < 14; i += .5f) { + var rightPosP = new Vector3d(i, 0, 0.45); + rightPosP.rotateZ(-this.getXRot() * Mth.DEG_TO_RAD); + rightPosP.rotateY(-yRot * Mth.DEG_TO_RAD); + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + rightPosP.x, + this.getEyeY() - 0.2 + rightPosP.y, + this.getZ() + rightPosP.z, + Mth.clamp(countR--, 1, 5), 0.1, 0.1, 0.1, 0.002); + } + + this.entityData.set(TYPE, 1); + } else { + this.entityData.set(TYPE, -1); + } + + if (player instanceof ServerPlayer serverPlayer) { + SoundTool.playLocalSound(serverPlayer, ModSounds.MK_42_FIRE_1P.get(), 2, 1); + ModUtils.queueServerWork(44, () -> SoundTool.playLocalSound(serverPlayer, ModSounds.CANNON_RELOAD.get(), 2, 1)); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MK_42_FIRE_3P.get(), SoundSource.PLAYERS, 6, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MK_42_FAR.get(), SoundSource.PLAYERS, 16, 1); + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MK_42_VERYFAR.get(), SoundSource.PLAYERS, 32, 1); + } + + this.entityData.set(COOL_DOWN, 74); + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + 5 * this.getLookAngle().x, + this.getY(), + this.getZ() + 5 * this.getLookAngle().z, + 100, 7, 0.02, 7, 0.005); + + final Vec3 center = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + + for (Entity target : level.getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(20), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(15, 15, 45, this.getX(), this.getEyeY(), this.getZ())); + } + } + } + } + + @Override + public void travel() { + Entity passenger = this.getFirstPassenger(); + if (passenger != null) { + entityData.set(YAW, passenger.getYHeadRot()); + entityData.set(PITCH, passenger.getXRot() - 1.2f); + } + + float diffY = Mth.wrapDegrees(entityData.get(YAW) - this.getYRot()); + float diffX = Mth.wrapDegrees(entityData.get(PITCH) - this.getXRot()); + + turretTurnSound(diffX, diffY, 0.95f); + + this.setYRot(this.getYRot() + Mth.clamp(0.5f * diffY, -1.25f, 1.25f)); + this.setXRot(Mth.clamp(this.getXRot() + Mth.clamp(0.5f * diffX, -2f, 2f), -30, 4f)); + } + + protected void clampRotation(Entity entity) { + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, -30.0F, 4.0F); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + private PlayState movementPredicate(AnimationState event) { + if (this.entityData.get(COOL_DOWN) > 64) { + if (this.entityData.get(TYPE) == 1) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.mle1934.salvo_fire")); + } else { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.mle1934.fire")); + } + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.mle1934.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public float getMaxHealth() { + return VehicleConfig.MLE1934_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + return 0; + } + + @Override + public boolean canShoot(Player player) { + return true; + } + + @Override + public int getAmmoCount(Player player) { + var ammo = getWeaponIndex(0) == 0 ? ModItems.AP_5_INCHES.get() : ModItems.HE_5_INCHES.get(); + return InventoryTool.countItem(player.getInventory().items, ammo); + } + + @Override + public boolean banHand(Player player) { + return true; + } + + @Override + public boolean hidePassenger(Entity entity) { + return true; + } + + @Override + public int zoomFov() { + return 5; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/mle1934_icon.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java new file mode 100644 index 000000000..03e92099a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/SpeedboatEntity.java @@ -0,0 +1,562 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.vehicle.base.*; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.ProjectileWeapon; +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.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.AmmoType; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.InventoryTool; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.mojang.math.Axis; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +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; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Comparator; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class SpeedboatEntity extends ContainerMobileVehicleEntity implements GeoEntity, ArmedVehicleEntity, WeaponVehicleEntity, LandArmorEntity { + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public SpeedboatEntity(EntityType type, Level world) { + super(type, world); + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + new ProjectileWeapon() + .damage(VehicleConfig.HEAVY_MACHINE_GUN_DAMAGE.get()) + .headShot(2) + .zoom(false) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/gun_12_7mm.png")) + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(3, 1, 0); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + } + + + // TODO AEP + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + + @Override + public @NotNull Vec3 getPassengerRidingPosition(@NotNull Entity entity) { + return super.getPassengerRidingPosition(entity).add(0, -0.8, 0); + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(0.5f) + .multiply(0.2f, DamageTypes.ARROW) + .multiply(0.4f, DamageTypes.TRIDENT) + .multiply(0.4f, DamageTypes.MOB_ATTACK) + .multiply(0.4f, DamageTypes.MOB_ATTACK_NO_AGGRO) + .multiply(0.4f, DamageTypes.MOB_PROJECTILE) + .multiply(0.4f, DamageTypes.PLAYER_ATTACK) + .multiply(4, DamageTypes.LAVA) + .multiply(4, DamageTypes.EXPLOSION) + .multiply(4, DamageTypes.PLAYER_EXPLOSION) + .multiply(0.8f, ModDamageTypes.CANNON_FIRE) + .multiply(0.16f, ModTags.DamageTypes.PROJECTILE) + .multiply(2, ModDamageTypes.VEHICLE_STRIKE) + .reduce(2); + } + + @Override + public void baseTick() { + super.baseTick(); + + double fluidFloat; + fluidFloat = 0.12 * getSubmergedHeight(this); + this.setDeltaMovement(this.getDeltaMovement().add(0.0, fluidFloat, 0.0)); + + if (this.onGround()) { + this.terrainCompat(2f, 3f); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.2, 0.85, 0.2)); + } else if (isInWater()) { + float f = (float) (0.75f - (0.04f * java.lang.Math.min(getSubmergedHeight(this), this.getBbHeight())) + 0.09f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90); + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.04 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f, 0.85, f)); + } else { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.99, 0.99, 0.99)); + } + + if (this.level() instanceof ServerLevel serverLevel && this.isInWater() && this.getDeltaMovement().length() > 0.1) { + sendParticle(serverLevel, ParticleTypes.CLOUD, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 4 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + sendParticle(serverLevel, ParticleTypes.BUBBLE_COLUMN_UP, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 10 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + sendParticle(serverLevel, ParticleTypes.BUBBLE_COLUMN_UP, this.getX() - 4.5 * this.getLookAngle().x, this.getY() - 0.25, this.getZ() - 4.5 * this.getLookAngle().z, (int) (40 * Mth.abs(this.entityData.get(POWER))), 0.15, 0.15, 0.15, 0.02, true); + } + + if (this.level() instanceof ServerLevel) { + this.handleAmmo(); + } + + turretAngle(40, 40); + lowHealthWarning(); + collideBlock(); + if (this.getDeltaMovement().length() > 0.15) { + collideHardBlock(); + } + inertiaRotate(2); + + 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 AmmoType.HEAVY.get(stack) > 0; + } + return false; + }).mapToInt(AmmoType.HEAVY::get).sum() + countItem(ModItems.HEAVY_AMMO.get()); + + + this.entityData.set(AMMO, ammoCount); + } + + /** + * 机枪塔开火 + */ + + @Override + public void vehicleShoot(Player player, int type) { + if (this.cannotFire) return; + + Matrix4f transform = getBarrelTransform(1); + + float x = 0f; + float y = 0.00106875f; + float z = 1.9117f; + + Vector4f worldPosition = transformPosition(transform, x, y, z); + + var projectile = ((ProjectileWeapon) getWeapon(0)).create(player); + + projectile.bypassArmorRate(0.4f); + projectile.setPos(worldPosition.x + 0.5 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z + 0.5 * this.getDeltaMovement().z); + projectile.shoot(player, getBarrelVector(1).x, getBarrelVector(1).y + 0.005f, getBarrelVector(1).z, 20, + (float) 0.4); + this.level().addFreshEntity(projectile); + + float pitch = this.entityData.get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - this.entityData.get(HEAT))); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.M_2_FIRE_3P.get(), 4, pitch); + serverPlayer.playSound(ModSounds.M_2_FAR.get(), 12, pitch); + serverPlayer.playSound(ModSounds.M_2_VERYFAR.get(), 24, pitch); + } + } + + 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(4), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 5, 5, this.getX(), this.getEyeY(), this.getZ())); + } + } + + this.entityData.set(CANNON_RECOIL_TIME, 30); + this.entityData.set(YAW, getTurretYRot()); + + this.entityData.set(HEAT, this.entityData.get(HEAT) + 4); + this.entityData.set(FIRE_ANIM, 3); + + boolean hasCreativeAmmo = false; + for (int i = 0; i < getMaxPassengers() - 1; i++) { + if (getNthEntity(i) instanceof Player pPlayer && InventoryTool.hasCreativeAmmoBox(pPlayer)) { + hasCreativeAmmo = true; + } + } + + if (!hasCreativeAmmo) { + ItemStack ammoBox = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return AmmoType.HEAVY.get(stack) > 0; + } + return false; + }).findFirst().orElse(ItemStack.EMPTY); + + if (!ammoBox.isEmpty()) { + AmmoType.HEAVY.add(ammoBox, -1); + } else { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.HEAVY_AMMO.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + } + } + + @Override + public void travel() { + Entity passenger0 = this.getFirstPassenger(); + + if (this.getEnergy() > 0) { + if (passenger0 == null) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + } + + if (forwardInputDown) { + this.entityData.set(POWER, this.entityData.get(POWER) + 0.005f); + } + + if (backInputDown) { + this.entityData.set(POWER, this.entityData.get(POWER) - 0.005f); + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } else if (leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } + } else { + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } + } + + if (this.forwardInputDown || this.backInputDown) { + 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); + + this.setRotorRot(this.getRotorRot() + 10 * this.entityData.get(POWER)); + this.setRudderRot(Mth.clamp(this.getRudderRot() - this.entityData.get(DELTA_ROT), -1.25f, 1.25f) * 0.7f * (this.entityData.get(POWER) > 0 ? 1 : -1)); + + if (this.isInWater() || this.isUnderWater()) { + this.setXRot(this.getXRot() * 0.85f); + float direct = (90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + + this.setXRot((float) (this.getXRot() - direct * (this.onGround() ? 0 : 1) * 1.1f * this.getDeltaMovement().horizontalDistance())); + this.setYRot((float) (this.getYRot() - Math.max(12 * this.getDeltaMovement().length(), 0.8) * this.entityData.get(DELTA_ROT))); + this.setZRot((float) (this.getRoll() - direct * this.entityData.get(DELTA_ROT) * (this.onGround() ? 0 : 1) * 10 * this.getDeltaMovement().horizontalDistance())); + + this.setDeltaMovement(this.getDeltaMovement().add(getViewVector(1).scale(this.entityData.get(POWER) * 1.75f))); + } else { + this.setXRot(this.getXRot() * 0.99f); + } + } + + this.setZRot(this.roll * 0.85f); + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.BOAT_ENGINE.get(); + } + + @Override + @ParametersAreNonnullByDefault + protected void positionRider(Entity passenger, MoveFunction callback) { + if (!this.hasPassenger(passenger)) { + return; + } + Matrix4f transform = getVehicleTransform(1); + int i = this.getOrderedPassengers().indexOf(passenger); + + float y = -0.65f; + + if (i == 0) { + Vector4f worldPosition = transformPosition(transform, 0, y + 0.25f, -0.2f); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 1) { + Vector4f worldPosition = transformPosition(transform, -0.8f, y, -1.2f); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 2) { + Vector4f worldPosition = transformPosition(transform, 0.8f, y, -1.2f); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 3) { + Vector4f worldPosition = transformPosition(transform, -0.8f, y, -2.2f); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } else if (i == 4) { + Vector4f worldPosition = transformPosition(transform, 0.8f, y, -2.2f); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } + + if (passenger != this.getFirstPassenger()) { + passenger.setXRot(passenger.getXRot() + (getXRot() - xRotO)); + } + + copyEntityData(passenger); + } + + public void copyEntityData(Entity entity) { + float f = Mth.wrapDegrees(entity.getYRot() - getYRot()); + float g = Mth.clamp(f, -105.0f, 105.0f); + entity.yRotO += g - f; + entity.setYRot(entity.getYRot() + g - f); + entity.setYHeadRot(entity.getYRot()); + entity.setYBodyRot(getYRot()); + } + + @Override + public void destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 80f, + this.getX(), this.getY(), this.getZ(), 5f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + protected void clampRotation(Entity entity) { + float a = getTurretYaw(1); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float min = -40f - r * getXRot() - r2 * getRoll(); + float max = 20f - r * getXRot() - r2 * getRoll(); + + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, min, max); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getYRot()); + float f3 = Mth.clamp(f2, -105.0F, 105.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(this.getYRot()); + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + public Vec3 driverZoomPos(float ticks) { + Matrix4f transform = getBarrelTransform(ticks); + + float x = 0f; + float y = 0.5f; + float z = -0.25f; + + Vector4f worldPosition = transformPosition(transform, x, y, z); + + return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); + } + + @Override + public Vec3 getBarrelVector(float pPartialTicks) { + Matrix4f transform = getBarrelTransform(pPartialTicks); + Vector4f rootPosition = transformPosition(transform, 0, 0, 0); + Vector4f targetPosition = transformPosition(transform, 0, 0, 1); + return new Vec3(rootPosition.x, rootPosition.y, rootPosition.z).vectorTo(new Vec3(targetPosition.x, targetPosition.y, targetPosition.z)); + } + + public Matrix4f getBarrelTransform(float ticks) { + Matrix4f transformT = getTurretTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0f, 0.5088375f, 0.04173125f); + + transformT.translate(worldPosition.x, worldPosition.y, worldPosition.z); + + float a = getTurretYaw(ticks); + + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float x = Mth.lerp(ticks, turretXRotO, getTurretXRot()); + float xV = Mth.lerp(ticks, xRotO, getXRot()); + float z = Mth.lerp(ticks, prevRoll, getRoll()); + + transformT.rotate(Axis.XP.rotationDegrees(x + r * xV + r2 * z)); + return transformT; + } + + public Matrix4f getTurretTransform(float ticks) { + Matrix4f transformV = getVehicleTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0, 1.5616625f, -0.565625f); + + transformV.translate(worldPosition.x, worldPosition.y, worldPosition.z); + transformV.rotate(Axis.YP.rotationDegrees(Mth.lerp(ticks, turretYRotO, getTurretYRot()))); + return transformV; + } + + @Override + public Matrix4f getVehicleTransform(float ticks) { + Matrix4f transform = new Matrix4f(); + transform.translate((float) Mth.lerp(ticks, xo, getX()), (float) Mth.lerp(ticks, yo + 0.9f, getY() + 0.9f), (float) Mth.lerp(ticks, zo, getZ())); + transform.rotate(Axis.YP.rotationDegrees(-Mth.lerp(ticks, yRotO, getYRot()))); + transform.rotate(Axis.XP.rotationDegrees(Mth.lerp(ticks, xRotO, getXRot()))); + transform.rotate(Axis.ZP.rotationDegrees(Mth.lerp(ticks, prevRoll, getRoll()))); + return transform; + } + + private PlayState firePredicate(AnimationState event) { + if (this.entityData.get(FIRE_ANIM) > 1) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.speedboat.fire")); + } + + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.speedboat.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "movement", 0, this::firePredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public int getMaxPassengers() { + return 5; + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.SPEEDBOAT_MAX_ENERGY.get(); + } + + @Override + public float getMaxHealth() { + return VehicleConfig.SPEEDBOAT_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + return 500; + } + + @Override + public boolean canShoot(Player player) { + return (this.entityData.get(AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) + && !cannotFire; + } + + @Override + public int getAmmoCount(Player player) { + return this.entityData.get(AMMO); + } + + @Override + public boolean hidePassenger(Entity entity) { + return false; + } + + @Override + public int zoomFov() { + return 1; + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/speedboat_icon.png"); + } + + @Override + public Vec3 getGunVec(float ticks) { + return getBarrelVector(ticks); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Tom6Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Tom6Entity.java new file mode 100644 index 000000000..8b218c6a6 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Tom6Entity.java @@ -0,0 +1,375 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.projectile.MelonBombEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.mojang.math.Axis; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +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.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +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.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.event.EventHooks; +import org.jetbrains.annotations.NotNull; +import org.joml.Math; +import org.joml.Matrix4f; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class Tom6Entity extends MobileVehicleEntity implements GeoEntity { + public static final EntityDataAccessor MELON = SynchedEntityData.defineId(Tom6Entity.class, EntityDataSerializers.BOOLEAN); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + + public Tom6Entity(EntityType type, Level world) { + super(type, world); + } + + @Override + public float maxUpStep() { + return 0.5F; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return new ThirdPersonCameraPosition(4, 1, 0); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(MELON, false); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putBoolean("Melon", this.entityData.get(MELON)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(MELON, compound.getBoolean("Melon")); + } + + @Override + @ParametersAreNonnullByDefault + protected void playStepSound(BlockPos pPos, BlockState pState) { + this.playSound(ModSounds.WHEEL_STEP.get(), (float) (getDeltaMovement().length() * 0.5), random.nextFloat() * 0.1f + 1f); + } + + // TODO AEP + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public boolean sendFireStarParticleOnHurt() { + return false; + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(2, ModDamageTypes.VEHICLE_STRIKE); + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + if (player.getMainHandItem().is(Items.MELON) && !entityData.get(MELON)) { + entityData.set(MELON, true); + player.getMainHandItem().shrink(1); + player.level().playSound(player, this.getOnPos(), SoundEvents.WOOD_PLACE, SoundSource.PLAYERS, 1, 1); + return InteractionResult.SUCCESS; + } + return super.interact(player, hand); + } + + @Override + public void baseTick() { + super.baseTick(); + float f; + + f = (float) Mth.clamp(0.759f + 0.041f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90, 0.01, 0.99); + + boolean forward = Mth.abs((float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) < 90; + + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).scale((forward ? 0.24 : -0.24) * this.getDeltaMovement().length()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f, f, f)); + + if (onGround()) { + this.terrainCompat(1f, 1.2f); + } + + if (this.isInWater() && this.tickCount % 4 == 0) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 0.6, 0.6)); + if (lastTickSpeed > 0.4) { + this.hurt(ModDamageTypes.causeVehicleStrikeDamage(this.level().registryAccess(), this, this.getFirstPassenger() == null ? this : this.getFirstPassenger()), (float) (20 * ((lastTickSpeed - 0.4) * (lastTickSpeed - 0.4)))); + } + } + + this.setDeltaMovement(this.getDeltaMovement().add(0.0, 0.01, 0.0)); + this.refreshDimensions(); + } + + @Override + public void travel() { + Entity passenger = this.getFirstPassenger(); + +// if (this.getEnergy() <= 0) return; + + float diffX; + float diffY; + + if (passenger == null || isInWater()) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + this.entityData.set(POWER, this.entityData.get(POWER) * 0.95f); + if (onGround()) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.96, 1, 0.96)); + } else { + this.setXRot(Mth.clamp(this.getXRot() + 0.1f, -89, 89)); + } + } else if (passenger instanceof Player player) { + if (level().isClientSide && this.getEnergy() > 0) { + level().playLocalSound(this.getX(), this.getY() + this.getBbHeight() * 0.5, this.getZ(), this.getEngineSound(), this.getSoundSource(), Math.min((this.forwardInputDown ? 7.5f : 5f) * 2 * Mth.abs(this.entityData.get(POWER)), 0.25f), (random.nextFloat() * 0.1f + 1.2f), false); + } + + if (forwardInputDown && getEnergy() > 0) { + this.consumeEnergy(VehicleConfig.TOM_6_ENERGY_COST.get()); + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + 0.01f, 0.15f)); + } + + if (backInputDown || downInputDown) { + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - (this.entityData.get(POWER) > 0 ? 0.01f : 0.001f), onGround() ? -0.06f : 0.03f)); + } + + if (!onGround()) { + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.4f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.4f); + } + } + + diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(passenger.getYHeadRot() - this.getYRot())); + diffX = Math.clamp(-60f, 60f, Mth.wrapDegrees(passenger.getXRot() - this.getXRot())); + + float roll = Mth.abs(Mth.clamp(getRoll() / 60, -1.5f, 1.5f)); + + float addY = Mth.clamp(Math.min((this.onGround() ? 1.5f : 0.9f) * (float) Math.max(getDeltaMovement().length() - 0.06, 0.1), 0.9f) * diffY - 0.5f * this.entityData.get(DELTA_ROT), -3 * (roll + 1), 3 * (roll + 1)); + float addX = Mth.clamp(Math.min((float) Math.max(getDeltaMovement().length() - 0.1, 0.01), 0.9f) * diffX, -4, 4); + + this.setYRot(this.getYRot() + addY); + this.setXRot(Mth.clamp(this.getXRot() + addX, onGround() ? -12 : -120, onGround() ? 3 : 120)); + this.setZRot(this.getRoll() - this.entityData.get(DELTA_ROT) + (this.onGround() ? 0 : 0.01f) * diffY * (float) getDeltaMovement().length()); + + // 空格投掷西瓜炸弹 + if (upInputDown && !onGround() && entityData.get(MELON)) { + entityData.set(MELON, false); + + Matrix4f transform = getVehicleTransform(1); + Vector4f worldPosition; + worldPosition = transformPosition(transform, 0, -0.2f, 0); + + MelonBombEntity melonBomb = new MelonBombEntity(player, player.level()); + melonBomb.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + melonBomb.shoot(getDeltaMovement().x, getDeltaMovement().y, getDeltaMovement().z, (float) getDeltaMovement().length(), 0); + passenger.level().addFreshEntity(melonBomb); + + this.level().playSound(null, getOnPos(), SoundEvents.IRON_DOOR_OPEN, SoundSource.PLAYERS, 1, 1); + upInputDown = false; + } + } + + this.entityData.set(POWER, this.entityData.get(POWER) * 0.99f); + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * 0.95f); + + this.setDeltaMovement(this.getDeltaMovement().add( + Mth.sin(-this.getYRot() * 0.017453292F) * 0.19 * this.entityData.get(POWER), + Mth.clamp(Math.sin((onGround() ? 45 : -(getXRot() - 30)) * Mth.DEG_TO_RAD) * getDeltaMovement().horizontalDistance() * 0.067, -0.04, 0.09), + Mth.cos(this.getYRot() * 0.017453292F) * 0.19 * this.entityData.get(POWER) + )); + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.WHEEL_CHAIR_ENGINE.get(); + } + + protected void clampRotation(Entity entity) { + float f = Mth.wrapDegrees(entity.getXRot() - this.getXRot()); + float f1 = Mth.clamp(f, -85.0F, 60F); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + entity.setYBodyRot(this.getYRot()); + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getYRot()); + float f3 = Mth.clamp(f2, -45.0F, 45.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(this.getYRot()); + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + @Override + public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) { + // From Immersive_Aircraft + if (!this.hasPassenger(passenger)) { + return; + } + + Matrix4f transform = getVehicleTransform(1); + + float x = 0f; + float y = 0.45f; + float z = -0.4f; + y += (float) passenger.getVehicleAttachmentPoint(this).y; + + int i = this.getSeatIndex(passenger); + + if (i == 0) { + Vector4f worldPosition = transformPosition(transform, x, y, z); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } + + if (passenger != this.getFirstPassenger()) { + passenger.setXRot(passenger.getXRot() + (getXRot() - xRotO)); + } + + copyEntityData(passenger); + } + + public void copyEntityData(Entity entity) { + float f = Mth.wrapDegrees(entity.getYRot() - getYRot()); + float g = Mth.clamp(f, -105.0f, 105.0f); + entity.yRotO += g - f; + entity.setYRot(entity.getYRot() + g - f); + entity.setYHeadRot(entity.getYRot()); + entity.setYBodyRot(getYRot()); + } + + @Override + public Matrix4f getVehicleTransform(float ticks) { + Matrix4f transform = new Matrix4f(); + transform.translate((float) Mth.lerp(ticks, xo, getX()), (float) Mth.lerp(ticks, yo + 0.5f, getY() + 0.5f), (float) Mth.lerp(ticks, zo, getZ())); + transform.rotate(Axis.YP.rotationDegrees(-Mth.lerp(ticks, yRotO, getYRot()))); + transform.rotate(Axis.XP.rotationDegrees(Mth.lerp(ticks, xRotO, getXRot()))); + transform.rotate(Axis.ZP.rotationDegrees(Mth.lerp(ticks, prevRoll, getRoll()))); + return transform; + } + + @Override + public void destroy() { + + if (this.crash) { + crashPassengers(); + } else { + explodePassengers(); + } + + if (level() instanceof ServerLevel) { + if (entityData.get(MELON)) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), this, getAttacker()), VehicleConfig.TOM_6_BOMB_EXPLOSION_DAMAGE.get(), + this.getX(), this.getY(), this.getZ(), VehicleConfig.TOM_6_BOMB_EXPLOSION_RADIUS.get().floatValue(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnHugeExplosionParticles(this.level(), this.position()); + } else { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), this, getAttacker()), 15.0f, + this.getX(), this.getY(), this.getZ(), 2f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + } + + this.discard(); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public float getMaxHealth() { + return VehicleConfig.TOM_6_HP.get(); + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.TOM_6_MAX_ENERGY.get(); + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/tom_6_icon.png"); + } + + @Override + public boolean allowFreeCam() { + return true; + } + + @Override + public void collideBlock() { + } + + @Override + public void collideHardBlock() { + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/WheelChairEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/WheelChairEntity.java new file mode 100644 index 000000000..6d65eeec2 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/WheelChairEntity.java @@ -0,0 +1,335 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.WaterAnimal; +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.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import org.jetbrains.annotations.NotNull; +import org.joml.Math; +import org.joml.Matrix4f; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.List; + +public class WheelChairEntity extends MobileVehicleEntity implements GeoEntity { + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public int jumpCoolDown; + public int handBusyTime; + + public WheelChairEntity(EntityType type, Level world) { + super(type, world); + } + + @Override + public float maxUpStep() { + return 1.1F; + } + + @Override + public void playerTouch(Player pPlayer) { + if (this.position().distanceTo(pPlayer.position()) > 1.4 || pPlayer == this.getFirstPassenger()) return; + if (!this.level().isClientSide) { + double entitySize = pPlayer.getBbWidth() * pPlayer.getBbHeight(); + double thisSize = this.getBbWidth() * this.getBbHeight(); + double f = Math.min(entitySize / thisSize, 2); + this.setDeltaMovement(this.getDeltaMovement().add(new Vec3(pPlayer.position().vectorTo(this.position()).toVector3f()).scale(0.5 * f * pPlayer.getDeltaMovement().length()))); + this.setYRot(pPlayer.getYHeadRot()); + } + } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .multiply(2, ModDamageTypes.VEHICLE_STRIKE); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + } + + @Override + protected void playStepSound(BlockPos pPos, BlockState pState) { + this.playSound(ModSounds.WHEEL_STEP.get(), (float) (getDeltaMovement().length() * 0.5), random.nextFloat() * 0.15f + 1); + } + + // TODO AEP + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + + @Override + public boolean sendFireStarParticleOnHurt() { + return false; + } + + @Override + public void baseTick() { + if (jumpCoolDown > 0 && onGround()) { + jumpCoolDown--; + } + + if (handBusyTime > 0) { + handBusyTime--; + } + + super.baseTick(); + if (this.onGround()) { + float f = (float) Mth.clamp(0.85f + 0.05f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90, 0.01, 0.99); + this.setDeltaMovement(this.getDeltaMovement().multiply(f, 0.95, f)); + } else { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.99, 0.95, 0.99)); + } + this.setSprinting(this.getDeltaMovement().horizontalDistance() > 0.15); + attractEntity(); + this.terrainCompat(0.9f, 1.2f); + inertiaRotate(10f); + + this.refreshDimensions(); + } + + public boolean hasEnoughSpaceFor(Entity pEntity) { + return pEntity.getBbWidth() < this.getBbWidth(); + } + + public void attractEntity() { + List list = this.level().getEntities(this, this.getBoundingBox().inflate(0.2F, -0.01F, 0.2F)); + if (!list.isEmpty()) { + boolean flag = !this.level().isClientSide && !(this.getControllingPassenger() instanceof Player); + + for (Entity entity : list) { + if (!entity.hasPassenger(this) && flag && !entity.isPassenger() && this.hasEnoughSpaceFor(entity) && (entity instanceof LivingEntity || entity instanceof MortarEntity) && !(entity instanceof WaterAnimal) && !(entity instanceof Player)) { + entity.startRiding(this); + } + } + } + } + + @Override + public void travel() { + Entity passenger = this.getFirstPassenger(); + + float diffY = 0; + + if (passenger == null) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + } else if (passenger instanceof Player) { + if (level().isClientSide && this.getEnergy() > 0) { + 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); + } + diffY = Math.clamp(-90f, 90f, Mth.wrapDegrees(passenger.getYHeadRot() - this.getYRot())); + this.setYRot(this.getYRot() + Mth.clamp(0.4f * diffY, -5f, 5f)); + + float direct = (90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + this.setZRot((float) (this.getRoll() + direct * diffY * 0.2 * this.getDeltaMovement().length())); + } + + if (this.forwardInputDown) { + this.entityData.set(POWER, this.entityData.get(POWER) + 0.01f); + if (this.getEnergy() <= 0 && passenger instanceof Player player) { + moveWithOutPower(player, true); + } + } + + if (this.backInputDown) { + this.entityData.set(POWER, this.entityData.get(POWER) - 0.01f); + if (this.getEnergy() <= 0 && passenger instanceof Player player) { + moveWithOutPower(player, false); + } + } + + if (this.upInputDown && this.onGround() && this.getEnergy() > 400 && jumpCoolDown == 0) { + if (passenger instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.WHEEL_CHAIR_JUMP.get(), SoundSource.PLAYERS, 1, 1); + } + this.consumeEnergy(VehicleConfig.WHEELCHAIR_JUMP_ENERGY_COST.get()); + this.setDeltaMovement(this.getDeltaMovement().add(0, 0.6, 0)); + jumpCoolDown = 3; + } + + if (this.forwardInputDown || this.backInputDown) { + this.consumeEnergy(VehicleConfig.WHEELCHAIR_MOVE_ENERGY_COST.get()); + } + + if (passenger instanceof Player player && player.level().isClientSide && this.handBusyTime > 0) { + var localPlayer = Minecraft.getInstance().player; + if (localPlayer != null && player.getUUID().equals(localPlayer.getUUID())) { + localPlayer.handsBusy = true; + } + } + + this.entityData.set(POWER, this.entityData.get(POWER) * 0.87f); + + float angle = (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1)); + double s0; + + if (Mth.abs(angle) < 90) { + s0 = this.getDeltaMovement().horizontalDistance(); + } else { + s0 = -this.getDeltaMovement().horizontalDistance(); + } + + this.setLeftWheelRot((float) (this.getLeftWheelRot() - 1.25 * s0) - 0.015f * Mth.clamp(0.4f * diffY, -5f, 5f)); + this.setRightWheelRot((float) (this.getRightWheelRot() - 1.25 * s0) + 0.015f * Mth.clamp(0.4f * diffY, -5f, 5f)); + + this.setDeltaMovement(this.getDeltaMovement().add(getViewVector(1).scale((this.onGround() ? 1 : 0.1) * this.entityData.get(POWER)))); + } + + public void moveWithOutPower(Player player, boolean forward) { + this.entityData.set(POWER, this.entityData.get(POWER) + (forward ? 0.015f : -0.015f)); + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), SoundEvents.BOAT_PADDLE_LAND, SoundSource.PLAYERS, 1, 1); + } + player.causeFoodExhaustion(0.03F); + + this.handBusyTime = 4; + this.forwardInputDown = false; + this.backInputDown = false; + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.WHEEL_CHAIR_ENGINE.get(); + } + + protected void clampRotation(Entity entity) { + entity.setYBodyRot(this.getYRot()); + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getYRot()); + float f3 = Mth.clamp(f2, -90F, 90.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(this.getYRot()); + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + @Override + public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) { + // From Immersive_Aircraft + if (!this.hasPassenger(passenger)) { + return; + } + + Matrix4f transform = getVehicleTransform(1); + + float x = 0f; + float y = 0.3f; + float z = 0f; + y += (float) passenger.getVehicleAttachmentPoint(this).y; + + int i = this.getSeatIndex(passenger); + + if (i == 0) { + Vector4f worldPosition = transformPosition(transform, x, y, z); + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + } + + if (passenger != this.getFirstPassenger()) { + passenger.setXRot(passenger.getXRot() + (getXRot() - xRotO)); + } + } + + @Override + public Matrix4f getVehicleTransform(float ticks) { + Matrix4f transform = new Matrix4f(); + transform.translate((float) Mth.lerp(ticks, xo, getX()), (float) Mth.lerp(ticks, yo + 0.4f, getY() + 0.4f), (float) Mth.lerp(ticks, zo, getZ())); + transform.rotate(Axis.YP.rotationDegrees(-Mth.lerp(ticks, yRotO, getYRot()))); + transform.rotate(Axis.XP.rotationDegrees(Mth.lerp(ticks, xRotO, getXRot()))); + transform.rotate(Axis.ZP.rotationDegrees(Mth.lerp(ticks, prevRoll, getRoll()))); + return transform; + } + + @Override + public void destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 10f, + this.getX(), this.getY(), this.getZ(), 2f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnSmallExplosionParticles(this.level(), this.position()); + } + + this.discard(); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public float getMaxHealth() { + return VehicleConfig.WHEELCHAIR_HP.get(); + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.WHEELCHAIR_MAX_ENERGY.get(); + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/wheel_chair_icon.png"); + } + + @Override + public void collideBlock() { + } + + @Override + public void collideHardBlock() { + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java new file mode 100644 index 000000000..b89ca1fd1 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java @@ -0,0 +1,893 @@ +package com.atsuishio.superbwarfare.entity.vehicle; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.config.server.VehicleConfig; +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import com.atsuishio.superbwarfare.entity.projectile.MelonBombEntity; +import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity; +import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.LandArmorEntity; +import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition; +import com.atsuishio.superbwarfare.entity.vehicle.base.WeaponVehicleEntity; +import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.CannonShellWeapon; +import com.atsuishio.superbwarfare.entity.vehicle.weapon.ProjectileWeapon; +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.network.message.ShakeClientMessage; +import com.atsuishio.superbwarfare.tools.*; +import com.mojang.math.Axis; +import net.minecraft.ChatFormatting; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundStopSoundPacket; +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.ServerEntity; +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; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +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.Matrix4f; +import org.joml.Vector4f; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.Comparator; + +import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; + +public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEntity, LandArmorEntity, WeaponVehicleEntity { + public static final EntityDataAccessor MG_AMMO = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor LOADED_AMMO = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); + public static final EntityDataAccessor GUN_FIRE_TIME = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public Yx100Entity(EntityType type, Level world) { + super(type, world); + } + + @Override + public float maxUpStep() { + return 2.25F; + } + + @Override + public VehicleWeapon[][] initWeapons() { + return new VehicleWeapon[][]{ + new VehicleWeapon[]{ + // AP + new CannonShellWeapon() + .hitDamage(VehicleConfig.YX_100_AP_CANNON_DAMAGE.get()) + .explosionRadius(VehicleConfig.YX_100_AP_CANNON_EXPLOSION_RADIUS.get().floatValue()) + .explosionDamage(VehicleConfig.YX_100_AP_CANNON_EXPLOSION_DAMAGE.get()) + .fireProbability(0) + .fireTime(0) + .durability(60) + .velocity(40) + .sound(ModSounds.INTO_MISSILE.get()) + .ammo(ModItems.AP_5_INCHES.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/ap_shell.png")), + // HE + new CannonShellWeapon() + .hitDamage(VehicleConfig.YX_100_HE_CANNON_DAMAGE.get()) + .explosionRadius(VehicleConfig.YX_100_HE_CANNON_EXPLOSION_RADIUS.get().floatValue()) + .explosionDamage(VehicleConfig.YX_100_HE_CANNON_EXPLOSION_DAMAGE.get()) + .fireProbability(0.18F) + .fireTime(2) + .durability(1) + .velocity(25) + .sound(ModSounds.INTO_CANNON.get()) + .ammo(ModItems.HE_5_INCHES.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/he_shell.png")), + }, + new VehicleWeapon[]{ + // 机枪 + new ProjectileWeapon() + .damage(VehicleConfig.HEAVY_MACHINE_GUN_DAMAGE.get()) + .headShot(2) + .zoom(false) + .bypassArmorRate(0.4f) + .ammo(ModItems.HEAVY_AMMO.get()) + .icon(ModUtils.loc("textures/screens/vehicle_weapon/gun_12_7mm.png")), + } + }; + } + + @Override + public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) { + return switch (index) { + case 0 -> new ThirdPersonCameraPosition(5, 1.5, -0.8669625); + case 1 -> new ThirdPersonCameraPosition(-1, 0.5, 0); + default -> null; + }; + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(MG_AMMO, 0) + .define(LOADED_AMMO, 0) + .define(GUN_FIRE_TIME, 0); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putInt("LoadedAmmo", this.entityData.get(LOADED_AMMO)); + compound.putInt("WeaponType", getWeaponIndex(0)); + compound.putInt("PassengerWeaponType", getWeaponIndex(1)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(LOADED_AMMO, compound.getInt("LoadedAmmo")); + setWeaponIndex(0, compound.getInt("WeaponType")); + setWeaponIndex(1, compound.getInt("PassengerWeaponType")); + } + + // TODO AEP + @Override + public @NotNull Packet getAddEntityPacket(@NotNull ServerEntity entity) { + return super.getAddEntityPacket(entity); + } + + // @Override +// public @NotNull Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } + + @Override + public DamageModifier getDamageModifier() { + return super.getDamageModifier() + .immuneTo(DamageTypes.ARROW) + .immuneTo(DamageTypes.TRIDENT) + .immuneTo(DamageTypes.MOB_ATTACK) + .immuneTo(DamageTypes.MOB_ATTACK_NO_AGGRO) + .immuneTo(DamageTypes.MOB_PROJECTILE) + .immuneTo(DamageTypes.PLAYER_ATTACK) + .immuneTo(ModTags.DamageTypes.PROJECTILE) + .immuneTo(ModDamageTypes.VEHICLE_STRIKE) + .multiply(0.2f) + .multiply(2f, DamageTypes.EXPLOSION) + .multiply(0.75f, ModDamageTypes.CUSTOM_EXPLOSION) + .multiply(0.75f, ModDamageTypes.PROJECTILE_BOOM) + .multiply(0.5f, ModDamageTypes.MINE) + .multiply(0.5f, ModDamageTypes.LUNGE_MINE) + .multiply(1.5f, ModDamageTypes.CANNON_FIRE) + .multiply(0.15f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE) + .custom((source, damage) -> getSourceAngle(source, 1f) * damage) + .custom((source, damage) -> { + if (source.getDirectEntity() instanceof MelonBombEntity) { + return 3f * damage; + } + if (source.getDirectEntity() instanceof SmallCannonShellEntity) { + return 0.375f * damage; + } + if (source.getDirectEntity() instanceof C4Entity) { + return 4f * damage; + } + if (source.getDirectEntity() instanceof RpgRocketEntity) { + return 1.5f * damage; + } + return damage; + }) + .reduce(9); + } + + @Override + protected void playStepSound(@NotNull BlockPos pPos, @NotNull BlockState pState) { + this.playSound(ModSounds.BMP_STEP.get(), Mth.abs(this.entityData.get(POWER)) * 8, random.nextFloat() * 0.15f + 1f); + } + + @Override + public void baseTick() { + super.baseTick(); + + if (getLeftTrack() < 0) { + setLeftTrack(80); + } + + if (getLeftTrack() > 80) { + setLeftTrack(0); + } + + if (getRightTrack() < 0) { + setRightTrack(80); + } + + if (getRightTrack() > 80) { + setRightTrack(0); + } + + if (this.entityData.get(GUN_FIRE_TIME) > 0) { + this.entityData.set(GUN_FIRE_TIME, this.entityData.get(GUN_FIRE_TIME) - 1); + } + + if (reloadCoolDown == 70 && this.getFirstPassenger() instanceof Player player) { + SoundTool.playLocalSound(player, ModSounds.YX_100_RELOAD.get()); + } + + if (this.level() instanceof ServerLevel) { + if (reloadCoolDown > 0 && this.entityData.get(AMMO) > 0) { + reloadCoolDown--; + } + this.handleAmmo(); + } + + if (this.onGround()) { + float f0 = 0.54f + 0.25f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90; + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.05 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f0, 0.85, f0)); + } else { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.98, 0.95, 0.98)); + } + + if (this.isInWater()) { + float f1 = (float) (0.7f - (0.04f * Math.min(getSubmergedHeight(this), this.getBbHeight())) + 0.08f * Mth.abs(90 - (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1))) / 90); + this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.04 * this.getDeltaMovement().horizontalDistance()))); + this.setDeltaMovement(this.getDeltaMovement().multiply(f1, 0.85, f1)); + } + + if (this.level() instanceof ServerLevel serverLevel && this.isInWater() && this.getDeltaMovement().length() > 0.1) { + sendParticle(serverLevel, ParticleTypes.CLOUD, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 4 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + sendParticle(serverLevel, ParticleTypes.BUBBLE_COLUMN_UP, this.getX() + 0.5 * this.getDeltaMovement().x, this.getY() + getSubmergedHeight(this) - 0.2, this.getZ() + 0.5 * this.getDeltaMovement().z, (int) (2 + 10 * this.getDeltaMovement().length()), 0.65, 0, 0.65, 0, true); + } + + collideBlock(); + if (this.getDeltaMovement().length() > 0.075) { + collideHardBlock(); + } + + turretAngle(5, 5); + gunnerAngle(15, 15); + lowHealthWarning(); + this.terrainCompat(4.6f, 6.7f); + inertiaRotate(1.2f); + + this.refreshDimensions(); + } + + + private void handleAmmo() { + boolean hasCreativeAmmo = false; + + if (this.getFirstPassenger() instanceof Player player) { + hasCreativeAmmo = InventoryTool.hasCreativeAmmoBox(player); + } + + if (hasCreativeAmmo) { + this.entityData.set(AMMO, 9999); + this.entityData.set(MG_AMMO, 9999); + } else { + this.entityData.set(AMMO, countItem(getWeapon(0).ammo)); + this.entityData.set(MG_AMMO, countItem(getWeapon(1).ammo)); + } + + if (this.getEntityData().get(LOADED_AMMO) == 0 + && reloadCoolDown <= 0 + && (hasCreativeAmmo || hasItem(getWeapon(0).ammo)) + ) { + this.entityData.set(LOADED_AMMO, 1); + if (!hasCreativeAmmo) { + consumeItem(getWeapon(0).ammo, 1); + } + } + } + + @Override + public void move(@NotNull MoverType movementType, @NotNull Vec3 movement) { + super.move(movementType, movement); + if (this.isInWater() && horizontalCollision) { + setDeltaMovement(this.getDeltaMovement().add(0, 0.07, 0)); + } + } + + @Override + public void vehicleShoot(Player player, int type) { + boolean hasCreativeAmmo = false; + for (int i = 0; i < getMaxPassengers() - 1; i++) { + if (getNthEntity(i) instanceof Player pPlayer && InventoryTool.hasCreativeAmmoBox(pPlayer)) { + hasCreativeAmmo = true; + } + } + if (reloadCoolDown == 0 && type == 0) { + + if (!this.canConsume(VehicleConfig.YX_100_SHOOT_COST.get())) { + player.displayClientMessage(Component.translatable("tips.superbwarfare.annihilator.energy_not_enough").withStyle(ChatFormatting.RED), true); + return; + } + + Matrix4f transform = getBarrelTransform(1); + Vector4f worldPosition = transformPosition(transform, 0, 0, 0); + + var cannonShell = (CannonShellWeapon) getWeapon(0); + var entityToSpawn = cannonShell.create(player); + + entityToSpawn.setPos(worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z); + entityToSpawn.shoot(getBarrelVector(1).x, getBarrelVector(1).y + 0.005f, getBarrelVector(1).z, cannonShell.velocity, 0.02f); + level().addFreshEntity(entityToSpawn); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.YX_100_FIRE_3P.get(), 8, 1); + serverPlayer.playSound(ModSounds.YX_100_FAR.get(), 16, 1); + serverPlayer.playSound(ModSounds.YX_100_VERYFAR.get(), 32, 1); + } + } + + this.entityData.set(CANNON_RECOIL_TIME, 40); + this.entityData.set(LOADED_AMMO, 0); + this.consumeEnergy(10000); + this.entityData.set(YAW, getTurretYRot()); + + reloadCoolDown = 80; + + if (this.level() instanceof ServerLevel server) { + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + this.getX() + 5 * getBarrelVector(1).x, + this.getY() + 0.1, + this.getZ() + 5 * getBarrelVector(1).z, + 300, 6, 0.02, 6, 0.005); + + double x = worldPosition.x + 9 * getBarrelVector(1).x; + double y = worldPosition.y + 9 * getBarrelVector(1).y; + double z = worldPosition.z + 9 * getBarrelVector(1).z; + + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, x, y, z, 10, 0.4, 0.4, 0.4, 0.0075); + server.sendParticles(ParticleTypes.CLOUD, x, y, z, 10, 0.4, 0.4, 0.4, 0.0075); + + int count = 6; + + for (float i = 9.5f; i < 23; i += .5f) { + server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, + worldPosition.x + i * getBarrelVector(1).x, + worldPosition.y + i * getBarrelVector(1).y, + worldPosition.z + i * getBarrelVector(1).z, + Mth.clamp(count--, 1, 5), 0.15, 0.15, 0.15, 0.0025); + } + + Vector4f worldPositionL = transformPosition(transform, -0.35f, 0, 0); + Vector4f worldPositionR = transformPosition(transform, 0.35f, 0, 0); + + for (float i = 3f; i < 6; i += .5f) { + server.sendParticles(ParticleTypes.CLOUD, + worldPositionL.x + i * getBarrelVector(1).x, + worldPositionL.y + i * getBarrelVector(1).y, + worldPositionL.z + i * getBarrelVector(1).z, + 1, 0.025, 0.025, 0.025, 0.0015); + + server.sendParticles(ParticleTypes.CLOUD, + worldPositionR.x + i * getBarrelVector(1).x, + worldPositionR.y + i * getBarrelVector(1).y, + worldPositionR.z + i * getBarrelVector(1).z, + 1, 0.025, 0.025, 0.025, 0.0015); + } + } + + + 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(8), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(10, 8, 40, this.getX(), this.getEyeY(), this.getZ())); + } + } + } + + if (type == 1) { + if (this.cannotFire) return; + Matrix4f transform = getGunTransform(1); + Vector4f worldPosition = transformPosition(transform, 0, -0.25f, 0); + + var projectile = (ProjectileWeapon) getWeapon(1); + var projectileEntity = projectile.create(player); + + projectileEntity.setPos(worldPosition.x - 1.1 * this.getDeltaMovement().x, worldPosition.y, worldPosition.z - 1.1 * this.getDeltaMovement().z); + projectileEntity.shoot(getGunnerVector(1).x, getGunnerVector(1).y, getGunnerVector(1).z, 20, 0.3f); + + this.level().addFreshEntity(projectileEntity); + + float pitch = this.entityData.get(HEAT) <= 60 ? 1 : (float) (1 - 0.011 * Math.abs(60 - this.entityData.get(HEAT))); + + if (!player.level().isClientSide) { + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.playSound(ModSounds.M_2_FIRE_3P.get(), 4, pitch); + serverPlayer.playSound(ModSounds.M_2_FAR.get(), 12, pitch); + serverPlayer.playSound(ModSounds.M_2_VERYFAR.get(), 24, pitch); + } + } + + this.entityData.set(GUN_FIRE_TIME, 2); + this.entityData.set(HEAT, this.entityData.get(HEAT) + 4); + + 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(4), e -> true).stream().sorted(Comparator.comparingDouble(e -> e.distanceToSqr(center))).toList()) { + if (target instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new ShakeClientMessage(6, 4, 8, this.getX(), this.getEyeY(), this.getZ())); + } + } + + if (hasCreativeAmmo) return; + + ItemStack ammoBox = this.getItemStacks().stream().filter(stack -> { + if (stack.is(ModItems.AMMO_BOX.get())) { + return AmmoType.HEAVY.get(stack) > 0; + } + return false; + }).findFirst().orElse(ItemStack.EMPTY); + + if (!ammoBox.isEmpty()) { + AmmoType.HEAVY.add(ammoBox, -1); + } else { + consumeItem(getWeapon(1).ammo, 1); + } + } + } + + @Override + public void travel() { + Entity passenger0 = this.getFirstPassenger(); + + if (this.getEnergy() <= 0) return; + + if (!(passenger0 instanceof Player)) { + this.leftInputDown = false; + this.rightInputDown = false; + this.forwardInputDown = false; + this.backInputDown = false; + this.entityData.set(POWER, 0f); + } + + if (forwardInputDown) { + this.entityData.set(POWER, Math.min(this.entityData.get(POWER) + (this.entityData.get(POWER) < 0 ? 0.004f : 0.0024f), 0.21f)); + } + + if (backInputDown) { + this.entityData.set(POWER, Math.max(this.entityData.get(POWER) - (this.entityData.get(POWER) > 0 ? 0.004f : 0.0024f), -0.16f)); + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } + } else { + if (rightInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) - 0.1f); + } else if (this.leftInputDown) { + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) + 0.1f); + } + } + + if (this.forwardInputDown || this.backInputDown) { + this.consumeEnergy(VehicleConfig.YX_100_ENERGY_COST.get()); + } + + this.entityData.set(POWER, this.entityData.get(POWER) * (upInputDown ? 0.5f : (rightInputDown || leftInputDown) ? 0.947f : 0.96f)); + this.entityData.set(DELTA_ROT, this.entityData.get(DELTA_ROT) * (float) Math.max(0.76f - 0.1f * this.getDeltaMovement().horizontalDistance(), 0.3)); + + float angle = (float) calculateAngle(this.getDeltaMovement(), this.getViewVector(1)); + double s0; + + if (Mth.abs(angle) < 90) { + s0 = this.getDeltaMovement().horizontalDistance(); + } else { + s0 = -this.getDeltaMovement().horizontalDistance(); + } + + this.setLeftWheelRot((float) ((this.getLeftWheelRot() - 1.25 * s0) + Mth.clamp(0.75f * this.entityData.get(DELTA_ROT), -5f, 5f))); + this.setRightWheelRot((float) ((this.getRightWheelRot() - 1.25 * s0) - Mth.clamp(0.75f * this.entityData.get(DELTA_ROT), -5f, 5f))); + + setLeftTrack((float) ((getLeftTrack() - 1.5 * Math.PI * s0) + Mth.clamp(0.4f * Math.PI * this.entityData.get(DELTA_ROT), -5f, 5f))); + setRightTrack((float) ((getRightTrack() - 1.5 * Math.PI * s0) - Mth.clamp(0.4f * Math.PI * this.entityData.get(DELTA_ROT), -5f, 5f))); + + if (this.isInWater() || onGround()) { + this.setYRot((float) (this.getYRot() - (isInWater() && !onGround() ? 2.5 : 6) * entityData.get(DELTA_ROT))); + this.setDeltaMovement(this.getDeltaMovement().add(getViewVector(1).scale((!isInWater() && !onGround() ? 0.13f : (isInWater() && !onGround() ? 2 : 2.4f)) * this.entityData.get(POWER)))); + } + } + + @Override + public SoundEvent getEngineSound() { + return ModSounds.BMP_ENGINE.get(); + } + + @Override + public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) { + // From Immersive_Aircraft + if (!this.hasPassenger(passenger)) { + return; + } + + Matrix4f transform = getTurretTransform(1); + + int i = this.getOrderedPassengers().indexOf(passenger); + + var worldPosition = switch (i) { + case 0 -> transformPosition(transform, 0.8669625f, 0.2f, 0.6076875f); + case 1 -> transformPosition(transform, -0.87890625f, 0.5f, -0.6640625f); + case 2 -> transformPosition(transform, 1f, 0.15f, -0.6640625f); + default -> throw new IllegalStateException("Unexpected value: " + i); + }; + + passenger.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + callback.accept(passenger, worldPosition.x, worldPosition.y, worldPosition.z); + + copyEntityData(passenger); + } + + public void copyEntityData(Entity entity) { + if (entity == getNthEntity(0)) { + entity.setYBodyRot(getBarrelYRot(1)); + } + } + + public Vec3 driverZoomPos(float ticks) { + Matrix4f transform = getTurretTransform(ticks); + Vector4f worldPosition = transformPosition(transform, 0, 0, 0.6076875f); + return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); + } + + public int getMaxPassengers() { + return 3; + } + + @Override + public Vec3 getBarrelVector(float pPartialTicks) { + Matrix4f transform = getBarrelTransform(pPartialTicks); + Vector4f rootPosition = transformPosition(transform, 0, 0, 0); + Vector4f targetPosition = transformPosition(transform, 0, 0, 1); + return new Vec3(rootPosition.x, rootPosition.y, rootPosition.z).vectorTo(new Vec3(targetPosition.x, targetPosition.y, targetPosition.z)); + } + + public Vec3 getGunnerVector(float pPartialTicks) { + Matrix4f transform = getGunnerBarrelTransform(pPartialTicks); + Vector4f rootPosition = transformPosition(transform, 0, 0, 0); + Vector4f targetPosition = transformPosition(transform, 0, 0, 1); + return new Vec3(rootPosition.x, rootPosition.y, rootPosition.z).vectorTo(new Vec3(targetPosition.x, targetPosition.y, targetPosition.z)); + } + + public Matrix4f getBarrelTransform(float ticks) { + Matrix4f transformT = getTurretTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0f, 0.653275f, 0.750975f); + + transformT.translate(worldPosition.x, worldPosition.y, worldPosition.z); + + float a = getTurretYaw(ticks); + + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float x = Mth.lerp(ticks, turretXRotO, getTurretXRot()); + float xV = Mth.lerp(ticks, xRotO, getXRot()); + float z = Mth.lerp(ticks, prevRoll, getRoll()); + + transformT.rotate(Axis.XP.rotationDegrees(x + r * xV + r2 * z)); + return transformT; + } + + public Matrix4f getTurretTransform(float ticks) { + Matrix4f transformV = getVehicleTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0, 2.1484375f, 0); + + transformV.translate(worldPosition.x, worldPosition.y, worldPosition.z); + transformV.rotate(Axis.YP.rotationDegrees(Mth.lerp(ticks, turretYRotO, getTurretYRot()))); + return transformV; + } + + public Matrix4f getGunTransform(float ticks) { + Matrix4f transformT = getTurretTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, -0.87890625f, 1.31171875F, -0.6640625f); + + transformT.translate(worldPosition.x, worldPosition.y, worldPosition.z); + transformT.rotate(Axis.YP.rotationDegrees(Mth.lerp(ticks, gunYRotO, getGunYRot()) - Mth.lerp(ticks, turretYRotO, getTurretYRot()))); + return transformT; + } + + public Matrix4f getGunnerBarrelTransform(float ticks) { + Matrix4f transformG = getGunTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0f, 0.4325125f, 0.0632125f); + + transformG.translate(worldPosition.x, worldPosition.y, worldPosition.z); + + float a = getTurretYaw(ticks); + + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float x = Mth.lerp(ticks, gunXRotO, getGunXRot()); + float xV = Mth.lerp(ticks, xRotO, getXRot()); + float z = Mth.lerp(ticks, prevRoll, getRoll()); + + transformG.rotate(Axis.XP.rotationDegrees(x + r * xV + r2 * z)); + return transformG; + } + + + @Override + public void destroy() { + if (level() instanceof ServerLevel) { + CustomExplosion explosion = new CustomExplosion(this.level(), this, + ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 80f, + this.getX(), this.getY(), this.getZ(), 5f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1); + explosion.explode(); + EventHooks.onExplosionStart(this.level(), explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(this.level(), this.position()); + } + + explodePassengers(); + this.discard(); + } + + protected void clampRotation(Entity entity) { + Minecraft mc = Minecraft.getInstance(); + if (entity.level().isClientSide && entity == getFirstPassenger()) { + float a = getTurretYaw(1); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float min = -30f - r * getXRot() - r2 * getRoll(); + float max = 10f - r * getXRot() - r2 * getRoll(); + + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, min, max); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + if (mc.options.getCameraType() == CameraType.FIRST_PERSON) { + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getBarrelYRot(1)); + float f3 = Mth.clamp(f2, -20.0F, 20.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(getBarrelYRot(1)); + } + } else if (entity == getNthEntity(1)) { + float a = getTurretYaw(1); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float min = -60f - r * getXRot() - r2 * getRoll(); + float max = 10f - r * getXRot() - r2 * getRoll(); + + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, min, max); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + + if (mc.options.getCameraType() == CameraType.FIRST_PERSON) { + float f2 = Mth.wrapDegrees(entity.getYRot() - this.getGunYRot(1)); + float f3 = Mth.clamp(f2, -150.0F, 150.0F); + entity.yRotO += f3 - f2; + entity.setYRot(entity.getYRot() + f3 - f2); + entity.setYBodyRot(entity.getYRot()); + } + } else if (entity == getNthEntity(2)) { + float a = getTurretYaw(1); + float r = (Mth.abs(a) - 90f) / 90f; + + float r2; + + if (Mth.abs(a) <= 90f) { + r2 = a / 90f; + } else { + if (a < 0) { + r2 = -(180f + a) / 90f; + } else { + r2 = (180f - a) / 90f; + } + } + + float min = -90f - r * getXRot() - r2 * getRoll(); + float max = 22.5f - r * getXRot() - r2 * getRoll(); + + float f = Mth.wrapDegrees(entity.getXRot()); + float f1 = Mth.clamp(f, min, max); + entity.xRotO += f1 - f; + entity.setXRot(entity.getXRot() + f1 - f); + } + } + + @Override + public void onPassengerTurned(@NotNull Entity entity) { + this.clampRotation(entity); + } + + private PlayState cannonShootPredicate(AnimationState event) { + if (this.entityData.get(CANNON_RECOIL_TIME) > 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.yx100.fire")); + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.yx100.idle")); + } + + private PlayState gunShootPredicate(AnimationState event) { + if (this.entityData.get(GUN_FIRE_TIME) > 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.yx100.fire2")); + } + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.yx100.idle2")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + data.add(new AnimationController<>(this, "cannon", 0, this::cannonShootPredicate)); + data.add(new AnimationController<>(this, "gun", 0, this::gunShootPredicate)); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + public int getMaxEnergy() { + return VehicleConfig.YX_100_MAX_ENERGY.get(); + } + + @Override + public float getMaxHealth() { + return VehicleConfig.YX_100_HP.get(); + } + + @Override + public int mainGunRpm(Player player) { + if (player == getNthEntity(0)) { + return 15; + } + + if (player == getNthEntity(1)) { + return 500; + } + return 15; + } + + @Override + public boolean canShoot(Player player) { + return switch (getSeatIndex(player)) { + case 0 -> this.entityData.get(LOADED_AMMO) > 0 && getEnergy() > VehicleConfig.YX_100_SHOOT_COST.get(); + case 1 -> (this.entityData.get(MG_AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFire; + default -> false; + }; + } + + @Override + public int getAmmoCount(Player player) { + if (player == getNthEntity(0)) { + return this.entityData.get(LOADED_AMMO); + } + if (player == getNthEntity(1)) { + return this.entityData.get(MG_AMMO); + } + return 0; + } + + @Override + public boolean banHand(Player player) { + return hidePassenger(player); + } + + @Override + public boolean hidePassenger(Entity entity) { + return entity == getNthEntity(0) || entity == getNthEntity(1); + } + + @Override + public int zoomFov() { + return 3; + } + + @Override + public void changeWeapon(int index, int value, boolean isScroll) { + if (index != 0) return; + + if (entityData.get(LOADED_AMMO) > 0) { + if (this.getFirstPassenger() instanceof Player player && !InventoryTool.hasCreativeAmmoBox(player)) { + this.insertItem(getWeapon(0).ammo, 1); + } + entityData.set(LOADED_AMMO, 0); + } + + this.reloadCoolDown = 80; + + if (this.getFirstPassenger() instanceof ServerPlayer player) { + var clientboundstopsoundpacket = new ClientboundStopSoundPacket(ModSounds.YX_100_RELOAD.get().getLocation(), SoundSource.PLAYERS); + player.connection.send(clientboundstopsoundpacket); + } + + WeaponVehicleEntity.super.changeWeapon(index, value, isScroll); + } + + public Vec3 getGunVec(float ticks) { + return getGunnerVector(ticks); + } + + @Override + public ResourceLocation getVehicleIcon() { + return ModUtils.loc("textures/vehicle_icon/yx_100_icon.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java index af06bb22d..c2f6f21b8 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java @@ -246,6 +246,10 @@ public abstract class VehicleEntity extends Entity { public VehicleEntity(EntityType pEntityType, Level pLevel) { super(pEntityType, pLevel); this.setHealth(this.getMaxHealth()); + + if (this instanceof WeaponVehicleEntity weaponVehicle && weaponVehicle.getAllWeapons().length > 0) { + this.entityData.set(SELECTED_WEAPON, IntList.of(initSelectedWeaponArray(weaponVehicle))); + } } @Override @@ -253,11 +257,9 @@ public abstract class VehicleEntity extends Entity { builder.define(HEALTH, this.getMaxHealth()) .define(LAST_ATTACKER_UUID, "undefined") .define(LAST_DRIVER_UUID, "undefined") - .define(DELTA_ROT, 0f); - - if (this instanceof WeaponVehicleEntity weaponVehicle && weaponVehicle.getAllWeapons().length > 0) { - builder.define(SELECTED_WEAPON, IntList.of(initSelectedWeaponArray(weaponVehicle))); - } + .define(DELTA_ROT, 0f) + .define(SELECTED_WEAPON, IntList.of(new int[this.getMaxPassengers()])); + // 怎么还不给玩动态注册了(恼) } private int[] initSelectedWeaponArray(WeaponVehicleEntity weaponVehicle) { diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/CannonShellWeapon.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/CannonShellWeapon.java index f5d854dac..b39b30cae 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/CannonShellWeapon.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/CannonShellWeapon.java @@ -1,5 +1,8 @@ package com.atsuishio.superbwarfare.entity.vehicle.weapon; +import com.atsuishio.superbwarfare.entity.projectile.CannonShellEntity; +import net.minecraft.world.entity.player.Player; + public class CannonShellWeapon extends VehicleWeapon { public float hitDamage, explosionRadius, explosionDamage, fireProbability, velocity; public int fireTime, durability; @@ -39,15 +42,14 @@ public class CannonShellWeapon extends VehicleWeapon { return this; } - // TODO create -// public CannonShellEntity create(Player player) { -// return new CannonShellEntity(player, -// player.level(), -// this.hitDamage, -// this.explosionRadius, -// this.explosionDamage, -// this.fireProbability, -// this.fireTime -// ).durability(this.durability); -// } + public CannonShellEntity create(Player player) { + return new CannonShellEntity(player, + player.level(), + this.hitDamage, + this.explosionRadius, + this.explosionDamage, + this.fireProbability, + this.fireTime + ).durability(this.durability); + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/HeliRocketWeapon.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/HeliRocketWeapon.java index c61581b7f..03728c34a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/HeliRocketWeapon.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/HeliRocketWeapon.java @@ -1,6 +1,8 @@ package com.atsuishio.superbwarfare.entity.vehicle.weapon; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.HeliRocketEntity; +import net.minecraft.world.entity.LivingEntity; public class HeliRocketWeapon extends VehicleWeapon { @@ -25,8 +27,7 @@ public class HeliRocketWeapon extends VehicleWeapon { return this; } - // TODO create -// public HeliRocketEntity create(LivingEntity entity) { -// return new HeliRocketEntity(entity, entity.level(), damage, explosionDamage, explosionRadius); -// } + public HeliRocketEntity create(LivingEntity entity) { + return new HeliRocketEntity(entity, entity.level(), damage, explosionDamage, explosionRadius); + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SmallCannonShellWeapon.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SmallCannonShellWeapon.java index 85e56569a..fa90f3ae0 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SmallCannonShellWeapon.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SmallCannonShellWeapon.java @@ -1,5 +1,8 @@ package com.atsuishio.superbwarfare.entity.vehicle.weapon; +import com.atsuishio.superbwarfare.entity.projectile.SmallCannonShellEntity; +import net.minecraft.world.entity.LivingEntity; + public class SmallCannonShellWeapon extends VehicleWeapon { public float damage = 40, explosionDamage = 80, explosionRadius = 5; @@ -19,8 +22,7 @@ public class SmallCannonShellWeapon extends VehicleWeapon { return this; } - // TODO create -// public SmallCannonShellEntity create(LivingEntity entity) { -// return new SmallCannonShellEntity(entity, entity.level(), damage, explosionDamage, explosionRadius); -// } + public SmallCannonShellEntity create(LivingEntity entity) { + return new SmallCannonShellEntity(entity, entity.level(), damage, explosionDamage, explosionRadius); + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/WgMissileWeapon.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/WgMissileWeapon.java index bedc12ada..25932012d 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/WgMissileWeapon.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/WgMissileWeapon.java @@ -1,6 +1,8 @@ package com.atsuishio.superbwarfare.entity.vehicle.weapon; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.projectile.WgMissileEntity; +import net.minecraft.world.entity.LivingEntity; public class WgMissileWeapon extends VehicleWeapon { @@ -25,8 +27,7 @@ public class WgMissileWeapon extends VehicleWeapon { return this; } - // TODO create -// public WgMissileEntity create(LivingEntity entity) { -// return new WgMissileEntity(entity, entity.level(), damage, explosionDamage, explosionRadius); -// } + public WgMissileEntity create(LivingEntity entity) { + return new WgMissileEntity(entity, entity.level(), damage, explosionDamage, explosionRadius); + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java index 29c168ed8..0eb22181a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java @@ -1,16 +1,22 @@ package com.atsuishio.superbwarfare.init; import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.config.server.SpawnConfig; +import com.atsuishio.superbwarfare.entity.ClaymoreEntity; +import com.atsuishio.superbwarfare.entity.MortarEntity; +import com.atsuishio.superbwarfare.entity.SenpaiEntity; import com.atsuishio.superbwarfare.entity.TargetEntity; -import com.atsuishio.superbwarfare.entity.projectile.LaserEntity; -import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity; +import com.atsuishio.superbwarfare.entity.projectile.*; +import com.atsuishio.superbwarfare.entity.vehicle.*; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.Difficulty; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.level.levelgen.Heightmap; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent; +import net.neoforged.neoforge.event.entity.RegisterSpawnPlacementsEvent; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; @@ -22,96 +28,96 @@ public class ModEntities { // Living Entities public static final DeferredHolder, EntityType> TARGET = register("target", EntityType.Builder.of(TargetEntity::new, MobCategory.CREATURE).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(0.875f, 2f)); - // public static final DeferredHolder, EntityType> SENPAI = register("senpai", -// EntityType.Builder.of(SenpaiEntity::new, MobCategory.MONSTER).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(SenpaiEntity::new) -// .sized(0.6f, 2f)); -// -// // Misc Entities -// public static final DeferredHolder, EntityType> MORTAR = register("mortar", -// EntityType.Builder.of(MortarEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(MortarEntity::new).fireImmune().sized(0.8f, 1.4f)); + public static final DeferredHolder, EntityType> SENPAI = register("senpai", + EntityType.Builder.of(SenpaiEntity::new, MobCategory.MONSTER).setTrackingRange(64).setUpdateInterval(3) + .sized(0.6f, 2f)); + + // // Misc Entities + public static final DeferredHolder, EntityType> MORTAR = register("mortar", + EntityType.Builder.of(MortarEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(0.8f, 1.4f)); public static final DeferredHolder, EntityType> LASER = register("laser", EntityType.Builder.of(LaserEntity::new, MobCategory.MISC).sized(0.1f, 0.1f).fireImmune().setUpdateInterval(1)); - // public static final DeferredHolder, EntityType> FLARE_DECOY = register("flare_decoy", -// EntityType.Builder.of(FlareDecoyEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(FlareDecoyEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> CLAYMORE = register("claymore", -// EntityType.Builder.of(ClaymoreEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> C_4 = register("c4", -// EntityType.Builder.of(C4Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); -// -// // Projectiles -// public static final DeferredHolder, EntityType> TASER_BULLET = register("taser_bullet", -// EntityType.Builder.of(TaserBulletEntity::new, MobCategory.MISC).setCustomClientFactory(TaserBulletEntity::new).setTrackingRange(64) -// .setUpdateInterval(1).sized(0.5f, 0.5f)); -// -// // Fast Projectiles -// public static final DeferredHolder, EntityType> SMALL_CANNON_SHELL = register("small_cannon_shell", -// EntityType.Builder.of(SmallCannonShellEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(SmallCannonShellEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> RPG_ROCKET = register("rpg_rocket", -// EntityType.Builder.of(RpgRocketEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(RpgRocketEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> MORTAR_SHELL = register("mortar_shell", -// EntityType.Builder.of(MortarShellEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(MortarShellEntity::new).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> FLARE_DECOY = register("flare_decoy", + EntityType.Builder.of(FlareDecoyEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> CLAYMORE = register("claymore", + EntityType.Builder.of(ClaymoreEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> C_4 = register("c4", + EntityType.Builder.of(C4Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + + // Projectiles + public static final DeferredHolder, EntityType> TASER_BULLET = register("taser_bullet", + EntityType.Builder.of(TaserBulletEntity::new, MobCategory.MISC).setTrackingRange(64) + .setUpdateInterval(1).sized(0.5f, 0.5f)); + + // Fast Projectiles + public static final DeferredHolder, EntityType> SMALL_CANNON_SHELL = register("small_cannon_shell", + EntityType.Builder.of(SmallCannonShellEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> RPG_ROCKET = register("rpg_rocket", + EntityType.Builder.of(RpgRocketEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> MORTAR_SHELL = register("mortar_shell", + EntityType.Builder.of(MortarShellEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); public static final DeferredHolder, EntityType> PROJECTILE = register("projectile", EntityType.Builder.of(ProjectileEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).noSave().noSummon().sized(0.25f, 0.25f)); -// public static final DeferredHolder, EntityType> CANNON_SHELL = register("cannon_shell", -// EntityType.Builder.of(CannonShellEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(CannonShellEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> GUN_GRENADE = register("gun_grenade", -// EntityType.Builder.of(GunGrenadeEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(GunGrenadeEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> MELON_BOMB = register("melon_bomb", -// EntityType.Builder.of(MelonBombEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(MelonBombEntity::new).sized(1f, 1f)); -// public static final DeferredHolder, EntityType> HAND_GRENADE = register("hand_grenade", -// EntityType.Builder.of(HandGrenadeEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(HandGrenadeEntity::new).sized(0.3f, 0.3f)); -// public static final DeferredHolder, EntityType> RGO_GRENADE = register("rgo_grenade", -// EntityType.Builder.of(RgoGrenadeEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(RgoGrenadeEntity::new).sized(0.3f, 0.3f)); -// public static final DeferredHolder, EntityType> JAVELIN_MISSILE = register("javelin_missile", -// EntityType.Builder.of(JavelinMissileEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(JavelinMissileEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> HELI_ROCKET = register("heli_rocket", -// EntityType.Builder.of(HeliRocketEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).setCustomClientFactory(HeliRocketEntity::new).sized(0.5f, 0.5f)); -// public static final DeferredHolder, EntityType> WG_MISSILE = register("wg_missile", -// EntityType.Builder.of(WgMissileEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(WgMissileEntity::new).fireImmune().sized(0.5f, 0.5f)); -// -// // Vehicles -// public static final DeferredHolder, EntityType> MK_42 = register("mk_42", -// EntityType.Builder.of(Mk42Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Mk42Entity::new).fireImmune().sized(3.4f, 3.5f)); -// public static final DeferredHolder, EntityType> MLE_1934 = register("mle_1934", -// EntityType.Builder.of(Mle1934Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Mle1934Entity::new).fireImmune().sized(4.5f, 2.8f)); -// public static final DeferredHolder, EntityType> ANNIHILATOR = register("annihilator", -// EntityType.Builder.of(AnnihilatorEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(AnnihilatorEntity::new).fireImmune().sized(13f, 4.2f)); -// -// public static final DeferredHolder, EntityType> SPEEDBOAT = register("speedboat", -// EntityType.Builder.of(SpeedboatEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(SpeedboatEntity::new).fireImmune().sized(3.0f, 2.0f)); -// public static final DeferredHolder, EntityType> WHEEL_CHAIR = register("wheel_chair", -// EntityType.Builder.of(WheelChairEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(WheelChairEntity::new).fireImmune().sized(1.0f, 1.0f)); -// public static final DeferredHolder, EntityType> AH_6 = register("ah_6", -// EntityType.Builder.of(Ah6Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Ah6Entity::new).fireImmune().sized(2.8f, 2.9f)); -// public static final DeferredHolder, EntityType> LAV_150 = register("lav_150", -// EntityType.Builder.of(Lav150Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Lav150Entity::new).fireImmune().sized(2.8f, 3.1f)); -// public static final DeferredHolder, EntityType> TOM_6 = register("tom_6", -// EntityType.Builder.of(Tom6Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Tom6Entity::new).fireImmune().sized(1.05f, 1.0f)); -// public static final DeferredHolder, EntityType> BMP_2 = register("bmp_2", -// EntityType.Builder.of(Bmp2Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Bmp2Entity::new).fireImmune().sized(4f, 3f)); -// public static final DeferredHolder, EntityType> YX_100 = register("yx_100", -// EntityType.Builder.of(Yx100Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(Yx100Entity::new).fireImmune().sized(5.5f, 3.25f)); -// -// public static final DeferredHolder, EntityType> DRONE = register("drone", -// EntityType.Builder.of(DroneEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(DroneEntity::new).sized(0.6f, 0.2f)); -// public static final DeferredHolder, EntityType> LASER_TOWER = register("laser_tower", -// EntityType.Builder.of(LaserTowerEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).setCustomClientFactory(LaserTowerEntity::new).fireImmune().sized(0.9f, 1.65f)); + public static final DeferredHolder, EntityType> CANNON_SHELL = register("cannon_shell", + EntityType.Builder.of(CannonShellEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> GUN_GRENADE = register("gun_grenade", + EntityType.Builder.of(GunGrenadeEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> MELON_BOMB = register("melon_bomb", + EntityType.Builder.of(MelonBombEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(1f, 1f)); + public static final DeferredHolder, EntityType> HAND_GRENADE = register("hand_grenade", + EntityType.Builder.of(HandGrenadeEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.3f, 0.3f)); + public static final DeferredHolder, EntityType> RGO_GRENADE = register("rgo_grenade", + EntityType.Builder.of(RgoGrenadeEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.3f, 0.3f)); + public static final DeferredHolder, EntityType> JAVELIN_MISSILE = register("javelin_missile", + EntityType.Builder.of(JavelinMissileEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> HELI_ROCKET = register("heli_rocket", + EntityType.Builder.of(HeliRocketEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final DeferredHolder, EntityType> WG_MISSILE = register("wg_missile", + EntityType.Builder.of(WgMissileEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(0.5f, 0.5f)); + + // Vehicles + public static final DeferredHolder, EntityType> MK_42 = register("mk_42", + EntityType.Builder.of(Mk42Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(3.4f, 3.5f)); + public static final DeferredHolder, EntityType> MLE_1934 = register("mle_1934", + EntityType.Builder.of(Mle1934Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(4.5f, 2.8f)); + public static final DeferredHolder, EntityType> ANNIHILATOR = register("annihilator", + EntityType.Builder.of(AnnihilatorEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(13f, 4.2f)); + + public static final DeferredHolder, EntityType> SPEEDBOAT = register("speedboat", + EntityType.Builder.of(SpeedboatEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(3.0f, 2.0f)); + public static final DeferredHolder, EntityType> WHEEL_CHAIR = register("wheel_chair", + EntityType.Builder.of(WheelChairEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(1.0f, 1.0f)); + public static final DeferredHolder, EntityType> AH_6 = register("ah_6", + EntityType.Builder.of(Ah6Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(2.8f, 2.9f)); + public static final DeferredHolder, EntityType> LAV_150 = register("lav_150", + EntityType.Builder.of(Lav150Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(2.8f, 3.1f)); + public static final DeferredHolder, EntityType> TOM_6 = register("tom_6", + EntityType.Builder.of(Tom6Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(1.05f, 1.0f)); + public static final DeferredHolder, EntityType> BMP_2 = register("bmp_2", + EntityType.Builder.of(Bmp2Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(4f, 3f)); + public static final DeferredHolder, EntityType> YX_100 = register("yx_100", + EntityType.Builder.of(Yx100Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(5.5f, 3.25f)); + + public static final DeferredHolder, EntityType> DRONE = register("drone", + EntityType.Builder.of(DroneEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).sized(0.6f, 0.2f)); + public static final DeferredHolder, EntityType> LASER_TOWER = register("laser_tower", + EntityType.Builder.of(LaserTowerEntity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(0.9f, 1.65f)); private static DeferredHolder, EntityType> register(String name, EntityType.Builder entityTypeBuilder) { return REGISTRY.register(name, () -> entityTypeBuilder.build(name)); } -// @SubscribeEvent -// public static void onRegisterSpawnPlacement(SpawnPlacementRegisterEvent event) { -// event.register(ModEntities.SENPAI.get(), SpawnPlacements.Type.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, -// (entityType, world, reason, pos, random) -> (world.getDifficulty() != Difficulty.PEACEFUL && SpawnConfig.SPAWN_SENPAI.get() -// && Monster.isDarkEnoughToSpawn(world, pos, random) && Mob.checkMobSpawnRules(entityType, world, reason, pos, random)), -// SpawnPlacementRegisterEvent.Operation.OR); -// } + @SubscribeEvent + public static void onRegisterSpawnPlacement(RegisterSpawnPlacementsEvent event) { + event.register(ModEntities.SENPAI.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, + (entityType, world, reason, pos, random) -> (world.getDifficulty() != Difficulty.PEACEFUL && SpawnConfig.SPAWN_SENPAI.get() + && Monster.isDarkEnoughToSpawn(world, pos, random) && Mob.checkMobSpawnRules(entityType, world, reason, pos, random)), + RegisterSpawnPlacementsEvent.Operation.OR); + } @SubscribeEvent public static void registerAttributes(EntityAttributeCreationEvent event) { event.put(TARGET.get(), TargetEntity.createAttributes().build()); -// event.put(SENPAI.get(), SenpaiEntity.createAttributes().build()); + event.put(SENPAI.get(), SenpaiEntity.createAttributes().build()); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java index 608723dbc..1a612dffc 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java @@ -1,8 +1,7 @@ package com.atsuishio.superbwarfare.init; import com.atsuishio.superbwarfare.ModUtils; -import com.atsuishio.superbwarfare.client.renderer.entity.LaserEntityRenderer; -import com.atsuishio.superbwarfare.client.renderer.entity.TargetRenderer; +import com.atsuishio.superbwarfare.client.renderer.entity.*; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -13,37 +12,37 @@ public class ModEntityRenderers { @SubscribeEvent public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) { -// event.registerEntityRenderer(ModEntities.MORTAR.get(), MortarRenderer::new); -// event.registerEntityRenderer(ModEntities.SENPAI.get(), SenpaiRenderer::new); -// event.registerEntityRenderer(ModEntities.CLAYMORE.get(), ClaymoreRenderer::new); -// event.registerEntityRenderer(ModEntities.C_4.get(), C4Renderer::new); -// event.registerEntityRenderer(ModEntities.TASER_BULLET.get(), TaserBulletProjectileRenderer::new); -// event.registerEntityRenderer(ModEntities.GUN_GRENADE.get(), GunGrenadeRenderer::new); + event.registerEntityRenderer(ModEntities.MORTAR.get(), MortarRenderer::new); + event.registerEntityRenderer(ModEntities.SENPAI.get(), SenpaiRenderer::new); + event.registerEntityRenderer(ModEntities.CLAYMORE.get(), ClaymoreRenderer::new); + event.registerEntityRenderer(ModEntities.C_4.get(), C4Renderer::new); + event.registerEntityRenderer(ModEntities.TASER_BULLET.get(), TaserBulletProjectileRenderer::new); + event.registerEntityRenderer(ModEntities.GUN_GRENADE.get(), GunGrenadeRenderer::new); event.registerEntityRenderer(ModEntities.TARGET.get(), TargetRenderer::new); -// event.registerEntityRenderer(ModEntities.RPG_ROCKET.get(), RpgRocketRenderer::new); -// event.registerEntityRenderer(ModEntities.HELI_ROCKET.get(), HeliRocketRenderer::new); -// event.registerEntityRenderer(ModEntities.MORTAR_SHELL.get(), MortarShellRenderer::new); -// event.registerEntityRenderer(ModEntities.CANNON_SHELL.get(), CannonShellRenderer::new); -// event.registerEntityRenderer(ModEntities.PROJECTILE.get(), ProjectileEntityRenderer::new); -// event.registerEntityRenderer(ModEntities.MK_42.get(), Mk42Renderer::new); -// event.registerEntityRenderer(ModEntities.DRONE.get(), DroneRenderer::new); -// event.registerEntityRenderer(ModEntities.HAND_GRENADE.get(), HandGrenadeRenderer::new); -// event.registerEntityRenderer(ModEntities.RGO_GRENADE.get(), RgoGrenadeRenderer::new); -// event.registerEntityRenderer(ModEntities.MLE_1934.get(), Mle1934Renderer::new); -// event.registerEntityRenderer(ModEntities.JAVELIN_MISSILE.get(), JavelinMissileRenderer::new); + event.registerEntityRenderer(ModEntities.RPG_ROCKET.get(), RpgRocketRenderer::new); + event.registerEntityRenderer(ModEntities.HELI_ROCKET.get(), HeliRocketRenderer::new); + event.registerEntityRenderer(ModEntities.MORTAR_SHELL.get(), MortarShellRenderer::new); + event.registerEntityRenderer(ModEntities.CANNON_SHELL.get(), CannonShellRenderer::new); + event.registerEntityRenderer(ModEntities.PROJECTILE.get(), ProjectileEntityRenderer::new); + event.registerEntityRenderer(ModEntities.MK_42.get(), Mk42Renderer::new); + event.registerEntityRenderer(ModEntities.DRONE.get(), DroneRenderer::new); + event.registerEntityRenderer(ModEntities.HAND_GRENADE.get(), HandGrenadeRenderer::new); + event.registerEntityRenderer(ModEntities.RGO_GRENADE.get(), RgoGrenadeRenderer::new); + event.registerEntityRenderer(ModEntities.MLE_1934.get(), Mle1934Renderer::new); + event.registerEntityRenderer(ModEntities.JAVELIN_MISSILE.get(), JavelinMissileRenderer::new); event.registerEntityRenderer(ModEntities.LASER.get(), LaserEntityRenderer::new); -// event.registerEntityRenderer(ModEntities.ANNIHILATOR.get(), AnnihilatorRenderer::new); -// event.registerEntityRenderer(ModEntities.SPEEDBOAT.get(), SpeedboatRenderer::new); -// event.registerEntityRenderer(ModEntities.WHEEL_CHAIR.get(), WheelChairRenderer::new); -// event.registerEntityRenderer(ModEntities.AH_6.get(), Ah6Renderer::new); -// event.registerEntityRenderer(ModEntities.FLARE_DECOY.get(), FlareDecoyEntityRenderer::new); -// event.registerEntityRenderer(ModEntities.LAV_150.get(), Lav150Renderer::new); -// event.registerEntityRenderer(ModEntities.SMALL_CANNON_SHELL.get(), SmallCannonShellRenderer::new); -// event.registerEntityRenderer(ModEntities.TOM_6.get(), Tom6Renderer::new); -// event.registerEntityRenderer(ModEntities.MELON_BOMB.get(), MelonBombEntityRenderer::new); -// event.registerEntityRenderer(ModEntities.BMP_2.get(), Bmp2Renderer::new); -// event.registerEntityRenderer(ModEntities.WG_MISSILE.get(), WgMissileRenderer::new); -// event.registerEntityRenderer(ModEntities.LASER_TOWER.get(), LaserTowerRenderer::new); -// event.registerEntityRenderer(ModEntities.YX_100.get(), Yx100Renderer::new); + event.registerEntityRenderer(ModEntities.ANNIHILATOR.get(), AnnihilatorRenderer::new); + event.registerEntityRenderer(ModEntities.SPEEDBOAT.get(), SpeedboatRenderer::new); + event.registerEntityRenderer(ModEntities.WHEEL_CHAIR.get(), WheelChairRenderer::new); + event.registerEntityRenderer(ModEntities.AH_6.get(), Ah6Renderer::new); + event.registerEntityRenderer(ModEntities.FLARE_DECOY.get(), FlareDecoyEntityRenderer::new); + event.registerEntityRenderer(ModEntities.LAV_150.get(), Lav150Renderer::new); + event.registerEntityRenderer(ModEntities.SMALL_CANNON_SHELL.get(), SmallCannonShellRenderer::new); + event.registerEntityRenderer(ModEntities.TOM_6.get(), Tom6Renderer::new); + event.registerEntityRenderer(ModEntities.MELON_BOMB.get(), MelonBombEntityRenderer::new); + event.registerEntityRenderer(ModEntities.BMP_2.get(), Bmp2Renderer::new); + event.registerEntityRenderer(ModEntities.WG_MISSILE.get(), WgMissileRenderer::new); + event.registerEntityRenderer(ModEntities.LASER_TOWER.get(), LaserTowerRenderer::new); + event.registerEntityRenderer(ModEntities.YX_100.get(), Yx100Renderer::new); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java index e133e8f76..8596724ac 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java @@ -31,16 +31,21 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ProjectileItem; import net.minecraft.world.item.Rarity; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.DispenserBlock; import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.common.DeferredSpawnEggItem; import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; +import java.util.ArrayList; +import java.util.List; + @SuppressWarnings("unused") public class ModItems { - public static final DeferredRegister REGISTRY = DeferredRegister.create(Registries.ITEM, ModUtils.MODID); - /** * guns */ @@ -103,13 +108,13 @@ public class ModItems { public static final DeferredHolder MORTAR_SHELL = AMMO.register("mortar_shell", MortarShell::new); public static final DeferredHolder POTION_MORTAR_SHELL = AMMO.register("potion_mortar_shell", PotionMortarShell::new); public static final DeferredHolder ROCKET = AMMO.register("rocket", Rocket::new); - // public static final DeferredHolder LUNGE_MINE = AMMO.register("lunge_mine", LungeMine::new); + public static final DeferredHolder LUNGE_MINE = AMMO.register("lunge_mine", LungeMine::new); public static final DeferredHolder HE_5_INCHES = AMMO.register("he_5_inches", () -> new CannonShellItem(new Item.Properties().rarity(Rarity.RARE))); public static final DeferredHolder AP_5_INCHES = AMMO.register("ap_5_inches", () -> new CannonShellItem(new Item.Properties().rarity(Rarity.RARE))); - // public static final DeferredHolder HAND_GRENADE = AMMO.register("hand_grenade", HandGrenade::new); -// public static final DeferredHolder RGO_GRENADE = AMMO.register("rgo_grenade", RgoGrenade::new); -// public static final DeferredHolder CLAYMORE_MINE = AMMO.register("claymore_mine", ClaymoreMine::new); -// public static final DeferredHolder C4_BOMB = AMMO.register("c4_bomb", C4Bomb::new); + public static final DeferredHolder HAND_GRENADE = AMMO.register("hand_grenade", HandGrenade::new); + public static final DeferredHolder RGO_GRENADE = AMMO.register("rgo_grenade", RgoGrenade::new); + public static final DeferredHolder CLAYMORE_MINE = AMMO.register("claymore_mine", ClaymoreMine::new); + public static final DeferredHolder C4_BOMB = AMMO.register("c4_bomb", C4Bomb::new); public static final DeferredHolder SMALL_SHELL = AMMO.register("small_shell", () -> new Item(new Item.Properties())); public static final DeferredHolder ROCKET_70 = AMMO.register("rocket_70", () -> new Item(new Item.Properties())); public static final DeferredHolder WIRE_GUIDE_MISSILE = AMMO.register("wire_guide_missile", () -> new Item(new Item.Properties())); @@ -122,7 +127,7 @@ public class ModItems { public static final DeferredHolder CONTAINER = ITEMS.register("container", ContainerBlockItem::new); public static final DeferredHolder SMALL_CONTAINER = ITEMS.register("small_container", SmallContainerBlockItem::new); -// public static final DeferredHolder SENPAI_SPAWN_EGG = ITEMS.register("senpai_spawn_egg", () -> new ForgeSpawnEggItem(ModEntities.SENPAI, -11584987, -14014413, new Item.Properties())); + public static final DeferredHolder SENPAI_SPAWN_EGG = ITEMS.register("senpai_spawn_egg", () -> new DeferredSpawnEggItem(ModEntities.SENPAI::value, -11584987, -14014413, new Item.Properties())); public static final DeferredHolder ANCIENT_CPU = ITEMS.register("ancient_cpu", () -> new Item(new Item.Properties().rarity(Rarity.RARE))); public static final DeferredHolder PROPELLER = ITEMS.register("propeller", () -> new Item(new Item.Properties())); public static final DeferredHolder LARGE_PROPELLER = ITEMS.register("large_propeller", () -> new Item(new Item.Properties())); @@ -130,16 +135,16 @@ public class ModItems { public static final DeferredHolder LARGE_MOTOR = ITEMS.register("large_motor", () -> new Item(new Item.Properties())); public static final DeferredHolder WHEEL = ITEMS.register("wheel", () -> new Item(new Item.Properties())); public static final DeferredHolder TRACK = ITEMS.register("track", () -> new Item(new Item.Properties())); - // public static final DeferredHolder DRONE = ITEMS.register("drone", Drone::new); -// -// public static final DeferredHolder MONITOR = ITEMS.register("monitor", Monitor::new); -// -// public static final DeferredHolder DETONATOR = ITEMS.register("detonator", Detonator::new); + public static final DeferredHolder DRONE = ITEMS.register("drone", Drone::new); + + public static final DeferredHolder MONITOR = ITEMS.register("monitor", Monitor::new); + + public static final DeferredHolder DETONATOR = ITEMS.register("detonator", Detonator::new); public static final DeferredHolder TARGET_DEPLOYER = ITEMS.register("target_deployer", TargetDeployer::new); public static final DeferredHolder KNIFE = ITEMS.register("knife", Knife::new); public static final DeferredHolder HAMMER = ITEMS.register("hammer", Hammer::new); public static final DeferredHolder CROWBAR = ITEMS.register("crowbar", Crowbar::new); - // public static final DeferredHolder DEFUSER = ITEMS.register("defuser", Defuser::new); + public static final DeferredHolder DEFUSER = ITEMS.register("defuser", Defuser::new); public static final DeferredHolder ARMOR_PLATE = ITEMS.register("armor_plate", ArmorPlate::new); public static final DeferredHolder RU_HELMET_6B47 = ITEMS.register("ru_helmet_6b47", RuHelmet6b47::new); @@ -147,7 +152,7 @@ public class ModItems { public static final DeferredHolder US_HELMET_PASTG = ITEMS.register("us_helmet_pastg", UsHelmetPastg::new); public static final DeferredHolder US_CHEST_IOTV = ITEMS.register("us_chest_iotv", UsChestIotv::new); public static final DeferredHolder GE_HELMET_M_35 = ITEMS.register("ge_helmet_m_35", GeHelmetM35::new); - // public static final DeferredHolder MORTAR_DEPLOYER = ITEMS.register("mortar_deployer", MortarDeployer::new); + public static final DeferredHolder MORTAR_DEPLOYER = ITEMS.register("mortar_deployer", MortarDeployer::new); public static final DeferredHolder MORTAR_BARREL = ITEMS.register("mortar_barrel", () -> new Item(new Item.Properties())); public static final DeferredHolder MORTAR_BASE_PLATE = ITEMS.register("mortar_base_plate", () -> new Item(new Item.Properties())); public static final DeferredHolder MORTAR_BIPOD = ITEMS.register("mortar_bipod", () -> new Item(new Item.Properties())); @@ -296,6 +301,18 @@ public class ModItems { return BLOCKS.register(block.getId().getPath(), () -> new BlockItem(block.get(), new Item.Properties())); } + public static void registerDispenserBehavior(FMLCommonSetupEvent event) { + List> list = new ArrayList<>(); + list.addAll(AMMO.getEntries()); + list.addAll(ITEMS.getEntries()); + + for (var item : list) { + if (item.get() instanceof ProjectileItem launchable) { + DispenserBlock.registerProjectileBehavior(item.get()); + } + } + } + public static void register(IEventBus bus) { ITEMS.register(bus); GUNS.register(bus); @@ -303,8 +320,6 @@ public class ModItems { BLOCKS.register(bus); registerPerkItems(); PERKS.register(bus); - - REGISTRY.register(bus); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java b/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java index 160f967f3..add3e886a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModTabs.java @@ -3,9 +3,11 @@ package com.atsuishio.superbwarfare.init; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.item.ArmorPlate; import com.atsuishio.superbwarfare.item.BatteryItem; +import com.atsuishio.superbwarfare.item.C4Bomb; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -48,13 +50,13 @@ public class ModTabs { if (registryObject.get() != ModItems.POTION_MORTAR_SHELL.get()) { output.accept(registryObject.get()); -// if (registryObject.get() == ModItems.C4_BOMB.get()) { -// output.accept(C4Bomb.makeInstance()); -// } + if (registryObject.get() == ModItems.C4_BOMB.get()) { + output.accept(C4Bomb.makeInstance()); + } } }); - // TODO c4, potion + // TODO potion mortar shell // param.holders().lookup(Registries.POTION) // .ifPresent(potion -> generatePotionEffectTypes(output, potion, ModItems.POTION_MORTAR_SHELL.get())); }) @@ -89,10 +91,9 @@ public class ModTabs { @SubscribeEvent public static void buildTabContentsVanilla(BuildCreativeModeTabContentsEvent tabData) { - // TODO senpai -// if (tabData.getTabKey() == CreativeModeTabs.SPAWN_EGGS) { -// tabData.accept(ModItems.SENPAI_SPAWN_EGG.get()); -// } + if (tabData.getTabKey() == CreativeModeTabs.SPAWN_EGGS) { + tabData.accept(ModItems.SENPAI_SPAWN_EGG.get()); + } } // TODO potion shell diff --git a/src/main/java/com/atsuishio/superbwarfare/item/C4Bomb.java b/src/main/java/com/atsuishio/superbwarfare/item/C4Bomb.java new file mode 100644 index 000000000..4df66a6f7 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/C4Bomb.java @@ -0,0 +1,93 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.NBTTool; +import net.minecraft.ChatFormatting; +import net.minecraft.core.Direction; +import net.minecraft.core.Position; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ProjectileItem; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; + +public class C4Bomb extends Item implements ProjectileItem { + + public static final String TAG_CONTROL = "Control"; + + public C4Bomb() { + super(new Properties()); + } + + @Override + public @NotNull InteractionResultHolder use(Level level, Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + + if (!level.isClientSide) { + boolean flag = NBTTool.getTag(stack).getBoolean(TAG_CONTROL); + + C4Entity entity = new C4Entity(player, level, flag); + entity.setPos(player.getX() + 0.25 * player.getLookAngle().x, player.getEyeY() - 0.2f + 0.25 * player.getLookAngle().y, player.getZ() + 0.25 * player.getLookAngle().z); + entity.setDeltaMovement(0.5 * player.getLookAngle().x, 0.5 * player.getLookAngle().y, 0.5 * player.getLookAngle().z); + entity.setOwner(player); + + level.addFreshEntity(entity); + } + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.C4_THROW.get(), SoundSource.PLAYERS, 1, 1); + } + + player.getCooldowns().addCooldown(this, 20); + + if (!player.getAbilities().instabuild) { + stack.shrink(1); + } + + return InteractionResultHolder.consume(stack); + } + + @Override + @ParametersAreNonnullByDefault + public void appendHoverText(ItemStack stack, TooltipContext context, List tooltipComponents, TooltipFlag tooltipFlag) { + if (NBTTool.getBoolean(stack, TAG_CONTROL, false)) { + tooltipComponents.add(Component.translatable("des.superbwarfare.c4_bomb.control").withStyle(ChatFormatting.GRAY)); + } else { + tooltipComponents.add(Component.translatable("des.superbwarfare.c4_bomb.time").withStyle(ChatFormatting.GRAY)); + } + } + + public static ItemStack makeInstance() { + ItemStack stack = new ItemStack(ModItems.C4_BOMB.get()); + NBTTool.setBoolean(stack, TAG_CONTROL, true); + return stack; + } + + // TODO play sound + @Override + @ParametersAreNonnullByDefault + public @NotNull Projectile asProjectile(Level level, Position pos, ItemStack stack, Direction direction) { + var c4 = new C4Entity((LivingEntity) null, level); + c4.setPos(pos.x(), pos.y(), pos.z()); + return c4; + } + + @Override + public @NotNull DispenseConfig createDispenseConfig() { + return DispenseConfig.builder().power(0.15F).build(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/ClaymoreMine.java b/src/main/java/com/atsuishio/superbwarfare/item/ClaymoreMine.java new file mode 100644 index 000000000..a53a43ecf --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/ClaymoreMine.java @@ -0,0 +1,77 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.ClaymoreEntity; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +public class ClaymoreMine extends Item { + public ClaymoreMine() { + super(new Properties()); + } + + @Override + public @NotNull InteractionResultHolder use(Level level, Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + + if (!level.isClientSide) { + ClaymoreEntity entity = new ClaymoreEntity(player, level); + entity.moveTo(player.getX(), player.getY() + 1.1, player.getZ(), player.getYRot(), 0); + entity.setYBodyRot(player.getYRot()); + entity.setYHeadRot(player.getYRot()); + entity.setDeltaMovement(0.5 * player.getLookAngle().x, 0.5 * player.getLookAngle().y, 0.5 * player.getLookAngle().z); + + level.addFreshEntity(entity); + } + + player.getCooldowns().addCooldown(this, 20); + + if (!player.getAbilities().instabuild) { + stack.shrink(1); + } + + return InteractionResultHolder.consume(stack); + } + + // TODO 发射器发射 +// @Override +// public DispenseItemBehavior getLaunchBehavior() { +// return new ProjectileDispenseBehavior() { +// @Override +// @ParametersAreNonnullByDefault +// public @NotNull ItemStack execute(BlockSource pSource, ItemStack pStack) { +// Level level = pSource.getLevel(); +// Position position = DispenserBlock.getDispensePosition(pSource); +// Direction direction = pSource.getBlockState().getValue(DispenserBlock.FACING); +// +// var claymore = new ClaymoreEntity(ModEntities.CLAYMORE.get(), level); +// claymore.setPos(position.x(), position.y(), position.z()); +// +// var pX = direction.getStepX(); +// var pY = direction.getStepY() + 0.1F; +// var pZ = direction.getStepZ(); +// Vec3 vec3 = (new Vec3(pX, pY, pZ)).normalize().scale(0.05); +// claymore.setDeltaMovement(vec3); +// double d0 = vec3.horizontalDistance(); +// claymore.setYRot((float) (Mth.atan2(vec3.x, vec3.z) * (double) (180F / (float) Math.PI))); +// claymore.setXRot((float) (Mth.atan2(vec3.y, d0) * (double) (180F / (float) Math.PI))); +// claymore.yRotO = claymore.getYRot(); +// claymore.xRotO = claymore.getXRot(); +// +// level.addFreshEntity(claymore); +// pStack.shrink(1); +// return pStack; +// } +// }; +// } +// +// @Override +// @ParametersAreNonnullByDefault +// public @NotNull Projectile asProjectile(Level level, Position pos, ItemStack stack, Direction direction) { +// return null; +// } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/ContainerBlockItem.java b/src/main/java/com/atsuishio/superbwarfare/item/ContainerBlockItem.java index bcd6f24ea..575c9bbd0 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/ContainerBlockItem.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/ContainerBlockItem.java @@ -46,20 +46,18 @@ public class ContainerBlockItem extends BlockItem implements GeoItem { /** * 集装箱可用实体列表 */ - // TODO 正确生成可用列表 public static final List> CONTAINER_ENTITIES = List.of( - () -> ContainerBlockItem.createInstance(ModEntities.TARGET.get()) -// () -> ContainerBlockItem.createInstance(ModEntities.MK_42.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.MLE_1934.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.ANNIHILATOR.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.LASER_TOWER.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.SPEEDBOAT.get(), true), -// () -> ContainerBlockItem.createInstance(ModEntities.AH_6.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.LAV_150.get(), true), -// () -> ContainerBlockItem.createInstance(ModEntities.BMP_2.get(), true), -// () -> ContainerBlockItem.createInstance(ModEntities.YX_100.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.WHEEL_CHAIR.get()), -// () -> ContainerBlockItem.createInstance(ModEntities.TOM_6.get()) + () -> ContainerBlockItem.createInstance(ModEntities.MK_42.get()), + () -> ContainerBlockItem.createInstance(ModEntities.MLE_1934.get()), + () -> ContainerBlockItem.createInstance(ModEntities.ANNIHILATOR.get()), + () -> ContainerBlockItem.createInstance(ModEntities.LASER_TOWER.get()), + () -> ContainerBlockItem.createInstance(ModEntities.SPEEDBOAT.get(), true), + () -> ContainerBlockItem.createInstance(ModEntities.AH_6.get()), + () -> ContainerBlockItem.createInstance(ModEntities.LAV_150.get(), true), + () -> ContainerBlockItem.createInstance(ModEntities.BMP_2.get(), true), + () -> ContainerBlockItem.createInstance(ModEntities.YX_100.get()), + () -> ContainerBlockItem.createInstance(ModEntities.WHEEL_CHAIR.get()), + () -> ContainerBlockItem.createInstance(ModEntities.TOM_6.get()) ); private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); diff --git a/src/main/java/com/atsuishio/superbwarfare/item/Defuser.java b/src/main/java/com/atsuishio/superbwarfare/item/Defuser.java new file mode 100644 index 000000000..03fec0764 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/Defuser.java @@ -0,0 +1,73 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.TraceTool; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class Defuser extends Item { + + public Defuser() { + super(new Properties().durability(8)); + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level pLevel, Player pPlayer, InteractionHand pUsedHand) { + ItemStack stack = pPlayer.getItemInHand(pUsedHand); + if (findBombInSight(pPlayer) != null) { + pPlayer.startUsingItem(pUsedHand); + return InteractionResultHolder.consume(stack); + } + return InteractionResultHolder.fail(stack); + } + + private static C4Entity findBombInSight(Player player) { + Entity target = TraceTool.findLookingEntity(player, 4); + return target instanceof C4Entity c4Entity ? c4Entity : null; + } + + @Override + @ParametersAreNonnullByDefault + public void onUseTick(Level pLevel, LivingEntity pLivingEntity, ItemStack pStack, int pRemainingUseDuration) { + if (!(pLivingEntity instanceof Player player)) return; + var target = findBombInSight(player); + if (target == null) return; + + int useTick = pStack.getUseDuration(player) - pRemainingUseDuration; + + if (!pLevel.isClientSide) { + player.displayClientMessage(Component.literal( + FormatTool.format1DZZ((C4Entity.DEFAULT_DEFUSE_PROGRESS - useTick) / 20d, "s") + ).withStyle(ChatFormatting.GREEN), true); + } + + if (useTick >= C4Entity.DEFAULT_DEFUSE_PROGRESS) { + player.stopUsingItem(); + if (pLevel instanceof ServerLevel serverLevel) { + pStack.hurtAndBreak(1, serverLevel, player, p -> { + }); + } + target.defuse(); + } + } + + @Override + @ParametersAreNonnullByDefault + public int getUseDuration(ItemStack stack, LivingEntity entity) { + return 72000; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/Detonator.java b/src/main/java/com/atsuishio/superbwarfare/item/Detonator.java new file mode 100644 index 000000000..ffa2eeaaf --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/Detonator.java @@ -0,0 +1,54 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.projectile.C4Entity; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; +import java.util.stream.StreamSupport; + +public class Detonator extends Item { + + public Detonator() { + super(new Properties().stacksTo(1)); + } + + public static List getC4(Player player, Level level) { + return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) + .filter(e -> e instanceof C4Entity c4 && c4.getOwner() == player) + .toList(); + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level world, Player player, InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + player.getCooldowns().addCooldown(stack.getItem(), 10); + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.C4_DETONATOR_CLICK.get(), SoundSource.PLAYERS, 1, 1); + } + + this.releaseUsing(stack, player.level(), player, 1); + + List entities = getC4(player, player.level()); + for (var e : entities) { + if (e instanceof C4Entity c4 && c4.getEntityData().get(C4Entity.IS_CONTROLLABLE)) { + c4.explode(); + } + } + + return InteractionResultHolder.consume(stack); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/Drone.java b/src/main/java/com/atsuishio/superbwarfare/item/Drone.java new file mode 100644 index 000000000..3dbd5aa75 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/Drone.java @@ -0,0 +1,93 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.init.ModEntities; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Objects; + +public class Drone extends Item { + + public Drone() { + super(new Properties().rarity(Rarity.UNCOMMON)); + } + + @Override + public @NotNull InteractionResult useOn(UseOnContext pContext) { + Level level = pContext.getLevel(); + if (!(level instanceof ServerLevel)) { + return InteractionResult.SUCCESS; + } else { + ItemStack itemstack = pContext.getItemInHand(); + BlockPos blockpos = pContext.getClickedPos(); + Direction direction = pContext.getClickedFace(); + BlockState blockstate = level.getBlockState(blockpos); + BlockPos pos; + if (blockstate.getCollisionShape(level, blockpos).isEmpty()) { + pos = blockpos; + } else { + pos = blockpos.relative(direction); + } + + if (ModEntities.DRONE.get().spawn((ServerLevel) level, itemstack, pContext.getPlayer(), pos, MobSpawnType.SPAWN_EGG, true, !Objects.equals(blockpos, pos) && direction == Direction.UP) != null) { + itemstack.shrink(1); + level.gameEvent(pContext.getPlayer(), GameEvent.ENTITY_PLACE, blockpos); + } + + return InteractionResult.CONSUME; + } + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level pLevel, Player pPlayer, InteractionHand pHand) { + ItemStack itemstack = pPlayer.getItemInHand(pHand); + BlockHitResult blockhitresult = getPlayerPOVHitResult(pLevel, pPlayer, ClipContext.Fluid.SOURCE_ONLY); + if (blockhitresult.getType() != HitResult.Type.BLOCK) { + return InteractionResultHolder.pass(itemstack); + } else if (!(pLevel instanceof ServerLevel)) { + return InteractionResultHolder.success(itemstack); + } else { + BlockPos blockpos = blockhitresult.getBlockPos(); + if (!(pLevel.getBlockState(blockpos).getBlock() instanceof LiquidBlock)) { + return InteractionResultHolder.pass(itemstack); + } else if (pLevel.mayInteract(pPlayer, blockpos) && pPlayer.mayUseItemAt(blockpos, blockhitresult.getDirection(), itemstack)) { + Entity entity = ModEntities.DRONE.get().spawn((ServerLevel) pLevel, itemstack, pPlayer, blockpos, MobSpawnType.SPAWN_EGG, false, false); + if (entity == null) { + return InteractionResultHolder.pass(itemstack); + } else { + if (!pPlayer.getAbilities().instabuild) { + itemstack.shrink(1); + } + + pPlayer.awardStat(Stats.ITEM_USED.get(this)); + pLevel.gameEvent(pPlayer, GameEvent.ENTITY_PLACE, entity.position()); + return InteractionResultHolder.consume(itemstack); + } + } else { + return InteractionResultHolder.fail(itemstack); + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/HandGrenade.java b/src/main/java/com/atsuishio/superbwarfare/item/HandGrenade.java new file mode 100644 index 000000000..8f765a38d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/HandGrenade.java @@ -0,0 +1,113 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.projectile.HandGrenadeEntity; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.core.Direction; +import net.minecraft.core.Position; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.item.*; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.event.EventHooks; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class HandGrenade extends Item implements ProjectileItem { + + public HandGrenade() { + super(new Properties().rarity(Rarity.UNCOMMON)); + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level worldIn, Player playerIn, InteractionHand handIn) { + ItemStack stack = playerIn.getItemInHand(handIn); + playerIn.startUsingItem(handIn); + if (playerIn instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.GRENADE_PULL.get(), SoundSource.PLAYERS, 1, 1); + } + return InteractionResultHolder.consume(stack); + } + + @Override + public @NotNull UseAnim getUseAnimation(@NotNull ItemStack stack) { + return UseAnim.SPEAR; + } + + @Override + @ParametersAreNonnullByDefault + public void releaseUsing(ItemStack stack, Level worldIn, LivingEntity entityLiving, int timeLeft) { + if (!worldIn.isClientSide) { + if (entityLiving instanceof Player player) { + int usingTime = this.getUseDuration(stack, player) - timeLeft; + if (usingTime > 3) { + player.getCooldowns().addCooldown(stack.getItem(), 25); + float power = Math.min(usingTime / 10.0f, 1.5f); + + HandGrenadeEntity handGrenade = new HandGrenadeEntity(player, worldIn, 100 - usingTime); + handGrenade.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0f, power, 0.0f); + worldIn.addFreshEntity(handGrenade); + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.GRENADE_THROW.get(), SoundSource.PLAYERS, 1, 1); + } + + if (!player.isCreative()) { + stack.shrink(1); + } + } + } + } + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull ItemStack finishUsingItem(ItemStack pStack, Level pLevel, LivingEntity pLivingEntity) { + if (!pLevel.isClientSide) { + HandGrenadeEntity handGrenade = new HandGrenadeEntity(pLivingEntity, pLevel, 100); + + CustomExplosion explosion = new CustomExplosion(pLevel, null, + ModDamageTypes.causeProjectileBoomDamage(pLevel.registryAccess(), handGrenade, pLivingEntity), ExplosionConfig.M67_GRENADE_EXPLOSION_DAMAGE.get(), + pLivingEntity.getX(), pLivingEntity.getY(), pLivingEntity.getZ(), ExplosionConfig.M67_GRENADE_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1.25f); + explosion.explode(); + EventHooks.onExplosionStart(pLevel, explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(pLevel, pLivingEntity.position()); + + if (pLivingEntity instanceof Player player) { + player.getCooldowns().addCooldown(pStack.getItem(), 25); + } + + if (pLivingEntity instanceof Player player && !player.isCreative()) { + pStack.shrink(1); + } + } + + return super.finishUsingItem(pStack, pLevel, pLivingEntity); + } + + @Override + @ParametersAreNonnullByDefault + public int getUseDuration(ItemStack stack, LivingEntity entity) { + return 100; + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull Projectile asProjectile(Level level, Position pos, ItemStack stack, Direction direction) { + return new HandGrenadeEntity(ModEntities.HAND_GRENADE.get(), pos.x(), pos.y(), pos.z(), level); + } +} + diff --git a/src/main/java/com/atsuishio/superbwarfare/item/LungeMine.java b/src/main/java/com/atsuishio/superbwarfare/item/LungeMine.java new file mode 100644 index 000000000..6bf878350 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/LungeMine.java @@ -0,0 +1,151 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.client.renderer.item.LungeMineRenderer; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.init.ModSounds; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions; +import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent; +import org.jetbrains.annotations.NotNull; +import software.bernie.geckolib.animatable.GeoItem; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.*; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.ParametersAreNonnullByDefault; + +@EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.MOD) +public class LungeMine extends Item implements GeoItem { + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public static ItemDisplayContext transformType; + + public LungeMine() { + super(new Properties().stacksTo(4)); + } + + @SubscribeEvent + private static void registerItemExtensions(RegisterClientExtensionsEvent event) { + event.registerItem(new IClientItemExtensions() { + + private final BlockEntityWithoutLevelRenderer renderer = new LungeMineRenderer(); + + @Override + public @NotNull BlockEntityWithoutLevelRenderer getCustomRenderer() { + return renderer; + } + + // TODO ArmPose +// private static final HumanoidModel.ArmPose LungeMinePose = HumanoidModel.ArmPose.create("LungeMine", false, (model, entity, arm) -> { +// if (arm != HumanoidArm.LEFT) { +// model.rightArm.xRot = 20f * Mth.DEG_TO_RAD + model.head.xRot; +// model.rightArm.yRot = -12f * Mth.DEG_TO_RAD; +// model.leftArm.xRot = -45f * Mth.DEG_TO_RAD + model.head.xRot; +// model.leftArm.yRot = 40f * Mth.DEG_TO_RAD; +// } +// }); + + @Override + @ParametersAreNonnullByDefault + public HumanoidModel.ArmPose getArmPose(LivingEntity entityLiving, InteractionHand hand, ItemStack itemStack) { + if (!itemStack.isEmpty()) { + if (entityLiving.getUsedItemHand() == hand) { +// return LungeMinePose; + } + } + return HumanoidModel.ArmPose.EMPTY; + } + }, ModItems.LUNGE_MINE); + } + + public void getTransformType(ItemDisplayContext type) { + transformType = type; + } + + private PlayState idlePredicate(AnimationState event) { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return PlayState.STOP; + if (ClientEventHandler.lungeSprint > 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lunge_mine.sprint")); + } + + if (ClientEventHandler.lungeDraw > 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lunge_mine.draw")); + } + + if (ClientEventHandler.lungeAttack > 0) { + return event.setAndContinue(RawAnimation.begin().thenPlay("animation.lunge_mine.fire")); + } + + if (player.isSprinting() && player.onGround() && ClientEventHandler.lungeDraw == 0) { + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.lunge_mine.run")); + } + + return event.setAndContinue(RawAnimation.begin().thenLoop("animation.lunge_mine.idle")); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + var idleController = new AnimationController<>(this, "idleController", 2, this::idlePredicate); + data.add(idleController); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } + + @Override + @ParametersAreNonnullByDefault + public boolean onEntitySwing(ItemStack stack, LivingEntity entity, InteractionHand hand) { + return false; + } + + @Override + @ParametersAreNonnullByDefault + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return false; + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level worldIn, Player playerIn, InteractionHand handIn) { + ItemStack stack = playerIn.getItemInHand(handIn); + if (playerIn instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.LUNGE_MINE_GROWL.get(), SoundSource.PLAYERS, 2, 1); + } + if (!playerIn.level().isClientSide()) { + playerIn.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SPEED, 100, (playerIn.hasEffect(MobEffects.MOVEMENT_SPEED) ? playerIn.getEffect(MobEffects.MOVEMENT_SPEED).getAmplifier() : 0) + 2)); + } else { + ClientEventHandler.lungeSprint = 180; + } + playerIn.getCooldowns().addCooldown(stack.getItem(), 300); + return InteractionResultHolder.consume(stack); + } + + @Override + @ParametersAreNonnullByDefault + public boolean canAttackBlock(BlockState p_41441_, Level p_41442_, BlockPos p_41443_, Player p_41444_) { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/item/Monitor.java b/src/main/java/com/atsuishio/superbwarfare/item/Monitor.java new file mode 100644 index 000000000..5eb11b99d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/Monitor.java @@ -0,0 +1,181 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; +import com.atsuishio.superbwarfare.event.ClientEventHandler; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.FormatTool; +import com.atsuishio.superbwarfare.tools.NBTTool; +import net.minecraft.ChatFormatting; +import net.minecraft.client.CameraType; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; + +public class Monitor extends Item { + + public static final String LINKED = "Linked"; + public static final String LINKED_DRONE = "LinkedDrone"; + + public Monitor() { + super(new Properties().stacksTo(1)); + } + + public static void link(ItemStack stack, String id) { + var tag = NBTTool.getTag(stack); + NBTTool.setBoolean(stack, LINKED, true); + tag.putString(LINKED_DRONE, id); + NBTTool.saveTag(stack, tag); + } + + public static void disLink(ItemStack stack, Player player) { + var tag = NBTTool.getTag(stack); + NBTTool.setBoolean(stack, LINKED, false); + tag.putString(LINKED_DRONE, "none"); + if (player instanceof ServerPlayer serverPlayer) { + // TODO reset camera type msg +// ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new ResetCameraTypeMessage(0)); + } + NBTTool.saveTag(stack, tag); + } + + private void resetDroneData(DroneEntity drone) { + if (drone == null) return; + + drone.getPersistentData().putBoolean("left", false); + drone.getPersistentData().putBoolean("right", false); + drone.getPersistentData().putBoolean("forward", false); + drone.getPersistentData().putBoolean("backward", false); + drone.getPersistentData().putBoolean("up", false); + drone.getPersistentData().putBoolean("down", false); + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level world, Player player, InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + + if (!NBTTool.getBoolean(stack, LINKED, false)) { + return super.use(world, player, hand); + } + + var tag = NBTTool.getTag(stack); + if (tag.getBoolean("Using")) { + tag.putBoolean("Using", false); + if (world.isClientSide) { + if (ClientEventHandler.lastCameraType != null) { + Minecraft.getInstance().options.setCameraType(ClientEventHandler.lastCameraType); + } + } + } else { + tag.putBoolean("Using", true); + if (world.isClientSide) { + ClientEventHandler.lastCameraType = Minecraft.getInstance().options.getCameraType(); + Minecraft.getInstance().options.setCameraType(CameraType.THIRD_PERSON_BACK); + } + } + + NBTTool.saveTag(stack, tag); + DroneEntity drone = EntityFindUtil.findDrone(player.level(), tag.getString(LINKED_DRONE)); + this.resetDroneData(drone); + + return super.use(world, player, hand); + } + + // TODO attribute +// @Override +// public Multimap getAttributeModifiers(EquipmentSlot slot, ItemStack stack) { +// if (slot == EquipmentSlot.MAINHAND) { +// ImmutableMultimap.Builder builder = ImmutableMultimap.builder(); +// builder.putAll(super.getAttributeModifiers(slot, stack)); +// builder.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Item modifier", 2d, AttributeModifier.Operation.ADDITION)); +// builder.put(Attributes.ATTACK_SPEED, new AttributeModifier(BASE_ATTACK_SPEED_UUID, "Item modifier", -2.4, AttributeModifier.Operation.ADDITION)); +// return builder.build(); +// } +// +// return super.getAttributeModifiers(slot, stack); +// } + + public static void getDronePos(ItemStack stack, Vec3 vec3) { + var tag = NBTTool.getTag(stack); + tag.putDouble("PosX", vec3.x); + tag.putDouble("PosY", vec3.y); + tag.putDouble("PosZ", vec3.z); + NBTTool.saveTag(stack, tag); + } + + @OnlyIn(Dist.CLIENT) + @Override + @ParametersAreNonnullByDefault + public void appendHoverText(ItemStack stack, TooltipContext context, List tooltipComponents, TooltipFlag tooltipFlag) { + var tag = NBTTool.getTag(stack); + if (!tag.contains(LINKED_DRONE) || tag.getString(LINKED_DRONE).equals("none")) + return; + + Player player = Minecraft.getInstance().player; + if (player == null) return; + + if (!tag.contains("PosX") || !tag.contains("PosY") || !tag.contains("PosZ")) + return; + + Vec3 droneVec = new Vec3(tag.getDouble("PosX"), tag.getDouble("PosY"), tag.getDouble("PosZ")); + + tooltipComponents.add(Component.translatable("des.superbwarfare.monitor", + FormatTool.format1D(player.position().distanceTo(droneVec), "m")).withStyle(ChatFormatting.GRAY)); + tooltipComponents.add(Component.literal("X: " + FormatTool.format1D(droneVec.x) + + " Y: " + FormatTool.format1D(droneVec.y) + + " Z: " + FormatTool.format1D(droneVec.z) + )); + } + + @Override + @ParametersAreNonnullByDefault + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return false; + } + + @Override + @ParametersAreNonnullByDefault + public void inventoryTick(ItemStack stack, Level world, Entity entity, int slot, boolean selected) { + super.inventoryTick(stack, world, entity, slot, selected); + var tag = NBTTool.getTag(stack); + DroneEntity drone = EntityFindUtil.findDrone(entity.level(), tag.getString(LINKED_DRONE)); + + if (!selected) { + if (tag.getBoolean("Using")) { + tag.putBoolean("Using", false); + NBTTool.saveTag(stack, tag); + if (entity.level().isClientSide) { + if (ClientEventHandler.lastCameraType != null) { + Minecraft.getInstance().options.setCameraType(ClientEventHandler.lastCameraType); + } + } + } + this.resetDroneData(drone); + } else if (drone == null) { + if (tag.getBoolean("Using")) { + tag.putBoolean("Using", false); + NBTTool.saveTag(stack, tag); + if (entity.level().isClientSide) { + if (ClientEventHandler.lastCameraType != null) { + Minecraft.getInstance().options.setCameraType(ClientEventHandler.lastCameraType); + } + } + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/MortarDeployer.java b/src/main/java/com/atsuishio/superbwarfare/item/MortarDeployer.java new file mode 100644 index 000000000..c667c7901 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/MortarDeployer.java @@ -0,0 +1,115 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.MortarEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Objects; + +public class MortarDeployer extends Item { + + public MortarDeployer() { + super(new Properties().rarity(Rarity.RARE)); + } + + @Override + public @NotNull InteractionResult useOn(UseOnContext pContext) { + Level level = pContext.getLevel(); + if (!(level instanceof ServerLevel)) { + return InteractionResult.SUCCESS; + } else { + ItemStack stack = pContext.getItemInHand(); + BlockPos clickedPos = pContext.getClickedPos(); + Direction direction = pContext.getClickedFace(); + Player player = pContext.getPlayer(); + if (player == null) { + return InteractionResult.PASS; + } + + BlockState blockstate = level.getBlockState(clickedPos); + BlockPos pos; + if (blockstate.getCollisionShape(level, clickedPos).isEmpty()) { + pos = clickedPos; + } else { + pos = clickedPos.relative(direction); + } + + MortarEntity mortarEntity = new MortarEntity(level, player.getYRot()); + mortarEntity.setPos((double) pos.getX() + 0.5D, pos.getY() + 1, (double) pos.getZ() + 0.5D); + double yOffset = this.getYOffset(level, pos, !Objects.equals(clickedPos, pos) && direction == Direction.UP, mortarEntity.getBoundingBox()); + mortarEntity.moveTo((double) pos.getX() + 0.5D, pos.getY() + yOffset, (double) pos.getZ() + 0.5D); + level.addFreshEntity(mortarEntity); + + if (!player.getAbilities().instabuild) { + stack.shrink(1); + } + level.gameEvent(pContext.getPlayer(), GameEvent.ENTITY_PLACE, clickedPos); + + return InteractionResult.CONSUME; + } + } + + public double getYOffset(LevelReader pLevel, BlockPos pPos, boolean pShouldOffsetYMore, AABB pBox) { + AABB aabb = new AABB(pPos); + if (pShouldOffsetYMore) { + aabb = aabb.expandTowards(0.0D, -1.0D, 0.0D); + } + + Iterable iterable = pLevel.getCollisions(null, aabb); + return 1.0D + Shapes.collide(Direction.Axis.Y, pBox, iterable, pShouldOffsetYMore ? -2.0D : -1.0D); + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level pLevel, Player pPlayer, InteractionHand pHand) { + ItemStack itemstack = pPlayer.getItemInHand(pHand); + BlockHitResult blockhitresult = getPlayerPOVHitResult(pLevel, pPlayer, ClipContext.Fluid.SOURCE_ONLY); + if (blockhitresult.getType() != HitResult.Type.BLOCK) { + return InteractionResultHolder.pass(itemstack); + } else if (!(pLevel instanceof ServerLevel)) { + return InteractionResultHolder.success(itemstack); + } else { + BlockPos blockpos = blockhitresult.getBlockPos(); + if (!(pLevel.getBlockState(blockpos).getBlock() instanceof LiquidBlock)) { + return InteractionResultHolder.pass(itemstack); + } else if (pLevel.mayInteract(pPlayer, blockpos) && pPlayer.mayUseItemAt(blockpos, blockhitresult.getDirection(), itemstack)) { + MortarEntity mortarEntity = new MortarEntity(pLevel, pPlayer.getYRot()); + mortarEntity.setPos((double) blockpos.getX() + 0.5D, blockpos.getY(), (double) blockpos.getZ() + 0.5D); + pLevel.addFreshEntity(mortarEntity); + + if (!pPlayer.getAbilities().instabuild) { + itemstack.shrink(1); + } + + pPlayer.awardStat(Stats.ITEM_USED.get(this)); + pLevel.gameEvent(pPlayer, GameEvent.ENTITY_PLACE, mortarEntity.position()); + return InteractionResultHolder.consume(itemstack); + } else { + return InteractionResultHolder.fail(itemstack); + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/item/RgoGrenade.java b/src/main/java/com/atsuishio/superbwarfare/item/RgoGrenade.java new file mode 100644 index 000000000..40fbc63f8 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/RgoGrenade.java @@ -0,0 +1,113 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.entity.projectile.RgoGrenadeEntity; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.CustomExplosion; +import com.atsuishio.superbwarfare.tools.ParticleTool; +import net.minecraft.core.Direction; +import net.minecraft.core.Position; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.item.*; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.event.EventHooks; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; + +public class RgoGrenade extends Item implements ProjectileItem { + + public RgoGrenade() { + super(new Properties().rarity(Rarity.UNCOMMON)); + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull InteractionResultHolder use(Level worldIn, Player playerIn, InteractionHand handIn) { + ItemStack stack = playerIn.getItemInHand(handIn); + playerIn.startUsingItem(handIn); + if (playerIn instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.GRENADE_PULL.get(), SoundSource.PLAYERS, 1, 1); + } + return InteractionResultHolder.consume(stack); + } + + @Override + public @NotNull UseAnim getUseAnimation(@NotNull ItemStack stack) { + return UseAnim.SPEAR; + } + + @Override + @ParametersAreNonnullByDefault + public void releaseUsing(ItemStack stack, Level worldIn, LivingEntity entityLiving, int timeLeft) { + if (!worldIn.isClientSide) { + if (entityLiving instanceof Player player) { + int usingTime = this.getUseDuration(stack, player) - timeLeft; + if (usingTime > 3) { + player.getCooldowns().addCooldown(stack.getItem(), 20); + float power = Math.min(usingTime / 8.0f, 1.8f); + + RgoGrenadeEntity rgoGrenade = new RgoGrenadeEntity(player, worldIn, 80 - usingTime); + rgoGrenade.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0f, power, 0.0f); + worldIn.addFreshEntity(rgoGrenade); + + if (player instanceof ServerPlayer serverPlayer) { + serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.GRENADE_THROW.get(), SoundSource.PLAYERS, 1, 1); + } + + if (!player.isCreative()) { + stack.shrink(1); + } + } + } + } + } + + @Override + @ParametersAreNonnullByDefault + public @NotNull ItemStack finishUsingItem(ItemStack pStack, Level pLevel, LivingEntity pLivingEntity) { + if (!pLevel.isClientSide) { + RgoGrenadeEntity rgoGrenade = new RgoGrenadeEntity(pLivingEntity, pLevel, 100); + CustomExplosion explosion = new CustomExplosion(pLevel, null, + ModDamageTypes.causeProjectileBoomDamage(pLevel.registryAccess(), rgoGrenade, pLivingEntity), ExplosionConfig.RGO_GRENADE_EXPLOSION_DAMAGE.get(), + pLivingEntity.getX(), pLivingEntity.getY(), pLivingEntity.getZ(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1.25f); + explosion.explode(); + EventHooks.onExplosionStart(pLevel, explosion); + explosion.finalizeExplosion(false); + ParticleTool.spawnMediumExplosionParticles(pLevel, pLivingEntity.position()); + + if (pLivingEntity instanceof Player player) { + player.getCooldowns().addCooldown(pStack.getItem(), 20); + } + + if (pLivingEntity instanceof Player player && !player.isCreative()) { + pStack.shrink(1); + } + } + + return super.finishUsingItem(pStack, pLevel, pLivingEntity); + } + + @Override + @ParametersAreNonnullByDefault + public int getUseDuration(ItemStack stack, LivingEntity entity) { + return 80; + } + + // TODO 音效播放 + @Override + @ParametersAreNonnullByDefault + public @NotNull Projectile asProjectile(Level level, Position pos, ItemStack stack, Direction direction) { + return new RgoGrenadeEntity(ModEntities.RGO_GRENADE.get(), pos.x(), pos.y(), pos.z(), level); + } +} + diff --git a/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/MortarShell.java b/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/MortarShell.java index 8dee786d5..fad6dcbb1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/MortarShell.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/MortarShell.java @@ -2,7 +2,11 @@ package com.atsuishio.superbwarfare.item.common.ammo; //import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity; +import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; public class MortarShell extends Item { @@ -10,10 +14,9 @@ public class MortarShell extends Item { super(new Properties()); } - // TODO createShell -// public MortarShellEntity createShell(LivingEntity entity, Level level, ItemStack stack) { -// MortarShellEntity shellEntity = new MortarShellEntity(entity, level); -// shellEntity.setEffectsFromItem(stack); -// return shellEntity; -// } + public MortarShellEntity createShell(LivingEntity entity, Level level, ItemStack stack) { + MortarShellEntity shellEntity = new MortarShellEntity(entity, level); + shellEntity.setEffectsFromItem(stack); + return shellEntity; + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/Rocket.java b/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/Rocket.java index d4b67e71e..db9d449dc 100644 --- a/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/Rocket.java +++ b/src/main/java/com/atsuishio/superbwarfare/item/common/ammo/Rocket.java @@ -3,17 +3,23 @@ package com.atsuishio.superbwarfare.item.common.ammo; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.client.PoseTool; import com.atsuishio.superbwarfare.client.renderer.item.RocketItemRenderer; +import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity; +import com.atsuishio.superbwarfare.init.ModEntities; import com.atsuishio.superbwarfare.init.ModItems; import com.atsuishio.superbwarfare.tools.ParticleTool; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.core.Direction; +import net.minecraft.core.Position; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ProjectileItem; import net.minecraft.world.level.Level; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -28,7 +34,7 @@ import software.bernie.geckolib.util.GeckoLibUtil; import javax.annotation.ParametersAreNonnullByDefault; @EventBusSubscriber(modid = ModUtils.MODID, bus = EventBusSubscriber.Bus.MOD) -public class Rocket extends Item implements GeoItem { +public class Rocket extends Item implements GeoItem, ProjectileItem { private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); public static ItemDisplayContext transformType; @@ -105,4 +111,15 @@ public class Rocket extends Item implements GeoItem { return super.hurtEnemy(stack, entity, source); } + @Override + @ParametersAreNonnullByDefault + public @NotNull Projectile asProjectile(Level level, Position pos, ItemStack stack, Direction direction) { + return new RpgRocketEntity(ModEntities.RPG_ROCKET.get(), pos.x(), pos.y(), pos.z(), level); + } + + // TODO 发射音效 + @Override + public @NotNull DispenseConfig createDispenseConfig() { + return DispenseConfig.builder().power(1.5F).build(); + } } \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java index 53a72d207..ca5f4bbbe 100644 --- a/src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/ClientMotionSyncMessage.java @@ -34,6 +34,7 @@ public record ClientMotionSyncMessage(int id, float x, float y, float z) impleme public static void handler(final ClientMotionSyncMessage message, final IPayloadContext context) { var level = Minecraft.getInstance().level; if (level == null) return; + Entity entity = level.getEntity(message.id); if (entity != null) { entity.lerpMotion(message.x, message.y, message.z); diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java b/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java index 0e2d63d96..fa4244138 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/CustomExplosion.java @@ -4,7 +4,9 @@ import com.atsuishio.superbwarfare.config.server.ExplosionConfig; import com.atsuishio.superbwarfare.network.message.ShakeClientMessage; import com.google.common.collect.Sets; import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -48,7 +50,7 @@ public class CustomExplosion extends Explosion { BlockInteraction pBlockInteraction) { // TODO what are these options? - super(pLevel, pSource, source, null, pToBlowX, pToBlowY, pToBlowZ, pRadius, false, pBlockInteraction, null, null, null); + super(pLevel, pSource, source, null, pToBlowX, pToBlowY, pToBlowZ, pRadius, false, pBlockInteraction, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE); // super(pLevel, pSource, source, null, pToBlowX, pToBlowY, pToBlowZ, pRadius, false, pBlockInteraction // , ?,?,? ); diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/EntityFindUtil.java b/src/main/java/com/atsuishio/superbwarfare/tools/EntityFindUtil.java index 183e89544..3c266c1d8 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/EntityFindUtil.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/EntityFindUtil.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare.tools; +import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -59,4 +60,13 @@ public class EntityFindUtil { return null; } + public static DroneEntity findDrone(Level level, String uuidString) { + var target = findEntity(level, uuidString); + if (target instanceof DroneEntity drone) { + return drone; + } + + return null; + } + } diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java index fafe15d8b..d9a6b5d5b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/GunsTool.java @@ -2,11 +2,11 @@ package com.atsuishio.superbwarfare.tools; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.capability.ModCapabilities; -import com.atsuishio.superbwarfare.component.ModDataComponents; import com.atsuishio.superbwarfare.init.ModTags; import com.atsuishio.superbwarfare.item.gun.GunItem; import com.atsuishio.superbwarfare.network.message.GunsDataMessage; import com.google.gson.stream.JsonReader; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.packs.resources.ResourceManager; @@ -266,8 +266,9 @@ public class GunsTool { @Nullable public static UUID getGunUUID(ItemStack stack) { - CompoundTag tag = stack.get(ModDataComponents.GUN_DATA); - if (tag == null || !tag.contains("GunData")) return null; + var customData = stack.get(DataComponents.CUSTOM_DATA); + CompoundTag tag = customData != null ? customData.copyTag() : new CompoundTag(); + if (!tag.contains("GunData")) return null; CompoundTag data = tag.getCompound("GunData"); if (!data.hasUUID("UUID")) return null; diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/ProjectileTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/ProjectileTool.java new file mode 100644 index 000000000..6e663c7ef --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/tools/ProjectileTool.java @@ -0,0 +1,58 @@ +package com.atsuishio.superbwarfare.tools; + +import com.atsuishio.superbwarfare.config.server.ExplosionConfig; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.projectile.ThrowableItemProjectile; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; + +import javax.annotation.Nullable; + +public class ProjectileTool { + + public static void causeCustomExplode(ThrowableItemProjectile projectile, @Nullable DamageSource source, Entity target, float damage, float radius, float damageMultiplier) { + CustomExplosion explosion = new CustomExplosion(projectile.level(), projectile, source, damage, + target.getX(), + target.getY() + 0.5 * target.getBbHeight(), + target.getZ(), + radius, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(damageMultiplier); + explosion.explode(); + EventHooks.onExplosionStart(projectile.level(), explosion); + explosion.finalizeExplosion(false); + + if (radius <= 5) { + ParticleTool.spawnSmallExplosionParticles(projectile.level(), projectile.position().add(projectile.getDeltaMovement().scale(0.5))); + } else if (radius > 5 && radius < 10) { + ParticleTool.spawnMediumExplosionParticles(projectile.level(), projectile.position().add(projectile.getDeltaMovement().scale(0.5))); + } else { + ParticleTool.spawnHugeExplosionParticles(projectile.level(), projectile.position().add(projectile.getDeltaMovement().scale(0.5))); + } + + Vec3 pos = projectile.position().add(projectile.getDeltaMovement().scale(0.5)); + + if (projectile.level() instanceof ServerLevel) { + projectile.level().explode(source == null ? null : source.getEntity(), pos.x, pos.y, pos.z, 0.5f * radius, ExplosionConfig.EXPLOSION_DESTROY.get() ? Level.ExplosionInteraction.BLOCK : Level.ExplosionInteraction.NONE); + } + + projectile.discard(); + } + + public static void causeCustomExplode(ThrowableItemProjectile projectile, Entity target, float damage, float radius, float damageMultiplier) { + causeCustomExplode(projectile, ModDamageTypes.causeCustomExplosionDamage(projectile.level().registryAccess(), projectile, projectile.getOwner()), + target, damage, radius, damageMultiplier); + } + + public static void causeCustomExplode(ThrowableItemProjectile projectile, float damage, float radius, float damageMultiplier) { + causeCustomExplode(projectile, projectile, damage, radius, damageMultiplier); + } + + public static void causeCustomExplode(ThrowableItemProjectile projectile, float damage, float radius) { + causeCustomExplode(projectile, damage, radius, 0.0f); + } + +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 2820100d2..e72d85370 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,3 +1,4 @@ public net.minecraft.client.multiplayer.ClientLevel getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter; # getEntities public net.minecraft.world.entity.Entity passengers # passengers -public net.minecraft.world.entity.Entity boardingCooldown # boardingCooldown \ No newline at end of file +public net.minecraft.world.entity.Entity boardingCooldown # boardingCooldown +public net.minecraft.client.player.LocalPlayer handsBusy # handsBusy \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/lang/en_us.json b/src/main/resources/assets/superbwarfare/lang/en_us.json index e115ce41e..1583dabd4 100644 --- a/src/main/resources/assets/superbwarfare/lang/en_us.json +++ b/src/main/resources/assets/superbwarfare/lang/en_us.json @@ -255,6 +255,7 @@ "des.superbwarfare.small_container": "Empty", "des.superbwarfare.small_container.random": "Random Supplies", "des.superbwarfare.small_container.special": "Random SUI-pplies", + "des.superbwarfare.small_container.loot.blueprints": "Gun Blueprints", "item.superbwarfare.high_energy_explosives": "High Energy Explosives", "item.superbwarfare.grain": "Grain", @@ -550,6 +551,9 @@ "config.jade.plugin_superbwarfare.vehicle_energy": "Vehicle Energy", "config.jade.plugin_superbwarfare.vehicle_health": "Vehicle Health", "config.jade.plugin_superbwarfare.container_entity": "Container Entity", + "config.jade.plugin_superbwarfare.c4_info": "C4 Info", + "des.jade_plugin_superbwarfare.c4.remote_control": "Remote Controlled", + "des.jade_plugin_superbwarfare.c4.time_left": "Time Before Explosion: %1$ss", "superbwarfare.advancement.main.root": "Superb Warfare", "superbwarfare.advancement.main.root.des": "Welcome to the Superb Warfare!", @@ -582,5 +586,8 @@ "superbwarfare.advancement.main.enclave": "Enclave", "superbwarfare.advancement.main.enclave.des": "Where is the pendulum?", "superbwarfare.advancement.main.boomstick_melee": "Boomstick Melee", - "superbwarfare.advancement.main.boomstick_melee.des": "Who said RPGs can't be baseball bats?" + "superbwarfare.advancement.main.boomstick_melee.des": "Who said RPGs can't be baseball bats?", + "warning.title.example": "[SuperbWarfare Mod Warning]", + "warning.content.example": "This mod is Free And Open-Source, No Commercial Use\nCode: GPL-3.0 License; Asserts: Private (No Commercialization)\nBan on paid downloads or EULA-breaking purchases\nReport violations by submitting an issue in the mod's repository", + "warning.check.example": "I have read and agreed to the content. Do not show this message again" } \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/lang/zh_cn.json b/src/main/resources/assets/superbwarfare/lang/zh_cn.json index c42cc9d59..454b171b7 100644 --- a/src/main/resources/assets/superbwarfare/lang/zh_cn.json +++ b/src/main/resources/assets/superbwarfare/lang/zh_cn.json @@ -253,6 +253,7 @@ "des.superbwarfare.small_container": "空的", "des.superbwarfare.small_container.random": "随机补给", "des.superbwarfare.small_container.special": "岁己补给", + "des.superbwarfare.small_container.loot.blueprints": "枪械蓝图", "item.superbwarfare.high_energy_explosives": "高能炸药", "item.superbwarfare.grain": "推进药柱", @@ -550,6 +551,9 @@ "config.jade.plugin_superbwarfare.vehicle_energy": "载具能量", "config.jade.plugin_superbwarfare.vehicle_health": "载具血量", "config.jade.plugin_superbwarfare.container_entity": "集装箱实体", + "config.jade.plugin_superbwarfare.c4_info": "C4信息", + "des.jade_plugin_superbwarfare.c4.remote_control": "远程遥控", + "des.jade_plugin_superbwarfare.c4.time_left": "爆炸剩余时间:%1$s秒", "superbwarfare.advancement.main.root": "卓越前线", "superbwarfare.advancement.main.root.des": "欢迎来到卓越前线!", @@ -582,5 +586,8 @@ "superbwarfare.advancement.main.enclave": "飞地", "superbwarfare.advancement.main.enclave.des": "钟摆在哪?", "superbwarfare.advancement.main.boomstick_melee": "跟你爆了", - "superbwarfare.advancement.main.boomstick_melee.des": "谁说RPG不能当棒球棒用?" + "superbwarfare.advancement.main.boomstick_melee.des": "谁说RPG不能当棒球棒用?", + "warning.title.example": "【卓越前线 警示声明】", + "warning.content.example": "== 本模组完全免费开源,禁止用于任何商业行为 ==\n本模组代码采用GPL-3协议开源,美术资源私有禁止商用\n禁止付费下载、充值获取道具等违反协议和Mojang EULA的行为\n如遇以上行为,请到本模组仓库处提交Issue进行举报", + "warning.check.example": "我已阅读并同意,不再显示此警告" } \ No newline at end of file