From 98fd33a17c8ac4f2373f3a8cf0f354483a53194b Mon Sep 17 00:00:00 2001 From: Atsuishio <842960157@qq.com> Date: Mon, 7 Apr 2025 07:12:11 +0800 Subject: [PATCH] =?UTF-8?q?YX100=E6=B7=BB=E5=8A=A0=E8=9C=82=E7=BE=A4?= =?UTF-8?q?=E6=97=A0=E4=BA=BA=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../b69ee8a2655365569b979911c0440daa8c470ac2 | 3 +- .../models/item/swarm_drone.json | 6 + .../client/model/entity/SwarmDroneModel.java | 24 + .../client/overlay/VehicleHudOverlay.java | 9 +- .../renderer/entity/SwarmDroneRenderer.java | 38 + .../datagen/ModItemModelProvider.java | 1 + .../entity/projectile/SwarmDroneEntity.java | 206 +++ .../entity/projectile/WgMissileEntity.java | 34 +- .../entity/vehicle/Bmp2Entity.java | 7 + .../entity/vehicle/Yx100Entity.java | 124 +- .../entity/vehicle/base/VehicleEntity.java | 4 + .../vehicle/weapon/SwarmDroneWeapon.java | 28 + .../event/ClientSoundHandler.java | 22 + .../superbwarfare/init/ModEntities.java | 2 + .../init/ModEntityRenderers.java | 1 + .../superbwarfare/init/ModItems.java | 1 + .../superbwarfare/tools/SeekTool.java | 29 + .../superbwarfare/tools/TraceTool.java | 26 + .../animations/swarm_drone.animation.json | 123 ++ .../superbwarfare/geo/swarm_drone.geo.json | 1319 +++++++++++++++++ .../assets/superbwarfare/lang/en_us.json | 2 + .../assets/superbwarfare/lang/zh_cn.json | 2 + .../textures/entity/swamDrone.png | Bin 0 -> 1255 bytes .../textures/item/swarm_drone.png | Bin 0 -> 385 bytes .../screens/vehicle_weapon/swarm_drone.png | Bin 0 -> 1588 bytes .../recipe/swarm_drone_crafting.json | 30 + 26 files changed, 2021 insertions(+), 20 deletions(-) create mode 100644 src/generated/resources/assets/superbwarfare/models/item/swarm_drone.json create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/model/entity/SwarmDroneModel.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SwarmDroneRenderer.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/projectile/SwarmDroneEntity.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SwarmDroneWeapon.java create mode 100644 src/main/resources/assets/superbwarfare/animations/swarm_drone.animation.json create mode 100644 src/main/resources/assets/superbwarfare/geo/swarm_drone.geo.json create mode 100644 src/main/resources/assets/superbwarfare/textures/entity/swamDrone.png create mode 100644 src/main/resources/assets/superbwarfare/textures/item/swarm_drone.png create mode 100644 src/main/resources/assets/superbwarfare/textures/screens/vehicle_weapon/swarm_drone.png create mode 100644 src/main/resources/data/superbwarfare/recipe/swarm_drone_crafting.json diff --git a/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 b/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 index cb5161cb8..f1d1cdcc2 100644 --- a/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 +++ b/src/generated/resources/.cache/b69ee8a2655365569b979911c0440daa8c470ac2 @@ -1,4 +1,4 @@ -// 1.21.1 2025-04-02T18:07:51.8677118 Item Models: superbwarfare +// 1.21.1 2025-04-08T06:51:00.2717304 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 @@ -113,6 +113,7 @@ b4e009177af3af6ad6dda54e3e2fed43dc243ff2 assets/superbwarfare/models/item/steel_ 28e5cc26e694d0cded97b343de94764b28f1651f assets/superbwarfare/models/item/steel_spring.json 7d3c98a32815191ef716a8595dda392a8dfea6ec assets/superbwarfare/models/item/steel_trigger.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/svd_blueprint.json +99b1799c7a12767decc900e9fbeac5859be13b50 assets/superbwarfare/models/item/swarm_drone.json dbba3ca532b6aa949c84ea8b3f10fe3a0bf472e7 assets/superbwarfare/models/item/target_deployer.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/taser_blueprint.json 13ca8d5676888ff51f3308d88e4bf67691fa34f8 assets/superbwarfare/models/item/trachelium_blueprint.json diff --git a/src/generated/resources/assets/superbwarfare/models/item/swarm_drone.json b/src/generated/resources/assets/superbwarfare/models/item/swarm_drone.json new file mode 100644 index 000000000..01ab18f37 --- /dev/null +++ b/src/generated/resources/assets/superbwarfare/models/item/swarm_drone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "superbwarfare:item/swarm_drone" + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SwarmDroneModel.java b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SwarmDroneModel.java new file mode 100644 index 000000000..f81122571 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/model/entity/SwarmDroneModel.java @@ -0,0 +1,24 @@ +package com.atsuishio.superbwarfare.client.model.entity; + +import com.atsuishio.superbwarfare.Mod; +import com.atsuishio.superbwarfare.entity.projectile.SwarmDroneEntity; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; + +public class SwarmDroneModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(SwarmDroneEntity entity) { + return Mod.loc("animations/swarm_drone.animation.json"); + } + + @Override + public ResourceLocation getModelResource(SwarmDroneEntity entity) { + return Mod.loc("geo/swarm_drone.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(SwarmDroneEntity entity) { + return Mod.loc("textures/entity/swamDrone.png"); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java index 15f76019b..4edae2331 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/overlay/VehicleHudOverlay.java @@ -48,6 +48,7 @@ import static com.atsuishio.superbwarfare.client.RenderHelper.preciseBlit; import static com.atsuishio.superbwarfare.client.overlay.CrossHairOverlay.*; import static com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity.LOADED_MISSILE; import static com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity.MISSILE_COUNT; +import static com.atsuishio.superbwarfare.entity.vehicle.Yx100Entity.LOADED_DRONE; import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.*; @EventBusSubscriber(value = Dist.CLIENT) @@ -187,6 +188,8 @@ public class VehicleHudOverlay { preciseBlit(guiGraphics, Mod.loc("textures/screens/land/tank_cannon_cross_he.png"), k, l, 0, 0.0F, i, j, i, j); } else if (weaponVehicle.getWeaponIndex(0) == 2) { preciseBlit(guiGraphics, Mod.loc("textures/screens/land/lav_gun_cross.png"), k, l, 0, 0.0F, i, j, i, j); + } else if (weaponVehicle.getWeaponIndex(0) == 3) { + preciseBlit(guiGraphics, Mod.loc("textures/screens/land/lav_missile_cross.png"), k, l, 0, 0.0F, i, j, i, j); } } else if (weaponVehicle instanceof PrismTankEntity) { @@ -288,6 +291,8 @@ public class VehicleHudOverlay { } else if (weaponVehicle.getWeaponIndex(0) == 2) { double heat = 1 - yx100.getEntityData().get(COAX_HEAT) / 100.0F; guiGraphics.drawString(mc.font, Component.literal(" 12.7MM HMG " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getAmmoCount(player))), w / 2 - 33, h - 65, Mth.hsvToRgb((float) heat / 3.745318352059925F, 1.0F, 1.0F), false); + } else { + guiGraphics.drawString(mc.font, Component.literal(" SWARM " + yx100.getEntityData().get(LOADED_DRONE) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), w / 2 - 33, h - 65, 0x66FF00, false); } } @@ -343,7 +348,9 @@ public class VehicleHudOverlay { guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("HE SHELL " + yx100.getAmmoCount(player) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), 30, -9, -1, false); } else if (weaponVehicle.getWeaponIndex(0) == 2) { double heat2 = yx100.getEntityData().get(COAX_HEAT) / 100.0F; - guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("7.62MM ПКТ " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("12.7MM HMG " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getAmmoCount(player))), 30, -9, Mth.hsvToRgb(0F, (float) heat2, 1.0F), false); + } else { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal("SWARM " + yx100.getEntityData().get(LOADED_DRONE) + " " + (InventoryTool.hasCreativeAmmoBox(player) ? "∞" : yx100.getEntityData().get(AMMO))), 30, -9, -1, false); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SwarmDroneRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SwarmDroneRenderer.java new file mode 100644 index 000000000..4e0d10e1d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/SwarmDroneRenderer.java @@ -0,0 +1,38 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.client.model.entity.SwarmDroneModel; +import com.atsuishio.superbwarfare.entity.projectile.SwarmDroneEntity; +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 SwarmDroneRenderer extends GeoEntityRenderer { + public SwarmDroneRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new SwarmDroneModel()); + } + + @Override + public RenderType getRenderType(SwarmDroneEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, SwarmDroneEntity 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(SwarmDroneEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java b/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java index 1600ed53c..9072debbd 100644 --- a/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java +++ b/src/main/java/com/atsuishio/superbwarfare/datagen/ModItemModelProvider.java @@ -81,6 +81,7 @@ public class ModItemModelProvider extends ItemModelProvider { simpleItem(ModItems.ROCKET_70); simpleItem(ModItems.WIRE_GUIDE_MISSILE); simpleItem(ModItems.SMALL_SHELL); + simpleItem(ModItems.SWARM_DRONE); simpleItem(ModItems.SMALL_BATTERY_PACK); simpleItem(ModItems.MEDIUM_BATTERY_PACK); simpleItem(ModItems.LARGE_BATTERY_PACK); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SwarmDroneEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SwarmDroneEntity.java new file mode 100644 index 000000000..d910e9c08 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/SwarmDroneEntity.java @@ -0,0 +1,206 @@ +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.CustomExplosion; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import com.atsuishio.superbwarfare.tools.ParticleTool; +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.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 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 SwarmDroneEntity extends FastThrowableProjectile implements GeoEntity { + + public static final EntityDataAccessor TARGET_UUID = SynchedEntityData.defineId(SwarmDroneEntity.class, EntityDataSerializers.STRING); + public static final EntityDataAccessor TARGET_X = SynchedEntityData.defineId(SwarmDroneEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor TARGET_Y = SynchedEntityData.defineId(SwarmDroneEntity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor TARGET_Z = SynchedEntityData.defineId(SwarmDroneEntity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + private float explosionDamage = 125f; + private float explosionRadius = 6f; + + private float randomFloat; + private int guide_type = 0; + + public SwarmDroneEntity(EntityType type, Level level) { + super(type, level); + this.noCulling = true; + } + + public SwarmDroneEntity(LivingEntity entity, Level level, float explosionDamage, float explosionRadius) { + super(ModEntities.SWARM_DRONE.get(), entity, level); + this.explosionDamage = explosionDamage; + this.explosionRadius = explosionRadius; + } + + @Override + protected @NotNull Item getDefaultItem() { + return ModItems.DRONE.get(); + } + + public void setTargetUuid(String uuid) { + this.entityData.set(TARGET_UUID, uuid); + } + + public void setGuideType(int guideType) { + this.guide_type = guideType; + } + + public void setTargetVec(Vec3 targetPos) { + this.entityData.set(TARGET_X, (float) targetPos.x); + this.entityData.set(TARGET_Y, (float) targetPos.y); + this.entityData.set(TARGET_Z, (float) targetPos.z); + } + + @Override + protected void defineSynchedData(SynchedEntityData.@NotNull Builder builder) { + super.defineSynchedData(builder); + + builder.define(TARGET_UUID, "none") + .define(TARGET_X, 0f) + .define(TARGET_Y, 0f) + .define(TARGET_Z, 0f); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + @Override + protected void onHitEntity(@NotNull EntityHitResult result) { + if (this.level() instanceof ServerLevel) { + causeMissileExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, 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(); + + Entity entity = EntityFindUtil.findEntity(this.level(), entityData.get(TARGET_UUID)); + + 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 (tickCount > 10 && this.getOwner() != null) { + Entity shooter = this.getOwner(); + Vec3 targetPos; + + if (guide_type == 0 && entity != null) { + targetPos = entity.getEyePosition(); + } else { + targetPos = new Vec3(this.entityData.get(TARGET_X), this.entityData.get(TARGET_Y), this.entityData.get(TARGET_Z)); + } + + if (tickCount % 5 == 0) { + randomFloat = random.nextFloat(); + } + + double dis = position().distanceTo(targetPos); + double disShooter = shooter.position().distanceTo(targetPos); + double randomPos = Mth.sin(0.25f * (tickCount + randomFloat)) * randomFloat * (dis / disShooter); + + Vec3 toVec = this.position().vectorTo(targetPos).normalize().add(new Vec3(randomPos, 0, randomPos)); + setDeltaMovement(getDeltaMovement().add(toVec.scale(0.5))); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.85, 0.85, 0.85)); + + if (dis < 0.5) { + if (this.level() instanceof ServerLevel) { + causeMissileExplode(this, + ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), this, this.getOwner()), + this, this.explosionDamage, this.explosionRadius); + } + this.discard(); + } + } + + 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(); + } + } + + @Override + protected void updateRotation() { + } + + 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.sd.fly")); + } + + @Override + protected double getDefaultGravity() { + return tickCount > 10 ? 0 : 0.1f; + } + + @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/WgMissileEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java index 3cffcd884..da684869b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/projectile/WgMissileEntity.java @@ -1,7 +1,7 @@ package com.atsuishio.superbwarfare.entity.projectile; import com.atsuishio.superbwarfare.config.server.ExplosionConfig; -import com.atsuishio.superbwarfare.entity.vehicle.Bmp2Entity; +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; @@ -9,18 +9,18 @@ import com.atsuishio.superbwarfare.init.ModSounds; import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.ParticleTool; -import com.atsuishio.superbwarfare.tools.VectorTool; +import com.atsuishio.superbwarfare.tools.TraceTool; 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.ClipContext; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; @@ -123,24 +123,26 @@ public class WgMissileEntity extends FastThrowableProjectile implements GeoEntit } } - if (tickCount > 5 && this.getOwner() != null && getOwner().getVehicle() instanceof Bmp2Entity bmp2) { + if (tickCount > 5 && this.getOwner() != null && getOwner().getVehicle() instanceof VehicleEntity vehicle) { 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)); + Vec3 lookVec = vehicle.getBarrelVec(1).normalize(); + Entity lookingEntity = TraceTool.vehiclefFindLookingEntity(vehicle, vehicle.getNewEyePos(1), 512); + Vec3 toVec; + + if (lookingEntity != null) { + toVec = this.position().vectorTo(lookingEntity.getEyePosition()).normalize(); + } else { + BlockHitResult result = level().clip(new ClipContext(vehicle.getNewEyePos(1), vehicle.getNewEyePos(1).add(lookVec.scale(512)), + ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, shooter)); + Vec3 hitPos = result.getLocation(); + + toVec = this.position().vectorTo(hitPos).normalize(); } - if (this.getDeltaMovement().length() > 3) { - this.setDeltaMovement(this.getDeltaMovement().multiply(0.9, 0.9, 0.9)); - } + setDeltaMovement(getDeltaMovement().add(toVec.scale(0.8))); - this.setDeltaMovement(this.getDeltaMovement().multiply(0.96, 0.96, 0.96)); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.8, 0.8, 0.8)); } if (this.tickCount > 300 || this.isInWater()) { diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java index 3230882a2..60e093639 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Bmp2Entity.java @@ -496,6 +496,13 @@ public class Bmp2Entity extends ContainerMobileVehicleEntity implements GeoEntit return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); } + @Override + public Vec3 getNewEyePos(float pPartialTicks) { + Matrix4f transform = getTurretTransform(pPartialTicks); + Vector4f worldPosition = transformPosition(transform, 0, 1.65f, 0.75f); + return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); + } + @Override public Vec3 getBarrelVector(float pPartialTicks) { Matrix4f transform = getBarrelTransform(pPartialTicks); diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java index 6b0c01130..263f970d5 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Yx100Entity.java @@ -11,6 +11,7 @@ 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.SwarmDroneWeapon; import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon; import com.atsuishio.superbwarfare.init.ModDamageTypes; import com.atsuishio.superbwarfare.init.ModItems; @@ -42,10 +43,12 @@ 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.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.AABB; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.event.EventHooks; import net.neoforged.neoforge.network.PacketDistributor; @@ -67,8 +70,9 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti public static final EntityDataAccessor LOADED_HE = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor LOADED_AMMO_TYPE = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); public static final EntityDataAccessor GUN_FIRE_TIME = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); - + public static final EntityDataAccessor LOADED_DRONE = SynchedEntityData.defineId(Yx100Entity.class, EntityDataSerializers.INT); private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + public int droneReloadCoolDown; public Yx100Entity(EntityType type, Level world) { super(type, world); @@ -116,6 +120,11 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti .ammo(ModItems.HEAVY_AMMO.get()) .sound(ModSounds.INTO_CANNON.get()) .icon(Mod.loc("textures/screens/vehicle_weapon/gun_12_7mm.png")), + // 蜂群无人机 + new SwarmDroneWeapon() + .explosionDamage(125) + .explosionRadius(6) + .sound(ModSounds.INTO_MISSILE.get()), }, new VehicleWeapon[]{ // 机枪 @@ -145,6 +154,7 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti builder.define(MG_AMMO, 0) .define(LOADED_AP, 0) .define(LOADED_HE, 0) + .define(LOADED_DRONE, 0) .define(LOADED_AMMO_TYPE, 0) .define(GUN_FIRE_TIME, 0); } @@ -154,6 +164,7 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti super.addAdditionalSaveData(compound); compound.putInt("LoadedAP", this.entityData.get(LOADED_AP)); compound.putInt("LoadedHE", this.entityData.get(LOADED_HE)); + compound.putInt("LoadedDrone", this.entityData.get(LOADED_DRONE)); compound.putInt("LoadedAmmoType", this.entityData.get(LOADED_AMMO_TYPE)); compound.putInt("WeaponType", getWeaponIndex(0)); compound.putInt("PassengerWeaponType", getWeaponIndex(1)); @@ -164,6 +175,7 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti super.readAdditionalSaveData(compound); this.entityData.set(LOADED_AP, compound.getInt("LoadedAP")); this.entityData.set(LOADED_HE, compound.getInt("LoadedHE")); + this.entityData.set(LOADED_DRONE, compound.getInt("LoadedDrone")); this.entityData.set(LOADED_AMMO_TYPE, compound.getInt("LoadedAmmoType")); setWeaponIndex(0, compound.getInt("WeaponType")); setWeaponIndex(1, compound.getInt("PassengerWeaponType")); @@ -256,6 +268,11 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti )) { reloadCoolDown--; } + + if (droneReloadCoolDown > 0) { + droneReloadCoolDown--; + } + this.handleAmmo(); } @@ -340,6 +357,15 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti } } } + + if ((hasItem(ModItems.SWARM_DRONE.get()) || hasCreativeAmmo) && droneReloadCoolDown == 0 && this.getEntityData().get(LOADED_DRONE) < 14) { + this.entityData.set(LOADED_DRONE, this.getEntityData().get(LOADED_DRONE) + 1); + droneReloadCoolDown = 20; + if (!hasCreativeAmmo) { + this.getItemStacks().stream().filter(stack -> stack.is(ModItems.SWARM_DRONE.get())).findFirst().ifPresent(stack -> stack.shrink(1)); + } + this.level().playSound(null, this, ModSounds.MISSILE_RELOAD.get(), this.getSoundSource(), 1, 1); + } } @Override @@ -488,6 +514,87 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti serverPlayer.playSound(ModSounds.M_2_VERYFAR.get(), 24, pitch); } } + } else if (getWeaponIndex(0) == 3) { + Matrix4f transformT = getTurretTransform(1); + Vector4f worldPosition = new Vector4f(); + + int ammo = this.getEntityData().get(LOADED_DRONE); + + if (ammo == 1) { + worldPosition = transformPosition(transformT, -2.315275f, 0.71894375f, -0.25390625f); + } + if (ammo == 2) { + worldPosition = transformPosition(transformT, 2.315275f, 0.71894375f, -0.25390625f); + } + if (ammo == 3) { + worldPosition = transformPosition(transformT, -2.49105625f, 0.71894375f, -0.4296875f); + } + if (ammo == 4) { + worldPosition = transformPosition(transformT, 2.49105625f, 0.71894375f, -0.4296875f); + } + if (ammo == 5) { + worldPosition = transformPosition(transformT, -2.315275f, 0.71894375f, -0.60546875f); + } + if (ammo == 6) { + worldPosition = transformPosition(transformT, 2.315275f, 0.71894375f, -0.60546875f); + } + if (ammo == 7) { + worldPosition = transformPosition(transformT, -2.49105625f, 0.71894375f, -0.78125f); + } + if (ammo == 8) { + worldPosition = transformPosition(transformT, 2.49105625f, 0.71894375f, -0.78125f); + } + if (ammo == 9) { + worldPosition = transformPosition(transformT, -2.315275f, 0.71894375f, -0.95703125f); + } + if (ammo == 10) { + worldPosition = transformPosition(transformT, 2.315275f, 0.71894375f, -0.95703125f); + } + if (ammo == 11) { + worldPosition = transformPosition(transformT, -2.49105625f, 0.71894375f, -1.1328125f); + } + if (ammo == 12) { + worldPosition = transformPosition(transformT, 2.49105625f, 0.71894375f, -1.1328125f); + } + if (ammo == 13) { + worldPosition = transformPosition(transformT, -2.315275f, 0.71894375f, -1.30859375f); + } + if (ammo == 14) { + worldPosition = transformPosition(transformT, 2.315275f, 0.71894375f, -1.30859375f); + } + + Vec3 lookVec = getBarrelVec(1).normalize(); + Entity lookingEntity = SeekTool.vehicleSeekEntity(this, level(), 512, 4); + + var swarmDroneEntity = ((SwarmDroneWeapon) getWeapon(0)).create(player); + + + Vector4f shootPosition1 = transformPosition(transformT, 0, 0, 0); + Vector4f shootPosition2 = transformPosition(transformT, 0, 1, 0); + Vec3 direct = new Vec3(shootPosition1.x, shootPosition1.y, shootPosition1.z).vectorTo(new Vec3(shootPosition2.x, shootPosition2.y, shootPosition2.z)); + + + swarmDroneEntity.setPos(worldPosition.x, worldPosition.y, worldPosition.z); + swarmDroneEntity.shoot(direct.x, direct.y, direct.z, 1.2f, 10); + + if (lookingEntity != null) { + swarmDroneEntity.setGuideType(0); + swarmDroneEntity.setTargetUuid(lookingEntity.getStringUUID()); + swarmDroneEntity.setTargetVec(lookingEntity.getEyePosition()); + } else { + swarmDroneEntity.setGuideType(1); + BlockHitResult result = level().clip(new ClipContext(getNewEyePos(1), getNewEyePos(1).add(lookVec.scale(512)), + ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)); + Vec3 hitPos = result.getLocation(); + swarmDroneEntity.setTargetVec(hitPos); + } + + player.level().addFreshEntity(swarmDroneEntity); + + this.level().playSound(null, BlockPos.containing(new Vec3(worldPosition.x, worldPosition.y, worldPosition.z)), ModSounds.DECOY_FIRE.get(), SoundSource.PLAYERS, 1, random.nextFloat() * 0.05f + 1); + + this.entityData.set(LOADED_DRONE, this.getEntityData().get(LOADED_DRONE) - 1); + droneReloadCoolDown = 100; } } @@ -646,6 +753,13 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); } + @Override + public Vec3 getNewEyePos(float pPartialTicks) { + Matrix4f transform = getTurretTransform(pPartialTicks); + Vector4f worldPosition = transformPosition(transform, 0, 1.65f, 0.6076875f); + return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z); + } + public int getMaxPassengers() { return 3; } @@ -914,6 +1028,8 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti return 15; } else if (getWeaponIndex(0) == 2) { return 500; + } else if (getWeaponIndex(0) == 3) { + return 600; } } @@ -932,6 +1048,8 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti return this.entityData.get(LOADED_HE) > 0 && getEnergy() > VehicleConfig.YX_100_SHOOT_COST.get(); } else if (getWeaponIndex(0) == 2) { return (this.entityData.get(MG_AMMO) > 0 || InventoryTool.hasCreativeAmmoBox(player)) && !cannotFireCoax; + } else if (getWeaponIndex(0) == 3) { + return this.entityData.get(LOADED_DRONE) > 0; } } @@ -950,6 +1068,8 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti return this.entityData.get(LOADED_HE); } else if (getWeaponIndex(0) == 2) { return this.entityData.get(MG_AMMO); + } else if (getWeaponIndex(0) == 3) { + return this.entityData.get(LOADED_DRONE); } } @@ -984,7 +1104,7 @@ public class Yx100Entity extends ContainerMobileVehicleEntity implements GeoEnti var typeIndex = isScroll ? (value + getWeaponIndex(index) + count) % count : value; - if (typeIndex != 2) { + if (typeIndex == 0 || typeIndex == 1) { if (entityData.get(LOADED_AP) > 0 && typeIndex == 1) { if (this.getFirstPassenger() instanceof Player player && !InventoryTool.hasCreativeAmmoBox(player)) { this.insertItem(ModItems.AP_5_INCHES.get(), 1); 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 30af0028c..edd417ea2 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 @@ -848,6 +848,10 @@ public abstract class VehicleEntity extends Entity { public void push(double pX, double pY, double pZ) { } + public Vec3 getNewEyePos(float pPartialTicks) { + return getEyePosition(); + } + public Vec3 getBarrelVector(float pPartialTicks) { return this.calculateViewVector(this.getBarrelXRot(pPartialTicks), this.getBarrelYRot(pPartialTicks)); } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SwarmDroneWeapon.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SwarmDroneWeapon.java new file mode 100644 index 000000000..01261d799 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/weapon/SwarmDroneWeapon.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.entity.vehicle.weapon; + +import com.atsuishio.superbwarfare.Mod; +import com.atsuishio.superbwarfare.entity.projectile.SwarmDroneEntity; +import net.minecraft.world.entity.LivingEntity; + +public class SwarmDroneWeapon extends VehicleWeapon { + + public float explosionDamage = 125, explosionRadius = 6; + + public SwarmDroneWeapon() { + this.icon = Mod.loc("textures/screens/vehicle_weapon/swarm_drone.png"); + } + + public SwarmDroneWeapon explosionDamage(float explosionDamage) { + this.explosionDamage = explosionDamage; + return this; + } + + public SwarmDroneWeapon explosionRadius(float explosionRadius) { + this.explosionRadius = explosionRadius; + return this; + } + + public SwarmDroneEntity create(LivingEntity entity) { + return new SwarmDroneEntity(entity, entity.level(), explosionDamage, explosionRadius); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java index 9c276eaeb..c5aba9078 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientSoundHandler.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare.event; +import com.atsuishio.superbwarfare.entity.projectile.SwarmDroneEntity; import com.atsuishio.superbwarfare.entity.vehicle.*; import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity; import com.atsuishio.superbwarfare.init.ModItems; @@ -98,5 +99,26 @@ public class ClientSoundHandler { } } } + + List swarmDrone = SeekTool.getEntityWithinRange(player, player.level(), 64); + + for (var e : swarmDrone) { + if (e instanceof SwarmDroneEntity swarmDroneEntity) { + + Vec3 listener = player.getEyePosition(); + Vec3 engineRealPos = e.getEyePosition(); + Vec3 toVec = listener.vectorTo(engineRealPos).normalize(); + double distance = listener.distanceTo(engineRealPos); + + var engineSoundPos = new Vec3(listener.x + toVec.x, listener.y + toVec.y, listener.z + toVec.z); + SoundEvent engineSound = ModSounds.DRONE_SOUND.get(); + float distanceReduce; + + distanceReduce = (float) Math.max((1 - distance / 64), 0); + if (swarmDroneEntity.tickCount > 10) { + player.level().playLocalSound(BlockPos.containing(engineSoundPos), engineSound, swarmDroneEntity.getSoundSource(), distanceReduce * distanceReduce, (float) ((2 * Math.random() - 1) * 0.002f + 1.15), false); + } + } + } } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java index b418d9393..ab6b86184 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java @@ -74,6 +74,8 @@ public class ModEntities { 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)); + public static final DeferredHolder, EntityType> SWARM_DRONE = register("swarm_drone", + EntityType.Builder.of(SwarmDroneEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(false).setTrackingRange(64).setUpdateInterval(1).fireImmune().sized(0.5f, 0.5f)); // Vehicles public static final DeferredHolder, EntityType> MK_42 = register("mk_42", diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java index f77f6b92d..283f2afd1 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java @@ -46,5 +46,6 @@ public class ModEntityRenderers { event.registerEntityRenderer(ModEntities.YX_100.get(), Yx100Renderer::new); event.registerEntityRenderer(ModEntities.WATER_MASK.get(), WaterMaskEntityRenderer::new); event.registerEntityRenderer(ModEntities.PRISM_TANK.get(), PrismTankRenderer::new); + event.registerEntityRenderer(ModEntities.SWARM_DRONE.get(), SwarmDroneRenderer::new); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java index 105ffd2f9..9d8e8c5c8 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java @@ -118,6 +118,7 @@ public class ModItems { 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())); + public static final DeferredHolder SWARM_DRONE = AMMO.register("swarm_drone", () -> new Item(new Item.Properties())); public static final DeferredHolder BEAM_TEST = AMMO.register("beam_test", BeamTest::new); /** diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java index e03a5d1f4..1cabcc227 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare.tools; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.Entity; @@ -23,6 +24,12 @@ public class SeekTool { .toList(); } + public static List getEntityWithinRange(Player player, Level level, double range) { + return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) + .filter(e -> e.position().distanceTo(player.getEyePosition()) <= range) + .toList(); + } + public static Entity seekEntity(Entity entity, Level level, double seekRange, double seekAngle) { return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) .filter(e -> { @@ -68,6 +75,21 @@ public class SeekTool { }).toList(); } + public static Entity vehicleSeekEntity(VehicleEntity vehicle, Level level, double seekRange, double seekAngle) { + return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) + .filter(e -> { + if (e.distanceTo(vehicle) <= seekRange && calculateAngleVehicle(e, vehicle) < seekAngle + && e != vehicle + && baseFilter(e) + && e.getVehicle() == null + && (!e.isAlliedTo(vehicle) || e.getTeam() == null || e.getTeam().getName().equals("TDM"))) { + return level.clip(new ClipContext(vehicle.getNewEyePos(1), vehicle.getNewEyePos(1), + ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, vehicle)).getType() != HitResult.Type.BLOCK; + } + return false; + }).min(Comparator.comparingDouble(e -> calculateAngleVehicle(e, vehicle))).orElse(null); + } + public static List seekLivingEntitiesThroughWall(Entity entity, Level level, double seekRange, double seekAngle) { return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) .filter(e -> e.distanceTo(entity) <= seekRange && calculateAngle(e, entity) < seekAngle @@ -90,6 +112,13 @@ public class SeekTool { return VectorTool.calculateAngle(start, end); } + private static double calculateAngleVehicle(Entity entityA, VehicleEntity entityB) { + Vec3 entityBEyePos = entityB.getNewEyePos(1); + Vec3 start = new Vec3(entityA.getX() - entityBEyePos.x, entityA.getY() - entityBEyePos.y, entityA.getZ() - entityBEyePos.z); + Vec3 end = entityB.getBarrelVector(1); + return VectorTool.calculateAngle(start, end); + } + public static boolean baseFilter(Entity entity) { return entity.isAlive() // && !(entity instanceof ItemEntity || entity instanceof ExperienceOrb || entity instanceof HangingEntity || entity instanceof Projectile || entity instanceof ArmorStand || entity instanceof ClaymoreEntity || entity instanceof C4Entity || entity instanceof AreaEffectCloud) diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java index 0812c002c..40c5a2c51 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java @@ -1,9 +1,11 @@ package com.atsuishio.superbwarfare.tools; +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.level.ClipContext; import net.minecraft.world.phys.*; @@ -94,4 +96,28 @@ public class TraceTool { public static boolean checkNoClip(Entity entity, Vec3 target) { return entity.level().clip(new ClipContext(entity.getEyePosition(), target, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType() != HitResult.Type.BLOCK; } + + public static Entity vehiclefFindLookingEntity(VehicleEntity vehicle, Vec3 eye, double entityReach) { + double distance = entityReach * entityReach; + HitResult hitResult = pickNew(eye, 512, vehicle); + + Vec3 viewVec = vehicle.getBarrelVector(1); + Vec3 toVec = eye.add(viewVec.x * entityReach, viewVec.y * entityReach, viewVec.z * entityReach); + AABB aabb = vehicle.getBoundingBox().expandTowards(viewVec.scale(entityReach)).inflate(1.0D, 1.0D, 1.0D); + EntityHitResult entityhitresult = ProjectileUtil.getEntityHitResult(vehicle, eye, toVec, aabb, p -> !p.isSpectator() && p.isAlive() && !(p instanceof Projectile), distance); + if (entityhitresult != null) { + hitResult = entityhitresult; + + } + if (hitResult.getType() == HitResult.Type.ENTITY) { + return ((EntityHitResult) hitResult).getEntity(); + } + return null; + } + + public static HitResult pickNew(Vec3 pos, double pHitDistance, VehicleEntity vehicle) { + Vec3 vec31 = vehicle.getBarrelVector(1); + Vec3 vec32 = pos.add(vec31.x * pHitDistance, vec31.y * pHitDistance, vec31.z * pHitDistance); + return vehicle.level().clip(new ClipContext(pos, vec32, ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, vehicle)); + } } diff --git a/src/main/resources/assets/superbwarfare/animations/swarm_drone.animation.json b/src/main/resources/assets/superbwarfare/animations/swarm_drone.animation.json new file mode 100644 index 000000000..55e0791bd --- /dev/null +++ b/src/main/resources/assets/superbwarfare/animations/swarm_drone.animation.json @@ -0,0 +1,123 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.sd.fly": { + "animation_length": 10.0083, + "bones": { + "main": { + "position": { + "0.0": [ + 0, + 0, + 0 + ], + "0.5": [ + 0, + 0, + 0 + ], + "0.6": [ + 0, + 4, + 0 + ] + } + }, + "rot1": { + "rotation": { + "0.6": [ + 0, + 0, + 0 + ], + "0.9917": [ + 0, + 750, + 0 + ], + "10.0": [ + 0, + 20000, + 0 + ] + } + }, + "bone": { + "rotation": { + "0.6": [ + 0, + 0, + 0 + ], + "0.7417": [ + 90, + 0, + 0 + ] + } + }, + "bone2": { + "rotation": { + "0.6": [ + 0, + 0, + 0 + ], + "0.7417": [ + -90, + 0, + 0 + ] + } + }, + "rot2": { + "rotation": { + "0.6": [ + 0, + 0, + 0 + ], + "0.9917": [ + 0, + -750, + 0 + ], + "10.0": [ + 0, + -20000, + 0 + ] + } + }, + "bone3": { + "rotation": { + "0.6": [ + 0, + 0, + 0 + ], + "0.7417": [ + 90, + 0, + 0 + ] + } + }, + "bone4": { + "rotation": { + "0.6": [ + 0, + 0, + 0 + ], + "0.7417": [ + -90, + 0, + 0 + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/geo/swarm_drone.geo.json b/src/main/resources/assets/superbwarfare/geo/swarm_drone.geo.json new file mode 100644 index 000000000..68d158a24 --- /dev/null +++ b/src/main/resources/assets/superbwarfare/geo/swarm_drone.geo.json @@ -0,0 +1,1319 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 32, + "texture_height": 32, + "visible_bounds_width": 2, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [ + 0, + 0.25, + 0 + ] + }, + "bones": [ + { + "name": "root", + "pivot": [ + 0, + 0, + 0 + ] + }, + { + "name": "cover2", + "parent": "root", + "pivot": [ + 0, + -1, + 0 + ], + "cubes": [ + { + "origin": [ + -1.5, + 0, + -0.62 + ], + "size": [ + 3, + 4, + 1.24 + ], + "uv": { + "east": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 1, + 0 + ], + "uv_size": [ + 1, + 4 + ] + }, + "up": { + "uv": [ + 6, + 8 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 1 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 0, + -0.62 + ], + "size": [ + 3, + 4, + 1.24 + ], + "pivot": [ + 0, + -1, + 0 + ], + "rotation": [ + 0, + 45, + 0 + ], + "uv": { + "east": { + "uv": [ + 2, + 0 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 3, + 0 + ], + "uv_size": [ + 1, + 4 + ] + }, + "up": { + "uv": [ + 9, + 1 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 3 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 0, + -0.62 + ], + "size": [ + 3, + 4, + 1.24 + ], + "pivot": [ + 0, + -1, + 0 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "east": { + "uv": [ + 0, + 4 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 4, + 0 + ], + "uv_size": [ + 1, + 4 + ] + }, + "up": { + "uv": [ + 9, + 3 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 5 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 0, + -0.62 + ], + "size": [ + 3, + 4, + 1.24 + ], + "pivot": [ + 0, + -1, + 0 + ], + "rotation": [ + 0, + 135, + 0 + ], + "uv": { + "east": { + "uv": [ + 1, + 4 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 2, + 4 + ], + "uv_size": [ + 1, + 4 + ] + }, + "up": { + "uv": [ + 9, + 5 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 6, + 10 + ], + "uv_size": [ + 3, + -1 + ] + } + } + } + ] + }, + { + "name": "main", + "parent": "root", + "pivot": [ + 0, + 3.9, + 0.10355 + ], + "cubes": [ + { + "origin": [ + -1.02, + 0, + -0.4216 + ], + "size": [ + 2.04, + 3.25, + 0.8432 + ], + "uv": { + "east": { + "uv": [ + 3, + 4 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 4, + 4 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "up": { + "uv": [ + 6, + 12 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -1.02, + 0, + -0.4216 + ], + "size": [ + 2.04, + 3.25, + 0.8432 + ], + "pivot": [ + 0, + 1.5, + 0 + ], + "rotation": [ + 0, + 45, + 0 + ], + "uv": { + "east": { + "uv": [ + 5, + 0 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 5, + 4 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "up": { + "uv": [ + 12, + 6 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -1.02, + 0, + -0.4216 + ], + "size": [ + 2.04, + 3.25, + 0.8432 + ], + "pivot": [ + 0, + 1.5, + 0 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "east": { + "uv": [ + 6, + 0 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 6, + 4 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "up": { + "uv": [ + 12, + 7 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -1.02, + 0, + -0.4216 + ], + "size": [ + 2.04, + 3.25, + 0.8432 + ], + "pivot": [ + 0, + 1.5, + 0 + ], + "rotation": [ + 0, + 135, + 0 + ], + "uv": { + "east": { + "uv": [ + 7, + 0 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 7, + 4 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "up": { + "uv": [ + 8, + 12 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -0.25, + 3, + -0.25 + ], + "size": [ + 0.5, + 1, + 0.5 + ], + "pivot": [ + 0, + 3.5, + 0 + ], + "rotation": [ + 0, + -45, + 0 + ], + "uv": { + "north": { + "uv": [ + 14, + 3 + ], + "uv_size": [ + 0.5, + 1 + ] + }, + "east": { + "uv": [ + 14, + 6 + ], + "uv_size": [ + 0.5, + 1 + ] + }, + "south": { + "uv": [ + 14, + 7 + ], + "uv_size": [ + 0.5, + 1 + ] + }, + "west": { + "uv": [ + 14, + 8 + ], + "uv_size": [ + 0.5, + 1 + ] + }, + "up": { + "uv": [ + 2, + 15 + ], + "uv_size": [ + 0.5, + 0.5 + ] + }, + "down": { + "uv": [ + 15, + 2.5 + ], + "uv_size": [ + 0.5, + -0.5 + ] + } + } + } + ] + }, + { + "name": "cover", + "parent": "main", + "pivot": [ + 0, + 5.125, + 0 + ], + "cubes": [ + { + "origin": [ + -1.5, + 4, + -0.62 + ], + "size": [ + 3, + 2.25, + 1.24 + ], + "uv": { + "east": { + "uv": [ + 4, + 12 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "west": { + "uv": [ + 5, + 12 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "up": { + "uv": [ + 6, + 11 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 12 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 4, + -0.62 + ], + "size": [ + 3, + 2.25, + 1.24 + ], + "pivot": [ + 0, + -1, + 0 + ], + "rotation": [ + 0, + 45, + 0 + ], + "uv": { + "east": { + "uv": [ + 3, + 12 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "west": { + "uv": [ + 12, + 3 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "up": { + "uv": [ + 6, + 10 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 11 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 4, + -0.62 + ], + "size": [ + 3, + 2.25, + 1.24 + ], + "pivot": [ + 0, + -1, + 0 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "east": { + "uv": [ + 1, + 12 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "west": { + "uv": [ + 2, + 12 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "up": { + "uv": [ + 9, + 8 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 10 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 4, + -0.62 + ], + "size": [ + 3, + 2.25, + 1.24 + ], + "pivot": [ + 0, + -1, + 0 + ], + "rotation": [ + 0, + 135, + 0 + ], + "uv": { + "east": { + "uv": [ + 0, + 12 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "west": { + "uv": [ + 12, + 0 + ], + "uv_size": [ + 1, + 2.5 + ] + }, + "up": { + "uv": [ + 9, + 6 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 9, + 8 + ], + "uv_size": [ + 3, + -1 + ] + } + } + } + ] + }, + { + "name": "rot1", + "parent": "main", + "pivot": [ + 0, + 3.775, + 0 + ], + "cubes": [ + { + "origin": [ + -0.35, + 3.65, + -1.15 + ], + "size": [ + 0.7, + 0.25, + 2.3 + ], + "uv": { + "east": { + "uv": [ + 13, + 4 + ], + "uv_size": [ + 2.5, + 0.5 + ] + }, + "west": { + "uv": [ + 13, + 5 + ], + "uv_size": [ + 2.5, + 0.5 + ] + }, + "up": { + "uv": [ + 13, + 8 + ], + "uv_size": [ + 0.5, + 2.5 + ] + }, + "down": { + "uv": [ + 9, + 15.5 + ], + "uv_size": [ + 0.5, + -2.5 + ] + } + } + } + ] + }, + { + "name": "bone", + "parent": "rot1", + "pivot": [ + 0, + 3.775, + 1.275 + ], + "cubes": [ + { + "origin": [ + -0.5, + 0.4, + 1.15 + ], + "size": [ + 1, + 3.5, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 0, + 8 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "east": { + "uv": [ + 12, + 8 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "south": { + "uv": [ + 8, + 0 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 10, + 12 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "up": { + "uv": [ + 14, + 9 + ], + "uv_size": [ + 1, + 0.5 + ] + }, + "down": { + "uv": [ + 14, + 10.5 + ], + "uv_size": [ + 1, + -0.5 + ] + } + } + } + ] + }, + { + "name": "bone2", + "parent": "rot1", + "pivot": [ + 0, + 3.775, + -1.275 + ], + "cubes": [ + { + "origin": [ + -0.5, + 0.4, + -1.4 + ], + "size": [ + 1, + 3.5, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 1, + 8 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "east": { + "uv": [ + 11, + 12 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "south": { + "uv": [ + 2, + 8 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 12, + 12 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "up": { + "uv": [ + 14, + 13 + ], + "uv_size": [ + 1, + 0.5 + ] + }, + "down": { + "uv": [ + 14, + 14.5 + ], + "uv_size": [ + 1, + -0.5 + ] + } + } + } + ] + }, + { + "name": "rot2", + "parent": "main", + "pivot": [ + 0, + 3.475, + 0 + ], + "rotation": [ + 0, + 90, + 0 + ], + "cubes": [ + { + "origin": [ + -0.35, + 3.35, + -1.15 + ], + "size": [ + 0.7, + 0.25, + 2.3 + ], + "uv": { + "east": { + "uv": [ + 13, + 11 + ], + "uv_size": [ + 2.5, + 0.5 + ] + }, + "west": { + "uv": [ + 13, + 12 + ], + "uv_size": [ + 2.5, + 0.5 + ] + }, + "up": { + "uv": [ + 13, + 13 + ], + "uv_size": [ + 0.5, + 2.5 + ] + }, + "down": { + "uv": [ + 14, + 2.5 + ], + "uv_size": [ + 0.5, + -2.5 + ] + } + } + } + ] + }, + { + "name": "bone3", + "parent": "rot2", + "pivot": [ + 0, + 3.475, + 1.275 + ], + "cubes": [ + { + "origin": [ + -0.5, + 0.1, + 1.15 + ], + "size": [ + 1, + 3.5, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 3, + 8 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "east": { + "uv": [ + 13, + 0 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "south": { + "uv": [ + 4, + 8 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 6, + 13 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "up": { + "uv": [ + 0, + 15 + ], + "uv_size": [ + 1, + 0.5 + ] + }, + "down": { + "uv": [ + 15, + 0.5 + ], + "uv_size": [ + 1, + -0.5 + ] + } + } + } + ] + }, + { + "name": "bone4", + "parent": "rot2", + "pivot": [ + 0, + 3.475, + -1.275 + ], + "cubes": [ + { + "origin": [ + -0.5, + 0.1, + -1.4 + ], + "size": [ + 1, + 3.5, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 8, + 4 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "east": { + "uv": [ + 7, + 13 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "south": { + "uv": [ + 5, + 8 + ], + "uv_size": [ + 1, + 3.5 + ] + }, + "west": { + "uv": [ + 8, + 13 + ], + "uv_size": [ + 0.5, + 3.5 + ] + }, + "up": { + "uv": [ + 1, + 15 + ], + "uv_size": [ + 1, + 0.5 + ] + }, + "down": { + "uv": [ + 15, + 1.5 + ], + "uv_size": [ + 1, + -0.5 + ] + } + } + } + ] + } + ] + } + ] +} \ 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 e28618c70..2b8184f08 100644 --- a/src/main/resources/assets/superbwarfare/lang/en_us.json +++ b/src/main/resources/assets/superbwarfare/lang/en_us.json @@ -164,6 +164,7 @@ "item.superbwarfare.rocket_70": "70mm Rocket", "item.superbwarfare.small_shell": "Small Caliber Shells", "item.superbwarfare.wire_guide_missile": "Wire Guide Missile", + "item.superbwarfare.swarm_drone": "Swarm Drone", "item.superbwarfare.firing_parameters": "Firing Parameters", "item.superbwarfare.ancient_cpu": "Ancient CPU", @@ -441,6 +442,7 @@ "entity.superbwarfare.wg_missile": "Wire Guide Missile", "entity.superbwarfare.laser_tower": "Laser Defense Tower", "entity.superbwarfare.prism_tank": "Prism Tank", + "entity.superbwarfare.swarm_drone": "Swarm Drone", "key.categories.superbwarfare": "Superb Warfare", "key.superbwarfare.hold_zoom": "Zoom (Hold)", diff --git a/src/main/resources/assets/superbwarfare/lang/zh_cn.json b/src/main/resources/assets/superbwarfare/lang/zh_cn.json index bc2b161f4..f17668212 100644 --- a/src/main/resources/assets/superbwarfare/lang/zh_cn.json +++ b/src/main/resources/assets/superbwarfare/lang/zh_cn.json @@ -164,6 +164,7 @@ "item.superbwarfare.rocket_70": "70mm火箭弹", "item.superbwarfare.small_shell": "小口径炮弹", "item.superbwarfare.wire_guide_missile": "线控导弹", + "item.superbwarfare.swarm_drone": "蜂群无人机", "item.superbwarfare.firing_parameters": "射击诸元", "item.superbwarfare.ancient_cpu": "古代处理器", @@ -439,6 +440,7 @@ "entity.superbwarfare.wg_missile": "线控导弹", "entity.superbwarfare.laser_tower": "激光防御塔", "entity.superbwarfare.prism_tank": "光棱坦克", + "entity.superbwarfare.swarm_drone": "蜂群无人机", "key.categories.superbwarfare": "卓越前线", "key.superbwarfare.hold_zoom": "瞄准(按住)", diff --git a/src/main/resources/assets/superbwarfare/textures/entity/swamDrone.png b/src/main/resources/assets/superbwarfare/textures/entity/swamDrone.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fdfb5caef8183af6c5275f485b7e50360a8372 GIT binary patch literal 1255 zcmVPx(p-DtRRCt{2naz(BMHq*l>aL!i?%lz-t0QDZ6ZVTc#_0cmaKr>mxN`91(S(C1 zl06$Q9!TJZL_u#RcoYq2;+4gN93(>)66d3LyQix>OjXl6^vup?#cfSJ$!2D1s<-?7 zsCs|(jyQGd9nB1^pFD{Mc6N5qTI2gZzVGwfufG5g&&^j}cV%M(fb$=oqtoe#cDt?Z zD?q2y5wqO?Wg%~U{`yQ4dzU+vUFDY>uCL=j}O~$i_Dh31VAZ8k|c!9CIFro zJ)aN)tu>#%@(Dr+f*>Hzb9~ zjKD-#m_LkDFvc~40K{Y)gb>C2GKX!rMJ7oCK+{A%3`3OGh)Z|XxYEiF}+)8&;_sL`4qr*a7Ztgf#kfMK2^rDSDo zP5Zu2GYrX0#A&R16 zjoWgUrs>E5!y%Y5h}MM;xO(k6Cze;BB$OU*KH%${H#J5y_4|FEK6_T15(pr-w-ds! zN$bcF0OscA==b}hZ?z^((^365hTD>urRgXWj1FK-AzJKvr4*i#&viofd%e*cIZvacuyZedbfNMFADlT0#sSJ)Qzzudmo8O)u~*$6XOa%E zhbbXMae%55^3kI|09agD03q1g+JaKuUR+oJVC(5qFezWf)oa&TSzRlZfl`Wxn-5;- z1Drl{cBcNrzeOR0Chg{pJ?eZJyFXN&{_0BM0K1!yGd@1))Hi7l7{@BXI%oi9&VYX~ zqIEIcvhNJIva!M1`pMC*ZYsm?4>xDdfI6K6C_5ksg37g9uJaaqB(^*JELel-+xPfO$zdRu-#)&th#d6c>y`m>+@N>g zd%sp4o7!O=HvalwrCRDkugidKp2MKc6M+nlEG2JQA>yX53vr02tu4(+By|9 zQv^A8e}D=Zq=aON&|gs~U1Dd4LkcQ_oA5d49l1->(thLdJjlSC^Rb zHg)?00#Jfir9}{O5<<{y)Kd}(+svV=6Kk+MRm$7i&r)DY>JsjqpW$u(soH+oy1?z} z4{YWD_`8gG9Vwu%_YV!0ZGZ3G;ADTSC6yvG33dAe5<(EayQe75D2lV?Z7&$InX@sh fNj8O*WS!+-RLQ>%SI!rS00000NkvXXu0mjfz%iiL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/superbwarfare/textures/screens/vehicle_weapon/swarm_drone.png b/src/main/resources/assets/superbwarfare/textures/screens/vehicle_weapon/swarm_drone.png new file mode 100644 index 0000000000000000000000000000000000000000..34463f58a10d9e9a066c95d7ffca6d4e3d2662cd GIT binary patch literal 1588 zcmV-42Fv-0P)dg!5>54|MaA0!IwA;_SRit0h>f>23FV5Gsxt{ipD>~3I^MwY)G)|y-mb557p zGpBv_?*qf$vu5o*dmlVM{%h@}f|;3_nVFfHnVFfH+5dqgjrTQ}HN^qreF0`>|C9r( z0V!W@xtSKB=W>y;xtO|KpXx3j2EHkSO z2Uf*gWtsJl1Ix^6!+~XHwc)_(0}l($`on=$0k6d}8;pa-`vL~3tb8IOdZ~m46;k6- zt#$j^IF#-GpfMHJpnvfv+OTk<-H+8%V*<;}>d%4IN3KfDs@14Dtnu_;!prkUW`E@h z%gk!SfmM;wsv!>x&8p+T>Vd<^Y_L3s)gwu2S67~MGV3n~Rz=3Dwj5+;)$owe%xc4d zWoEVEz%sMiaA28PZ8)&ZtTz0Vup)jEXx4uYtO|{`w83F!Rt*mcd*m=O8yp8#56ZA| zb!FCn4lFaP4bNc>h$}6#-nqi+BZrh(wH#PxRvV28tU*^h6RogW@~GKh_$gr@)UCRbG!3{GxEeST*bFRTRX5ufO&a%*Ue`U@o_}F1uOzS1C9mubo4ul6lMT#j&(ye zad{5QrsVAm;QhS62Dl3NCBJXw?Ns)M2Bg56+|dU~$B`D93Hk`LJNugD?S%WyRdQ`Wkf}JAb z*NAu&IG;4s+6|lwtdVp>?zRnh2RNA&Y$N$~BJcsQ3)l-F=|JGSeB2yhJFo(nC24V& zOSlA>pZfwl2Heuo=S$#DQee%_ZR`Kj4VyJt9hWkUMbb%<-p;qRUDA}?-YS+7+%4(; z;{9-O{CQ(6Sy+_&l*<}sDJ_*4mb6FGZN<6T%Nkyl^m^XkCuxVI$Gxnfd0b&NSPqvr zBrR{ZMZ^ej4e&W>xOaN~s8t*~0&FVYZ!PxQb5$+i?fm*Aw{;s9Zi$HZfOWtj{B_wx zsXastQdRf;X!m6kmjkQW4kJyFUn%LZqWwqU>yEyyVt*4UwA!{5`|VI#91(LPVlHrf zZks1*v_N_|pZ8`-H+K2FoYV4fu%R4S6{zXcK}gFO){>ST+$re@Nda63TnPM3s%Bt+ zV2QNIvka`Q0D1U0CHE=UYpn;KAT5EIOcxQc33!(jqNjA}vSE~cYY+!kgGIzn;APT8 z`hBFy?eBqSa+mufVpra85Bt7}h^3?oY-w(52T7Ck zw@O;r@!1yA-&q6)R%3bLXpd@KT>%ggk4gFhxCuB1m;`JDmPN#qMc2)witD3%9Fpeb zw#~WEbW)hS(B-RMCWYAvq$i5)(D}W%mQN+ULV992DW7`-Fp|G-Dya(ljkG9r1MqDx m_ituqW@ct)W@ctqr9S|Kguq<_5>8710000VpW literal 0 HcmV?d00001 diff --git a/src/main/resources/data/superbwarfare/recipe/swarm_drone_crafting.json b/src/main/resources/data/superbwarfare/recipe/swarm_drone_crafting.json new file mode 100644 index 000000000..262492b75 --- /dev/null +++ b/src/main/resources/data/superbwarfare/recipe/swarm_drone_crafting.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + " a ", + "bcb", + "ded" + ], + "key": { + "a": { + "item": "superbwarfare:seeker" + }, + "b": { + "item": "superbwarfare:propeller" + }, + "c": { + "item": "superbwarfare:motor" + }, + "d": { + "item": "superbwarfare:high_energy_explosives" + }, + "e": { + "item": "superbwarfare:cell" + } + }, + "result": { + "id": "superbwarfare:swarm_drone", + "count": 4 + } +} \ No newline at end of file