Add new files for the particle refactoring
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
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.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;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class ParticleBuff extends ParticleEntityLinked {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png");
|
||||
private final boolean mirror;
|
||||
|
||||
public ParticleBuff(World world, Entity entity, float r, float g, float b, boolean mirror){
|
||||
super(world, entity);
|
||||
this.setRBGColorF(r, g, b);
|
||||
this.mirror = mirror;
|
||||
}
|
||||
|
||||
public ParticleBuff(World world, Entity entity, int maxAge, float r, float g, float b, boolean mirror){
|
||||
super(world, entity, maxAge);
|
||||
this.setRBGColorF(r, g, b);
|
||||
this.mirror = mirror;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
this.particleGravity = 0;
|
||||
this.posY += 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
super.onUpdate();
|
||||
this.setPosition(this.entity.posX, this.entity.posY + 1 + 4f * this.particleAge/this.particleMaxAge, this.entity.posZ);
|
||||
if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ,
|
||||
float rotationYZ, float rotationXY, float rotationXZ){
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* Abstract superclass for particles that are linked to entities, i.e. move with a given entity. This is generally used
|
||||
* for visual effects in spell casting.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract class ParticleEntityLinked extends Particle {
|
||||
|
||||
/** True if the particle always renders at full brightness. Defaults to false. */
|
||||
protected boolean fullBrightness = false;
|
||||
|
||||
/** The entity this particle is linked to. The particle will move with this entity. */
|
||||
protected Entity entity;
|
||||
|
||||
public ParticleEntityLinked(World world, Entity entity){
|
||||
super(world, entity.posX, entity.posY, entity.posZ, entity.motionX, entity.motionY, entity.motionZ);
|
||||
this.entity = entity;
|
||||
this.init();
|
||||
}
|
||||
|
||||
public ParticleEntityLinked(World world, Entity entity, int maxAge){
|
||||
this(world, entity);
|
||||
this.particleMaxAge = maxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from both constructors to set constants, avoiding duplicate code. Common fields to set here include:
|
||||
* particleScale, particleGravity, canCollide, fullBrightness and setting the texture index.
|
||||
*/
|
||||
public abstract void init();
|
||||
|
||||
/* 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 int getBrightnessForRender(float partialTick){
|
||||
return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Copied from ParticleFirework.Overlay; for some reason that class has no public constructors, plus I want to change the
|
||||
* scale and a few other things
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2.0
|
||||
*/
|
||||
public class ParticleFlash extends ParticleWizardry {
|
||||
|
||||
public ParticleFlash(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
this.particleScale = 7.1f; // 7.1f is the value used in fireworks
|
||||
this.particleMaxAge = 4;
|
||||
}
|
||||
|
||||
@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) * 0.25F * (float)Math.PI);
|
||||
this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F) * 0.25F * 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);
|
||||
float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
|
||||
int i = this.getBrightnessForRender(partialTicks);
|
||||
int j = i >> 16 & 65535;
|
||||
int k = i & 65535;
|
||||
buffer.pos((double)(f5 - rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 - rotationYZ * f4 - rotationXZ * f4)).tex(0.5D, 0.375D).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.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){
|
||||
return 15728880;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
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)
|
||||
public class ParticleMagicBubble extends ParticleWizardry {
|
||||
|
||||
public ParticleMagicBubble(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.particleRed = 1.0F;
|
||||
this.particleGreen = 1.0F;
|
||||
this.particleBlue = 1.0F;
|
||||
this.setParticleTextureIndex(32);
|
||||
this.setSize(0.02F, 0.02F);
|
||||
this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F;
|
||||
// this.motionX = par8 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
|
||||
// this.motionY = par10 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
|
||||
// this.motionZ = par12 * 0.20000000298023224D + (double)((float)(Math.random() * 2.0D - 1.0D) * 0.02F);
|
||||
this.particleMaxAge = (int)(8.0D / (Math.random() * 0.8D + 0.2D));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
this.motionY += 0.002D;
|
||||
this.move(this.motionX, this.motionY, this.motionZ);
|
||||
this.motionX *= 0.8500000238418579D;
|
||||
this.motionY *= 0.8500000238418579D;
|
||||
this.motionZ *= 0.8500000238418579D;
|
||||
|
||||
if(this.particleMaxAge-- <= 0){
|
||||
this.setExpired();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* The new system is as follows:
|
||||
* <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>
|
||||
* This beauty of this system is that there are never any redundant parameters when spawning particles. For example,
|
||||
* snow particles nearly always fall at the same speed, which can now be defined in the particle class and no longer
|
||||
* needs to be defined when spawning the particle - but importantly, it can still be overridden if desired.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2.0
|
||||
* @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
/** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */
|
||||
protected boolean shaded = false;
|
||||
|
||||
protected float fadeRed = 1;
|
||||
protected float fadeGreen = 1;
|
||||
protected float fadeBlue = 0;
|
||||
|
||||
public ParticleWizardry(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
}
|
||||
|
||||
/** 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.*/
|
||||
public void setShaded(boolean shaded){
|
||||
this.shaded = shaded;
|
||||
}
|
||||
|
||||
/** Sets this particle's gravity. True to enable gravity, false to disable. Defaults to false.*/
|
||||
public void setGravity(boolean gravity){
|
||||
this.particleGravity = gravity ? 1 : 0;
|
||||
}
|
||||
|
||||
/** Sets this particle's lifetime in ticks.*/
|
||||
public void setLifetime(int lifetime){
|
||||
this.particleMaxAge = lifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the velocity of the particle.
|
||||
* @param vx The x velocity
|
||||
* @param vy The y velocity
|
||||
* @param vz The z velocity
|
||||
*/
|
||||
public void setVelocity(double vx, double vy, double vz){
|
||||
this.motionX = vx;
|
||||
this.motionY = vy;
|
||||
this.motionZ = vz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fade colour of the particle.
|
||||
* @param r The red colour component
|
||||
* @param g The green colour component
|
||||
* @param g The blue colour component
|
||||
*/
|
||||
public void setFadeColour(float r, float g, float b){
|
||||
this.fadeRed = r;
|
||||
this.fadeGreen = g;
|
||||
this.fadeBlue = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightnessForRender(float partialTick){
|
||||
return shaded ? super.getBrightnessForRender(partialTick) : 15728880;
|
||||
}
|
||||
|
||||
/** Simple particle factory interface which takes a world and a position and returns a particle. Used (via lambda
|
||||
* expressions) in the client proxy to link particle enum types to actual particle classes. */
|
||||
@SideOnly(Side.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface IWizardryParticleFactory {
|
||||
ParticleWizardry createParticle(World world, double x, double y, double z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
package electroblob.wizardry.util;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* <i>"Don't waste time spawning particles manually - let {@code ParticleBuilder} do the work for you!"</i>
|
||||
* <p>
|
||||
* Singleton class that builds wizardry particles. This is an alternative (and neater, I think) solution to using varargs.
|
||||
* All building methods are chainable, so particles can be created using only one line of code (This is similar to the
|
||||
* BufferBuilder system). The number of different combinations of parameters now required for the various particle
|
||||
* types in wizardry made the method overloads in the proxies very cumbersome and inevitably resulted in redundant
|
||||
* parameters, which made the code messy and hard to read. Those methods have now been removed.
|
||||
* <p>
|
||||
* It also goes without saying that <b>this class should only ever be used client-side</b>.
|
||||
* <p>
|
||||
* {@link ParticleBuilder#instance} retrieves the static instance of the particle builder. Use
|
||||
* {@link ParticleBuilder#particle(Type)} to start building a particle, or alternatively use the static
|
||||
* convenience version {@link ParticleBuilder#create(Type)}. Use {@link ParticleBuilder#spawn()}
|
||||
* to finish building and spawn the particle. Between these two, a variety of parameters can be set using the various
|
||||
* setter methods (see individual method descriptions for more details). These, along with {@code ParticleBuilder.particle(...)},
|
||||
* return the particle builder instance, allowing them to be chained together to spawn particles using a single line of code.
|
||||
* If any parameters are unspecified these will default to certain values, which may or may not depend on the particle type.
|
||||
* Not all parameters affect all particles. Again, see individual method descriptions for more details.
|
||||
* <p>
|
||||
* For example, a typical call to the particle builder might look something like this:
|
||||
* <p>
|
||||
* <code>ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).colour(r, g, b).spawn(world);</code>
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2.0
|
||||
*/
|
||||
public final class ParticleBuilder {
|
||||
|
||||
/** The static instance of the particle builder. */
|
||||
public static final ParticleBuilder instance = new ParticleBuilder();
|
||||
|
||||
/** Whether the particle builder is currently building or not. */
|
||||
private boolean building = false;
|
||||
|
||||
// Builder variables
|
||||
// We can't just store a particle and set its parameters in the builder methods, because the server won't like having
|
||||
// a field of a client-only type
|
||||
private Type type;
|
||||
private double x, y, z;
|
||||
private double vx, vy, vz;
|
||||
private float r, g, b;
|
||||
private float fr, fg, fb;
|
||||
private double radius;
|
||||
private int lifetime;
|
||||
private boolean gravity;
|
||||
private boolean shaded;
|
||||
private float scale;
|
||||
private Entity entity;
|
||||
|
||||
/** Enum constants representing the different types of particle added by wizardry. As of 4.2.0, this has been moved
|
||||
* from its own file {@code Type} to inside {@link ParticleBuilder}. This allowed its name to be
|
||||
* shortened to simply {@code Type}, making most references more concise. References in classes where another
|
||||
* {@code Type} is also used can simply refer to the full name, {@code ParticleBuilder.Type}, which is no more verbose
|
||||
* than before.
|
||||
* <p>
|
||||
* Individual constants have comments detailing their corresponding default parameters. A range of values indicates
|
||||
* randomness. */
|
||||
public static enum Type {
|
||||
@Deprecated BLIZZARD,
|
||||
/** Spiral particle, like potions.<p><b>Defaults:</b><p>Lifetime: 8-40 ticks<br>Colour: white */ DARK_MAGIC,
|
||||
/** Single pixel particle.<p><b>Defaults:</b><p>Lifetime: 16-80 ticks<br>Colour: white */ DUST,
|
||||
/** Rapid flash, like fireworks.<p><b>Defaults:</b><p>Lifetime: 4 ticks<br>Colour: white */ FLASH,
|
||||
/** Small shard of ice.<p><b>Defaults:</b><p>Lifetime: 8-40 ticks<br>Gravity: true */ ICE,
|
||||
/** Single green/brown leaf.<p><b>Defaults:</b><p>Lifetime: 10-15 ticks<br>Velocity: (0, -0.03, 0) */ LEAF,
|
||||
/** Bubble that doesn't burst in air.<p><b>Defaults:</b><p>Lifetime: 8-40 ticks */ MAGIC_BUBBLE,
|
||||
/** Scaleable, moving flame.<p><b>Defaults:</b><p>Lifetime: 8-40 ticks<br> */ MAGIC_FIRE,
|
||||
/** Soft-edged round particle.<p><b>Defaults:</b><p>Lifetime: 8-40 ticks<br>Colour: white */ PATH,
|
||||
/** Snowflake particle.<p><b>Defaults:</b><p>Lifetime: 40-50 ticks<br>Velocity: (0, -0.02, 0) */ SNOW,
|
||||
/** Animated lightning particle.<p><b>Defaults:</b><p>Lifetime: 3 ticks */ SPARK,
|
||||
/** Animated sparkle particle.<p><b>Defaults:</b><p>Lifetime: 48-60 ticks<br>Colour: white */ SPARKLE,
|
||||
@Deprecated SPARKLE_ROTATING
|
||||
}
|
||||
|
||||
private ParticleBuilder(){
|
||||
reset();
|
||||
}
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/**
|
||||
* Starts building a particle of the given type. Static convenience version of
|
||||
* {@link ParticleBuilder#particle(Type)}; makes code more concise.
|
||||
* @param type The type of particle to build
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is already building.
|
||||
*/
|
||||
public static ParticleBuilder create(Type type){
|
||||
return ParticleBuilder.instance.particle(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building a particle of the given type and positions it randomly within the given entity's bounding box.
|
||||
* Equivalent to calling {@code ParticleBuilder.create(type).pos(...)}; users should chain any additional builder
|
||||
* methods onto this one and finish with {@code .spawn(world)} as normal.
|
||||
* Used extensively with summoned creatures; makes code much neater and more concise.
|
||||
* @param type The type of particle to build
|
||||
* @param entity The entity to position the particle at
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is already building.
|
||||
*/
|
||||
public static ParticleBuilder create(Type type, Entity entity){
|
||||
|
||||
double x = entity.posX + (entity.world.rand.nextDouble() - 0.5D) * (double)entity.width;
|
||||
double y = entity.posY + entity.world.rand.nextDouble() * (double)entity.height;
|
||||
double z = entity.posZ + (entity.world.rand.nextDouble() - 0.5D) * (double)entity.width;
|
||||
|
||||
return ParticleBuilder.instance.particle(type).pos(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building a particle of the given type and positions it randomly within the given radius of the given position,
|
||||
* with velocity proportional to distance from the given position if move is true. Good for making explosion-type effects.
|
||||
* Equivalent to calling {@code ParticleBuilder.create(type).pos(...).vel(...)}; users should chain any additional builder
|
||||
* methods onto this one and finish with {@code .spawn(world)} as normal.
|
||||
* @param type The type of particle to build
|
||||
* @param random An RNG instance
|
||||
* @param x The x coordinate of the centre of the region in which to position the particle
|
||||
* @param y The y coordinate of the centre of the region in which to position the particle
|
||||
* @param z The z coordinate of the centre of the region in which to position the particle
|
||||
* @param radius The radius of the region in which to position the particle
|
||||
* @param move Whether the particle should move outwards from the centre (note that if this is false, the particle's
|
||||
* default velocity will apply)
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is already building.
|
||||
*/
|
||||
public static ParticleBuilder create(Type type, Random random, double x, double y, double z, double radius, boolean move){
|
||||
|
||||
double px = x + (random.nextDouble() - 0.5D) * radius;
|
||||
double py = y + (random.nextDouble() - 0.5D) * radius;
|
||||
double pz = z + (random.nextDouble() - 0.5D) * radius;
|
||||
|
||||
if(move) return ParticleBuilder.instance.particle(type).pos(x, y, z).vel(px-x, py-y, pz-z);
|
||||
|
||||
return ParticleBuilder.instance.particle(type).pos(x, y, z);
|
||||
}
|
||||
|
||||
// Core builder methods
|
||||
|
||||
/**
|
||||
* Starts building a particle of the given type.
|
||||
* @param type The type of particle to build
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is already building.
|
||||
*/
|
||||
public ParticleBuilder particle(Type type){
|
||||
if(building) throw new IllegalStateException("Already building!");
|
||||
this.type = type;
|
||||
this.building = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the particle being built. If unspecified, this defaults to the origin (0, 0, 0).
|
||||
* <p>
|
||||
* <b>Affects:</b> All particle types
|
||||
* @param x The x coordinate to set
|
||||
* @param y The y coordinate to set
|
||||
* @param z The z coordinate to set
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder pos(double x, double y, double z){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the velocity of the particle being built. If unspecified, this defaults to the particle's default velocity,
|
||||
* specified within its constructor.
|
||||
* <p>
|
||||
* <b>Affects:</b> All particle types except {@link Type#DUST DUST}
|
||||
* @param x The x coordinate to set
|
||||
* @param y The y coordinate to set
|
||||
* @param z The z coordinate to set
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder vel(double vx, double vy, double vz){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.vx = vx;
|
||||
this.vy = vy;
|
||||
this.vz = vz;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the colour of the particle being built. If unspecified, this defaults to the particle's default colour,
|
||||
* specified within its constructor.
|
||||
* <p>
|
||||
* <b>Affects:</b> {@link Type#DARK_MAGIC DARK_MAGIC}, {@link Type#DUST DUST}, {@link Type#FLASH FLASH},
|
||||
* {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE}
|
||||
* @param r The red colour component to set; will be clamped to between 0 and 1
|
||||
* @param g The green colour component to set; will be clamped to between 0 and 1
|
||||
* @param b The blue colour component to set; will be clamped to between 0 and 1
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder colour(float r, float g, float b){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.r = MathHelper.clamp(r, 0, 1);
|
||||
this.g = MathHelper.clamp(g, 0, 1);
|
||||
this.b = MathHelper.clamp(b, 0, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fade colour of the particle being built. If unspecified, this defaults to the whatever the particle's base
|
||||
* colour is.
|
||||
* <p>
|
||||
* <b>Affects:</b> {@link Type#DUST DUST}, {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE}
|
||||
* @param r The red colour component to set; will be clamped to between 0 and 1
|
||||
* @param g The green colour component to set; will be clamped to between 0 and 1
|
||||
* @param b The blue colour component to set; will be clamped to between 0 and 1
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder fade(float r, float g, float b){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.fr = MathHelper.clamp(r, 0, 1);
|
||||
this.fg = MathHelper.clamp(g, 0, 1);
|
||||
this.fb = MathHelper.clamp(b, 0, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scale of the particle being built. If unspecified, this defaults to 1.
|
||||
* <p>
|
||||
* <b>Affects:</b> All particle types
|
||||
* @param scale The scale to set, as a multiple of the particle's default scale
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder scale(float scale){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.scale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lifetime of the particle being built. If unspecified, this defaults to the particle's default lifetime,
|
||||
* specified within its constructor.
|
||||
* <p>
|
||||
* <b>Affects:</b> All particle types
|
||||
* @param lifetime The lifetime to set in ticks
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder lifetime(int lifetime){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.lifetime = lifetime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rotation radius of the particle being built. If unspecified, this defaults to 0.
|
||||
* <p>
|
||||
* <b>Affects:</b> All particle types
|
||||
* @param radius The rotation radius to set
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder radius(double radius){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.radius = radius;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gravity of the particle being built. If unspecified, this defaults to false.
|
||||
* <p>
|
||||
* <b>Affects:</b> {@link Type#ICE ICE}, {@link Type#SPARKLE SPARKLE}
|
||||
* @param gravity True to enable gravity for the particle, false to disable
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder gravity(boolean gravity){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.gravity = gravity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shading of the particle being built. If unspecified, this defaults to false.
|
||||
* <p>
|
||||
* <b>Affects:</b> All particle types
|
||||
* @param shaded True to enable shading for the particle, false for full brightness
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder shaded(boolean shaded){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.shaded = shaded;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the entity of the particle being built. This <b>must</b> be specified for entity-linked particles.
|
||||
* @param entity The entity to set
|
||||
* @return The particle builder instance, allowing other methods to be chained onto this one
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public ParticleBuilder entity(Entity entity){
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
this.entity = entity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns the particle that has been built and resets the particle builder.
|
||||
* @param world The world in which to spawn the particle
|
||||
* @throws IllegalStateException if the particle builder is not yet building.
|
||||
*/
|
||||
public void spawn(World world){
|
||||
|
||||
if(!building) throw new IllegalStateException("Not building yet!");
|
||||
|
||||
if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity"
|
||||
+ "has been set correctly?");
|
||||
|
||||
electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z);
|
||||
|
||||
if(particle == null){
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
particle.multipleParticleScaleBy(scale);
|
||||
if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz);
|
||||
if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b);
|
||||
if(fr >= 0 && fg >= 0 && fb >= 0) particle.setFadeColour(fr, fg, fb);
|
||||
if(lifetime >= 0) particle.setLifetime(lifetime);
|
||||
particle.setGravity(gravity);
|
||||
particle.setShaded(shaded);
|
||||
|
||||
net.minecraft.client.Minecraft.getMinecraft().effectRenderer.addEffect(particle);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/** Resets the state of the particle builder and resets all the builder variables to their default values. */
|
||||
private void reset(){
|
||||
building = false;
|
||||
type = null;
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
// NaN indicates the velocity was not set (can't use -1 since it could very reasonably be -1)
|
||||
// For all other values -1 indicates the value was not set
|
||||
vx = Double.NaN;
|
||||
vy = Double.NaN;
|
||||
vz = Double.NaN;
|
||||
r = -1;
|
||||
g = -1;
|
||||
b = -1;
|
||||
fr = -1;
|
||||
fg = -1;
|
||||
fb = -1;
|
||||
radius = 0;
|
||||
lifetime = -1;
|
||||
gravity = false;
|
||||
shaded = false;
|
||||
scale = 1;
|
||||
entity = null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user