diff --git a/src/main/java/com/hbm/handler/BulletConfiguration.java b/src/main/java/com/hbm/handler/BulletConfiguration.java index acf2ad30b..95115b66c 100644 --- a/src/main/java/com/hbm/handler/BulletConfiguration.java +++ b/src/main/java/com/hbm/handler/BulletConfiguration.java @@ -13,9 +13,9 @@ import com.hbm.interfaces.Untested; import com.hbm.inventory.RecipesCommon.ComparableStack; import com.hbm.lib.ModDamageSource; import com.hbm.main.MainRegistry; +import com.hbm.particle.SpentCasing; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; @@ -101,6 +101,7 @@ public class BulletConfiguration implements Cloneable { public int plink; //vanilla particle FX public String vPFX = ""; + public SpentCasing spentCasing; //energy projectiles //power consumed per shot diff --git a/src/main/java/com/hbm/handler/CasingEjector.java b/src/main/java/com/hbm/handler/CasingEjector.java new file mode 100644 index 000000000..adac3cc43 --- /dev/null +++ b/src/main/java/com/hbm/handler/CasingEjector.java @@ -0,0 +1,147 @@ +package com.hbm.handler; + +import java.util.HashMap; +import java.util.Random; + +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; +import org.lwjgl.util.vector.Vector4f; + +import com.hbm.particle.ParticleSpentCasing; +import com.hbm.particle.SpentCasing; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +/** + * Config for the guns themselves on where to spawn casings and at what angle + * @author uffr, hbm + */ +public class CasingEjector implements Cloneable { + + public static HashMap mappings = new HashMap(); + public static final Random rand = new Random(); + + private int id; + private static int nextId = 0; + private Vec3 posOffset = Vec3.createVectorHelper(0, 0, 0); + private Vec3 initialMotion = Vec3.createVectorHelper(0, 0, 0); + private int casingAmount = 1; + private boolean afterReload = false; + private int delay = 0; + private float randomYaw = 0F; + private float randomPitch = 0F; + + public CasingEjector() { + this.id = nextId; + nextId++; + + mappings.put(id, this); + } + + public CasingEjector setOffset(Vec3 vec) { + this.posOffset = vec; + return this; + } + + public CasingEjector setMotion(Vec3 vec) { + this.initialMotion = vec; + return this; + } + + public CasingEjector setAmount(int am) { + this.casingAmount = am; + return this; + } + + public CasingEjector setAfterReload() { + this.afterReload = true; + return this; + } + + public CasingEjector setDelay(int delay) { + this.delay = delay; + return this; + } + + public CasingEjector setAngleRange(float yaw, float pitch) { + this.randomYaw = yaw; + this.randomPitch = pitch; + return this; + } + + public int getId() { return this.id; } + public Vec3 getOffset() { return this.posOffset; } + public Vec3 getMotion() { return this.initialMotion; } + public int getAmount() { return this.casingAmount; } + public boolean getAfterReload() { return this.afterReload; } + public int getDelay() { return this.delay; } + public float getYawFactor() { return this.randomYaw; } + public float getPitchFactor() { return this.randomPitch; } + + public void spawnCasing(TextureManager textureManager, SpentCasing config, World world, double x, double y, double z, float pitch, float yaw, boolean crouched) { + Vec3 rotatedMotionVec = rotateVector(getMotion(), pitch + (float) rand.nextGaussian() * getPitchFactor(), yaw + (float) rand.nextGaussian() * getPitchFactor(), getPitchFactor(), getPitchFactor()); + ParticleSpentCasing casing = new ParticleSpentCasing(textureManager, world, x, y, z, rotatedMotionVec.xCoord, rotatedMotionVec.yCoord, rotatedMotionVec.zCoord, (float) (getPitchFactor() * rand.nextGaussian()), (float) (getYawFactor() * rand.nextGaussian()), config); + + offsetCasing(casing, getOffset(), pitch, yaw, crouched); + + casing.rotationPitch = (float) Math.toDegrees(pitch); + casing.rotationYaw = (float) Math.toDegrees(yaw); + + Minecraft.getMinecraft().effectRenderer.addEffect(casing); + } + + // Rotate a position + private static void offsetCasing(ParticleSpentCasing casing, Vec3 offset, float pitch, float yaw, boolean crouched) { + // x-axis offset, 0 if crouched to center + final float oX = (float) (crouched ? 0 : offset.xCoord); + // Create rotation matrices for pitch and yaw + final Matrix4f pitchMatrix = new Matrix4f(), yawMatrix = new Matrix4f(); + + pitchMatrix.rotate(pitch, new Vector3f(1, 0, 0)); // modify axis of rotation + yawMatrix.rotate(-yaw, new Vector3f(0, 1, 0)); + + // Multiply matrices to get combined rotation matrix + final Matrix4f rotMatrix = Matrix4f.mul(yawMatrix, pitchMatrix, null); + // Create vector representing the offset and apply rotation + final Vector4f offsetVector = new Vector4f(oX, (float) offset.yCoord, (float) offset.zCoord, 1); // set fourth coordinate to 1 + Matrix4f.transform(rotMatrix, offsetVector, offsetVector); + final Vector3f result = new Vector3f(); // create result vector + result.set(offsetVector.x, offsetVector.y, offsetVector.z); // set result vector using transformed coordinates + // Apply rotation + casing.setPosition(casing.posX + result.x, casing.posY + result.y, casing.posZ + result.z); + } + + private static Vec3 rotateVector(Vec3 vector, float pitch, float yaw, float pitchFactor, float yawFactor) { + // Apply randomness to vector + vector.xCoord += rand.nextGaussian() * yawFactor; + vector.yCoord += rand.nextGaussian() * pitchFactor; + vector.zCoord += rand.nextGaussian() * yawFactor; + + final Matrix4f pitchMatrix = new Matrix4f(), yawMatrix = new Matrix4f(); + + pitchMatrix.setIdentity(); + pitchMatrix.rotate(-pitch, new Vector3f(1, 0, 0)); + + yawMatrix.setIdentity(); + yawMatrix.rotate(-yaw, new Vector3f(0, 1, 0)); + + final Vector4f vector4f = new Vector4f((float) vector.xCoord, (float) vector.yCoord, (float) vector.zCoord, 1); + + Matrix4f.transform(pitchMatrix, vector4f, vector4f); + Matrix4f.transform(yawMatrix, vector4f, vector4f); + + return Vec3.createVectorHelper(vector4f.x, vector4f.y, vector4f.z); + } + + public static CasingEjector fromId(int id) { + return mappings.get(id); + } + + @Override + public CasingEjector clone() throws CloneNotSupportedException { + return (CasingEjector) super.clone(); + } +} diff --git a/src/main/java/com/hbm/handler/GunConfiguration.java b/src/main/java/com/hbm/handler/GunConfiguration.java index 4efa68883..ab7fe8cca 100644 --- a/src/main/java/com/hbm/handler/GunConfiguration.java +++ b/src/main/java/com/hbm/handler/GunConfiguration.java @@ -5,7 +5,6 @@ import java.util.HashMap; import java.util.List; import com.hbm.lib.HbmCollection.EnumGunManufacturer; -import com.hbm.particle.SpentCasingConfig; import com.hbm.render.anim.BusAnimation; import com.hbm.render.anim.HbmAnimations.AnimType; import com.hbm.render.util.RenderScreenOverlay.Crosshair; @@ -78,7 +77,7 @@ public class GunConfiguration implements Cloneable { public Crosshair crosshair; //casing eject behavior - public SpentCasingConfig casingConfig = null; + public CasingEjector ejector = null; public static final int MODE_NORMAL = 0; public static final int MODE_RELEASE = 1; diff --git a/src/main/java/com/hbm/handler/guncfg/Gun12GaugeFactory.java b/src/main/java/com/hbm/handler/guncfg/Gun12GaugeFactory.java index 5ad09cde8..5cd57516b 100644 --- a/src/main/java/com/hbm/handler/guncfg/Gun12GaugeFactory.java +++ b/src/main/java/com/hbm/handler/guncfg/Gun12GaugeFactory.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import com.hbm.entity.projectile.EntityBulletBase; import com.hbm.handler.BulletConfigSyncingUtil; import com.hbm.handler.BulletConfiguration; +import com.hbm.handler.CasingEjector; import com.hbm.handler.GunConfiguration; import com.hbm.interfaces.IBulletHurtBehavior; import com.hbm.inventory.RecipesCommon.ComparableStack; @@ -12,9 +13,8 @@ import com.hbm.items.ItemAmmoEnums.Ammo12Gauge; import com.hbm.items.ModItems; import com.hbm.lib.HbmCollection; import com.hbm.lib.HbmCollection.EnumGunManufacturer; -import com.hbm.particle.SpentCasingConfig; -import com.hbm.particle.SpentCasingConfig.CasingType; -import com.hbm.particle.SpentCasingConfigBuilder; +import com.hbm.particle.SpentCasing; +import com.hbm.particle.SpentCasing.CasingType; import com.hbm.potion.HbmPotion; import com.hbm.render.anim.BusAnimation; import com.hbm.render.anim.BusAnimationKeyframe; @@ -29,32 +29,17 @@ import net.minecraft.util.Vec3; public class Gun12GaugeFactory { - static final SpentCasingConfig CASING_SPAS, CASING_SPAS_ALT, CASING_BENELLI, CASING_UBOINIK, CASING_SSG; + private static final CasingEjector CASING_SPAS, CASING_SPAS_ALT, CASING_BENELLI, CASING_UBOINIK, CASING_SSG; + private static final SpentCasing CASING12GAUGE; - static - { - final SpentCasingConfigBuilder CASING_12G_BUILDER = new SpentCasingConfigBuilder("", CasingType.SHOTGUN, false) - .setScaleX(1.5f).setScaleY(1.5f).setScaleZ(1.5f); - CASING_SPAS = CASING_12G_BUILDER.setRegistryName("spas12").setInitialMotion(Vec3.createVectorHelper(-0.4, 0.1, 0)) - .setPosOffset(Vec3.createVectorHelper(-0.35, 0, 0.5)).setPitchFactor(0.03f).setYawFactor(0.01f) - .setSmokeChance(0).setDelay(10) - .build(); - - CASING_SPAS_ALT = CASING_12G_BUILDER.setRegistryName("spas12alt").setCasingAmount(2) - .build(); - - CASING_BENELLI = CASING_12G_BUILDER.setRegistryName("benelli").setCasingAmount(1).setDelay(0) - .setInitialMotion(Vec3.createVectorHelper(-0.3, 1, 0)) - .build(); - - CASING_UBOINIK = CASING_12G_BUILDER.setRegistryName("uboinik").setOverrideColor(true) - .setBlueOverride(255).setPosOffset(Vec3.createVectorHelper(-0.35, -0.3, 0.5)) - .build(); - - CASING_SSG = CASING_12G_BUILDER.setRegistryName("ssg").setBlueOverride(0).setRedOverride(255).setCasingAmount(2) - .setPosOffset(Vec3.createVectorHelper(0.8, 0, 0)).setInitialMotion(Vec3.createVectorHelper(0.2, 0, -0.2)) - .setPitchFactor(0.05f).setYawFactor(0.02f) - .build(); + static { + CASING_SPAS = new CasingEjector().setMotion(Vec3.createVectorHelper(-0.4, 0.1, 0)).setOffset(Vec3.createVectorHelper(-0.35, 0, 0.5)).setAngleRange(0.01F, 0.03F).setDelay(10); + CASING_SPAS_ALT = new CasingEjector().setMotion(Vec3.createVectorHelper(-0.4, 0.1, 0)).setOffset(Vec3.createVectorHelper(-0.35, 0, 0.5)).setAngleRange(0.01F, 0.03F).setDelay(10).setAmount(2); + CASING_BENELLI = new CasingEjector().setMotion(Vec3.createVectorHelper(-0.4, 0.1, 0)).setOffset(Vec3.createVectorHelper(-0.3, 1, 0)).setAngleRange(0.01F, 0.03F); + CASING_UBOINIK = new CasingEjector().setMotion(Vec3.createVectorHelper(-0.4, 0.1, 0)).setOffset(Vec3.createVectorHelper(-0.35, -0.3, 0.5)).setAngleRange(0.01F, 0.03F); + CASING_SSG = new CasingEjector().setMotion(Vec3.createVectorHelper(0.2, 0, -0.2)).setOffset(Vec3.createVectorHelper(0.8, 0, 0)).setAngleRange(0.05F, 0.02F).setDelay(20).setAmount(2); + + CASING12GAUGE = new SpentCasing(CasingType.SHOTGUN).setScale(1.5F).setBounceMotion(0.05F, 0.02F); } public static GunConfiguration getSpas12Config() { @@ -98,12 +83,12 @@ public class Gun12GaugeFactory { ) ); - config.casingConfig = CASING_SPAS; + config.ejector = CASING_SPAS; return config; } -public static GunConfiguration getSpas12AltConfig() { + public static GunConfiguration getSpas12AltConfig() { GunConfiguration config = new GunConfiguration(); @@ -125,6 +110,8 @@ public static GunConfiguration getSpas12AltConfig() { config.config.add(BulletConfigSyncingUtil.G12_DU); config.config.add(BulletConfigSyncingUtil.G12_AM); config.config.add(BulletConfigSyncingUtil.G12_SLEEK); + + config.ejector = CASING_SPAS_ALT; return config; } @@ -152,6 +139,8 @@ public static GunConfiguration getSpas12AltConfig() { config.config = HbmCollection.twelveGauge; + config.ejector = CASING_UBOINIK; + return config; } @@ -203,6 +192,8 @@ public static GunConfiguration getSpas12AltConfig() { config.config = HbmCollection.twelveGauge; + config.ejector = CASING_SSG; + return config; } @@ -214,6 +205,8 @@ public static GunConfiguration getSpas12AltConfig() { bullet.dmgMin = 5; bullet.dmgMax = 7; + bullet.spentCasing = CASING12GAUGE.clone().register("12GaStock").setColor(0x2847FF, 0x757575); + return bullet; } @@ -227,6 +220,8 @@ public static GunConfiguration getSpas12AltConfig() { bullet.dmgMax = 7; bullet.incendiary = 5; + bullet.spentCasing = CASING12GAUGE.clone().register("12GaInc").setColor(0xFF6329, 0x757575); + return bullet; } @@ -242,6 +237,8 @@ public static GunConfiguration getSpas12AltConfig() { bullet.HBRC = 80; bullet.LBRC = 95; + bullet.spentCasing = CASING12GAUGE.clone().register("12GaShrap").setColor(0xF0E800, 0x757575); + return bullet; } @@ -256,6 +253,8 @@ public static GunConfiguration getSpas12AltConfig() { bullet.doesPenetrate = true; bullet.leadChance = 50; + bullet.spentCasing = CASING12GAUGE.clone().register("12GaDU").setColor(0x62A362, 0x757575); + return bullet; } @@ -280,6 +279,8 @@ public static GunConfiguration getSpas12AltConfig() { }; + bullet.spentCasing = CASING12GAUGE.clone().register("12GaAM").setColor(0x416645, 0x757575); + return bullet; } @@ -289,6 +290,8 @@ public static GunConfiguration getSpas12AltConfig() { bullet.ammo = new ComparableStack(ModItems.ammo_12gauge.stackFromEnum(Ammo12Gauge.SLEEK)); + bullet.spentCasing = CASING12GAUGE.clone().register("12GaIF").setColor(0x2A2A2A, 0x757575); + return bullet; } diff --git a/src/main/java/com/hbm/handler/guncfg/Gun20GaugeFactory.java b/src/main/java/com/hbm/handler/guncfg/Gun20GaugeFactory.java index fde72bcca..cd78761c4 100644 --- a/src/main/java/com/hbm/handler/guncfg/Gun20GaugeFactory.java +++ b/src/main/java/com/hbm/handler/guncfg/Gun20GaugeFactory.java @@ -3,12 +3,15 @@ package com.hbm.handler.guncfg; import java.util.ArrayList; import com.hbm.handler.BulletConfiguration; +import com.hbm.handler.CasingEjector; import com.hbm.handler.GunConfiguration; import com.hbm.inventory.RecipesCommon.ComparableStack; import com.hbm.items.ModItems; import com.hbm.items.ItemAmmoEnums.Ammo20Gauge; import com.hbm.lib.HbmCollection; import com.hbm.lib.HbmCollection.EnumGunManufacturer; +import com.hbm.particle.SpentCasing; +import com.hbm.particle.SpentCasing.CasingType; import com.hbm.render.anim.BusAnimation; import com.hbm.render.anim.BusAnimationKeyframe; import com.hbm.render.anim.BusAnimationSequence; @@ -17,9 +20,19 @@ import com.hbm.render.util.RenderScreenOverlay.Crosshair; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; +import net.minecraft.util.Vec3; public class Gun20GaugeFactory { + private static final CasingEjector CASING_LEVER; + private static final SpentCasing CASING20GAUGE; + + static { + CASING_LEVER = new CasingEjector().setMotion(Vec3.createVectorHelper(-0.4, 0.95, 0)).setOffset(Vec3.createVectorHelper(-0.55, 0, 0.5)).setAngleRange(0.01F, 0.05F); + + CASING20GAUGE = new SpentCasing(CasingType.SHOTGUN).setScale(1.25F).setBounceMotion(0.01F, 0.05F); + } + public static GunConfiguration getShotgunConfig() { GunConfiguration config = new GunConfiguration(); @@ -53,6 +66,8 @@ public class Gun20GaugeFactory { config.config = HbmCollection.twentyGauge; + config.ejector = CASING_LEVER; + return config; } @@ -206,6 +221,8 @@ public class Gun20GaugeFactory { bullet.dmgMin = 3; bullet.dmgMax = 5; + bullet.spentCasing = CASING20GAUGE.clone().register("20GaStock").setColor(0xB52B2B, 0xEBC35E); + return bullet; } @@ -219,6 +236,8 @@ public class Gun20GaugeFactory { bullet.wear = 7; bullet.style = BulletConfiguration.STYLE_NORMAL; + bullet.spentCasing = CASING20GAUGE.clone().register("20GaSlug").setColor(0x2A2A2A, 0xEBC35E); + return bullet; } @@ -234,6 +253,8 @@ public class Gun20GaugeFactory { bullet.HBRC = 2; bullet.LBRC = 95; + bullet.spentCasing = CASING20GAUGE.clone().register("20GaFlech").setColor(0x2847FF, 0xEBC35E); + return bullet; } @@ -247,6 +268,8 @@ public class Gun20GaugeFactory { bullet.wear = 15; bullet.incendiary = 5; + bullet.spentCasing = CASING20GAUGE.clone().register("20GaInc").setColor(0xFF6329, 0xEBC35E); + return bullet; } @@ -262,6 +285,8 @@ public class Gun20GaugeFactory { bullet.HBRC = 80; bullet.LBRC = 95; + bullet.spentCasing = CASING20GAUGE.clone().register("20GaShrap").setColor(0xF0E800, 0xEBC35E); + return bullet; } @@ -275,6 +300,8 @@ public class Gun20GaugeFactory { bullet.wear = 25; bullet.explosive = 0.5F; + bullet.spentCasing = CASING20GAUGE.clone().register("20GaExp").setColor(0xF0E800, 0xEBC35E); + return bullet; } @@ -294,6 +321,8 @@ public class Gun20GaugeFactory { bullet.effects = new ArrayList(); bullet.effects.add(new PotionEffect(Potion.poison.id, 10 * 20, 1)); + bullet.spentCasing = CASING20GAUGE.clone().register("20GaCaus").setColor(0x64E800, 0xEBC35E); + return bullet; } @@ -314,6 +343,8 @@ public class Gun20GaugeFactory { bullet.effects.add(new PotionEffect(Potion.moveSlowdown.id, 10 * 20, 1)); bullet.effects.add(new PotionEffect(Potion.weakness.id, 10 * 20, 4)); + bullet.spentCasing = CASING20GAUGE.clone().register("20GaShock").setColor(0x00EFEF, 0xEBC35E); + return bullet; } @@ -328,6 +359,8 @@ public class Gun20GaugeFactory { bullet.effects = new ArrayList(); bullet.effects.add(new PotionEffect(Potion.wither.id, 10 * 20, 2)); + bullet.spentCasing = CASING20GAUGE.clone().register("20GaWith").setColor(0x391717, 0xEBC35E); + return bullet; } @@ -337,6 +370,8 @@ public class Gun20GaugeFactory { bullet.ammo = new ComparableStack(ModItems.ammo_20gauge.stackFromEnum(Ammo20Gauge.SLEEK)); + bullet.spentCasing = CASING20GAUGE.clone().register("20GaIF").setColor(0x2A2A2A, 0xEBC35E); + return bullet; } diff --git a/src/main/java/com/hbm/items/weapon/ItemGunBase.java b/src/main/java/com/hbm/items/weapon/ItemGunBase.java index ef1b37507..ce01c2f66 100644 --- a/src/main/java/com/hbm/items/weapon/ItemGunBase.java +++ b/src/main/java/com/hbm/items/weapon/ItemGunBase.java @@ -8,6 +8,7 @@ import com.hbm.config.GeneralConfig; import com.hbm.entity.projectile.EntityBulletBase; import com.hbm.handler.BulletConfigSyncingUtil; import com.hbm.handler.BulletConfiguration; +import com.hbm.handler.CasingEjector; import com.hbm.handler.GunConfiguration; import com.hbm.handler.HbmKeybinds; import com.hbm.interfaces.IHoldableWeapon; @@ -19,7 +20,6 @@ import com.hbm.main.MainRegistry; import com.hbm.packet.GunAnimationPacket; import com.hbm.packet.GunButtonPacket; import com.hbm.packet.PacketDispatcher; -import com.hbm.particle.SpentCasingConfig; import com.hbm.render.anim.BusAnimation; import com.hbm.render.anim.HbmAnimations.AnimType; import com.hbm.render.util.RenderScreenOverlay; @@ -211,8 +211,8 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD, IEqu world.playSoundAtEntity(player, mainConfig.firingSound, 1.0F, mainConfig.firingPitch); - if(mainConfig.casingConfig != null && !mainConfig.casingConfig.isAfterReload()) - spawnCasing(player, mainConfig.casingConfig, stack); + if(mainConfig.ejector != null && !mainConfig.ejector.getAfterReload()) + trySpawnCasing(player, mainConfig.ejector, config, stack); } //unlike fire(), being called does not automatically imply success, some things may still have to be handled before spawning the projectile @@ -245,8 +245,8 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD, IEqu world.playSoundAtEntity(player, altConfig.firingSound, 1.0F, altConfig.firingPitch); - if(altConfig.casingConfig != null) - spawnCasing(player, altConfig.casingConfig, stack); + if(altConfig.ejector != null) + trySpawnCasing(player, altConfig.ejector, config, stack); } //spawns the actual projectile, can be overridden to change projectile entity @@ -297,6 +297,9 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD, IEqu } if(getReloadCycle(stack) <= 0) { + + + BulletConfiguration prevCfg = BulletConfigSyncingUtil.pullConfig(mainConfig.config.get(getMagType(stack))); if (getMag(stack) == 0) resetAmmoType(stack, world, player); @@ -327,8 +330,8 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD, IEqu if(hasLoaded && mainConfig.reloadSoundEnd) world.playSoundAtEntity(player, mainConfig.reloadSound, 1.0F, 1.0F); - if(mainConfig.casingConfig != null && mainConfig.casingConfig.isAfterReload()) - spawnCasing(player, mainConfig.casingConfig, stack); + if(mainConfig.ejector != null && mainConfig.ejector.getAfterReload()) + trySpawnCasing(player, mainConfig.ejector, prevCfg, stack); InventoryUtil.tryConsumeAStack(player.inventory.mainInventory, 0, player.inventory.mainInventory.length, ammo); } else { @@ -704,7 +707,12 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD, IEqu } } - protected static void spawnCasing(Entity entity, SpentCasingConfig config, ItemStack stack) { + protected static void trySpawnCasing(Entity entity, CasingEjector ejector, BulletConfiguration bullet, ItemStack stack) { + + if(ejector == null) return; //abort if the gun can't eject bullets at all + if(bullet == null) return; //abort if there's no valid bullet cfg + if(bullet.spentCasing == null) return; //abort if the bullet is caseless + NBTTagCompound data = new NBTTagCompound(); data.setString("type", "casing"); data.setDouble("posX", entity.posX); @@ -713,7 +721,9 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD, IEqu data.setFloat("pitch", (float) Math.toRadians(entity.rotationPitch)); data.setFloat("yaw", (float) Math.toRadians(entity.rotationYaw)); data.setBoolean("crouched", entity.isSneaking()); - data.setString("name", config.getRegistryName()); + data.setString("name", bullet.spentCasing.getName()); + data.setInteger("ej", ejector.getId()); + //TODO: use packets MainRegistry.proxy.effectNT(data); } } diff --git a/src/main/java/com/hbm/main/ClientProxy.java b/src/main/java/com/hbm/main/ClientProxy.java index 185e7955e..9bfd5e61a 100644 --- a/src/main/java/com/hbm/main/ClientProxy.java +++ b/src/main/java/com/hbm/main/ClientProxy.java @@ -58,6 +58,7 @@ import com.hbm.entity.mob.botprime.*; import com.hbm.entity.mob.siege.*; import com.hbm.entity.particle.*; import com.hbm.entity.projectile.*; +import com.hbm.handler.CasingEjector; import com.hbm.handler.HbmKeybinds; import com.hbm.handler.ImpactWorldHandler; import com.hbm.handler.HbmKeybinds.EnumKeybind; @@ -1791,9 +1792,14 @@ public class ClientProxy extends ServerProxy { } if("casing".equals(type)) { - SpentCasingConfig casingConfig = SpentCasingConfig.get(data.getString("name")); - for(int i = 0; i < casingConfig.getCasingAmount(); i++) - casingConfig.spawnCasing(man, world, x, y, z, data.getFloat("pitch"), data.getFloat("yaw"), data.getBoolean("crouched")); + CasingEjector ejector = CasingEjector.fromId(data.getInteger("ej")); + if(ejector == null) return; + SpentCasing casingConfig = SpentCasing.fromName((data.getString("name"))); + if(casingConfig == null) return; + + for(int i = 0; i < ejector.getAmount(); i++) { + ejector.spawnCasing(man, casingConfig, world, x, y, z, data.getFloat("pitch"), data.getFloat("yaw"), data.getBoolean("crouched")); + } } } diff --git a/src/main/java/com/hbm/particle/ParticleSpentCasing.java b/src/main/java/com/hbm/particle/ParticleSpentCasing.java index ced897913..17426c92d 100644 --- a/src/main/java/com/hbm/particle/ParticleSpentCasing.java +++ b/src/main/java/com/hbm/particle/ParticleSpentCasing.java @@ -2,6 +2,7 @@ package com.hbm.particle; import java.util.ArrayList; import java.util.List; +import java.util.Random; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -23,6 +24,7 @@ import net.minecraft.world.World; @SideOnly(Side.CLIENT) public class ParticleSpentCasing extends EntityFX { + public static final Random rand = new Random(); private static float dScale = 0.05F, smokeJitter = 0.025F, smokeAccel = 0.5F; private static byte maxSmokeGen = 60, maxSmokeLife = 120; @@ -30,14 +32,14 @@ public class ParticleSpentCasing extends EntityFX private final TextureManager textureManager; - private final SpentCasingConfig config; + private final SpentCasing config; private boolean smoke; private float momentumPitch, momentumYaw; private boolean onGroundPreviously = false; private double maxHeight; - public ParticleSpentCasing(TextureManager textureManager, World world, double x, double y, double z, double mx, double my, double mz, float momentumPitch, float momentumYaw, SpentCasingConfig config) { + public ParticleSpentCasing(TextureManager textureManager, World world, double x, double y, double z, double mx, double my, double mz, float momentumPitch, float momentumYaw, SpentCasing config) { super(world, x, y, z, 0, 0, 0); this.textureManager = textureManager; this.momentumPitch = momentumPitch; @@ -45,9 +47,7 @@ public class ParticleSpentCasing extends EntityFX this.config = config; particleMaxAge = 240; -// smoke = config.getSmokeChance() == 0 ? true -// : config.getSmokeChance() < 0 ? false -// : rand.nextInt(config.getSmokeChance()) == 0; + smoke = rand.nextFloat() < config.getSmokeChance(); motionX = mx; motionY = my; @@ -73,43 +73,37 @@ public class ParticleSpentCasing extends EntityFX if(!onGroundPreviously && onGround) tryPlayBounceSound(); - // TODO Bounce factor in config if(!onGroundPreviously && onGround) { onGroundPreviously = true; motionY = Math.log10(maxHeight - posY + 2); - momentumPitch = (float) rand.nextGaussian() * config.getPitchFactor(); - momentumYaw = (float) rand.nextGaussian() * config.getYawFactor(); + momentumPitch = (float) rand.nextGaussian() * config.getBouncePitch(); + momentumYaw = (float) rand.nextGaussian() * config.getBounceYaw(); maxHeight = posY; } else if(onGroundPreviously && !onGround) { onGroundPreviously = false; } -// if (particleAge > maxSmokeLife && !smokeNodes.isEmpty()) -// smokeNodes.clear(); + if (particleAge > maxSmokeLife && !smokeNodes.isEmpty()) + smokeNodes.clear(); -// if (smoke && particleAge <= maxSmokeLife) -// { -// final double side = (rotationYaw - prevRotationYaw) * 0.1D; -// final Vec3 prev = Vec3.createVectorHelper(motionX, motionY, motionZ); -// prev.rotateAroundY((float) Math.toRadians(rotationYaw)); -// -// for (Pair pair : smokeNodes) -// { -// final EasyLocation node = pair.getKey(); -// -// node.posX += prev.xCoord * smokeAccel + rand.nextGaussian() * smokeJitter + side; -// node.posY += prev.yCoord + smokeAccel; -// node.posZ += prev.zCoord * smokeAccel + rand.nextGaussian() * smokeJitter; -// } -// -// if (particleAge < maxSmokeGen || inWater) -// { -// final double alpha = (particleAge / 20d); -// smokeNodes.add(new Pair(EasyLocation.getZeroLocation(), alpha)); -// } -// } + if(smoke && particleAge <= maxSmokeLife) { + + //motion-based smoke changes were moved to rendering (to account for interp in realtime) + + for(Pair pair : smokeNodes) { + final Vec3 node = pair.getKey(); + + node.xCoord += rand.nextGaussian() * smokeJitter; + node.zCoord += rand.nextGaussian() * smokeJitter; + } + + if(particleAge < maxSmokeGen || inWater) { + final double alpha = (particleAge / 20d); + smokeNodes.add(new Pair(Vec3.createVectorHelper(0, 0, 0), alpha)); + } + } prevRotationPitch = rotationPitch; prevRotationYaw = rotationYaw; @@ -152,10 +146,11 @@ public class ParticleSpentCasing extends EntityFX GL11.glScalef(config.getScaleX(), config.getScaleY(), config.getScaleZ()); - if(config.doesOverrideColor()) - GL11.glColor3b((byte) config.getRedOverride(), (byte) config.getGreenOverride(), (byte) config.getBlueOverride()); - - ResourceManager.casings.renderPart(config.getCasingType().objName); + for(String name : config.getType().partNames) { + //TODO: set part color + ResourceManager.casings.renderPart(name); + } + GL11.glDisable(GL12.GL_RESCALE_NORMAL); /*if(!smokeNodes.isEmpty()) { @@ -202,8 +197,10 @@ public class ParticleSpentCasing extends EntityFX private void tryPlayBounceSound() { - if(!config.getBounceSound().isEmpty()) { - worldObj.playSoundAtEntity(this, config.getBounceSound(), 2, 1); + String sound = config.getSound(); + + if(sound != null && !sound.isEmpty()) { + worldObj.playSoundAtEntity(this, sound, 2, 1); } } } \ No newline at end of file diff --git a/src/main/java/com/hbm/particle/SpentCasing.java b/src/main/java/com/hbm/particle/SpentCasing.java new file mode 100644 index 000000000..f0ed9a7eb --- /dev/null +++ b/src/main/java/com/hbm/particle/SpentCasing.java @@ -0,0 +1,105 @@ +package com.hbm.particle; + +import java.util.HashMap; + +/** + * Definition for spent casing particles, what style and color they should use + * @author uffr, hbm + */ +public class SpentCasing implements Cloneable { + + public static final HashMap casingMap = new HashMap(); + + public enum CasingType { + BRASS_STRAIGHT_WALL("Straight"), + BRASS_BOTTLENECK("Bottleneck"), + SHOTGUN("Shotgun", "ShotgunBase"), //plastic shell, brass case + AR2("AR2", "AR2Highlight"); //plug, back detailing + + public final String[] partNames; + + private CasingType(String... names) { + this.partNames = names; + } + } + + private String registryName; + private float scaleX = 1F; + private float scaleY = 1F; + private float scaleZ = 1F; + private int[] colors; + private CasingType type; + private String bounceSound; + private float smokeChance; + private float bounceYaw = 0F; + private float bouncePitch = 0F; + + public SpentCasing(CasingType type) { + this.type = type; + } + + public SpentCasing register(String name) { + this.registryName = name; + casingMap.put(name, this); + return this; + } + + public SpentCasing setScale(float scale) { + this.scaleX = scale; + this.scaleY = scale; + this.scaleZ = scale; + return this; + } + + public SpentCasing setScale(float x, float y, float z) { + this.scaleX = x; + this.scaleY = y; + this.scaleZ = z; + return this; + } + + public SpentCasing setColor(int... color) { + this.colors = color; + return this; + } + + public SpentCasing setSound(String bounce) { + this.bounceSound = bounce; + return this; + } + + public SpentCasing setupSmoke(float chance, float lift, float duration) { + this.smokeChance = chance; + return this; + } + + public static SpentCasing fromName(String name) { + return casingMap.get(name); + } + + public SpentCasing setBounceMotion(float yaw, float pitch) { + this.bounceYaw = yaw; + this.bouncePitch = pitch; + return this; + } + + public String getName() { return this.registryName; } + public float getScaleX() { return this.scaleX; } + public float getScaleY() { return this.scaleY; } + public float getScaleZ() { return this.scaleZ; } + public int[] getColors() { return this.colors; } + public CasingType getType() { return this.type; } + public String getSound() { return this.bounceSound; } + public float getSmokeChance() { return this.smokeChance; } + public float getBounceYaw() { return this.bounceYaw; } + public float getBouncePitch() { return this.bouncePitch; } + + @Override + public SpentCasing clone() { + try { + return (SpentCasing) super.clone(); + } catch(CloneNotSupportedException e) { + return new SpentCasing(this.type); + } + } +} diff --git a/src/main/java/com/hbm/particle/SpentCasingConfig.java b/src/main/java/com/hbm/particle/SpentCasingConfig.java deleted file mode 100644 index 89f55b076..000000000 --- a/src/main/java/com/hbm/particle/SpentCasingConfig.java +++ /dev/null @@ -1,323 +0,0 @@ -package com.hbm.particle; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Random; - -import org.lwjgl.util.vector.Matrix4f; -import org.lwjgl.util.vector.Vector3f; -import org.lwjgl.util.vector.Vector4f; - -import com.google.common.annotations.Beta; -import com.google.common.collect.ImmutableMap; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.util.Vec3; -import net.minecraft.world.World; - -@Beta -public class SpentCasingConfig { - - private static final Map CONFIG_MAP = new HashMap(); - private static final Random RANDOM = new Random(); - - public enum CasingType { - BRASS_STRAIGHT_WALL("Straight"), - BRASS_BOTTLENECK("Bottleneck"), - SHOTGUN("Shotgun"), - AR2("AR2"); - - public final String objName; - - private CasingType(String objName) { - this.objName = objName; - } - } - - /**Unique name used for map lookup.**/ - private final String registryName; - /**Change position of the ejecting shell.**/ - private final Vec3 posOffset; - /**Set initial motion after ejecting.**/ - private final Vec3 initialMotion; - /**Multipliers for random pitch and yaw.**/ - private final float pitchFactor, yawFactor; - /**Rescale the sprite to match the approximate scale of the rounds.**/ - private final float scaleX, scaleY, scaleZ; - /**Overrides for the sprite colors.**/ - private final int redOverride, greenOverride, blueOverride; - /**Whether or not to override the default sprite color scheme.**/ - private final boolean overrideColor; - /**The type of casing.**/ - private final CasingType casingType; - /**Amount of casings to spawn per event. Default 1.**/ - private final byte casingAmount; - /**If the casing(s) should be spawned after reloading, instead of after firing.**/ - private final boolean afterReload; - /**Sound effect for bouncing. Make empty string to have no sound.**/ - private final String bounceSound; - /**Delay before casings are actually spawned**/ - private final byte delay; - /**Chance for the casing to emit smoke. 0 for 100% chance and -1 for it to never make smoke.**/ - private final byte smokeChance; - // TODO Setting to disregard crouch effect and/or another offset specifically for crouching which can be set to null to use the default one - public SpentCasingConfig( - String registryName, Vec3 posOffset, Vec3 initialMotion, float pitchFactor, float yawFactor, - float scaleX, float scaleY, float scaleZ, int redOverride, int greenOverride, int blueOverride, - boolean overrideColor, CasingType casingType, byte casingAmount, boolean afterReload, String bounceSound, - byte delay, byte smokeChance) { - - this.registryName = registryName; - this.posOffset = posOffset; - this.initialMotion = initialMotion; - this.pitchFactor = pitchFactor; - this.yawFactor = yawFactor; - this.scaleX = scaleX; - this.scaleY = scaleY; - this.scaleZ = scaleZ; - this.redOverride = redOverride; - this.greenOverride = greenOverride; - this.blueOverride = blueOverride; - this.overrideColor = overrideColor; - this.casingType = casingType; - this.casingAmount = casingAmount; - this.afterReload = afterReload; - this.bounceSound = bounceSound; - this.delay = delay; - this.smokeChance = smokeChance; - - CONFIG_MAP.put(registryName, this); - } - - public void spawnCasing(TextureManager textureManager, World world, double x, double y, double z, float pitch, float yaw, boolean crouched) { - Vec3 rotatedMotionVec = rotateVector(getInitialMotion(), - pitch + (float) RANDOM.nextGaussian() * getPitchFactor(), yaw + (float) RANDOM.nextGaussian() * getPitchFactor(), - getPitchFactor(), getPitchFactor()); - - ParticleSpentCasing casing = new ParticleSpentCasing(textureManager, world, x, - y, z, rotatedMotionVec.xCoord, rotatedMotionVec.yCoord, rotatedMotionVec.zCoord, -// 0, 0, - (float) (getPitchFactor() * RANDOM.nextGaussian()), (float) (getYawFactor() * RANDOM.nextGaussian()), - this); - - offsetCasing(casing, getPosOffset(), pitch, yaw, crouched); - - casing.rotationPitch = (float) Math.toDegrees(pitch); - casing.rotationYaw = (float) Math.toDegrees(yaw); - - if(overrideColor) - casing.setRBGColorF(redOverride / 255f, blueOverride / 255f, greenOverride / 255f); - Minecraft.getMinecraft().effectRenderer.addEffect(casing); - } - - // Rotate a position - private static void offsetCasing(ParticleSpentCasing casing, Vec3 offset, float pitch, float yaw, boolean crouched) - { -// // x-axis offset, 0 if crouched to center -// final double oX = crouched ? 0 : offset.posX(); -// // Trigonometric operations, saved for convenience -// final double sinP = Math.sin(pitch), cosP = Math.cos(pitch), sinY = Math.sin(yaw), cosY = Math.cos(yaw); -// // New offsets -// final double newX = oX * cosY - offset.posZ() * sinY, -// newY = offset.posY() * cosP - sinP * (oX * sinY + offset.posZ() * cosY), -// newZ = offset.posZ() * sinP + cosP * (oX * sinY + offset.posZ() * cosY); -// -// // Apply -// casing.setPosition(casing.posX + newX, casing.posY + newY, casing.posZ + newZ); - - // x-axis offset, 0 if crouched to center - final float oX = (float) (crouched ? 0 : offset.xCoord); - // Create rotation matrices for pitch and yaw - final Matrix4f pitchMatrix = new Matrix4f(), yawMatrix = new Matrix4f(); - - pitchMatrix.rotate(pitch, new Vector3f(1, 0, 0)); // modify axis of rotation - yawMatrix.rotate(-yaw, new Vector3f(0, 1, 0)); - - // Multiply matrices to get combined rotation matrix - final Matrix4f rotMatrix = Matrix4f.mul(yawMatrix, pitchMatrix, null); - // Create vector representing the offset and apply rotation - final Vector4f offsetVector = new Vector4f(oX, (float) offset.yCoord, (float) offset.zCoord, 1); // set fourth coordinate to 1 - Matrix4f.transform(rotMatrix, offsetVector, offsetVector); - final Vector3f result = new Vector3f(); // create result vector - result.set(offsetVector.x, offsetVector.y, offsetVector.z); // set result vector using transformed coordinates - // Apply rotation - casing.setPosition(casing.posX + result.x, casing.posY + result.y, casing.posZ + result.z); - } - -// Rotate a vector - private static Vec3 rotateVector(Vec3 vector, float pitch, float yaw, float pitchFactor, float yawFactor) - { - // Apply randomness to vector - vector.xCoord += RANDOM.nextGaussian() * yawFactor; - vector.yCoord += RANDOM.nextGaussian() * pitchFactor; - vector.zCoord += RANDOM.nextGaussian() * yawFactor; - - final Matrix4f pitchMatrix = new Matrix4f(), yawMatrix = new Matrix4f(); - - pitchMatrix.setIdentity(); - pitchMatrix.rotate(-pitch, new Vector3f(1, 0, 0)); - - yawMatrix.setIdentity(); - yawMatrix.rotate(-yaw, new Vector3f(0, 1, 0)); - - final Vector4f vector4f = new Vector4f((float) vector.xCoord, (float) vector.yCoord, (float) vector.zCoord, 1); - - Matrix4f.transform(pitchMatrix, vector4f, vector4f); - Matrix4f.transform(yawMatrix, vector4f, vector4f); - - return Vec3.createVectorHelper(vector4f.x, vector4f.y, vector4f.z); - } - - public Vec3 getPosOffset() - { - return posOffset; - } - public Vec3 getInitialMotion() - { - return Vec3.createVectorHelper(initialMotion.xCoord, initialMotion.yCoord, initialMotion.zCoord); - } - public float getScaleX() - { - return scaleX; - } - public float getScaleY() - { - return scaleY; - } - public float getScaleZ() - { - return scaleZ; - } - public float getPitchFactor() - { - return pitchFactor; - } - public float getYawFactor() - { - return yawFactor; - } - public int getRedOverride() - { - return redOverride; - } - public int getGreenOverride() - { - return greenOverride; - } - public int getBlueOverride() - { - return blueOverride; - } - public boolean doesOverrideColor() - { - return overrideColor; - } - public CasingType getCasingType() - { - return casingType; - } - public byte getCasingAmount() - { - return casingAmount; - } - public boolean isAfterReload() - { - return afterReload; - } - public String getRegistryName() - { - return registryName; - } - public String getBounceSound() - { - return bounceSound; - } - public byte getDelay() - { - return delay; - } - public byte getSmokeChance() - { - return smokeChance; - } - - /** - * Convert to a new builder for modification. - * @param newName The new registry name. - * @return A new builder with all the settings inherited from this config, except for registry name. - */ - public SpentCasingConfigBuilder toBuilder(String newName) - { - final SpentCasingConfigBuilder builder = new SpentCasingConfigBuilder(newName, casingType, overrideColor); - builder.setAfterReload(afterReload).setBlueOverride(blueOverride).setBounceSound(bounceSound).setCasingAmount(casingAmount) - .setDelay(delay).setGreenOverride(greenOverride).setInitialMotion(getInitialMotion()).setPitchFactor(pitchFactor) - .setPosOffset(getPosOffset()).setRedOverride(redOverride).setScaleX(scaleX).setScaleY(scaleY).setScaleZ(scaleZ) - .setSmokeChance(smokeChance).setYawFactor(yawFactor); - return builder; - } - - @Override - public int hashCode() - { - return Objects.hash(afterReload, blueOverride, bounceSound, casingAmount, casingType, delay, greenOverride, - initialMotion.xCoord, initialMotion.yCoord, initialMotion.zCoord, overrideColor, pitchFactor, - posOffset, redOverride, registryName, scaleX, scaleY, scaleZ, smokeChance, yawFactor); - } - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (!(obj instanceof SpentCasingConfig)) - return false; - final SpentCasingConfig other = (SpentCasingConfig) obj; - return afterReload == other.afterReload && blueOverride == other.blueOverride - && Objects.equals(bounceSound, other.bounceSound) && casingAmount == other.casingAmount - && casingType == other.casingType && delay == other.delay && greenOverride == other.greenOverride - && Double.doubleToLongBits(initialMotion.xCoord) == Double.doubleToLongBits(other.initialMotion.xCoord) - && Double.doubleToLongBits(initialMotion.yCoord) == Double.doubleToLongBits(other.initialMotion.yCoord) - && Double.doubleToLongBits(initialMotion.zCoord) == Double.doubleToLongBits(other.initialMotion.zCoord) - && overrideColor == other.overrideColor - && Float.floatToIntBits(pitchFactor) == Float.floatToIntBits(other.pitchFactor) - && Objects.equals(posOffset, other.posOffset) && redOverride == other.redOverride - && Objects.equals(registryName, other.registryName) - && Float.floatToIntBits(scaleX) == Float.floatToIntBits(other.scaleX) - && Float.floatToIntBits(scaleY) == Float.floatToIntBits(other.scaleY) - && Float.floatToIntBits(scaleZ) == Float.floatToIntBits(other.scaleZ) - && smokeChance == other.smokeChance - && Float.floatToIntBits(yawFactor) == Float.floatToIntBits(other.yawFactor); - } - @Override - public String toString() - { - final StringBuilder builder = new StringBuilder(); - builder.append("SpentCasingConfig [registryName=").append(registryName).append(", posOffset=").append(posOffset) - .append(", initialMotion=").append(initialMotion).append(", pitchFactor=").append(pitchFactor) - .append(", yawFactor=").append(yawFactor).append(", scaleX=").append(scaleX).append(", scaleY=") - .append(scaleY).append(", scaleZ=").append(scaleZ).append(", redOverride=").append(redOverride) - .append(", greenOverride=").append(greenOverride).append(", blueOverride=").append(blueOverride) - .append(", overrideColor=").append(overrideColor).append(", casingType=").append(casingType) - .append(", casingAmount=").append(casingAmount).append(", afterReload=").append(afterReload) - .append(", bounceSound=").append(bounceSound).append(", delay=").append(delay).append(", smokeChance=") - .append(smokeChance).append("]"); - return builder.toString(); - } - - public static boolean containsKey(String key) - { - return CONFIG_MAP.containsKey(key); - } - - public static SpentCasingConfig get(String key) - { - return CONFIG_MAP.get(key); - } - - public static Map getConfigMap() - { - return ImmutableMap.copyOf(CONFIG_MAP); - } - -} \ No newline at end of file diff --git a/src/main/java/com/hbm/particle/SpentCasingConfigBuilder.java b/src/main/java/com/hbm/particle/SpentCasingConfigBuilder.java deleted file mode 100644 index 67c30cad9..000000000 --- a/src/main/java/com/hbm/particle/SpentCasingConfigBuilder.java +++ /dev/null @@ -1,377 +0,0 @@ -package com.hbm.particle; - -import java.util.Objects; - -import com.google.common.annotations.Beta; -import com.hbm.main.MainRegistry; -import com.hbm.particle.SpentCasingConfig.CasingType; - -import net.minecraft.util.MathHelper; -import net.minecraft.util.Vec3; - -@Beta -public class SpentCasingConfigBuilder implements Cloneable -{ - /**Unique name used for map lookup.**/ - private String registryName; - /**Change position of the ejecting shell.**/ - private Vec3 posOffset = Vec3.createVectorHelper(0, 0, 0); - /**Set initial motion after ejecting.**/ - private Vec3 initialMotion = Vec3.createVectorHelper(0, 0, 0); - /**Multipliers for random pitch and yaw.**/ - private float pitchFactor, yawFactor; - /**Rescale the sprite to match the approximate scale of the rounds.**/ - private float scaleX = 1, scaleY = 1, scaleZ = 1; - /**Overrides for the sprite colors.**/ - private int redOverride, greenOverride, blueOverride; - /**Whether or not to override the default sprite color scheme.**/ - private boolean overrideColor; - /**The type of casing.**/ - private CasingType casingType = CasingType.BRASS_STRAIGHT_WALL; - /**Amount of casings to spawn per event. Default 1.**/ - private byte casingAmount = 1; - /**If the casing(s) should be spawned after reloading, instead of after firing.**/ - private boolean afterReload; - /**Sound effect for bouncing. Make empty string to have no sound.**/ - private String bounceSound = ""; - /**Delay before casings are actually spawned**/ - private byte delay; - /**Chance for the casing to emit smoke. 0 for 100% chance and -1 for it to never make smoke.**/ - private byte smokeChance = -1; - // TODO Setting to disregard crouch effect and/or another offset specifically for crouching which can be set to null to use the default one - /** - * Constructor with fields for the required bare minimum parameters.
- * All parameters may overridden using setters at any time at your discretion, however. - * @param registryName The unique name for map lookup. Null not permitted, becomes empty string. - * @param casingType Type of casing model to use. Null not permitted, defaults to straight wall type. - * @param overrideColor Whether or not the config will override the model texture's color. - */ - public SpentCasingConfigBuilder(String registryName, CasingType casingType, boolean overrideColor) { - this.registryName = registryName == null ? "" : registryName; - this.casingType = casingType == null ? CasingType.BRASS_STRAIGHT_WALL : casingType; - this.overrideColor = overrideColor; - } - - public Vec3 getPosOffset() { - return posOffset; - } - - /** - * Set the relative x, y, z coordinate offset on spawn. - * @param posOffset Any ILocationProvider that serves as the offset. Null becomes a zero location. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setPosOffset(Vec3 posOffset) { - this.posOffset = posOffset == null ? Vec3.createVectorHelper(0, 0, 0) : posOffset; - return this; - } - - public Vec3 getInitialMotion() { - return initialMotion; - } - - /** - * Sets the casing's initial relative x, y, z motion on spawn. - * @param initialMotion Vector representing the initial motion. Null becomes a zero vector. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setInitialMotion(Vec3 initialMotion) { - this.initialMotion = initialMotion == null ? Vec3.createVectorHelper(0, 0, 0) : initialMotion; - return this; - } - - public double getScaleX() { - return scaleX; - } - - /** - * Scale of the model on its x-axis. - * @param scaleX The scale/stretch factor of the model on the x-axis. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setScaleX(float scaleX) { - this.scaleX = scaleX; - return this; - } - - public double getScaleY() { - return scaleY; - } - - /** - * Scale of the model on its y-axis. - * @param scaleY The scale/stretch factor of the model on the y-axis. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setScaleY(float scaleY) { - this.scaleY = scaleY; - return this; - } - - public float getScaleZ() { - return scaleZ; - } - - /** - * Scale of the model on its z-axis. - * @param scaleZ The scale/stretch of the model on the z-axis. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setScaleZ(float scaleZ) { - this.scaleZ = scaleZ; - return this; - } - - public float getPitchFactor() { - return pitchFactor; - } - - /** - * Multiplier for random pitch-related motion. Recommended to keep in the thousanths (0.00X), as even with the hundreths (0.0X) the pitch can get crazy at times. - * @param pitchFactor The multiplier. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setPitchFactor(float pitchFactor) { - this.pitchFactor = pitchFactor; - return this; - } - - public float getYawFactor() { - return yawFactor; - } - - /** - * Multiplier for random yaw-related motion. Recommended to keep in the thousanths (0.00X), as even with the hundreths (0.0X) the yaw can get crazy at times. - * @param yawFactor The multiplier. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setYawFactor(float yawFactor) { - this.yawFactor = yawFactor; - return this; - } - - public int getRedOverride() { - return redOverride; - } - - /** - * Red color override. Clamped between 0-255, but I don't know how it actually works on the receiving end, so feel free to change. - * @param redOverride Red color override. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setRedOverride(int redOverride) { - this.redOverride = MathHelper.clamp_int(redOverride, 0, 255); - return this; - } - - public int getGreenOverride() { - return greenOverride; - } - - /** - * Green color override. Clamped between 0-255, but I don't know how it actually works on the receiving end, so feel free to change. - * @param greenOverride Green color override. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setGreenOverride(int greenOverride) { - this.greenOverride = MathHelper.clamp_int(greenOverride, 0, 255); - return this; - } - - public int getBlueOverride() { - return blueOverride; - } - - /** - * Blue color override. Clamped between 0-255, but I don't know how it actually works on the receiving end, so feel free to change. - * @param blueOverride Blue color override. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setBlueOverride(int blueOverride) { - this.blueOverride = MathHelper.clamp_int(blueOverride, 0, 255); - return this; - } - - public boolean doesOverrideColor() { - return overrideColor; - } - - /** - * Sets whether or not the config will override color. If false, the integer overrides will be ignored. - * @param overrideColor True, to use the integer color overrides, false to ignore them. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setOverrideColor(boolean overrideColor) { - this.overrideColor = overrideColor; - return this; - } - - public CasingType getCasingType() { - return casingType; - } - - /** - * Sets the model the casing will use. - * @param casingType One of the 4 casing model types. Null is not permitted, will have no effect. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setCasingType(CasingType casingType) { - this.casingType = casingType == null ? this.casingType : casingType; - return this; - } - - public byte getCasingAmount() { - return casingAmount; - } - - /** - * Sets the amount of casings to spawn. Default is 1. - * @param casingAmount Amount of casings to spawn. Clamped to a positive byte (0 - 127). - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setCasingAmount(int casingAmount) { - this.casingAmount = (byte) MathHelper.clamp_int(casingAmount, 0, 127); - return this; - } - - public boolean isAfterReload() { - return afterReload; - } - - /** - * Sets whether or not the casing will be spawned after reloading is done or after firing. - * @param afterReload If true, casings will be spawned when reloading, false, they will be spawned after firing. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setAfterReload(boolean afterReload) { - this.afterReload = afterReload; - return this; - } - - public String getRegistryName() { - return registryName; - } - - /** - * Resets the unique name for the config used in map lookup.
- * As the real class is self-registering, make sure to set this in reused builders. - * @param registryName The registry name to use. Null is not permitted, becomes an empty string. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setRegistryName(String registryName) { - this.registryName = registryName == null ? "" : registryName; - return this; - } - - public String getBounceSound() { - return bounceSound; - } - - /** - * The sound used when bouncing. If empty, no sound will be made. - * @param bounceSound The sound path. Null is not permitted, becomes an empty string. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setBounceSound(String bounceSound) { - this.bounceSound = bounceSound == null ? "" : bounceSound; - return this; - } - - public byte getDelay() { - return delay; - } - - /** - * The delay in ticks before spawning. - * @param delay Tick spawn delay. Must be nonnegative, otherwise 0. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setDelay(int delay) { - this.delay = (byte) (delay < 0 ? 0 : delay); - return this; - } - - public byte getSmokeChance() { - return smokeChance; - } - - /** - * Chance for the casing to emit smoke. 0 for 100% chance and -1 for it to never make smoke. - * @param smokeChance Chance to emit smoke. Clamped to a byte. - * @return Itself for chaining. - */ - public SpentCasingConfigBuilder setSmokeChance(int smokeChance) { - this.smokeChance = (byte) smokeChance; - return this; - } - - /** - * Constructs the true immutable config with all settings loaded from this builder.
- * This builder may be reused as all non-immutable and primitive fields are copied before being passed to the constructor.
- * The config's constructor is self-registering. - * @return The finished config with its settings specified by this builder. - */ - public SpentCasingConfig build() { - return new SpentCasingConfig(registryName, Vec3.createVectorHelper(posOffset.xCoord, posOffset.yCoord, posOffset.zCoord), - Vec3.createVectorHelper(initialMotion.xCoord, initialMotion.yCoord, initialMotion.zCoord), pitchFactor, - yawFactor, scaleX, scaleY, scaleZ, redOverride, greenOverride, blueOverride, overrideColor, casingType, - casingAmount, afterReload, bounceSound, delay, smokeChance); - } - - @Override - public int hashCode() { - return Objects.hash(afterReload, blueOverride, bounceSound, casingAmount, casingType, delay, greenOverride, - initialMotion.xCoord, initialMotion.yCoord, initialMotion.zCoord, overrideColor, pitchFactor, - posOffset, redOverride, registryName, scaleX, scaleY, scaleZ, smokeChance, yawFactor); - } - - @Override - public boolean equals(Object obj) { - - if(this == obj) return true; - if(!(obj instanceof SpentCasingConfigBuilder)) return false; - - SpentCasingConfigBuilder other = (SpentCasingConfigBuilder) obj; - return afterReload == other.afterReload && blueOverride == other.blueOverride - && Objects.equals(bounceSound, other.bounceSound) && casingAmount == other.casingAmount - && casingType == other.casingType && delay == other.delay && greenOverride == other.greenOverride - && Double.doubleToLongBits(initialMotion.xCoord) == Double.doubleToLongBits(other.initialMotion.xCoord) - && Double.doubleToLongBits(initialMotion.yCoord) == Double.doubleToLongBits(other.initialMotion.yCoord) - && Double.doubleToLongBits(initialMotion.zCoord) == Double.doubleToLongBits(other.initialMotion.zCoord) - && overrideColor == other.overrideColor - && Float.floatToIntBits(pitchFactor) == Float.floatToIntBits(other.pitchFactor) - && Objects.equals(posOffset, other.posOffset) && redOverride == other.redOverride - && Objects.equals(registryName, other.registryName) - && Float.floatToIntBits(scaleX) == Float.floatToIntBits(other.scaleX) - && Float.floatToIntBits(scaleY) == Float.floatToIntBits(other.scaleY) - && Float.floatToIntBits(scaleZ) == Float.floatToIntBits(other.scaleZ) - && smokeChance == other.smokeChance - && Float.floatToIntBits(yawFactor) == Float.floatToIntBits(other.yawFactor); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("SpentCasingConfigBuilder [registryName=").append(registryName).append(", posOffset=") - .append(posOffset).append(", initialMotion=").append(initialMotion).append(", pitchFactor=") - .append(pitchFactor).append(", yawFactor=").append(yawFactor).append(", scaleX=").append(scaleX) - .append(", scaleY=").append(scaleY).append(", scaleZ=").append(scaleZ).append(", redOverride=") - .append(redOverride).append(", greenOverride=").append(greenOverride).append(", blueOverride=") - .append(blueOverride).append(", overrideColor=").append(overrideColor).append(", casingType=") - .append(casingType).append(", casingAmount=").append(casingAmount).append(", afterReload=") - .append(afterReload).append(", bounceSound=").append(bounceSound).append(", delay=").append(delay) - .append(", smokeChance=").append(smokeChance).append(']'); - return builder.toString(); - } - - @Override - public SpentCasingConfigBuilder clone() { - try { - return (SpentCasingConfigBuilder) super.clone(); - } catch(CloneNotSupportedException e) { - MainRegistry.logger.catching(e); - return new SpentCasingConfigBuilder(registryName, casingType, overrideColor); - } - } - -} \ No newline at end of file