diff options
| author | BuildTools <james.jenour@protonmail.com> | 2021-05-29 22:02:37 +0800 |
|---|---|---|
| committer | BuildTools <james.jenour@protonmail.com> | 2021-05-29 22:02:37 +0800 |
| commit | 1b172089ce502803f7644611afd618ce00dcb860 (patch) | |
| tree | bcc17b38c97dfdd5a2147aed8e7700700fec732c /src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java | |
| parent | 9aa7b49d224bfde055e12bc84f6908ba0a50090d (diff) | |
| download | notenoughupdates-1b172089ce502803f7644611afd618ce00dcb860.tar.gz notenoughupdates-1b172089ce502803f7644611afd618ce00dcb860.tar.bz2 notenoughupdates-1b172089ce502803f7644611afd618ce00dcb860.zip | |
PRE28
Diffstat (limited to 'src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java')
| -rw-r--r-- | src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java new file mode 100644 index 00000000..2c59fcd8 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java @@ -0,0 +1,549 @@ +package io.github.moulberry.notenoughupdates.miscfeatures; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.ISound; +import net.minecraft.client.audio.PositionedSound; +import net.minecraft.client.audio.PositionedSoundRecord; +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.Items; +import net.minecraft.item.ItemStack; +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.*; + +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<Integer, Double> 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; + } + } + + private enum PlayerWarningState { + NOTHING, + FISH_INCOMING, + FISH_HOOKED + } + private PlayerWarningState warningState = PlayerWarningState.NOTHING; + private int hookedWarningStateTicks = 0; + + public final HashMap<Integer, EntityFishHook> hookEntities = new HashMap<>(); + public final HashMap<WakeChain, List<Integer>> chains = new HashMap<>(); + + private long lastCastRodMillis = 0; + private int pingDelayTicks = 0; + private final List<Integer> pingDelayList = new ArrayList<>(); + private int buildupSoundDelay = 0; + + private static final ResourceLocation FISHING_WARNING_EXCLAM = new ResourceLocation("notenoughupdates:fishing_warning_exclam.png"); + public void onRenderBobber(EntityFishHook hook) { + if(Minecraft.getMinecraft().thePlayer.fishEntity == hook && warningState != PlayerWarningState.NOTHING) { + GlStateManager.disableCull(); + GlStateManager.disableLighting(); + GL11.glDepthFunc(GL11.GL_ALWAYS); + GlStateManager.scale(1, -1, 1); + + 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); + + GlStateManager.scale(1, -1, 1); + GL11.glDepthFunc(GL11.GL_LEQUAL); + GlStateManager.enableLighting(); + GlStateManager.enableCull(); + } + } + + 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) { + 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.ceil(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<WakeChain, List<Integer>> 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<Integer> toRemoveEnt = new HashSet<>(); + for(Map.Entry<Integer, EntityFishHook> entry : hookEntities.entrySet()) { + if(entry.getValue().isDead) { + toRemoveEnt.add(entry.getKey()); + } + } + hookEntities.keySet().removeAll(toRemoveEnt); + + Set<WakeChain> toRemoveChain = new HashSet<>(); + for(Map.Entry<WakeChain, List<Integer>> 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; + if(Math.abs(dY) > 0.5f) { + 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; + } + + public boolean onSpawnParticle(EnumParticleTypes particleType, double x, double y, double z, double xOffset, double yOffset, double zOffset) { + if(!NotEnoughUpdates.INSTANCE.config.fishing.hideOtherPlayerAll && + !NotEnoughUpdates.INSTANCE.config.fishing.enableCustomParticles && + !NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning) { + return false; + } + if(hookEntities.isEmpty()) { + return false; + } + + if(particleType == EnumParticleTypes.WATER_WAKE && Math.abs(yOffset - 0.01f) < 0.001f) { + double angle1 = calculateAngleFromOffsets(xOffset, -zOffset); + double angle2 = calculateAngleFromOffsets(-xOffset, zOffset); + + final List<Integer> possibleHooks1 = new ArrayList<>(); + final List<Integer> 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<WakeChain, List<Integer>> entry : chains.entrySet()) { + WakeChain chain = entry.getKey(); + + if(currentTime - chain.lastUpdate > 200) continue; + + double updateAngle; + List<Integer> 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<Integer> 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 && + Minecraft.getMinecraft().thePlayer.fishEntity != null && + Minecraft.getMinecraft().thePlayer.fishEntity.getEntityId() == hookEntityId && + chain.particleNum > 3) { + + if(newDistance <= 0.2f + 0.1f*pingDelayTicks) { + if(NotEnoughUpdates.INSTANCE.config.fishing.incomingFishHookedSounds && + hookedWarningStateTicks <= 0) { + Minecraft.getMinecraft().getSoundHandler().playSound( + PositionedSoundRecord.create(new ResourceLocation("note.pling"), 2f)); + } + + hookedWarningStateTicks = 12; + } else if(newDistance >= 0.4f + 0.1f*pingDelayTicks) { + if(NotEnoughUpdates.INSTANCE.config.fishing.incomingFishIncSounds && + buildupSoundDelay <= 0) { + ISound sound = new PositionedSound(new ResourceLocation("note.pling")) {{ + volume = 0.1f; + pitch = calculatePitchFromDistance((float)newDistance - (0.3f+0.1f*pingDelayTicks)); + repeat = false; + repeatDelay = 0; + attenuationType = ISound.AttenuationType.NONE; + }}; + Minecraft.getMinecraft().getSoundHandler().playSound(sound); + 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) { + return true; + } else { + particleTypeI = NotEnoughUpdates.INSTANCE.config.fishing.otherParticleType; + particleCustomColour = NotEnoughUpdates.INSTANCE.config.fishing.otherParticleColour; + } + + if(!NotEnoughUpdates.INSTANCE.config.fishing.enableCustomParticles) { + return false; + } + + int argb = SpecialColour.specialToChromaRGB(particleCustomColour); + + if(particleTypeI == 0) { + return false; + } else if(particleTypeI == 1) { + return true; + } + + 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) { + return true; + } + + if(i >= 2) { + return true; + } + + 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)) { + return true; + } + + 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); + } + } + } + + return true; + } + } + + return false; + } + +} |
