    001    package net.minecraft.client.particle;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.SideOnly;
    005    import java.util.ArrayList;
    006    import java.util.Iterator;
    007    import java.util.List;
    008    import java.util.Map.Entry;
    009    import java.util.Random;
    010    import net.minecraft.block.Block;
    011    import net.minecraft.client.renderer.ActiveRenderInfo;
    012    import net.minecraft.client.renderer.RenderEngine;
    013    import net.minecraft.client.renderer.Tessellator;
    014    import net.minecraft.crash.CrashReport;
    015    import net.minecraft.crash.CrashReportCategory;
    016    import net.minecraft.entity.Entity;
    017    import net.minecraft.item.Item;
    018    import net.minecraft.util.MathHelper;
    019    import net.minecraft.util.MovingObjectPosition;
    020    import net.minecraft.util.ReportedException;
    021    import net.minecraft.world.World;
    022    import org.lwjgl.opengl.GL11;
    023
    024    import net.minecraftforge.client.ForgeHooksClient;
    025    import net.minecraftforge.common.ForgeHooks;
    026    import com.google.common.collect.ArrayListMultimap;
    027    import com.google.common.collect.Multimap;
    028
    029    @SideOnly(Side.CLIENT)
    030    public class EffectRenderer
    031    {
    032        /** Reference to the World object. */
    033        protected World worldObj;
    034        private List[] fxLayers = new List[4];
    035        private RenderEngine renderer;
    036
    037        /** RNG. */
    038        private Random rand = new Random();
    039
    040        private Multimap<String, EntityFX> effectList = ArrayListMultimap.create();
    041
    042        public EffectRenderer(World par1World, RenderEngine par2RenderEngine)
    043        {
    044            if (par1World != null)
    045            {
    046                this.worldObj = par1World;
    047            }
    048
    049            this.renderer = par2RenderEngine;
    050
    051            for (int var3 = 0; var3 < 4; ++var3)
    052            {
    053                this.fxLayers[var3] = new ArrayList();
    054            }
    055        }
    056
    057        public void addEffect(EntityFX par1EntityFX)
    058        {
    059            int var2 = par1EntityFX.getFXLayer();
    060
    061            if (this.fxLayers[var2].size() >= 4000)
    062            {
    063                this.fxLayers[var2].remove(0);
    064            }
    065
    066            this.fxLayers[var2].add(par1EntityFX);
    067        }
    068
    069        public void updateEffects()
    070        {
    071            for (int var1 = 0; var1 < 4; ++var1)
    072            {
    073                EntityFX var2 = null;
    074
    075                try
    076                {
    077                    for (int var3 = 0; var3 < this.fxLayers[var1].size(); ++var3)
    078                    {
    079                        var2 = (EntityFX)this.fxLayers[var1].get(var3);
    080
    081                        if (var2 != null)
    082                        {
    083                            var2.onUpdate();
    084                        }
    085
    086                        if (var2 == null || var2.isDead)
    087                        {
    088                            this.fxLayers[var1].remove(var3--);
    089                        }
    090                    }
    091                }
    092                catch (Throwable var7)
    093                {
    094                    CrashReport var4 = CrashReport.func_85055_a(var7, "Uncaught exception while ticking particles");
    095                    CrashReportCategory var5 = var4.func_85058_a("Particle engine details");
    096                    var5.addCrashSectionCallable("Last ticked particle", new CallableLastTickedParticle(this, var2));
    097                    var5.addCrashSection("Texture index", Integer.valueOf(var1));
    098                    throw new ReportedException(var4);
    099                }
    100            }
    101
    102            Iterator<Entry<String, EntityFX>> itr = effectList.entries().iterator();
    103            while (itr.hasNext())
    104            {
    105                EntityFX fx = itr.next().getValue();
    106                fx.onUpdate();
    107                if (fx.isDead)
    108                {
    109                    itr.remove();
    110                }
    111            }
    112        }
    113
    114        /**
    115         * Renders all current particles. Args player, partialTickTime
    116         */
    117        public void renderParticles(Entity par1Entity, float par2)
    118        {
    119            float var3 = ActiveRenderInfo.rotationX;
    120            float var4 = ActiveRenderInfo.rotationZ;
    121            float var5 = ActiveRenderInfo.rotationYZ;
    122            float var6 = ActiveRenderInfo.rotationXY;
    123            float var7 = ActiveRenderInfo.rotationXZ;
    124            EntityFX.interpPosX = par1Entity.lastTickPosX + (par1Entity.posX - par1Entity.lastTickPosX) * (double)par2;
    125            EntityFX.interpPosY = par1Entity.lastTickPosY + (par1Entity.posY - par1Entity.lastTickPosY) * (double)par2;
    126            EntityFX.interpPosZ = par1Entity.lastTickPosZ + (par1Entity.posZ - par1Entity.lastTickPosZ) * (double)par2;
    127
    128            for (int var8 = 0; var8 < 3; ++var8)
    129            {
    130                if (!this.fxLayers[var8].isEmpty())
    131                {
    132                    int var9 = 0;
    133
    134                    if (var8 == 0)
    135                    {
    136                        var9 = this.renderer.getTexture("/particles.png");
    137                    }
    138
    139                    if (var8 == 1)
    140                    {
    141                        var9 = this.renderer.getTexture("/terrain.png");
    142                    }
    143
    144                    if (var8 == 2)
    145                    {
    146                        var9 = this.renderer.getTexture("/gui/items.png");
    147                    }
    148
    149                    GL11.glBindTexture(GL11.GL_TEXTURE_2D, var9);
    150                    Tessellator var10 = Tessellator.instance;
    151                    GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
    152                    GL11.glEnable(GL11.GL_BLEND);
    153                    GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
    154                    var10.startDrawingQuads();
    155
    156                    for (int var11 = 0; var11 < this.fxLayers[var8].size(); ++var11)
    157                    {
    158                        EntityFX var12 = (EntityFX)this.fxLayers[var8].get(var11);
    159                        if (var12 == null) continue;
    160                        var10.setBrightness(var12.getBrightnessForRender(par2));
    161                        var12.renderParticle(var10, par2, var3, var7, var4, var5, var6);
    162                    }
    163
    164                    var10.draw();
    165                    GL11.glDisable(GL11.GL_BLEND);
    166                }
    167            }
    168
    169            for (String key : effectList.keySet())
    170            {
    171                ForgeHooksClient.bindTexture(key, 0);
    172                for (EntityFX entry : effectList.get(key))
    173                {
    174                    if (entry == null) continue;
    175                    Tessellator tessallator = Tessellator.instance;
    176                    //GL11.glBindTexture(GL11.GL_TEXTURE_2D, renderer.getTexture(key));
    177                    tessallator.startDrawingQuads();
    178
    179                    if (entry.getFXLayer() != 3)
    180                    {
    181                        tessallator.setBrightness(entry.getBrightnessForRender(par2));
    182                        entry.renderParticle(tessallator, par2, var3, var7, var4, var5, var6);
    183                    }
    184
    185                    tessallator.draw();
    186                }
    187                ForgeHooksClient.unbindTexture();
    188            }
    189        }
    190
    191        public void renderLitParticles(Entity par1Entity, float par2)
    192        {
    193            float var4 = MathHelper.cos(par1Entity.rotationYaw * 0.017453292F);
    194            float var5 = MathHelper.sin(par1Entity.rotationYaw * 0.017453292F);
    195            float var6 = -var5 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F);
    196            float var7 = var4 * MathHelper.sin(par1Entity.rotationPitch * 0.017453292F);
    197            float var8 = MathHelper.cos(par1Entity.rotationPitch * 0.017453292F);
    198            byte var9 = 3;
    199
    200            if (!this.fxLayers[var9].isEmpty())
    201            {
    202                Tessellator var10 = Tessellator.instance;
    203
    204                for (int var11 = 0; var11 < this.fxLayers[var9].size(); ++var11)
    205                {
    206                    EntityFX var12 = (EntityFX)this.fxLayers[var9].get(var11);
    207                    if (var12 == null) continue;
    208                    var10.setBrightness(var12.getBrightnessForRender(par2));
    209                    var12.renderParticle(var10, par2, var4, var8, var5, var6, var7);
    210                }
    211            }
    212        }
    213
    214        public void clearEffects(World par1World)
    215        {
    216            this.worldObj = par1World;
    217
    218            for (int var2 = 0; var2 < 4; ++var2)
    219            {
    220                this.fxLayers[var2].clear();
    221            }
    222
    223            effectList.clear();
    224        }
    225
    226        public void addBlockDestroyEffects(int par1, int par2, int par3, int par4, int par5)
    227        {
    228            Block var6 = Block.blocksList[par4];
    229            if (var6 != null && !var6.addBlockDestroyEffects(worldObj, par1, par2, par3, par5, this))
    230            {
    231                byte var7 = 4;
    232
    233                for (int var8 = 0; var8 < var7; ++var8)
    234                {
    235                    for (int var9 = 0; var9 < var7; ++var9)
    236                    {
    237                        for (int var10 = 0; var10 < var7; ++var10)
    238                        {
    239                            double var11 = (double)par1 + ((double)var8 + 0.5D) / (double)var7;
    240                            double var13 = (double)par2 + ((double)var9 + 0.5D) / (double)var7;
    241                            double var15 = (double)par3 + ((double)var10 + 0.5D) / (double)var7;
    242                            int var17 = this.rand.nextInt(6);
    243                            this.addEffect((new EntityDiggingFX(this.worldObj, var11, var13, var15, var11 - (double)par1 - 0.5D, var13 - (double)par2 - 0.5D, var15 - (double)par3 - 0.5D, var6, var17, par5)).func_70596_a(par1, par2, par3), var6);
    244                        }
    245                    }
    246                }
    247            }
    248        }
    249
    250        /**
    251         * Adds block hit particles for the specified block. Args: x, y, z, sideHit
    252         */
    253        public void addBlockHitEffects(int par1, int par2, int par3, int par4)
    254        {
    255            int var5 = this.worldObj.getBlockId(par1, par2, par3);
    256
    257            if (var5 != 0)
    258            {
    259                Block var6 = Block.blocksList[var5];
    260                float var7 = 0.1F;
    261                double var8 = (double)par1 + this.rand.nextDouble() * (var6.getBlockBoundsMaxX() - var6.getBlockBoundsMinX() - (double)(var7 * 2.0F)) + (double)var7 + var6.getBlockBoundsMinX();
    262                double var10 = (double)par2 + this.rand.nextDouble() * (var6.getBlockBoundsMaxY() - var6.getBlockBoundsMinY() - (double)(var7 * 2.0F)) + (double)var7 + var6.getBlockBoundsMinY();
    263                double var12 = (double)par3 + this.rand.nextDouble() * (var6.getBlockBoundsMaxZ() - var6.getBlockBoundsMinZ() - (double)(var7 * 2.0F)) + (double)var7 + var6.getBlockBoundsMinZ();
    264
    265                if (par4 == 0)
    266                {
    267                    var10 = (double)par2 + var6.getBlockBoundsMinY() - (double)var7;
    268                }
    269
    270                if (par4 == 1)
    271                {
    272                    var10 = (double)par2 + var6.getBlockBoundsMaxY() + (double)var7;
    273                }
    274
    275                if (par4 == 2)
    276                {
    277                    var12 = (double)par3 + var6.getBlockBoundsMinZ() - (double)var7;
    278                }
    279
    280                if (par4 == 3)
    281                {
    282                    var12 = (double)par3 + var6.getBlockBoundsMaxZ() + (double)var7;
    283                }
    284
    285                if (par4 == 4)
    286                {
    287                    var8 = (double)par1 + var6.getBlockBoundsMinX() - (double)var7;
    288                }
    289
    290                if (par4 == 5)
    291                {
    292                    var8 = (double)par1 + var6.getBlockBoundsMaxX() + (double)var7;
    293                }
    294
    295                this.addEffect((new EntityDiggingFX(this.worldObj, var8, var10, var12, 0.0D, 0.0D, 0.0D, var6, par4, this.worldObj.getBlockMetadata(par1, par2, par3))).func_70596_a(par1, par2, par3).multiplyVelocity(0.2F).multipleParticleScaleBy(0.6F), var6);
    296            }
    297        }
    298
    299        public String getStatistics()
    300        {
    301            int size = 0;
    302            for (List x : fxLayers)
    303            {
    304                size += x.size();
    305            }
    306            size += effectList.size();
    307            return Integer.toString(size);
    308        }
    309
    310        public void addEffect(EntityFX effect, Object obj)
    311        {
    312            if (obj == null || !(obj instanceof Block || obj instanceof Item))
    313            {
    314                addEffect(effect);
    315                return;
    316            }
    317
    318            if (obj instanceof Item && ((Item)obj).isDefaultTexture)
    319            {
    320                addEffect(effect);
    321                return;
    322            }
    323
    324            if (obj instanceof Block && ((Block)obj).isDefaultTexture)
    325            {
    326                addEffect(effect);
    327                return;
    328            }
    329
    330            String texture = "/terrain.png";
    331            if (effect.getFXLayer() == 0)
    332            {
    333                texture = "/particles.png";
    334            }
    335            else if (effect.getFXLayer() == 2)
    336            {
    337                texture = "/gui/items.png";
    338            }
    339            texture = ForgeHooks.getTexture(texture, obj);
    340            effectList.put(texture, effect);
    341        }
    342
    343        public void addBlockHitEffects(int x, int y, int z, MovingObjectPosition target)
    344        {
    345            Block block = Block.blocksList[worldObj.getBlockId(x, y, z)];
    346            if (block != null && !block.addBlockHitEffects(worldObj, target, this))
    347            {
    348                addBlockHitEffects(x, y, z, target.sideHit);
    349            }
    350        }
    351    }