From 00b6ef249e8ee0d1a06056f2534a17f6a64fdb55 Mon Sep 17 00:00:00 2001 From: Boblet Date: Thu, 13 Oct 2022 16:26:24 +0200 Subject: [PATCH] artillery rocket behavior --- src/main/java/com/hbm/blocks/ModBlocks.java | 2 +- .../projectile/EntityArtilleryRocket.java | 109 +++++++++++++++++- .../IRocketSteeringBehavior.java | 9 ++ .../IRocketTargetingBehavior.java | 11 ++ .../RocketSteeringBallisticArc.java | 11 ++ .../RocketTargetingPredictive.java | 51 ++++++++ .../rocketbehavior/RocketTargetingSimple.java | 17 +++ .../com/hbm/items/weapon/ItemAmmoHIMARS.java | 45 ++++++-- 8 files changed, 240 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketSteeringBehavior.java create mode 100644 src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketTargetingBehavior.java create mode 100644 src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketSteeringBallisticArc.java create mode 100644 src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingPredictive.java create mode 100644 src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingSimple.java diff --git a/src/main/java/com/hbm/blocks/ModBlocks.java b/src/main/java/com/hbm/blocks/ModBlocks.java index d9cdcaed4..00ebc6cc9 100644 --- a/src/main/java/com/hbm/blocks/ModBlocks.java +++ b/src/main/java/com/hbm/blocks/ModBlocks.java @@ -2901,7 +2901,7 @@ public class ModBlocks { GameRegistry.registerBlock(turret_fritz, turret_fritz.getUnlocalizedName()); GameRegistry.registerBlock(turret_brandon, turret_brandon.getUnlocalizedName()); GameRegistry.registerBlock(turret_arty, turret_arty.getUnlocalizedName()); - //GameRegistry.registerBlock(turret_himars, turret_himars.getUnlocalizedName()); + GameRegistry.registerBlock(turret_himars, turret_himars.getUnlocalizedName()); //Wall-mounted Explosives GameRegistry.registerBlock(charge_dynamite, ItemBlockBase.class, charge_dynamite.getUnlocalizedName()); diff --git a/src/main/java/com/hbm/entity/projectile/EntityArtilleryRocket.java b/src/main/java/com/hbm/entity/projectile/EntityArtilleryRocket.java index afcb64f90..7b69f6562 100644 --- a/src/main/java/com/hbm/entity/projectile/EntityArtilleryRocket.java +++ b/src/main/java/com/hbm/entity/projectile/EntityArtilleryRocket.java @@ -1,10 +1,21 @@ package com.hbm.entity.projectile; +import java.util.ArrayList; +import java.util.List; + import com.hbm.entity.logic.IChunkLoader; +import com.hbm.entity.projectile.rocketbehavior.IRocketSteeringBehavior; +import com.hbm.entity.projectile.rocketbehavior.IRocketTargetingBehavior; +import com.hbm.items.weapon.ItemAmmoHIMARS; +import com.hbm.items.weapon.ItemAmmoHIMARS.HIMARSRocket; import com.hbm.main.MainRegistry; import api.hbm.entity.IRadarDetectable; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.Entity; import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraftforge.common.ForgeChunkManager; @@ -15,6 +26,13 @@ public class EntityArtilleryRocket extends EntityThrowableInterp implements IChu private Ticket loaderTicket; + //TODO: find satisfying solution for when an entity is unloaded and reloaded, possibly a custom entity lookup using persistent UUIDs + private Entity targetEntity = null; + private Vec3 lastTargetPos; + + private IRocketTargetingBehavior targeting; + private IRocketSteeringBehavior steering; + public EntityArtilleryRocket(World world) { super(world); this.ignoreFrustumCheck = true; @@ -25,15 +43,61 @@ public class EntityArtilleryRocket extends EntityThrowableInterp implements IChu init(ForgeChunkManager.requestTicket(MainRegistry.instance, worldObj, Type.ENTITY)); this.dataWatcher.addObject(10, new Integer(0)); } + + @Override + @SideOnly(Side.CLIENT) + public boolean isInRangeToRenderDist(double distance) { + return true; + } + + public EntityArtilleryRocket setType(int type) { + this.dataWatcher.updateObject(10, type); + return this; + } + + public HIMARSRocket getType() { + try { + return ItemAmmoHIMARS.itemTypes[this.dataWatcher.getWatchableObjectInt(10)]; + } catch(Exception ex) { + return ItemAmmoHIMARS.itemTypes[0]; + } + } + + public EntityArtilleryRocket setTarget(Entity target) { + this.targetEntity = target; + setTarget(target.posX, target.posY - target.yOffset + target.height / 2D, target.posZ); + return this; + } + + public EntityArtilleryRocket setTarget(double x, double y, double z) { + this.lastTargetPos = Vec3.createVectorHelper(x, y, z); + return this; + } + + public Vec3 getLastTarget() { + return this.lastTargetPos; + } + + @Override + public void onUpdate() { + super.onUpdate(); + + if(!worldObj.isRemote) { + + if(this.targetEntity != null) this.targeting.recalculateTargetPosition(this, this.targetEntity); + this.steering.adjustCourse(this); + + loadNeighboringChunks((int)Math.floor(posX / 16D), (int)Math.floor(posZ / 16D)); + this.getType().onUpdate(this); + } + } @Override protected void onImpact(MovingObjectPosition mop) { - } - - @Override - public RadarTargetType getTargetType() { - return RadarTargetType.ARTILLERY; + if(!worldObj.isRemote) { + this.getType().onImpact(this, mop); + } } @Override @@ -47,4 +111,39 @@ public class EntityArtilleryRocket extends EntityThrowableInterp implements IChu ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(chunkCoordX, chunkCoordZ)); } } + + List loadedChunks = new ArrayList(); + + public void loadNeighboringChunks(int newChunkX, int newChunkZ) { + if(!worldObj.isRemote && loaderTicket != null) { + + clearChunkLoader(); + + loadedChunks.clear(); + loadedChunks.add(new ChunkCoordIntPair(newChunkX, newChunkZ)); + loadedChunks.add(new ChunkCoordIntPair(newChunkX + (int) Math.ceil((this.posX + this.motionX) / 16D), newChunkZ + (int) Math.ceil((this.posZ + this.motionZ) / 16D))); + + for(ChunkCoordIntPair chunk : loadedChunks) { + ForgeChunkManager.forceChunk(loaderTicket, chunk); + } + } + } + + public void killAndClear() { + this.setDead(); + this.clearChunkLoader(); + } + + public void clearChunkLoader() { + if(!worldObj.isRemote && loaderTicket != null) { + for(ChunkCoordIntPair chunk : loadedChunks) { + ForgeChunkManager.unforceChunk(loaderTicket, chunk); + } + } + } + + @Override + public RadarTargetType getTargetType() { + return RadarTargetType.ARTILLERY; + } } diff --git a/src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketSteeringBehavior.java b/src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketSteeringBehavior.java new file mode 100644 index 000000000..eb9ef1141 --- /dev/null +++ b/src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketSteeringBehavior.java @@ -0,0 +1,9 @@ +package com.hbm.entity.projectile.rocketbehavior; + +import com.hbm.entity.projectile.EntityArtilleryRocket; + +public interface IRocketSteeringBehavior { + + /** Modifies the motion to steer towards the set target. */ + public void adjustCourse(EntityArtilleryRocket rocket); +} diff --git a/src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketTargetingBehavior.java b/src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketTargetingBehavior.java new file mode 100644 index 000000000..43a46df7a --- /dev/null +++ b/src/main/java/com/hbm/entity/projectile/rocketbehavior/IRocketTargetingBehavior.java @@ -0,0 +1,11 @@ +package com.hbm.entity.projectile.rocketbehavior; + +import com.hbm.entity.projectile.EntityArtilleryRocket; + +import net.minecraft.entity.Entity; + +public interface IRocketTargetingBehavior { + + /** Recalculates the position that should be steered towards. */ + public void recalculateTargetPosition(EntityArtilleryRocket rocket, Entity target); +} diff --git a/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketSteeringBallisticArc.java b/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketSteeringBallisticArc.java new file mode 100644 index 000000000..c6b494fb2 --- /dev/null +++ b/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketSteeringBallisticArc.java @@ -0,0 +1,11 @@ +package com.hbm.entity.projectile.rocketbehavior; + +import com.hbm.entity.projectile.EntityArtilleryRocket; + +public class RocketSteeringBallisticArc implements IRocketSteeringBehavior { + + @Override + public void adjustCourse(EntityArtilleryRocket rocket) { + //TBI + } +} diff --git a/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingPredictive.java b/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingPredictive.java new file mode 100644 index 000000000..76a6131b1 --- /dev/null +++ b/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingPredictive.java @@ -0,0 +1,51 @@ +package com.hbm.entity.projectile.rocketbehavior; + +import com.hbm.entity.projectile.EntityArtilleryRocket; + +import net.minecraft.entity.Entity; + +/** + * Basic implementation of predictive targeting. + * My current best guess for "smart" targeting + * Keeps a buffer of the last second's velocity values and generates a predicted target based on the average speed. + * @author hbm + */ +public class RocketTargetingPredictive implements IRocketTargetingBehavior { + + /* + * unlikely to work for things that move extremely erratically and quickly, + * but there's barely any cases where that would apply. + * a single second of prediction is good enough at long distances where there's + * still room for error, like player vehicles or ICBMs. + */ + private double[][] targetMotion = new double[20][3]; + + @Override + public void recalculateTargetPosition(EntityArtilleryRocket rocket, Entity target) { + + /* initialize with the values we already know */ + double motionX = target.motionX; + double motionY = target.motionY; + double motionZ = target.motionZ; + + /* shift the buffer and add the older values */ + for(int i = 1; i < 20; i++) { + targetMotion[i - 1] = targetMotion[i]; + motionX += targetMotion[i][0]; + motionY += targetMotion[i][1]; + motionZ += targetMotion[i][2]; + } + + /* push the new values to the buffer for future use */ + targetMotion[19][0] = target.motionX; + targetMotion[19][1] = target.motionY; + targetMotion[19][2] = target.motionZ; + + /* generate averages and predict a new position */ + double predX = target.posX + (motionX / 20D); + double predY = target.posY - target.yOffset + target.height * 0.5D + (motionY / 20D); + double predZ = target.posZ + (motionZ / 20D); + + rocket.setTarget(predX, predY, predZ); + } +} diff --git a/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingSimple.java b/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingSimple.java new file mode 100644 index 000000000..6d180fd6e --- /dev/null +++ b/src/main/java/com/hbm/entity/projectile/rocketbehavior/RocketTargetingSimple.java @@ -0,0 +1,17 @@ +package com.hbm.entity.projectile.rocketbehavior; + +import com.hbm.entity.projectile.EntityArtilleryRocket; + +import net.minecraft.entity.Entity; + +/** + * "Stupid targeting for rockets, they move straight towards the target's current position" + * @author hbm + */ +public class RocketTargetingSimple implements IRocketTargetingBehavior { + + @Override + public void recalculateTargetPosition(EntityArtilleryRocket rocket, Entity target) { + rocket.setTarget(target.posX, target.posY - target.yOffset + target.height * 0.5D, target.posZ); + } +} diff --git a/src/main/java/com/hbm/items/weapon/ItemAmmoHIMARS.java b/src/main/java/com/hbm/items/weapon/ItemAmmoHIMARS.java index 5ee9b7e0c..117bf15f6 100644 --- a/src/main/java/com/hbm/items/weapon/ItemAmmoHIMARS.java +++ b/src/main/java/com/hbm/items/weapon/ItemAmmoHIMARS.java @@ -2,16 +2,24 @@ package com.hbm.items.weapon; import java.util.List; +import com.hbm.entity.projectile.EntityArtilleryRocket; +import com.hbm.explosion.vanillant.ExplosionVNT; +import com.hbm.explosion.vanillant.standard.BlockAllocatorStandard; +import com.hbm.explosion.vanillant.standard.BlockProcessorStandard; +import com.hbm.explosion.vanillant.standard.EntityProcessorStandard; +import com.hbm.explosion.vanillant.standard.ExplosionEffectStandard; +import com.hbm.explosion.vanillant.standard.PlayerProcessorStandard; import com.hbm.lib.RefStrings; import com.hbm.main.MainRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.entity.Entity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Vec3; public class ItemAmmoHIMARS extends Item { @@ -36,21 +44,40 @@ public class ItemAmmoHIMARS extends Item { public abstract class HIMARSRocket { - String name; + ResourceLocation texture; + int amount; + int modelType; /* 0 = sixfold/standard ; 1 = single */ public HIMARSRocket() { } - public HIMARSRocket(String name) { - this.name = name; + public HIMARSRocket(String name, int type, int amount) { + this.texture = new ResourceLocation(RefStrings.MODID + ":textures/models/projectiles/" + name); + this.amount = amount; + this.modelType = type; } - public abstract void onImpact(Entity rocket, MovingObjectPosition mop); - public void onUpdate(Entity rocket) { } + public abstract void onImpact(EntityArtilleryRocket rocket, MovingObjectPosition mop); + public void onUpdate(EntityArtilleryRocket rocket) { } + } + + public static void standardExplosion(EntityArtilleryRocket rocket, MovingObjectPosition mop, float size, float rangeMod, boolean breaksBlocks) { + rocket.worldObj.playSoundEffect(rocket.posX, rocket.posY, rocket.posZ, "hbm:weapon.explosionMedium", 20.0F, 0.9F + rocket.worldObj.rand.nextFloat() * 0.2F); + Vec3 vec = Vec3.createVectorHelper(rocket.motionX, rocket.motionY, rocket.motionZ).normalize(); + ExplosionVNT xnt = new ExplosionVNT(rocket.worldObj, mop.hitVec.xCoord - vec.xCoord, mop.hitVec.yCoord - vec.yCoord, mop.hitVec.zCoord - vec.zCoord, size); + if(breaksBlocks) { + xnt.setBlockAllocator(new BlockAllocatorStandard(48)); + xnt.setBlockProcessor(new BlockProcessorStandard().setNoDrop()); + } + xnt.setEntityProcessor(new EntityProcessorStandard().withRangeMod(rangeMod)); + xnt.setPlayerProcessor(new PlayerProcessorStandard()); + xnt.setSFX(new ExplosionEffectStandard()); + xnt.explode(); + rocket.killAndClear(); } private void init() { - /* STANDARD SHELLS */ - this.itemTypes[SMALL] = new HIMARSRocket("ammo_himars") { public void onImpact(Entity rocket, MovingObjectPosition mop) { }}; - this.itemTypes[LARGE] = new HIMARSRocket("ammo_himars_large") { public void onImpact(Entity rocket, MovingObjectPosition mop) { }}; + /* STANDARD ROCKETS */ + this.itemTypes[SMALL] = new HIMARSRocket("himars_standard", 0, 6) { public void onImpact(EntityArtilleryRocket rocket, MovingObjectPosition mop) { standardExplosion(rocket, mop, 25F, 3F, true); }}; + this.itemTypes[LARGE] = new HIMARSRocket("himars_single", 1, 1) { public void onImpact(EntityArtilleryRocket rocket, MovingObjectPosition mop) { standardExplosion(rocket, mop, 50F, 5F, true); }}; } }