/*
* Copyright (C) 2022 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see .
*/
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.core.ChromaColour;
import io.github.moulberry.notenoughupdates.events.SpawnParticleEvent;
import io.github.moulberry.notenoughupdates.util.SpecialColour;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.PositionedSound;
import net.minecraft.client.audio.SoundCategory;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.EntityFishHook;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@NEUAutoSubscribe
public class FishingHelper {
private static final FishingHelper INSTANCE = new FishingHelper();
public static FishingHelper getInstance() {
return INSTANCE;
}
public static class WakeChain {
public int particleNum = 0;
public long lastUpdate;
public double currentAngle;
public double currentX;
public double currentZ;
public final HashMap distances = new HashMap<>();
public WakeChain(long lastUpdate, double currentAngle, double currentX, double currentZ) {
this.lastUpdate = lastUpdate;
this.currentAngle = currentAngle;
this.currentX = currentX;
this.currentZ = currentZ;
}
}
public enum PlayerWarningState {
NOTHING,
FISH_INCOMING,
FISH_HOOKED
}
public PlayerWarningState warningState = PlayerWarningState.NOTHING;
private int hookedWarningStateTicks = 0;
public final HashMap hookEntities = new HashMap<>();
public final HashMap> chains = new HashMap<>();
private long lastCastRodMillis = 0;
private int pingDelayTicks = 0;
private final List pingDelayList = new ArrayList<>();
private int buildupSoundDelay = 0;
private boolean playedSound = false;
private static final ResourceLocation FISHING_WARNING_EXCLAM = new ResourceLocation(
"notenoughupdates:fishing_warning_exclam.png");
public boolean renderWarning() {
if (warningState == PlayerWarningState.NOTHING) return false;
if (!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning &&
warningState == PlayerWarningState.FISH_INCOMING)
return false;
if (!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR &&
warningState == PlayerWarningState.FISH_HOOKED)
return false;
float offset = warningState == PlayerWarningState.FISH_HOOKED ? 0.5f : 0f;
float centerOffset = 0.5f / 8f;
Minecraft.getMinecraft().getTextureManager().bindTexture(FISHING_WARNING_EXCLAM);
Utils.drawTexturedRect(
centerOffset - 4f / 8f,
-20 / 8f,
1f,
2f,
0 + offset,
0.5f + offset,
0,
1,
GL11.GL_NEAREST
);
return true;
}
public void onRenderBobber(EntityFishHook hook) {
if (Minecraft.getMinecraft().thePlayer.fishEntity != hook) return;
GlStateManager.pushMatrix();
GlStateManager.disableCull();
GlStateManager.disableLighting();
GL11.glDepthFunc(GL11.GL_ALWAYS);
GlStateManager.scale(1, -1, 1);
boolean isExclamationMarkPresent = renderWarning();
GlStateManager.scale(0.1, 0.1, 1);
drawFishingTimer(hook, isExclamationMarkPresent);
GL11.glDepthFunc(GL11.GL_LEQUAL);
GlStateManager.enableLighting();
GlStateManager.enableCull();
GlStateManager.popMatrix();
}
private void drawFishingTimer(EntityFishHook hook, boolean isExclamationMarkPresent) {
if (!NotEnoughUpdates.INSTANCE.config.fishing.fishingTimer) return;
float baseHeight = isExclamationMarkPresent ? 20 : 0;
int ticksExisted = hook.ticksExisted;
float seconds = ticksExisted / 20F;
int color;
float maxSlugTime = 20;
PetInfoOverlay.Pet pet = PetInfoOverlay.getCurrentPet();
if (NotEnoughUpdates.INSTANCE.config.fishing.enableSlugCheck && pet != null) {
if (pet.petLevel != null &&
pet.petType.equalsIgnoreCase("slug")
) {
double slugFactor = 0.005 * pet.petLevel.getCurrentLevel();
maxSlugTime = (float) (maxSlugTime * (1 - slugFactor));
}
}
if (seconds >= maxSlugTime) {
color = ChromaColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.fishing.fishingTimerColor30SecPlus);
if (NotEnoughUpdates.INSTANCE.config.fishing.fishingSound30Sec && !playedSound) {
ISound sound = new PositionedSound(new ResourceLocation("random.orb")) {{
volume = 50;
pitch = 2f;
repeat = false;
repeatDelay = 0;
attenuationType = ISound.AttenuationType.NONE;
}};
float oldLevel = Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS);
Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, 1);
Minecraft.getMinecraft().getSoundHandler().playSound(sound);
Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, oldLevel);
playedSound = true;
}
} else {
color = ChromaColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.fishing.fishingTimerColor);
playedSound = false;
}
Utils.drawStringCentered(
String.format("%.02fs", seconds),
0, -baseHeight - Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT, false, color
);
}
public void addEntity(int entityId, Entity entity) {
if (entity instanceof EntityFishHook) {
hookEntities.put(entityId, (EntityFishHook) entity);
if (((EntityFishHook) entity).angler == Minecraft.getMinecraft().thePlayer) {
long currentTime = System.currentTimeMillis();
long delay = currentTime - lastCastRodMillis;
if (delay > 0 && delay < 500) {
if (delay > 300) delay = 300;
pingDelayList.add(0, (int) delay);
}
}
}
}
public void removeEntity(int entityId) {
hookEntities.remove(entityId);
}
@SubscribeEvent
public void onWorldUnload(WorldEvent.Unload event) {
hookEntities.clear();
chains.clear();
}
@SubscribeEvent
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR &&
event.entityPlayer == Minecraft.getMinecraft().thePlayer) {
ItemStack heldItem = event.entityPlayer.getHeldItem();
if (heldItem != null && heldItem.getItem() == Items.fishing_rod) {
long currentTime = System.currentTimeMillis();
if (currentTime - lastCastRodMillis > 500) {
lastCastRodMillis = currentTime;
}
}
}
}
private int tickCounter = 0;
@SubscribeEvent
public void onTick(TickEvent.ClientTickEvent event) {
if (Minecraft.getMinecraft().thePlayer != null && event.phase == TickEvent.Phase.END) {
if (buildupSoundDelay > 0) buildupSoundDelay--;
if (NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning ||
NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR) {
if (Minecraft.getMinecraft().thePlayer.fishEntity != null) {
if (!pingDelayList.isEmpty()) {
while (pingDelayList.size() > 5) pingDelayList.remove(pingDelayList.size() - 1);
int totalMS = 0;
for (int delay : pingDelayList) {
totalMS += delay;
}
int averageMS = totalMS / pingDelayList.size();
pingDelayTicks = (int) Math.floor(averageMS / 50f);
}
}
if (hookedWarningStateTicks > 0) {
hookedWarningStateTicks--;
warningState = PlayerWarningState.FISH_HOOKED;
} else {
warningState = PlayerWarningState.NOTHING;
if (Minecraft.getMinecraft().thePlayer.fishEntity != null) {
int fishEntityId = Minecraft.getMinecraft().thePlayer.fishEntity.getEntityId();
for (Map.Entry> entry : chains.entrySet()) {
if (entry.getKey().particleNum >= 3 && entry.getValue().contains(fishEntityId)) {
warningState = PlayerWarningState.FISH_INCOMING;
break;
}
}
}
}
}
if (tickCounter++ >= 20) {
long currentTime = System.currentTimeMillis();
tickCounter = 0;
Set toRemoveEnt = new HashSet<>();
for (Map.Entry entry : hookEntities.entrySet()) {
if (entry.getValue().isDead) {
toRemoveEnt.add(entry.getKey());
}
}
hookEntities.keySet().removeAll(toRemoveEnt);
Set toRemoveChain = new HashSet<>();
for (Map.Entry> entry : chains.entrySet()) {
if (currentTime - entry.getKey().lastUpdate > 200 ||
entry.getValue().isEmpty() ||
Collections.disjoint(entry.getValue(), hookEntities.keySet())) {
toRemoveChain.add(entry.getKey());
}
}
chains.keySet().removeAll(toRemoveChain);
}
}
}
private double calculateAngleFromOffsets(double xOffset, double zOffset) {
double angleX = Math.toDegrees(Math.acos(xOffset / 0.04f));
double angleZ = Math.toDegrees(Math.asin(zOffset / 0.04f));
if (xOffset < 0) {
angleZ = 180 - angleZ;
}
if (zOffset < 0) {
angleX = 360 - angleX;
}
angleX %= 360;
angleZ %= 360;
if (angleX < 0) angleX += 360;
if (angleZ < 0) angleZ += 360;
double dist = angleX - angleZ;
if (dist < -180) dist += 360;
if (dist > 180) dist -= 360;
return angleZ + dist / 2;
}
private boolean checkAngleWithinRange(double angle1, double angle2, double range) {
double dist = Math.abs(angle1 - angle2);
if (dist > 180) dist = 360 - dist;
return dist <= range;
}
private enum HookPossibleRet {
NOT_POSSIBLE,
EITHER,
ANGLE1,
ANGLE2
}
private HookPossibleRet isHookPossible(
EntityFishHook hook,
double particleX,
double particleY,
double particleZ,
double angle1,
double angle2
) {
double dY = particleY - hook.posY;
double tolerance = 0.5F;
if (hook.worldObj != null) {
for (int i = -2; i < 2; i++) {
IBlockState state = hook.worldObj.getBlockState(new BlockPos(particleX, particleY + i, particleZ));
if (state != null && (state.getBlock() == Blocks.flowing_lava
|| state.getBlock() == Blocks.flowing_water
|| state.getBlock() == Blocks.lava))
tolerance = 2.0F;
}
}
if (Math.abs(dY) > tolerance) {
return HookPossibleRet.NOT_POSSIBLE;
}
double dX = particleX - hook.posX;
double dZ = particleZ - hook.posZ;
double dist = Math.sqrt(dX * dX + dZ * dZ);
if (dist < 0.2) {
return HookPossibleRet.EITHER;
} else {
float angleAllowance = (float) Math.toDegrees(Math.atan2(0.03125f, dist)) * 1.5f;
float angleHook = (float) Math.toDegrees(Math.atan2(dX, dZ));
angleHook %= 360;
if (angleHook < 0) angleHook += 360;
if (checkAngleWithinRange(angle1, angleHook, angleAllowance)) {
return HookPossibleRet.ANGLE1;
} else if (checkAngleWithinRange(angle2, angleHook, angleAllowance)) {
return HookPossibleRet.ANGLE2;
}
}
return HookPossibleRet.NOT_POSSIBLE;
}
public static EnumParticleTypes type = EnumParticleTypes.BARRIER;
private static final float ZERO_PITCH = 1.0f;
private static final float MAX_PITCH = 0.1f;
private static final float MAX_DISTANCE = 5f;
private float calculatePitchFromDistance(float d) {
if (d < 0.1f) d = 0.1f;
if (d > MAX_DISTANCE) d = MAX_DISTANCE;
return 1 / (d + (1 / (ZERO_PITCH - MAX_PITCH))) * (1 - d / MAX_DISTANCE) + MAX_PITCH;
}
@SubscribeEvent
public void onSpawnParticle(SpawnParticleEvent event) {
EnumParticleTypes particleType = event.getParticleTypes();
double x = event.getXCoord();
double y = event.getYCoord();
double z = event.getZCoord();
double xOffset = event.getXOffset();
double yOffset = event.getYOffset();
double zOffset = event.getZOffset();
if (!NotEnoughUpdates.INSTANCE.config.fishing.hideOtherPlayerAll &&
!NotEnoughUpdates.INSTANCE.config.fishing.enableCustomParticles &&
!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning &&
!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR) {
return;
}
if (hookEntities.isEmpty()) {
return;
}
if ((particleType == EnumParticleTypes.WATER_WAKE || particleType == EnumParticleTypes.SMOKE_NORMAL || particleType == EnumParticleTypes.FLAME) && Math.abs(
yOffset - 0.01f) < 0.001f) {
double angle1 = calculateAngleFromOffsets(xOffset, -zOffset);
double angle2 = calculateAngleFromOffsets(-xOffset, zOffset);
final List possibleHooks1 = new ArrayList<>();
final List possibleHooks2 = new ArrayList<>();
for (EntityFishHook hook : hookEntities.values()) {
if (hook.isDead) continue;
if (possibleHooks1.contains(hook.getEntityId())) continue;
if (possibleHooks2.contains(hook.getEntityId())) continue;
HookPossibleRet ret = isHookPossible(hook, x, y, z, angle1, angle2);
if (ret == HookPossibleRet.ANGLE1) {
possibleHooks1.add(hook.getEntityId());
} else if (ret == HookPossibleRet.ANGLE2) {
possibleHooks2.add(hook.getEntityId());
} else if (ret == HookPossibleRet.EITHER) {
possibleHooks1.add(hook.getEntityId());
possibleHooks2.add(hook.getEntityId());
}
}
if (!possibleHooks1.isEmpty() || !possibleHooks2.isEmpty()) {
long currentTime = System.currentTimeMillis();
boolean isMainPlayer = false;
boolean foundChain = false;
for (Map.Entry> entry : chains.entrySet()) {
WakeChain chain = entry.getKey();
if (currentTime - chain.lastUpdate > 200) continue;
double updateAngle;
List possibleHooks;
if (checkAngleWithinRange(chain.currentAngle, angle1, 16)) {
possibleHooks = possibleHooks1;
updateAngle = angle1;
} else if (checkAngleWithinRange(chain.currentAngle, angle2, 16)) {
possibleHooks = possibleHooks2;
updateAngle = angle2;
} else {
continue;
}
if (!Collections.disjoint(entry.getValue(), possibleHooks)) {
HashSet newHooks = new HashSet<>();
for (int hookEntityId : possibleHooks) {
if (entry.getValue().contains(hookEntityId) && chain.distances.containsKey(hookEntityId)) {
EntityFishHook entity = hookEntities.get(hookEntityId);
if (entity != null && !entity.isDead) {
double oldDistance = chain.distances.get(hookEntityId);
double dX = entity.posX - x;
double dZ = entity.posZ - z;
double newDistance = Math.sqrt(dX * dX + dZ * dZ);
double delta = oldDistance - newDistance;
if (newDistance < 0.2 || (delta > -0.1 && delta < 0.3)) {
if ((NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning ||
NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR) &&
Minecraft.getMinecraft().thePlayer.fishEntity != null &&
Minecraft.getMinecraft().thePlayer.fishEntity.getEntityId() == hookEntityId &&
chain.particleNum > 3) {
float lavaOffset = 0.1f;
if (particleType == EnumParticleTypes.SMOKE_NORMAL) {
lavaOffset = 0.03f;
} else if (particleType == EnumParticleTypes.WATER_WAKE) {
lavaOffset = 0.1f;
}
if (newDistance <= 0.2f + lavaOffset * pingDelayTicks &&
NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR) {
if (NotEnoughUpdates.INSTANCE.config.fishing.incomingFishHookedSounds &&
hookedWarningStateTicks <= 0) {
float vol = NotEnoughUpdates.INSTANCE.config.fishing.incomingFishHookedSoundsVol / 100f;
if (vol > 0) {
if (vol > 1) vol = 1;
final float volF = vol;
ISound sound = new PositionedSound(new ResourceLocation("note.pling")) {{
volume = volF;
pitch = 2f;
repeat = false;
repeatDelay = 0;
attenuationType = ISound.AttenuationType.NONE;
}};
float oldLevel = Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS);
Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, 1);
Minecraft.getMinecraft().getSoundHandler().playSound(sound);
Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, oldLevel);
}
}
hookedWarningStateTicks = 12;
} else if (newDistance >= 0.4f + 0.1f * pingDelayTicks &&
NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning) {
if (NotEnoughUpdates.INSTANCE.config.fishing.incomingFishIncSounds &&
buildupSoundDelay <= 0) {
float vol = NotEnoughUpdates.INSTANCE.config.fishing.incomingFishIncSoundsVol / 100f;
if (vol > 0) {
if (vol > 1) vol = 1;
final float volF = vol;
ISound sound = new PositionedSound(new ResourceLocation("note.pling")) {{
volume = volF;
pitch = calculatePitchFromDistance((float) newDistance - (0.3f + 0.1f * pingDelayTicks));
repeat = false;
repeatDelay = 0;
attenuationType = ISound.AttenuationType.NONE;
}};
float oldLevel = Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS);
Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, 1);
Minecraft.getMinecraft().getSoundHandler().playSound(sound);
Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, oldLevel);
buildupSoundDelay = 4;
}
}
}
}
chain.distances.put(hookEntityId, newDistance);
newHooks.add(hookEntityId);
}
}
}
}
if (newHooks.isEmpty()) {
continue;
}
entry.getValue().retainAll(newHooks);
chain.distances.keySet().retainAll(newHooks);
for (int i : entry.getValue()) {
EntityFishHook hook = hookEntities.get(i);
if (hook != null && hook.angler == Minecraft.getMinecraft().thePlayer) {
isMainPlayer = true;
break;
}
}
chain.lastUpdate = currentTime;
chain.particleNum++;
chain.currentAngle = updateAngle;
foundChain = true;
}
}
if (!foundChain) {
possibleHooks1.removeAll(possibleHooks2);
if (!possibleHooks1.isEmpty()) {
for (int i : possibleHooks1) {
EntityFishHook hook = hookEntities.get(i);
if (hook != null && hook.angler == Minecraft.getMinecraft().thePlayer) {
isMainPlayer = true;
break;
}
}
WakeChain chain = new WakeChain(currentTime, angle1, x, z);
for (int hookEntityId : possibleHooks1) {
EntityFishHook entity = hookEntities.get(hookEntityId);
if (entity != null && !entity.isDead) {
double dX = entity.posX - x;
double dZ = entity.posZ - z;
double newDistance = Math.sqrt(dX * dX + dZ * dZ);
chain.distances.put(hookEntityId, newDistance);
}
}
chains.put(chain, possibleHooks1);
} else if (!possibleHooks2.isEmpty()) {
for (int i : possibleHooks2) {
EntityFishHook hook = hookEntities.get(i);
if (hook != null && hook.angler == Minecraft.getMinecraft().thePlayer) {
isMainPlayer = true;
break;
}
}
WakeChain chain = new WakeChain(currentTime, angle2, x, z);
for (int hookEntityId : possibleHooks2) {
EntityFishHook entity = hookEntities.get(hookEntityId);
if (entity != null && !entity.isDead) {
double dX = entity.posX - x;
double dZ = entity.posZ - z;
double newDistance = Math.sqrt(dX * dX + dZ * dZ);
chain.distances.put(hookEntityId, newDistance);
}
}
chains.put(chain, possibleHooks2);
}
}
int particleTypeI;
String particleCustomColour;
if (isMainPlayer) {
particleTypeI = NotEnoughUpdates.INSTANCE.config.fishing.yourParticleType;
particleCustomColour = NotEnoughUpdates.INSTANCE.config.fishing.yourParticleColour;
} else if (NotEnoughUpdates.INSTANCE.config.fishing.hideOtherPlayerAll) {
event.cancel();
return;
} else {
particleTypeI = NotEnoughUpdates.INSTANCE.config.fishing.otherParticleType;
particleCustomColour = NotEnoughUpdates.INSTANCE.config.fishing.otherParticleColour;
}
if (!NotEnoughUpdates.INSTANCE.config.fishing.enableCustomParticles) {
return;
}
int argb = SpecialColour.specialToChromaRGB(particleCustomColour);
if (particleTypeI == 0) {
return;
} else if (particleTypeI == 1) {
event.cancel();
return;
}
if (Minecraft.getMinecraft() != null && Minecraft.getMinecraft().getRenderViewEntity() != null &&
Minecraft.getMinecraft().effectRenderer != null) {
int i = Minecraft.getMinecraft().gameSettings.particleSetting;
if (i == 1 && Minecraft.getMinecraft().theWorld.rand.nextInt(3) == 0) {
event.cancel();
return;
}
if (i >= 2) {
event.cancel();
return;
}
double xDist = Minecraft.getMinecraft().getRenderViewEntity().posX - x;
double yDist = Minecraft.getMinecraft().getRenderViewEntity().posY - y;
double zDist = Minecraft.getMinecraft().getRenderViewEntity().posZ - z;
double distSq = xDist * xDist + yDist * yDist + zDist * zDist;
if (distSq < 32 * 32) {
boolean customColour = false;
double yVel = 0;
switch (particleTypeI) {
case 2:
particleType = EnumParticleTypes.FIREWORKS_SPARK;
customColour = true;
yVel = 0.05;
break;
case 3:
particleType = EnumParticleTypes.SPELL_MOB;
customColour = true;
break;
case 4:
particleType = EnumParticleTypes.REDSTONE;
customColour = true;
break;
case 5:
particleType = EnumParticleTypes.FLAME;
yVel = 0.015;
break;
case 6:
particleType = EnumParticleTypes.CRIT;
yVel = 0.05;
break;
case 7:
particleType = EnumParticleTypes.CRIT_MAGIC;
yVel = 0.05;
break;
}
if (customColour && (((argb >> 24) & 0xFF) < 10)) {
event.cancel();
return;
}
EntityFX fx = Minecraft.getMinecraft().effectRenderer.spawnEffectParticle(
particleType.getParticleID(),
x,
y,
z,
0,
0,
0
);
fx.motionX = Math.random() * 0.02 - 0.01;
fx.motionY = yVel;
fx.motionZ = Math.random() * 0.02 - 0.01;
if (customColour) {
float red = ((argb >> 16) & 0xFF) / 255f;
float green = ((argb >> 8) & 0xFF) / 255f;
float blue = (argb & 0xFF) / 255f;
float alpha = ((argb >> 24) & 0xFF) / 255f;
fx.setRBGColorF(red, green, blue);
fx.setAlphaF(alpha);
}
}
}
event.cancel();
return;
}
}
}
}