That's one heck of a commit you've got there...
I may have got a bit behind with version control. A lot behind, in fact. Maybe I'll go back and split this sometime - then again, I probably won't. But hey, at least it's here!
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class ParticleBeam extends ParticleTargeted {
|
||||
|
||||
@@ -17,10 +16,15 @@ public class ParticleBeam extends ParticleTargeted {
|
||||
public ParticleBeam(World world, double x, double y, double z){
|
||||
super(world, x, y, z); // Does not have a texture!
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
this.setMaxAge(1);
|
||||
this.setMaxAge(0);
|
||||
this.particleScale = 1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFXLayer(){
|
||||
return 3;
|
||||
@@ -31,7 +35,7 @@ public class ParticleBeam extends ParticleTargeted {
|
||||
|
||||
float scale = this.particleScale;
|
||||
|
||||
if(this.particleMaxAge > 1){
|
||||
if(this.particleMaxAge > 0){
|
||||
float ageFraction = (particleAge + partialTicks - 1)/particleMaxAge;
|
||||
// Squaring this makes it look smoother than a linear shrinking effect
|
||||
scale = this.particleScale * (1 - ageFraction*ageFraction);
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleBuff extends ParticleWizardry {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png");
|
||||
@@ -28,13 +20,19 @@ public class ParticleBuff extends ParticleWizardry {
|
||||
|
||||
public ParticleBuff(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.setVelocity(0, 0.27, 0); // Approximately what it was before
|
||||
this.mirror = world.rand.nextBoolean();
|
||||
this.setVelocity(0, 0.162, 0); // Approximately what it was before
|
||||
this.mirror = random.nextBoolean();
|
||||
this.setMaxAge(15);
|
||||
this.setGravity(false);
|
||||
this.canCollide = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
super.onUpdate();
|
||||
@@ -59,14 +57,13 @@ public class ParticleBuff extends ParticleWizardry {
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ,
|
||||
float rotationYZ, float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushAttrib();
|
||||
|
||||
float scale = 0.6f;
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
if(mirror) GlStateManager.scale(-1, 1, 1);
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableAlpha();
|
||||
GlStateManager.disableCull();
|
||||
@@ -94,31 +91,29 @@ public class ParticleBuff extends ParticleWizardry {
|
||||
|
||||
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
// I'm pretty sure these were always static.
|
||||
Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks;
|
||||
Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks;
|
||||
Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks;
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
|
||||
|
||||
|
||||
// Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime
|
||||
float f = 0.875f - 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f);
|
||||
float g = f + 0.125f;
|
||||
float hrepeat = 1;
|
||||
float yScale = 0.7f;
|
||||
float scale = 0.6f;
|
||||
float yScale = 0.7f * scale;
|
||||
float dx = mirror ? -scale : scale;
|
||||
float dz = scale;
|
||||
|
||||
buffer.pos(x-1, y-yScale, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y-yScale, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y-yScale, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y-yScale, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y-yScale, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-dx, y-yScale, z-dz).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-dx, y+yScale, z-dz).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+dx, y-yScale, z-dz).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+dx, y+yScale, z-dz).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+dx, y-yScale, z+dz).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+dx, y+yScale, z+dz).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-dx, y-yScale, z+dz).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-dx, y+yScale, z+dz).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-dx, y-yScale, z-dz).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-dx, y+yScale, z-dz).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
|
||||
Tessellator.getInstance().draw();
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@ package electroblob.wizardry.client.particle;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleDarkMagic extends ParticleWizardry {
|
||||
|
||||
/** Base spell texture index */
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleDust extends ParticleWizardry {
|
||||
|
||||
public ParticleDust(World world, double x, double y, double z){
|
||||
@@ -24,7 +22,7 @@ public class ParticleDust extends ParticleWizardry {
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
// this.moveEntity(this.motionX, this.motionY, this.motionZ);
|
||||
this.move(this.motionX, this.motionY, this.motionZ);
|
||||
|
||||
if(this.particleMaxAge-- <= 0){
|
||||
this.setExpired();
|
||||
|
||||
@@ -19,10 +19,15 @@ public class ParticleFlash extends ParticleWizardry {
|
||||
this.particleScale = 0.6f; // 7.1f is the value used in fireworks
|
||||
this.particleMaxAge = 6;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
|
||||
float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * (float)Math.PI);
|
||||
public boolean shouldDisableDepth(){
|
||||
return true; // Well this fixes everything... let's hope it doesn't cause any side-effects!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
|
||||
float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * (float)Math.PI);
|
||||
this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * 0.5F);
|
||||
float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
|
||||
float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
|
||||
@@ -34,7 +39,7 @@ public class ParticleFlash extends ParticleWizardry {
|
||||
buffer.pos((double)(f5 - rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 - rotationYZ * f4 + rotationXZ * f4)).tex(0.5D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos((double)(f5 + rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 + rotationYZ * f4 + rotationXZ * f4)).tex(0.25D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos((double)(f5 + rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 + rotationYZ * f4 - rotationXZ * f4)).tex(0.25D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightnessForRender(float partialTicks){
|
||||
|
||||
@@ -6,9 +6,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleIce extends ParticleWizardry {
|
||||
|
||||
|
||||
@@ -6,9 +6,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleLeaf extends ParticleWizardry {
|
||||
|
||||
@@ -24,7 +23,7 @@ public class ParticleLeaf extends ParticleWizardry {
|
||||
this.particleGravity = 0;
|
||||
this.canCollide = true;
|
||||
// Produces a variety of browns and greens
|
||||
this.setRBGColorF(0.1f + 0.3f * world.rand.nextFloat(), 0.5f + 0.3f * world.rand.nextFloat(), 0.1f);
|
||||
this.setRBGColorF(0.1f + 0.3f * random.nextFloat(), 0.5f + 0.3f * random.nextFloat(), 0.1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class ParticleLightning extends ParticleTargeted {
|
||||
|
||||
@@ -28,10 +25,6 @@ public class ParticleLightning extends ParticleTargeted {
|
||||
/** Number of ticks to wait before the arc changes shape again. */
|
||||
private static final int UPDATE_PERIOD = 1;
|
||||
|
||||
/** A random long value used by the renderer as a seed to generate its vertices from, ensuring they remain the same
|
||||
* across multiple frames. Not synced. */
|
||||
public final long seed;
|
||||
|
||||
public ParticleLightning(World world, double x, double y, double z){
|
||||
super(world, x, y, z); // Does not have a texture!
|
||||
seed = this.rand.nextLong();
|
||||
@@ -39,7 +32,12 @@ public class ParticleLightning extends ParticleTargeted {
|
||||
this.setMaxAge(3);
|
||||
this.particleScale = 1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFXLayer(){
|
||||
return 3;
|
||||
@@ -67,7 +65,7 @@ public class ParticleLightning extends ParticleTargeted {
|
||||
// Creates a random from the arc's seed field + the number of ticks it has existed/the update period.
|
||||
// By using a seed, we can ensure the vertex positions and forks are identical a) for each layer, even
|
||||
// though they are rendered sequentially, and b) across many frames (and ticks, if updateTime > 1).
|
||||
Random random = new Random(this.seed + this.particleAge/UPDATE_PERIOD);
|
||||
random.setSeed(this.seed + this.particleAge/UPDATE_PERIOD);
|
||||
|
||||
// numberOfSegments-1 because the last segment is handled separately.
|
||||
for(int i=0; i<numberOfSegments-1; i++){
|
||||
|
||||
@@ -6,9 +6,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleLightningPulse extends ParticleWizardry {
|
||||
|
||||
@@ -27,7 +26,12 @@ public class ParticleLightningPulse extends ParticleWizardry {
|
||||
this.pitch = 90;
|
||||
this.yaw = 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
for(ResourceLocation texture : TEXTURES){
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleMagicBubble extends ParticleWizardry {
|
||||
|
||||
public ParticleMagicBubble(World world, double x, double y, double z){
|
||||
|
||||
@@ -1,46 +1,36 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleMagicFlame extends ParticleWizardry {
|
||||
|
||||
/** The scale of the flame particle */
|
||||
private float flameScale;
|
||||
// 4 different animation strips, 8 frames in each strip
|
||||
private static final ResourceLocation[][] TEXTURES = generateTextures("flame", 4, 8);
|
||||
|
||||
public ParticleMagicFlame(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.flameScale = 1 + world.rand.nextFloat();
|
||||
|
||||
super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]);
|
||||
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
this.particleAlpha = 1;
|
||||
this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D));
|
||||
this.particleMaxAge = 12 + rand.nextInt(4);
|
||||
this.shaded = false;
|
||||
// IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff.
|
||||
this.canCollide = false;
|
||||
this.setParticleTextureIndex(48);
|
||||
this.canCollide = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity entity, float partialTicks, float rotationX, float rotationZ,
|
||||
float rotationYZ, float rotationXY, float rotationXZ){
|
||||
float f6 = ((float)this.particleAge + partialTicks) / (float)this.particleMaxAge;
|
||||
this.particleScale = this.flameScale * (1.0F - f6 * f6 * 0.5F);
|
||||
super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightnessForRender(float par1){
|
||||
return 256;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Particle multipleParticleScaleBy(float scale){
|
||||
this.flameScale *= scale;
|
||||
return super.multipleParticleScaleBy(scale);
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
for(ResourceLocation[] array : TEXTURES){
|
||||
for(ResourceLocation texture : array){
|
||||
event.getMap().registerSprite(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticlePath extends ParticleWizardry {
|
||||
|
||||
@@ -34,6 +33,11 @@ public class ParticlePath extends ParticleWizardry {
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
|
||||
@@ -8,9 +8,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleScorch extends ParticleWizardry {
|
||||
|
||||
@@ -27,7 +26,12 @@ public class ParticleScorch extends ParticleWizardry {
|
||||
this.setRBGColorF(0, 0, 0);
|
||||
this.shaded = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRBGColorF(float r, float g, float b){
|
||||
super.setRBGColorF(r, g, b);
|
||||
@@ -48,7 +52,7 @@ public class ParticleScorch extends ParticleWizardry {
|
||||
|
||||
// Fading
|
||||
if(this.particleAge > this.particleMaxAge/2){
|
||||
this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge/2)) / (float)this.particleMaxAge);
|
||||
this.setAlphaF(1 - ((float)this.particleAge - this.particleMaxAge/2f) / (this.particleMaxAge/2f));
|
||||
}
|
||||
|
||||
EnumFacing facing = EnumFacing.fromAngle(yaw);
|
||||
|
||||
@@ -6,9 +6,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleSnow extends ParticleWizardry {
|
||||
|
||||
@@ -24,7 +23,7 @@ public class ParticleSnow extends ParticleWizardry {
|
||||
this.canCollide = true;
|
||||
this.setMaxAge(40 + rand.nextInt(10));
|
||||
// Produces a variety of light blues and whites
|
||||
this.setRBGColorF(0.9f + 0.1f * world.rand.nextFloat(), 0.95f + 0.05f * world.rand.nextFloat(), 1);
|
||||
this.setRBGColorF(0.9f + 0.1f * random.nextFloat(), 0.95f + 0.05f * random.nextFloat(), 1);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
||||
@@ -6,9 +6,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleSpark extends ParticleWizardry {
|
||||
|
||||
@@ -25,14 +24,18 @@ public class ParticleSpark extends ParticleWizardry {
|
||||
this.canCollide = false;
|
||||
this.setMaxAge(3); // Lifetime defaults to 3 (and is very unlikely to be changed)
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
// May no longer be necessary, ParticleManager seems to enable blending now
|
||||
|
||||
// @Override
|
||||
// public void applyGLStateChanges(){
|
||||
// GlStateManager.enableBlend();
|
||||
// GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
// // TESTME: Are these two actually necessary?
|
||||
// GlStateManager.disableLighting();
|
||||
// OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
// }
|
||||
|
||||
@@ -6,9 +6,8 @@ import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleSparkle extends ParticleWizardry {
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class ParticleSphere extends ParticleWizardry {
|
||||
|
||||
public ParticleSphere(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
this.particleMaxAge = 5;
|
||||
this.particleAlpha = 0.8f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFXLayer(){
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ,
|
||||
float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate(x - interpPosX, y - interpPosY, z - interpPosZ);
|
||||
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE);
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
float latStep = (float)Math.PI/20;
|
||||
float longStep = (float)Math.PI/20;
|
||||
|
||||
float sphereRadius = this.particleScale * (this.particleAge + partialTicks - 1) / this.particleMaxAge;
|
||||
float alpha = this.particleAlpha * (1 - (this.particleAge + partialTicks - 1) / this.particleMaxAge);
|
||||
|
||||
drawSphere(Tessellator.getInstance(), buffer, sphereRadius, latStep, longStep, true, particleRed, particleGreen, particleBlue, alpha);
|
||||
drawSphere(Tessellator.getInstance(), buffer, sphereRadius, latStep, longStep, false, particleRed, particleGreen, particleBlue, alpha);
|
||||
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableBlend();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightnessForRender(float partialTicks){
|
||||
return 15728880;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sphere (using lat/long triangles) with the given parameters.
|
||||
* @param radius The radius of the sphere.
|
||||
* @param latStep The latitude step; smaller is smoother but increases performance cost.
|
||||
* @param longStep The longitude step; smaller is smoother but increases performance cost.
|
||||
* @param inside Whether to draw the outside or the inside of the sphere.
|
||||
* @param r The red component of the sphere colour.
|
||||
* @param g The green component of the sphere colour.
|
||||
* @param b The blue component of the sphere colour.
|
||||
* @param a The alpha component of the sphere colour.
|
||||
*/
|
||||
private static void drawSphere(Tessellator tessellator, BufferBuilder buffer, float radius, float latStep, float longStep, boolean inside, float r, float g, float b, float a){
|
||||
|
||||
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR);
|
||||
|
||||
boolean goingUp = inside;
|
||||
|
||||
buffer.pos(0, goingUp ? -radius : radius, 0).color(r, g, b, a).endVertex(); // Start at the north pole
|
||||
|
||||
for(float longitude = -(float)Math.PI; longitude <= (float)Math.PI; longitude += longStep){
|
||||
|
||||
// Leave the poles out since they only have a single point per stack instead of two
|
||||
for(float theta = (float)Math.PI/2 - latStep; theta >= -(float)Math.PI/2 + latStep; theta -= latStep){
|
||||
|
||||
float latitude = goingUp ? -theta : theta;
|
||||
|
||||
float hRadius = radius * MathHelper.cos(latitude);
|
||||
float vy = radius * MathHelper.sin(latitude);
|
||||
float vx = hRadius * MathHelper.sin(longitude);
|
||||
float vz = hRadius * MathHelper.cos(longitude);
|
||||
|
||||
buffer.pos(vx, vy, vz).color(r, g, b, a).endVertex();
|
||||
|
||||
vx = hRadius * MathHelper.sin(longitude + longStep);
|
||||
vz = hRadius * MathHelper.cos(longitude + longStep);
|
||||
|
||||
buffer.pos(vx, vy, vz).color(r, g, b, a).endVertex();
|
||||
}
|
||||
|
||||
// The next pole
|
||||
buffer.pos(0, goingUp ? radius : -radius, 0).color(r, g, b, a).endVertex();
|
||||
|
||||
goingUp = !goingUp;
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleSummon extends ParticleWizardry {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/summon.png");
|
||||
private final boolean mirror;
|
||||
|
||||
public ParticleSummon(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.mirror = random.nextBoolean();
|
||||
this.setMaxAge(10);
|
||||
this.setGravity(false);
|
||||
this.canCollide = false;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void onUpdate(){
|
||||
// super.onUpdate();
|
||||
// if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge;
|
||||
// }
|
||||
|
||||
/* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png
|
||||
* to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the
|
||||
* render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine
|
||||
* for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was
|
||||
* presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning
|
||||
* you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten
|
||||
* anyway since they bind their own textures. It is of course important to bind the texture every time you render a
|
||||
* custom particle, but I don't see how you could do it any other way, since you don't have access to
|
||||
* EffectRenderer. */
|
||||
@Override
|
||||
public int getFXLayer(){
|
||||
// This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer.
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ,
|
||||
float rotationYZ, float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushAttrib();
|
||||
|
||||
float scale = 0.6f;
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
if(mirror) GlStateManager.scale(-1, 1, 1);
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableAlpha();
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE);
|
||||
// Makes the particle colour add to the colour of the texture pixels, rather than the default multiplying
|
||||
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_ADD);
|
||||
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
// Does the texture translation wrapping thing (the cool stuff)
|
||||
// GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
// GlStateManager.loadIdentity();
|
||||
//
|
||||
// GlStateManager.translate((this.particleAge + partialTicks)/(float)this.particleMaxAge * -2, 0, 0);
|
||||
//
|
||||
// GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
|
||||
|
||||
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
|
||||
|
||||
// Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime
|
||||
float f = 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f);
|
||||
float g = f + 0.125f;
|
||||
float hrepeat = 1;
|
||||
float yScale = 3f;
|
||||
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
|
||||
buffer.pos(x-1, y, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
|
||||
Tessellator.getInstance().draw();
|
||||
|
||||
// Undoes the texture transformations
|
||||
// GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
// GlStateManager.loadIdentity();
|
||||
// GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.enableLighting();
|
||||
// Reverses the colour addition change from before
|
||||
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
|
||||
|
||||
GlStateManager.popAttrib();
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Superclass for particles with a second target entity or target position. */
|
||||
public abstract class ParticleTargeted extends ParticleWizardry {
|
||||
|
||||
|
||||
protected double targetX;
|
||||
protected double targetY;
|
||||
protected double targetZ;
|
||||
protected double targetVelX;
|
||||
protected double targetVelY;
|
||||
protected double targetVelZ;
|
||||
|
||||
protected double length;
|
||||
|
||||
/** The target this particle is linked to. The particle will stretch to touch this entity. */
|
||||
@Nullable
|
||||
@@ -33,43 +38,83 @@ public abstract class ParticleTargeted extends ParticleWizardry {
|
||||
this.targetY = y;
|
||||
this.targetZ = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetVelocity(double vx, double vy, double vz){
|
||||
this.targetVelX = vx;
|
||||
this.targetVelY = vy;
|
||||
this.targetVelZ = vz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetEntity(Entity target){
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setLength(double length){
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
if(!Double.isNaN(targetVelX) && !Double.isNaN(targetVelY) && !Double.isNaN(targetVelZ)){
|
||||
this.targetX += this.targetVelX;
|
||||
this.targetY += this.targetVelY;
|
||||
this.targetZ += this.targetVelZ;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ,
|
||||
float rotationXY, float rotationXZ){
|
||||
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks);
|
||||
|
||||
if(this.target != null){
|
||||
this.targetX = this.target.posX;
|
||||
this.targetY = this.target.getEntityBoundingBox().minY + target.height/2;
|
||||
this.targetZ = this.target.posZ;
|
||||
|
||||
this.targetX = this.target.prevPosX + (this.target.posX - this.target.prevPosX) * partialTicks;
|
||||
double correction = this.target.getEntityBoundingBox().minY - this.target.posY;
|
||||
this.targetY = this.target.prevPosY + (this.target.posY - this.target.prevPosY) * partialTicks
|
||||
+ target.height/2 + correction;
|
||||
this.targetZ = this.target.prevPosZ + (this.target.posZ - this.target.prevPosZ) * partialTicks;
|
||||
|
||||
}else if(this.entity != null && this.length > 0){
|
||||
|
||||
Vec3d look = entity.getLook(partialTicks).scale(length);
|
||||
this.targetX = x + look.x;
|
||||
this.targetY = y + look.y;
|
||||
this.targetZ = z + look.z;
|
||||
}
|
||||
|
||||
if(Double.isNaN(targetX) || Double.isNaN(targetY) || Double.isNaN(targetZ)){
|
||||
Wizardry.logger.warn("Attempted to render a targeted particle, but neither its target entity nor target"
|
||||
+ "position was set!");
|
||||
+ "position was set, and it either had no length assigned or was not linked to an entity!");
|
||||
return;
|
||||
}
|
||||
|
||||
// I'm pretty sure these were always static.
|
||||
interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks;
|
||||
interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks;
|
||||
interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks;
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate(x, y, z);
|
||||
GlStateManager.translate(x - interpPosX, y - interpPosY, z - interpPosZ);
|
||||
|
||||
double dx = this.targetX - this.posX;
|
||||
double dy = this.targetY - this.posY;
|
||||
double dz = this.targetZ - this.posZ;
|
||||
double dx = this.targetX - x;
|
||||
double dy = this.targetY - y;
|
||||
double dz = this.targetZ - z;
|
||||
|
||||
// No need for previous tick target positions and all that stuff since this is the only place they're used
|
||||
// and interpolating like this works just as well
|
||||
if(!Double.isNaN(targetVelX) && !Double.isNaN(targetVelY) && !Double.isNaN(targetVelZ)){
|
||||
dx += partialTicks * this.targetVelX;
|
||||
dy += partialTicks * this.targetVelY;
|
||||
dz += partialTicks * this.targetVelZ;
|
||||
}
|
||||
|
||||
// The distance from origin to endpoint
|
||||
double length = Math.sqrt(dx*dx+dy*dy+dz*dz);
|
||||
@@ -87,12 +132,12 @@ public abstract class ParticleTargeted extends ParticleWizardry {
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
|
||||
/** Called from {@link ParticleTargeted#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)},
|
||||
* once the appropriate calculations and transformations have been applied, to actually render the particle. Subclasses
|
||||
* override this <i>instead</i> of overriding {@code renderParticle} directly, and inside render the particle <b>along
|
||||
* the z-axis, starting at (0, 0, 0)</b> - it will be translated and rotated automatically.
|
||||
* <p>
|
||||
* <p></p>
|
||||
* <i>N.B. Other than transformations, no GL state changes are applied; these should be done within this method.</i>
|
||||
*
|
||||
* @param tessellator A reference to the tessellator, for convenience.
|
||||
|
||||
@@ -3,14 +3,13 @@ package electroblob.wizardry.client.particle;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.particle.ParticleDigging;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleTornado extends ParticleDigging {
|
||||
|
||||
private double angle;
|
||||
private float angle;
|
||||
private double radius;
|
||||
private double speed;
|
||||
/** Velocity of the tornado itself; in other words the velocity of the point the particle circles around. */
|
||||
@@ -20,9 +19,9 @@ public class ParticleTornado extends ParticleDigging {
|
||||
public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos,
|
||||
double velX, double velZ, IBlockState block){
|
||||
super(world, 0, 0, 0, 0, 0, 0, block);
|
||||
this.angle = this.rand.nextDouble() * Math.PI * 2;
|
||||
double x = originX - Math.cos(angle) * radius;
|
||||
double z = originZ + radius * Math.sin(angle);
|
||||
float angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = originX - MathHelper.cos(angle) * radius;
|
||||
double z = originZ + radius * MathHelper.sin(angle);
|
||||
this.radius = radius;
|
||||
this.setPosition(x, yPos, z);
|
||||
this.prevPosX = x;
|
||||
@@ -66,8 +65,8 @@ public class ParticleTornado extends ParticleDigging {
|
||||
// v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi.
|
||||
this.angle += omega;
|
||||
|
||||
this.motionZ = radius * omega * Math.cos(angle);
|
||||
this.motionX = radius * omega * Math.sin(angle);
|
||||
this.motionZ = radius * omega * MathHelper.cos(angle);
|
||||
this.motionX = radius * omega * MathHelper.sin(angle);
|
||||
this.move(motionX + velX, 0, motionZ + velZ);
|
||||
|
||||
if(this.particleAge > this.particleMaxAge / 2){
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleVine extends ParticleTargeted {
|
||||
|
||||
/** Half the width of the vine. */
|
||||
private static final float THICKNESS = 0.02f;
|
||||
private static final float LEAF_SPACING = 0.5f;
|
||||
private static final float SEGMENT_LENGTH = 1;
|
||||
|
||||
private static final ResourceLocation STEM_TEXTURE = new ResourceLocation(Wizardry.MODID, "particle/vine");
|
||||
private static final ResourceLocation[] LEAF_TEXTURES = generateTextures("vine_leaf", 5);
|
||||
|
||||
public ParticleVine(World world, double x, double y, double z){
|
||||
super(world, x, y, z, STEM_TEXTURE);
|
||||
//this.setRBGColorF(1, 1, 1);
|
||||
this.setMaxAge(0);
|
||||
this.particleScale = 1;
|
||||
this.setRBGColorF(0.2f, 0.65f, 0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){
|
||||
// When using FX layer 1 the BufferBuilder is already drawing... but in the wrong mode :/
|
||||
Tessellator.getInstance().draw();
|
||||
super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ);
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void draw(Tessellator tessellator, double length, float partialTicks){
|
||||
|
||||
random.setSeed(seed); // Reset the random so we get the same sequence of numbers each frame
|
||||
|
||||
float scale = this.particleScale;
|
||||
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
// Hmmmm we can't get the texture to tile using OpenGL texture space because it's on a sprite sheet...
|
||||
// Solution: Draw loads of boxes. Simple!
|
||||
// (Since there aren't going to be that many of these particles around we could have not used sprite sheets
|
||||
// and done the OpenGL texture space thing, but this is kinda easier)
|
||||
// Everything is drawn back-to-front so it looks like the vine is growing from the origin, not the endpoint
|
||||
int i = 0;
|
||||
while(i + SEGMENT_LENGTH < length){
|
||||
drawShearedBox(tessellator, 0, 0, length-i, 0, 0, length-i-SEGMENT_LENGTH, THICKNESS * scale,
|
||||
particleRed, particleGreen, particleBlue, particleAlpha);
|
||||
i += SEGMENT_LENGTH;
|
||||
}
|
||||
|
||||
drawShearedBox(tessellator, 0, 0, length-i, 0, 0, 0, THICKNESS * scale,
|
||||
particleRed, particleGreen, particleBlue, particleAlpha);
|
||||
|
||||
for(double l=length; l>0; l-=LEAF_SPACING){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.rotate(random.nextInt(4) * 90, 0, 0, 1);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
TextureAtlasSprite leaf = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(
|
||||
LEAF_TEXTURES[random.nextInt(LEAF_TEXTURES.length)].toString());
|
||||
|
||||
float w = 16 * THICKNESS * scale;
|
||||
float u1 = leaf.getMinU();
|
||||
float u2 = leaf.getMaxU();
|
||||
float v1 = leaf.getMinV();
|
||||
float v2 = leaf.getMaxV();
|
||||
|
||||
float colourVariation = 0.3f;
|
||||
|
||||
float r = MathHelper.clamp(particleRed + (random.nextFloat() - 0.5f) * colourVariation, 0, 1);
|
||||
float g = MathHelper.clamp(particleGreen + (random.nextFloat() - 0.5f) * colourVariation, 0, 1);
|
||||
float b = MathHelper.clamp(particleBlue + (random.nextFloat() - 0.5f) * colourVariation, 0, 1);
|
||||
|
||||
buffer.pos(0, 0, l).tex(u1, v1).color(r, g, b, particleAlpha).endVertex();
|
||||
buffer.pos(w, 0, l).tex(u2, v1).color(r, g, b, particleAlpha).endVertex();
|
||||
buffer.pos(w, w, l).tex(u2, v2).color(r, g, b, particleAlpha).endVertex();
|
||||
buffer.pos(0, w, l).tex(u1, v2).color(r, g, b, particleAlpha).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
// Makes the rain go weird
|
||||
//GlStateManager.enableLighting();
|
||||
}
|
||||
|
||||
/** Draws a single box for one segment of the arc, from the point (x1, y1, z1) to the point (x2, y2, z2), with given width and colour. */
|
||||
private void drawShearedBox(Tessellator tessellator, double x1, double y1, double z1, double x2, double y2, double z2, float width, float r, float g, float b, float a){
|
||||
|
||||
float u1 = particleTexture.getMinU();
|
||||
float u2 = u1 + (particleTexture.getMaxU() - u1) * (float)(z1-z2)/SEGMENT_LENGTH;
|
||||
float v1 = particleTexture.getMinV();
|
||||
float dv = particleTexture.getMaxV() - v1;
|
||||
// width * 8 gives the total 'circumference' of the box
|
||||
float v2 = v1 + dv * 0.0625f;
|
||||
float v3 = v1 + dv * 0.125f;
|
||||
float v4 = v1 + dv * 0.1875f;
|
||||
float v5 = v1 + dv * 0.25f;
|
||||
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
buffer.pos(x1-width, y1-width, z1).tex(u1, v1).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x2-width, y2-width, z2).tex(u2, v1).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x1-width, y1+width, z1).tex(u1, v2).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x2-width, y2+width, z2).tex(u2, v2).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x1+width, y1+width, z1).tex(u1, v3).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x2+width, y2+width, z2).tex(u2, v3).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x1+width, y1-width, z1).tex(u1, v4).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x2+width, y2-width, z2).tex(u2, v4).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x1-width, y1-width, z1).tex(u1, v5).color(r, g, b, a).endVertex();
|
||||
buffer.pos(x2-width, y2-width, z2).tex(u2, v5).color(r, g, b, a).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
|
||||
event.getMap().registerSprite(STEM_TEXTURE);
|
||||
|
||||
for(ResourceLocation texture : LEAF_TEXTURES){
|
||||
event.getMap().registerSprite(texture);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +1,41 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import electroblob.wizardry.entity.ICustomHitbox;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Abstract superclass for all of wizardry's particles. This replaces {@code ParticleCustomTexture} (the functionality of
|
||||
* which is no longer necessary since wizardry now uses {@code TextureAtlasSprite}s to do the rendering), and fits into
|
||||
* {@code ParticleBuilder} by exposing all the necessary variables through getters, allowing them to be set on the fly
|
||||
* rather than needing to be passed into the constructor.
|
||||
* <p>
|
||||
* <p></p>
|
||||
* The new system is as follows:
|
||||
* <p>
|
||||
* <p></p>
|
||||
* - All particle classes have a single constructor which takes a world and a position only.<br>
|
||||
* - Each particle class defines any relevant default values in its constructor, including velocity.<br>
|
||||
* - The particle builder then overwrites any other values that were set during building.
|
||||
* <p>
|
||||
* <p></p>
|
||||
* This beauty of this system is that there are never any redundant parameters when spawning particles, since you can set
|
||||
* as many or as few parameters as necessary - and in addition, common defaults don't need setting at all. For example,
|
||||
* snow particles nearly always fall at the same speed, which can now be defined in the particle class and no longer
|
||||
@@ -39,12 +45,24 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
* @since Wizardry 4.2.0
|
||||
* @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
/** Implementation of animated particles using the TextureAtlasSprite system. Why vanilla doesn't support this I
|
||||
* don't know, considering it too has animated particles. */
|
||||
protected final TextureAtlasSprite[] sprites;
|
||||
|
||||
/** A long value used by the renderer as a random number seed, ensuring anything that is randomised remains the
|
||||
* same across multiple frames. For example, lightning particles use this to keep their shape across ticks.
|
||||
* This value can also be set during particle creation, allowing users to keep randomised properties the same
|
||||
* even across multiple particles. If unspecified, the seed is chosen at random. */
|
||||
protected long seed;
|
||||
/** This particle's random number generator. All particles should use this in preference to any other random
|
||||
* instance (like random), even if it isn't actually necessary to keep properties across frames. Note that
|
||||
* if you <b>do</b> need to generate the same sequence of random numbers each frame, you must call
|
||||
* {@code random.setSeed(seed)} from the {@link ParticleWizardry#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)}
|
||||
* method - this is not done automatically. */
|
||||
protected Random random = new Random(); // If we're not using a seed, this defaults to any old seed
|
||||
|
||||
/** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */
|
||||
protected boolean shaded = false;
|
||||
@@ -64,12 +82,12 @@ public abstract class ParticleWizardry extends Particle {
|
||||
/** The entity this particle is linked to. The particle will move with this entity. */
|
||||
@Nullable
|
||||
protected Entity entity = null;
|
||||
/** Coordinates of this particle relative to the linked entity. If the linked entity is null, these are not used. */
|
||||
/** Coordinates of this particle relative to the linked entity. If the linked entity is null, these are used as
|
||||
* the absolute coordinates of the centre of rotation for particles with spin. If the particle has neither a
|
||||
* linked entity nor spin, these are not used. */
|
||||
protected double relativeX, relativeY, relativeZ;
|
||||
/** Velocity of this particle relative to the linked entity. The relative x and z velocities are also used when
|
||||
* the particle has spin to move the centre of rotation. If the linked entity is null and the particle is not
|
||||
* spinning, these are not used and will be {@code NaN}. */
|
||||
protected double relativeMotionX = Double.NaN, relativeMotionY = Double.NaN, relativeMotionZ = Double.NaN;
|
||||
/** Velocity of this particle relative to the linked entity. If the linked entity is null, these are not used. */
|
||||
protected double relativeMotionX, relativeMotionY, relativeMotionZ;
|
||||
// Note that roll (equivalent to rotating the texture) is effectively handled by particleAngle - although that is
|
||||
// actually the rotation speed and not the angle itself.
|
||||
/** The yaw angle this particle is facing, or {@code NaN} if this particle always faces the viewer (default behaviour). */
|
||||
@@ -77,6 +95,14 @@ public abstract class ParticleWizardry extends Particle {
|
||||
/** The pitch angle this particle is facing, or {@code NaN} if this particle always faces the viewer (default behaviour). */
|
||||
protected float pitch = Float.NaN;
|
||||
|
||||
/** The fraction of the impact velocity that should be the maximum spread speed added on impact. */
|
||||
private static final double SPREAD_FACTOR = 0.2;
|
||||
/** Lateral velocity is reduced by this factor on impact, before adding random spread velocity. */
|
||||
private static final double IMPACT_FRICTION = 0.2;
|
||||
|
||||
/** Previous-tick velocity, used in collision detection. */
|
||||
private double prevVelX, prevVelY, prevVelZ;
|
||||
|
||||
/**
|
||||
* Creates a new particle in the given world at the given position. All other parameters are set via the various
|
||||
* setter methods ({@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder} deals with all of that anyway).
|
||||
@@ -108,7 +134,6 @@ public abstract class ParticleWizardry extends Particle {
|
||||
this.setParticleTexture(sprites[0]);
|
||||
|
||||
}else{
|
||||
|
||||
sprites = new TextureAtlasSprite[0];
|
||||
}
|
||||
}
|
||||
@@ -117,6 +142,15 @@ public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
// Setters for parameters that affect all particles - these are implemented in this class (although they may be
|
||||
// reimplemented in subclasses)
|
||||
|
||||
/** Sets the seed for this particle's randomly generated values and resets {@link ParticleWizardry#random} to use
|
||||
* that seed. Implementations will differ between particle types; for example, ParticleLightning has an update
|
||||
* period which changes the seed every few ticks, whereas ParticleVine simply retains the same seed for its entire
|
||||
* lifetime. */
|
||||
public void setSeed(long seed){
|
||||
this.seed = seed;
|
||||
this.random = new Random(seed);
|
||||
}
|
||||
|
||||
/** Sets whether the particle should render at full brightness or not. True if the particle is shaded, false if
|
||||
* the particle always renders at full brightness. Defaults to false.*/
|
||||
@@ -154,13 +188,10 @@ public abstract class ParticleWizardry extends Particle {
|
||||
public void setSpin(double radius, double speed){
|
||||
this.radius = radius;
|
||||
this.speed = speed * 2 * Math.PI; // Converts rotations per tick into radians per tick for the trig functions
|
||||
this.angle = this.rand.nextFloat() * (float)Math.PI * 2; // Random start angle TODO: Perhaps this should be specified?
|
||||
this.angle = this.rand.nextFloat() * (float)Math.PI * 2; // Random start angle
|
||||
// Need to set the start position or the circle won't be centred on the correct position
|
||||
this.relativeX = radius * -MathHelper.cos(angle);
|
||||
this.relativeZ = radius * MathHelper.sin(angle);
|
||||
this.setPosition(posX + relativeX, posY, posZ + relativeZ);
|
||||
this.prevPosX = posX;
|
||||
this.prevPosZ = posZ;
|
||||
this.posX = relativeX - radius * MathHelper.cos(angle);
|
||||
this.posZ = relativeZ + radius * MathHelper.sin(angle);
|
||||
// Set these to the correct values
|
||||
this.relativeMotionX = motionX;
|
||||
this.relativeMotionY = motionY;
|
||||
@@ -180,6 +211,7 @@ public abstract class ParticleWizardry extends Particle {
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
// Set these to the correct values
|
||||
this.relativeMotionX = motionX;
|
||||
this.relativeMotionY = motionY;
|
||||
this.relativeMotionZ = motionZ;
|
||||
@@ -218,7 +250,7 @@ public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
/**
|
||||
* Sets the direction this particle faces. This will cause the particle to render facing the given direction.
|
||||
* @param yaw The yaw angle of this particle in degrees, where 0 is [TODO south?].
|
||||
* @param yaw The yaw angle of this particle in degrees, where 0 is south.
|
||||
* @param pitch The pitch angle of this particle in degrees, where 0 is horizontal.
|
||||
*/
|
||||
public void setFacing(float yaw, float pitch){
|
||||
@@ -239,6 +271,18 @@ public abstract class ParticleWizardry extends Particle {
|
||||
public void setTargetPosition(double x, double y, double z){
|
||||
// Does nothing for normal particles since normal particles always render at a single point
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target point velocity for this particle. This will cause the position it stretches to touch to move
|
||||
* at the given velocity. Has no effect unless {@link ParticleWizardry#setTargetVelocity(double, double, double)}
|
||||
* is also used.
|
||||
* @param vx The x velocity of the target point.
|
||||
* @param vy The y velocity of the target point.
|
||||
* @param vz The z velocity of the target point.
|
||||
*/
|
||||
public void setTargetVelocity(double vx, double vy, double vz){
|
||||
// Does nothing for normal particles since normal particles always render at a single point
|
||||
}
|
||||
|
||||
/**
|
||||
* Links this particle to the given target. This will cause it to stretch to touch the target, if supported.
|
||||
@@ -247,6 +291,15 @@ public abstract class ParticleWizardry extends Particle {
|
||||
public void setTargetEntity(Entity target){
|
||||
// Does nothing for normal particles since normal particles always render at a single point
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of this particle. This will cause it to stretch to touch a point this distance along its
|
||||
* linked entity's line of sight.
|
||||
* @param length The length to set.
|
||||
*/
|
||||
public void setLength(double length){
|
||||
// Does nothing for normal particles since normal particles always render at a single point
|
||||
}
|
||||
|
||||
// ============================================== Method Overrides ==============================================
|
||||
|
||||
@@ -278,15 +331,16 @@ public abstract class ParticleWizardry extends Particle {
|
||||
* @param lookYZ Equal to {@code -lookZ} times the sine of {@code viewer.rotationPitch}. Will be 0 when facing directly horizontal.
|
||||
* When facing directly up, will be equal to {@code -lookZ}. When facing directly down, will be equal to {@code lookZ}.
|
||||
*/
|
||||
// Fun fact: unlike entities, particles don't seem to bother checking the camera frustum...
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float lookZ, float lookY,
|
||||
float lookX, float lookXY, float lookYZ){
|
||||
|
||||
updateEntityLinking(partialTicks);
|
||||
|
||||
if(Float.isNaN(this.yaw) || Float.isNaN(this.pitch)){
|
||||
|
||||
// Normal behaviour (rotates to face the viewer)
|
||||
super.renderParticle(buffer, viewer, partialTicks, lookZ, lookY, lookX, lookXY, lookYZ);
|
||||
|
||||
drawParticle(buffer, viewer, partialTicks, lookZ, lookY, lookX, lookXY, lookYZ);
|
||||
}else{
|
||||
|
||||
// Specific rotation
|
||||
@@ -302,7 +356,25 @@ public abstract class ParticleWizardry extends Particle {
|
||||
float rotationYZ = -rotationZ * MathHelper.sin(pitch * degToRadFactor);
|
||||
float rotationXY = rotationX * MathHelper.sin(pitch * degToRadFactor);
|
||||
|
||||
super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY);
|
||||
drawParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate function for {@link ParticleWizardry#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)};
|
||||
* does the actual rendering. Subclasses should override this method instead of renderParticle. By default, this
|
||||
* method simply calls super.renderParticle.
|
||||
*/
|
||||
protected void drawParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationY, float rotationZ, float rotationYZ, float rotationXY){
|
||||
super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY);
|
||||
}
|
||||
|
||||
protected void updateEntityLinking(float partialTicks){
|
||||
if(this.entity != null){
|
||||
// This is kind of cheating but we know it's always a constant velocity so it works fine
|
||||
prevPosX = posX + entity.prevPosX - entity.posX - relativeMotionX * (1-partialTicks);
|
||||
prevPosY = posY + entity.prevPosY - entity.posY - relativeMotionY * (1-partialTicks);
|
||||
prevPosZ = posZ + entity.prevPosZ - entity.posZ - relativeMotionZ * (1-partialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,38 +382,43 @@ public abstract class ParticleWizardry extends Particle {
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
// If any of these values is NaN, the particle has neither an entity nor a spin
|
||||
if(!Double.isNaN(relativeMotionX) && !Double.isNaN(relativeMotionY) && !Double.isNaN(relativeMotionZ)){
|
||||
|
||||
// This allows velocity changes from entity linking and spin to stack
|
||||
double vx = relativeMotionX;
|
||||
double vy = relativeMotionY;
|
||||
double vz = relativeMotionZ;
|
||||
|
||||
if(this.canCollide && this.onGround){
|
||||
// I reject your friction and substitute my own!
|
||||
this.motionX /= 0.699999988079071D;
|
||||
this.motionZ /= 0.699999988079071D;
|
||||
}
|
||||
|
||||
if(entity != null || radius > 0){
|
||||
|
||||
double x = relativeX;
|
||||
double y = relativeY;
|
||||
double z = relativeZ;
|
||||
|
||||
// Entity linking
|
||||
if(this.entity != null){
|
||||
|
||||
if(this.entity.isDead) this.setExpired();
|
||||
|
||||
this.setPosition(this.entity.posX + relativeX, this.entity.getEntityBoundingBox().minY + relativeY,
|
||||
this.entity.posZ + relativeZ);
|
||||
// Velocity is set so that the renderer will interpolate correctly between ticks
|
||||
vx += this.entity.motionX;
|
||||
vy += this.entity.motionY;
|
||||
vz += this.entity.motionZ;
|
||||
if(this.entity.isDead){
|
||||
this.setExpired();
|
||||
}else{
|
||||
x += this.entity.posX;
|
||||
y += this.entity.posY;
|
||||
z += this.entity.posZ;
|
||||
}
|
||||
}
|
||||
|
||||
// Spin
|
||||
if(radius > 0){
|
||||
angle += speed;
|
||||
vx += radius * speed * MathHelper.sin(angle);
|
||||
vz += radius * speed * MathHelper.cos(angle);
|
||||
// If the particle has spin, x/z relative position is used as centre and coords are changed each tick
|
||||
x += radius * -MathHelper.cos(angle);
|
||||
z += radius * MathHelper.sin(angle);
|
||||
}
|
||||
|
||||
this.relativeX += vx;
|
||||
this.relativeY += vy;
|
||||
this.relativeZ += vz;
|
||||
|
||||
this.setPosition(x, y, z);
|
||||
|
||||
this.relativeX += relativeMotionX;
|
||||
this.relativeY += relativeMotionY;
|
||||
this.relativeZ += relativeMotionZ;
|
||||
}
|
||||
|
||||
// Colour fading
|
||||
@@ -357,8 +434,96 @@ public abstract class ParticleWizardry extends Particle {
|
||||
// (which would probably otherwise happen if particleAge == particleMaxAge)
|
||||
this.setParticleTexture(sprites[Math.min((int)(ageFraction * sprites.length), sprites.length - 1)]);
|
||||
}
|
||||
|
||||
// Collision spreading
|
||||
if(canCollide){
|
||||
|
||||
if(this.motionX == 0 && this.prevVelX != 0){ // If the particle just collided in x
|
||||
// Reduce lateral velocity so the added spread speed actually has an effect
|
||||
this.motionY *= IMPACT_FRICTION;
|
||||
this.motionZ *= IMPACT_FRICTION;
|
||||
// Add random velocity in y and z proportional to the impact velocity
|
||||
this.motionY += (rand.nextDouble()*2 - 1) * this.prevVelX * SPREAD_FACTOR;
|
||||
this.motionZ += (rand.nextDouble()*2 - 1) * this.prevVelX * SPREAD_FACTOR;
|
||||
}
|
||||
|
||||
if(this.motionY == 0 && this.prevVelY != 0){ // If the particle just collided in y
|
||||
// Reduce lateral velocity so the added spread speed actually has an effect
|
||||
this.motionX *= IMPACT_FRICTION;
|
||||
this.motionZ *= IMPACT_FRICTION;
|
||||
// Add random velocity in x and z proportional to the impact velocity
|
||||
this.motionX += (rand.nextDouble()*2 - 1) * this.prevVelY * SPREAD_FACTOR;
|
||||
this.motionZ += (rand.nextDouble()*2 - 1) * this.prevVelY * SPREAD_FACTOR;
|
||||
}
|
||||
|
||||
if(this.motionZ == 0 && this.prevVelZ != 0){ // If the particle just collided in z
|
||||
// Reduce lateral velocity so the added spread speed actually has an effect
|
||||
this.motionX *= IMPACT_FRICTION;
|
||||
this.motionY *= IMPACT_FRICTION;
|
||||
// Add random velocity in x and y proportional to the impact velocity
|
||||
this.motionX += (rand.nextDouble()*2 - 1) * this.prevVelZ * SPREAD_FACTOR;
|
||||
this.motionY += (rand.nextDouble()*2 - 1) * this.prevVelZ * SPREAD_FACTOR;
|
||||
}
|
||||
|
||||
double searchRadius = 20;
|
||||
|
||||
List<Entity> nearbyEntities = WizardryUtilities.getEntitiesWithinRadius(searchRadius, this.posX,
|
||||
this.posY, this.posZ, world, Entity.class);
|
||||
|
||||
nearbyEntities.removeIf(e -> !(e instanceof ICustomHitbox && ((ICustomHitbox)e).contains(new Vec3d(this.posX, this.posY, this.posZ))));
|
||||
|
||||
if(nearbyEntities.size() > 0) this.setExpired();
|
||||
|
||||
}
|
||||
|
||||
this.prevVelX = motionX;
|
||||
this.prevVelY = motionY;
|
||||
this.prevVelZ = motionZ;
|
||||
}
|
||||
|
||||
|
||||
// Overridden and copied to fix the collision behaviour
|
||||
@Override
|
||||
public void move(double x, double y, double z){
|
||||
|
||||
double origY = y;
|
||||
double origX = x;
|
||||
double origZ = z;
|
||||
|
||||
if(this.canCollide){
|
||||
|
||||
List<AxisAlignedBB> list = this.world.getCollisionBoxes(null, this.getBoundingBox().expand(x, y, z));
|
||||
|
||||
for(AxisAlignedBB axisalignedbb : list){
|
||||
y = axisalignedbb.calculateYOffset(this.getBoundingBox(), y);
|
||||
}
|
||||
|
||||
this.setBoundingBox(this.getBoundingBox().offset(0.0D, y, 0.0D));
|
||||
|
||||
for(AxisAlignedBB axisalignedbb1 : list){
|
||||
x = axisalignedbb1.calculateXOffset(this.getBoundingBox(), x);
|
||||
}
|
||||
|
||||
this.setBoundingBox(this.getBoundingBox().offset(x, 0.0D, 0.0D));
|
||||
|
||||
for(AxisAlignedBB axisalignedbb2 : list){
|
||||
z = axisalignedbb2.calculateZOffset(this.getBoundingBox(), z);
|
||||
}
|
||||
|
||||
this.setBoundingBox(this.getBoundingBox().offset(0.0D, 0.0D, z));
|
||||
|
||||
}else{
|
||||
this.setBoundingBox(this.getBoundingBox().offset(x, y, z));
|
||||
}
|
||||
|
||||
this.resetPositionToBB();
|
||||
this.onGround = origY != y && origY < 0.0D;
|
||||
|
||||
if(origX != x) this.motionX = 0.0D;
|
||||
if(origY != y) this.motionY = 0.0D; // Why doesn't Particle do this for y?
|
||||
if(origZ != z) this.motionZ = 0.0D;
|
||||
}
|
||||
|
||||
|
||||
// =============================================== Helper Methods ===============================================
|
||||
|
||||
/** Static helper method that generates an array of n ResourceLocations using the particle file naming convention,
|
||||
@@ -390,6 +555,21 @@ public abstract class ParticleWizardry extends Particle {
|
||||
return textures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the given {@link ResourceLocation} with the given {@link IWizardryParticleFactory}, allowing it to
|
||||
* be used in the {@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder}. This is a similar concept to
|
||||
* registering entity renderers, in that it associates the client-only bit with its common-code counterpart - but
|
||||
* of course, particles are client-side only so a simple identifier is all that is necessary. As with entity
|
||||
* renderers, <b>this method may only be called from the client side</b>, probably a client proxy.
|
||||
* @param name The {@link ResourceLocation} to use for the particle. This effectively replaces the particle type
|
||||
* enum from previous versions. Keep a reference to this somewhere in <b>common</b> code for use later.
|
||||
* @param factory A {@link IWizardryParticleFactory} that produces your particle. A constructor reference is usually
|
||||
* sufficient.
|
||||
*/
|
||||
public static void registerParticle(ResourceLocation name, IWizardryParticleFactory factory){
|
||||
ClientProxy.addParticleFactory(name, factory);
|
||||
}
|
||||
|
||||
/** Simple particle factory interface which takes a world and a position and returns a particle. Used (via method
|
||||
* references) in the client proxy to link particle enum types to actual particle classes. */
|
||||
@SideOnly(Side.CLIENT)
|
||||
|
||||
Reference in New Issue
Block a user