[Tutorial] Custom particle direction

Discussion in 'Resources' started by RingOfStorms, Nov 6, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    RingOfStorms

    Once MCP 1.8 came out I took a peak at new packets in the client and looked at the particles packet in the client. I realized that there were parameters for the motion of the particle and thought it was a new feature in 1.8 packet. However, the functionality for determining particle direction has been there all along, just no one ever looked for it.

    Many particle libraries have something called offset, or stack x/y/z. This is actually a double meaning variable and depending on the particle count, this x,y,z are vector coordinates that can control the exact velocity of the particle.

    Lets get to the goods:


    Edit: Disclaimer - This will not work on ALL particles, some of the particles have hard coded motion and therefor wont be affected when doing this. You'll need to experiment with which it effects and which it does not.

    I'm using my own particle library for this, but it should be very similar to the ones that most people are using. You'll be using the function that has the offset parameters.

    We will be shooting a flame particle in the direction that someone is looking: (Note this method will only shoot one particle at a time)
    Code:java
    1.  
    2. Player player = //some player you have
    3. Vector dir = p.getLocation().getDirection().normalize(); //normalizing is important, your vector is multiplied by particle speed client side.
    4. ParticleEffect.FLAME.setStack((float) dir.getX(), (float) dir.getY(), (float) dir,getZ()); //this is the offset in most other particle libraries
    5. ParticleEffect.FLAME.animateToLocation(player.getEyeLocation(), 0, 1);// Where 0 is the count of particles, and 1 is the speed.
    6.  


    Another example using another particle library:
    Show Spoiler

    Library by DarkBlade12
    Note that if you use this, you will have to remove the amount check inside of the ParticleEffectPacket class as the author assumed that zero would be invalid.
    Code:java
    1.  
    2. float speed = 1F;
    3. int amount = 0;
    4. Location center = player.getEyeLocation();
    5. ParticleEffect.FLAME.display((float) dir.getX(), (float) dir.getY(), (float) dir.getZ(), speed, amount, center, 256D);
    6.  



    That is all there is to it. Note that the count of particles is zero. When the particle count is zero, the client will turn the offset into a vector. Also, you should normalize the vector that you use because the client will multiply it by the particle's speed.

    Why does this work? Gist
    When the count of particles is zero, the client will instead spawn one particle with the given x,y,z as a vector direction. Below is the code where this happens in the client.
    g/h/i are the offset x/y/z and j is the speed. k is the number of particles.
    Show Spoiler

    Code:java
    1.  
    2. public void handleParticles(S2APacketParticles packetIn)
    3. {
    4. PacketThreadUtil.func_180031_a(packetIn, this, this.gameController);
    5.  
    6. if (packetIn.func_149222_k() == 0)
    7. {
    8. double var2 = (double)(packetIn.func_149227_j() * packetIn.func_149221_g());
    9. double var4 = (double)(packetIn.func_149227_j() * packetIn.func_149224_h());
    10. double var6 = (double)(packetIn.func_149227_j() * packetIn.func_149223_i());
    11.  
    12. try
    13. {
    14. this.clientWorldController.spawnParticle(packetIn.func_179749_a(), packetIn.func_179750_b(), packetIn.func_149220_d(), packetIn.func_149226_e(), packetIn.func_149225_f(), var2, var4, var6, packetIn.func_179748_k());
    15. }
    16. catch (Throwable var17)
    17. {
    18. logger.warn("Could not spawn particle effect " + packetIn.func_179749_a());
    19. }
    20. }
    21. else
    22. {
    23. for (int var18 = 0; var18 < packetIn.func_149222_k(); ++var18)
    24. {
    25. double var3 = this.avRandomizer.nextGaussian() * (double)packetIn.func_149221_g();
    26. double var5 = this.avRandomizer.nextGaussian() * (double)packetIn.func_149224_h();
    27. double var7 = this.avRandomizer.nextGaussian() * (double)packetIn.func_149223_i();
    28. double var9 = this.avRandomizer.nextGaussian() * (double)packetIn.func_149227_j();
    29. double var11 = this.avRandomizer.nextGaussian() * (double)packetIn.func_149227_j();
    30. double var13 = this.avRandomizer.nextGaussian() * (double)packetIn.func_149227_j();
    31.  
    32. try
    33. {
    34. this.clientWorldController.spawnParticle(packetIn.func_179749_a(), packetIn.func_179750_b(), packetIn.func_149220_d() + var3, packetIn.func_149226_e() + var5, packetIn.func_149225_f() + var7, var9, var11, var13, packetIn.func_179748_k());
    35. }
    36. catch (Throwable var16)
    37. {
    38. logger.warn("Could not spawn particle effect " + packetIn.func_179749_a());
    39. return;
    40. }
    41. }
    42. }
    43. }
    44.  



    You may run into a slight problem with whatever particle library you are using. Some particle libraries have restricted the offset values to ints, even though the packet takes them in as floats. If this is the case, you may need to edit the library a bit to accept floats, otherwise your vector will be rounded off and only fire on an axis rather than the angles you expected.

    Side note to DarkBlade12 as you can see from this tutorial you may want to update your particle library to allow for this sort of use. Either remove the amount limit of at least 1, or add new methods that take direction params.
     
    DarkBladee12, DSH105, Assist and 2 others like this.
Thread Status:
Not open for further replies.

Share This Page