artillery rocket behavior

This commit is contained in:
Boblet 2022-10-13 16:26:24 +02:00
parent 52a8c0df77
commit 00b6ef249e
8 changed files with 240 additions and 15 deletions

View File

@ -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());

View File

@ -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<ChunkCoordIntPair> loadedChunks = new ArrayList<ChunkCoordIntPair>();
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;
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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); }};
}
}