diff options
author | Mark Cockram <kiwiszijncool@gmail.com> | 2023-07-14 21:25:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-14 21:25:59 +0200 |
commit | e05840f4ad02579ae66fb75defbac6f686610e56 (patch) | |
tree | aebadc5c8b94f36556eabee0e2d7058cdf3e3f34 | |
parent | 897d727953562d487e9d2f1d77fdb1d83f16da0a (diff) | |
download | NotEnoughUpdates-e05840f4ad02579ae66fb75defbac6f686610e56.tar.gz NotEnoughUpdates-e05840f4ad02579ae66fb75defbac6f686610e56.tar.bz2 NotEnoughUpdates-e05840f4ad02579ae66fb75defbac6f686610e56.zip |
Farming overlay update (#731)
* Update README.md
Explain why this repository exists
* Add crops/s line with config option for yield calculation time frame
* Add crop/s to default farming line list
* Function decomposition
* More detailed description
* Find average since start of farming instead of full timeframe. Add documentation
* Modulo wrap around instead of limiting backwards perspective to 0
* Separate cps update from the render function to the update loop
* Rearrange code
* Add cps reset timeout
* Add unit option
* Replace old crops per second system with new system
* Seperate unit option for crops and coins
* Organize code
* Update config
* Allow up to 5 minute rate calculation timeframe
* Update config description
* Fix coins/s and crops/s always displaying 0
2 files changed, 446 insertions, 330 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java index 6437f4f8..520adcb1 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java @@ -36,6 +36,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static io.github.moulberry.notenoughupdates.overlays.FarmingSkillOverlay.CPS_WINDOW_SIZE; + public class SkillOverlays { @ConfigOption( name = "Skill Overlay info", @@ -49,12 +51,14 @@ public class SkillOverlays { buttonText = "" ) public boolean skillInfo = false; + @ConfigOption( name = "Farming", desc = "" ) @ConfigEditorAccordion(id = 0) public boolean farmingAccordion = false; + @Expose @ConfigOption( name = "Enable Farming Overlay", @@ -73,7 +77,7 @@ public class SkillOverlays { @ConfigEditorDraggableList( exampleText = { "\u00a7bCounter: \u00a7e37,547,860", - "\u00a7bCrops/m: \u00a7e38.29", + "\u00a7bCrops/s: \u00a7e732", "\u00a7bFarming: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%", "\u00a7bCurrent XP: \u00a7e6,734", "\u00a7bRemaining XP: \u00a7e3,265", @@ -83,7 +87,7 @@ public class SkillOverlays { "\u00a7bPitch: \u00a7e69.42\u00a7l\u1D52", "\u00a7bCultivating: \u00a7e10,137,945/20,000,000", "\u00a7bCoins/m \u00a7e57,432", - "\u00a7bContest Estimate \u00a7e342,784" + "\u00a7bContest Estimate \u00a7e342,784", } ) @ConfigAccordionId(id = 0) @@ -100,34 +104,64 @@ public class SkillOverlays { @Expose @ConfigOption( - name = "Use coins per hour", - desc = "Uses coins/h instead of coins/m" + name = "Pause Timer", + desc = "How many seconds does it wait before pausing the XP/h timer" ) - @ConfigEditorBoolean @ConfigAccordionId(id = 0) - public boolean coinsPerHour = false; + @ConfigEditorSlider( + minValue = 1, + maxValue = 20, + minStep = 1 + ) + public int farmingPauseTimer = 3; @Expose @ConfigOption( - name = "Use crops per hour", - desc = "Uses crops/h instead of crops/m" + name = "Crop rate time frame", + desc = "Defines the duration in seconds over which the average crop yield is calculated" ) - @ConfigEditorBoolean @ConfigAccordionId(id = 0) - public boolean cropsPerHour = false; + @ConfigEditorSlider( + minValue = 1, + maxValue = CPS_WINDOW_SIZE - 2, + minStep = 1 + ) + public int farmingCropsPerSecondTimeFrame = 5; @Expose @ConfigOption( - name = "Pause Timer", - desc = "How many seconds does it wait before pausing" + name = "Crop rate unit", + desc = "Choose the unit for displaying the crop rate" + ) + @ConfigAccordionId(id = 0) + @ConfigEditorDropdown( + values = {"/s", "/m", "/h"} + ) + public int farmingCropRateUnit = 0; + + @Expose + @ConfigOption( + name = "Coin rate unit", + desc = "Choose the unit for displaying the coin rate" + ) + @ConfigAccordionId(id = 0) + @ConfigEditorDropdown( + values = {"/s", "/m", "/h"} + ) + public int farmingCoinRateUnit = 0; + + @Expose + @ConfigOption( + name = "Reset crop rate", + desc = "How many seconds does it wait before resetting the crop rate values when inactive" ) @ConfigAccordionId(id = 0) @ConfigEditorSlider( minValue = 1, - maxValue = 20, + maxValue = CPS_WINDOW_SIZE - 2, minStep = 1 ) - public int farmingPauseTimer = 3; + public int farmingResetCPS = 5; @Expose public Position farmingPosition = new Position(10, 200); @@ -142,12 +176,14 @@ public class SkillOverlays { ) @ConfigAccordionId(id = 0) public int farmingStyle = 0; + @ConfigOption( name = "Mining", desc = "" ) @ConfigEditorAccordion(id = 1) public boolean miningAccordion = false; + @Expose @ConfigOption( name = "Enable Mining Overlay", diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingSkillOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingSkillOverlay.java index ae2ea046..29244343 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingSkillOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingSkillOverlay.java @@ -36,13 +36,14 @@ import net.minecraft.util.EnumChatFormatting; import java.text.NumberFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.function.Supplier; public class FarmingSkillOverlay extends TextOverlay { + private static final NumberFormat format = NumberFormat.getIntegerInstance(); + private final HashMap<Integer, String> lineMap = new HashMap<>(); private long lastUpdate = -1; private int counterLast = -1; private int counter = -1; @@ -52,9 +53,6 @@ public class FarmingSkillOverlay extends TextOverlay { private String cultivatingTierAmount = "1"; private int foraging = 0; private double coins = -1; - private float cropsPerSecondLast = 0; - private float cropsPerSecond = 0; - private final LinkedList<Integer> counterQueue = new LinkedList<>(); private String lastItemHeld = "null"; private int jacobPredictionLast = -1; private int jacobPrediction = -1; @@ -71,6 +69,23 @@ public class FarmingSkillOverlay extends TextOverlay { private int xpGainTimer = 0; + public static final int CPS_WINDOW_SIZE = 302; + /** + * Stores the values of the crop counter as a sliding window. + * Values can be accessed using the {@link #cropsPerSecondCursor}. + */ + private int[] cropsPerSecondValues = new int[CPS_WINDOW_SIZE]; + /** + * The theoretical call interval of {@link #update()} is 1 second, + * but in reality it can deviate by one tick, or 50ms, + * which means we have to save time stamps of the values in order to prevent up to 5% (50ms) incorrectness. + */ + private long[] cropsPerSecondTimeStamps = new long[CPS_WINDOW_SIZE]; + private int cropsPerSecondCursor = -1; + private float cropsPerSecondLast = 0; + private float cropsPerSecond = 0; + private float cpsResetTimer = 1; + private String skillType = "Farming"; public FarmingSkillOverlay( @@ -81,7 +96,7 @@ public class FarmingSkillOverlay extends TextOverlay { super(position, dummyStrings, styleSupplier); } - private float interp(float now, float last) { + private float interpolate(float now, float last) { float interp = now; if (last >= 0 && last != now) { float factor = (System.currentTimeMillis() - lastUpdate) / 1000f; @@ -91,6 +106,24 @@ public class FarmingSkillOverlay extends TextOverlay { return interp; } + /** + * @return x mod y with the sign of the divisor, y, instead of the dividend, x. + * Moreover -1 % 2 is mathematically both -1 and 1. Java chose -1, we want 1. + */ + private int mod(int x, int y) { + int mod = x % y; + if (mod < 0) + mod += y; + return mod; + } + + private void resetCropsPerSecond() { + cropsPerSecondTimeStamps = new long[CPS_WINDOW_SIZE]; + cropsPerSecondValues = new int[CPS_WINDOW_SIZE]; + cropsPerSecond = 0; + cropsPerSecondLast = 0; + } + private double getCoinsBz(String enchCropName, int numItemsForEnch) { JsonObject crop = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(enchCropName); if (crop != null && crop.has("curr_sell")) { @@ -121,16 +154,14 @@ public class FarmingSkillOverlay extends TextOverlay { } } - // Check if there is an active Jacob's contest + /** + * @return if there is an active Jacob's contest + */ private static boolean isJacobTime() { long now = System.currentTimeMillis(); return now % 3600000 >= 900000 && now % 3600000 <= 2100000; } - //This is a list of the last X cropsPerSeconds to try and calm down the fluctuation for crops/min (they will be averaged) - //Needed due to farming fortune causing inconsistent amounts of crops each block break - private static ArrayList<Float> cropsOverLastXSeconds = new ArrayList<>(); - @Override public boolean isEnabled() { return NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingOverlay; @@ -165,6 +196,7 @@ public class FarmingSkillOverlay extends TextOverlay { if (!isEnabled()) { counter = -1; overlayStrings = null; + resetCropsPerSecond(); return; } @@ -177,102 +209,69 @@ public class FarmingSkillOverlay extends TextOverlay { if (Minecraft.getMinecraft().thePlayer == null) return; ItemStack stack = Minecraft.getMinecraft().thePlayer.getHeldItem(); - if (stack != null && stack.hasTagCompound()) { - NBTTagCompound tag = stack.getTagCompound(); - if (tag.hasKey("ExtraAttributes", 10)) { - NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + updateCounter(stack); - if (ea.hasKey("mined_crops", 99)) { - counter = ea.getInteger("mined_crops"); - cultivating = ea.getInteger("farmed_cultivating"); - counterQueue.add(0, counter); - } else if (ea.hasKey("farmed_cultivating", 99)) { - counter = ea.getInteger("farmed_cultivating"); - cultivating = ea.getInteger("farmed_cultivating"); - counterQueue.add(0, counter); - } - } - } - - if (cultivating < 1000) { - cultivatingTier = 1; - cultivatingTierAmount = "1,000"; - } else if (cultivating < 5000) { - cultivatingTier = 2; - cultivatingTierAmount = "5,000"; - } else if (cultivating < 25000) { - cultivatingTier = 3; - cultivatingTierAmount = "25,000"; - } else if (cultivating < 100000) { - cultivatingTier = 4; - cultivatingTierAmount = "100,000"; - } else if (cultivating < 300000) { - cultivatingTier = 5; - cultivatingTierAmount = "300,000"; - } else if (cultivating < 1500000) { - cultivatingTier = 6; - cultivatingTierAmount = "1,500,000"; - } else if (cultivating < 5000000) { - cultivatingTier = 7; - cultivatingTierAmount = "5,000,000"; - } else if (cultivating < 20000000) { - cultivatingTier = 8; - cultivatingTierAmount = "20,000,000"; - } else if (cultivating < 100000000) { - cultivatingTier = 9; - cultivatingTierAmount = "100,000,000"; - } else if (cultivating > 100000000) { - cultivatingTier = 10; - cultivatingTierAmount = "Maxed"; - } + updateCropsPerSecond(); String internalName = new ItemResolutionQuery(NotEnoughUpdates.INSTANCE.manager).withItemStack(stack).resolveInternalName(); + if (internalName != null) { + updateSkillType(internalName); + } - //Set default skillType to Farming and get BZ price config value - skillType = "Farming"; - foraging = 0; + updateSkillInfo(); + if (counter != -1) { + overlayStrings = new ArrayList<>(); + } else { + overlayStrings = null; + } + gatherJacobData(); + } + + private void updateSkillType(String internalName) { + //Set default skillType to Farming and get BZ price config value + skillType = "Farming"; + foraging = 0; + + boolean useBZPrice = NotEnoughUpdates.INSTANCE.config.skillOverlays.useBZPrice; + if (internalName.equals("TREECAPITATOR_AXE") || internalName.equalsIgnoreCase("JUNGLE_AXE")) { //WOOD - boolean useBZPrice = NotEnoughUpdates.INSTANCE.config.skillOverlays.useBZPrice; - if (internalName.equals("TREECAPITATOR_AXE") || internalName.equalsIgnoreCase("JUNGLE_AXE")) { - skillType = "Foraging"; - foraging = 1; - coins = 2; - - //MUSHROOM - } else if (internalName.equals("FUNGI_CUTTER")) { - - if (useBZPrice) { - coins = (getCoinsBz("ENCHANTED_RED_MUSHROOM", 160) + - getCoinsBz("ENCHANTED_BROWN_MUSHROOM", 160)) / 2; + skillType = "Foraging"; + foraging = 1; + coins = 2; + } else if (internalName.equals("FUNGI_CUTTER")) { + //MUSHROOM + if (useBZPrice) { + coins = (getCoinsBz("ENCHANTED_RED_MUSHROOM", 160) + + getCoinsBz("ENCHANTED_BROWN_MUSHROOM", 160)) / 2; + } else { + Double red = HypixelItemAPI.getNPCSellPrice("ENCHANTED_RED_MUSHROOM"); + Double brown = HypixelItemAPI.getNPCSellPrice("ENCHANTED_BROWN_MUSHROOM"); + if (red == null || brown == null) { + coins = 0; } else { - Double red = HypixelItemAPI.getNPCSellPrice("ENCHANTED_RED_MUSHROOM"); - Double brown = HypixelItemAPI.getNPCSellPrice("ENCHANTED_BROWN_MUSHROOM"); - if (red == null || brown == null) { - coins = 0; - } else { - coins = (red * 160 + brown * 160) / 2; - } + coins = (red * 160 + brown * 160) / 2; } - - } else { - // EVERYTHING ELSE - coins = 0; - for (CropType crop : CropType.values()) { - if (internalName.startsWith(crop.toolName)) { - Double npcSellPrice = HypixelItemAPI.getNPCSellPrice(crop.item); - if (npcSellPrice == null) { - npcSellPrice = 0.0; - } - coins = useBZPrice ? getCoinsBz(crop.item, crop.enchSize) : npcSellPrice / crop.enchSize; + } + } else { + // EVERYTHING ELSE + coins = 0; + for (CropType crop : CropType.values()) { + if (internalName.startsWith(crop.toolName)) { + Double npcSellPrice = HypixelItemAPI.getNPCSellPrice(crop.item); + if (npcSellPrice == null) { + npcSellPrice = 0.0; } + coins = useBZPrice ? getCoinsBz(crop.item, crop.enchSize) : npcSellPrice / crop.enchSize; } } } + } + private void updateSkillInfo() { skillInfoLast = skillInfo; skillInfo = XPInformation.getInstance().getSkillInfo(skillType); if (skillInfo != null) { @@ -317,79 +316,111 @@ public class FarmingSkillOverlay extends TextOverlay { lastTotalXp = totalXp; } + } - while (counterQueue.size() >= 4) { - counterQueue.removeLast(); - } + private void updateCounter(ItemStack stack) { + if (stack != null && stack.hasTagCompound()) { + NBTTagCompound tag = stack.getTagCompound(); - if (counterQueue.isEmpty()) { - cropsPerSecond = -1; - cropsPerSecondLast = 0; - } else { - cropsPerSecondLast = cropsPerSecond; - int last = counterQueue.getLast(); - int first = counterQueue.getFirst(); - - //This is a list of the last X cropsPerSeconds to try and calm down the fluctuation for crops/min (they will be averaged) - //Needed due to farming fortune causing inconsistent amounts of crops each block break - //Making this while in case somehow it goes over X+1 - while (cropsOverLastXSeconds.size() > 60) { - cropsOverLastXSeconds.remove(0); - } - if ((first - last) / 2f != 0) { - cropsOverLastXSeconds.add((first - last) / 2f); - } else { - if (cropsPerSecondLast == 0) { - //This is to prevent bleeding from one crop to the next (or if you stop and then start again at a different pace) - //It removes 12 per tick because otherwise it would take 60s to go to N/A (now it only takes 5s) - int i = 12; - while (i > 0) { - i--; - if (cropsOverLastXSeconds.size() > 0) { - cropsOverLastXSeconds.remove(0); - } else { - break; - } - } - } - } + if (tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); - if (!lastItemHeld.equals(NEUManager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()) == null - ? "null" - : NEUManager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()))) { - lastItemHeld = NEUManager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()) == null - ? "null" - : NEUManager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()); - cropsOverLastXSeconds.clear(); + if (ea.hasKey("mined_crops", 99)) { + counter = ea.getInteger("mined_crops"); + cultivating = ea.getInteger("farmed_cultivating"); + } else if (ea.hasKey("farmed_cultivating", 99)) { + counter = ea.getInteger("farmed_cultivating"); + cultivating = ea.getInteger("farmed_cultivating"); + } } + } - ArrayList<Float> temp = new ArrayList<>(cropsOverLastXSeconds); - if (cropsOverLastXSeconds.size() >= 3) { - temp.remove(Collections.min(temp)); - } - if (cropsOverLastXSeconds.size() >= 6) { - temp.remove(Collections.min(temp)); - temp.remove(Collections.max(temp)); - } - if (cropsOverLastXSeconds.size() >= 10) { - temp.remove(Collections.max(temp)); - } + if (cultivating < 1000) { + cultivatingTier = 1; + cultivatingTierAmount = "1,000"; + } else if (cultivating < 5000) { + cultivatingTier = 2; + cultivatingTierAmount = "5,000"; + } else if (cultivating < 25000) { + cultivatingTier = 3; + cultivatingTierAmount = "25,000"; + } else if (cultivating < 100000) { + cultivatingTier = 4; + cultivatingTierAmount = "100,000"; + } else if (cultivating < 300000) { + cultivatingTier = 5; + cultivatingTierAmount = "300,000"; + } else if (cultivating < 1500000) { + cultivatingTier = 6; + cultivatingTierAmount = "1,500,000"; + } else if (cultivating < 5000000) { + cultivatingTier = 7; + cultivatingTierAmount = "5,000,000"; + } else if (cultivating < 20000000) { + cultivatingTier = 8; + cultivatingTierAmount = "20,000,000"; + } else if (cultivating < 100000000) { + cultivatingTier = 9; + cultivatingTierAmount = "100,000,000"; + } else if (cultivating > 100000000) { + cultivatingTier = 10; + cultivatingTierAmount = "Maxed"; + } + } - float cropsOverLastXSecondsTotal = 0; - for (Float crops : temp) { - cropsOverLastXSecondsTotal += crops; - } - //To prevent 0/0 - cropsPerSecond = - temp.size() != 0 && cropsOverLastXSecondsTotal != 0 ? cropsOverLastXSecondsTotal / temp.size() : 0; + /** + * Finds the average crops farmed during the configured time frame or since the player has started farming. + */ + private void updateCropsPerSecond() { + //update values in arrays + cropsPerSecondTimeStamps[++cropsPerSecondCursor % CPS_WINDOW_SIZE] = + System.currentTimeMillis(); + cropsPerSecondValues[cropsPerSecondCursor % CPS_WINDOW_SIZE] = counter; + + //calculate + int current = cropsPerSecondValues[cropsPerSecondCursor % CPS_WINDOW_SIZE]; + int timeFrame = Math.min( + NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingCropsPerSecondTimeFrame, + CPS_WINDOW_SIZE + ); + + //The searchIndex serves to find the start of the player farming. + //This makes it so that even if the timeframe is set high, + // the initial average will be the average since the player starts farming instead of the full timeframe. + int searchIndex = mod(cropsPerSecondCursor - timeFrame, CPS_WINDOW_SIZE); + while (cropsPerSecondValues[searchIndex] == cropsPerSecondValues[mod(searchIndex - 1, CPS_WINDOW_SIZE)] && + mod(searchIndex, CPS_WINDOW_SIZE) != mod(cropsPerSecondCursor, CPS_WINDOW_SIZE)) { + searchIndex++; + searchIndex %= CPS_WINDOW_SIZE; } - if (counter != -1) { - overlayStrings = new ArrayList<>(); + float newCropsPerSecond = current - cropsPerSecondValues[searchIndex]; + + float timePassed = + cropsPerSecondTimeStamps[cropsPerSecondCursor % CPS_WINDOW_SIZE] - cropsPerSecondTimeStamps[searchIndex]; + timePassed /= 1000f; + newCropsPerSecond /= timePassed; + + if (Float.isNaN(newCropsPerSecond)) newCropsPerSecond = 0; + cropsPerSecondLast = cropsPerSecond; + cropsPerSecond = newCropsPerSecond; + + //reset logic + if (counter == counterLast) { + cpsResetTimer++; } else { - overlayStrings = null; + //starts at 1 because by the time the increment takes place, a second has already passed. + cpsResetTimer = 1; + } + + String currentItemHeld = NEUManager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()) == null + ? "null" : NEUManager.getUUIDForItem(Minecraft.getMinecraft().thePlayer.getHeldItem()); + if (!lastItemHeld.equals(currentItemHeld)) { + lastItemHeld = currentItemHeld; + resetCropsPerSecond(); + } else if (cpsResetTimer > NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingResetCPS) { + resetCropsPerSecond(); } - gatherJacobData(); } @Override @@ -399,208 +430,257 @@ public class FarmingSkillOverlay extends TextOverlay { if (counter < 0) { overlayStrings = null; } else { - HashMap<Integer, String> lineMap = new HashMap<>(); - + lineMap.clear(); overlayStrings = new ArrayList<>(); - NumberFormat format = NumberFormat.getIntegerInstance(); + if (cultivating != counter) { + renderCounter(); + } - String cropsTimeSuffix = NotEnoughUpdates.INSTANCE.config.skillOverlays.cropsPerHour ? "h" : "m"; - int cropMultiplier = NotEnoughUpdates.INSTANCE.config.skillOverlays.cropsPerHour ? 60 : 1; - int cropDecimals = NotEnoughUpdates.INSTANCE.config.skillOverlays.cropsPerHour ? 0 : 2; + if (counter >= 0) { + renderCropsPerSecond(); + if (coins > 0) { + renderCoins(); + } + } - String coinsTimeSuffix = NotEnoughUpdates.INSTANCE.config.skillOverlays.coinsPerHour ? "h" : "m"; - int coinMultiplier = NotEnoughUpdates.INSTANCE.config.skillOverlays.coinsPerHour ? 60 : 1; - int coinDecimals = NotEnoughUpdates.INSTANCE.config.skillOverlays.coinsPerHour ? 0 : 2; + renderCultivating(); - if (counter >= 0 && cultivating != counter) { - int counterInterp = (int) interp(counter, counterLast); + renderJacob(); - lineMap.put( - 0, - EnumChatFormatting.AQUA + "Counter: " + EnumChatFormatting.YELLOW + format.format(counterInterp) - ); - } + renderLevelAndXP(); - if (counter >= 0) { - if (cropsPerSecondLast == cropsPerSecond && cropsPerSecond <= 0) { - lineMap.put( - 1, - EnumChatFormatting.AQUA + - (foraging == 1 ? "Logs/" + cropsTimeSuffix + ": " : "Crops/" + cropsTimeSuffix + ": ") + - EnumChatFormatting.YELLOW + "N/A" - ); - } else { - float cpsInterp = interp(cropsPerSecond, cropsPerSecondLast); + renderYawPitch(); - lineMap.put( - 1, - EnumChatFormatting.AQUA + - (foraging == 1 ? "Logs/" + cropsTimeSuffix + ": " : "Crops/" + cropsTimeSuffix + ": ") + - EnumChatFormatting.YELLOW + - String.format("%,." + cropDecimals + "f", cpsInterp * 60 * cropMultiplier) - ); + for (int strIndex : NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingText) { + if (lineMap.get(strIndex) != null) { + overlayStrings.add(lineMap.get(strIndex)); } } + if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null; + } + } - if (counter >= 0 && coins > 0) { - if (cropsPerSecondLast == cropsPerSecond && cropsPerSecond <= 0) { - lineMap.put( - 10, - EnumChatFormatting.AQUA + "Coins/" + coinsTimeSuffix + ": " + EnumChatFormatting.YELLOW + "N/A" - ); - } else { - float cpsInterp = interp(cropsPerSecond, cropsPerSecondLast); - lineMap.put(10, EnumChatFormatting.AQUA + "Coins/" + coinsTimeSuffix + ": " + EnumChatFormatting.YELLOW + - String.format("%,." + coinDecimals + "f", (cpsInterp * 60) * coins * coinMultiplier)); - } - } + private void renderCounter() { + int counterInterp = (int) interpolate(counter, counterLast); + lineMap.put(0, EnumChatFormatting.AQUA + "Counter: " + EnumChatFormatting.YELLOW + format.format(counterInterp)); + } - if (cultivatingTier <= 9 && cultivating > 0) { - int counterInterp = (int) interp(cultivating, cultivatingLast); - lineMap.put( - 9, - EnumChatFormatting.AQUA + "Cultivating: " + EnumChatFormatting.YELLOW + format.format(counterInterp) + "/" + - cultivatingTierAmount - ); - } - if (cultivatingTier == 10) { - int counterInterp = (int) interp(cultivating, cultivatingLast); + private void renderCoins() { + float coinsMultiplier = 0; + String unit = null; + switch (NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingCoinRateUnit) { + case 0: + coinsMultiplier = 1; + unit = "/s"; + break; + case 1: + coinsMultiplier = 60; + unit = "/m"; + break; + case 2: + coinsMultiplier = 3600; + unit = "/h"; + break; + } + + if (cropsPerSecondLast == cropsPerSecond && cropsPerSecond <= 0) { + lineMap.put(10, EnumChatFormatting.AQUA + "Coins" + unit + ": " + EnumChatFormatting.YELLOW + "N/A"); + } else { + float cropsPerSecond = cropsPerSecondLast != 0 + ? interpolate(this.cropsPerSecond, cropsPerSecondLast) + : this.cropsPerSecond; + float cropsPerUnit = cropsPerSecond * coinsMultiplier; + lineMap.put(10, EnumChatFormatting.AQUA + "Coins" + unit + ": " + EnumChatFormatting.YELLOW + + String.format("%,.0f", cropsPerUnit * coins)); + } + } + + private void renderCultivating() { + if (cultivatingTier <= 9 && cultivating > 0) { + int counterInterp = (int) interpolate(cultivating, cultivatingLast); + lineMap.put( + 9, + EnumChatFormatting.AQUA + "Cultivating: " + EnumChatFormatting.YELLOW + format.format(counterInterp) + "/" + + cultivatingTierAmount + ); + } + if (cultivatingTier == 10) { + int counterInterp = (int) interpolate(cultivating, cultivatingLast); + lineMap.put( + 9, + EnumChatFormatting.AQUA + "Cultivating: " + EnumChatFormatting.YELLOW + format.format(counterInterp) + ); + } + } + + private void renderJacob() { + if (isJacobTime() && inJacobContest) { + if (jacobPredictionLast == jacobPrediction && jacobPrediction <= 0) { + lineMap.put(11, EnumChatFormatting.AQUA + "Contest Estimate: " + EnumChatFormatting.YELLOW + "N/A"); + } else { + float predInterp = interpolate(jacobPrediction, jacobPredictionLast); lineMap.put( - 9, - EnumChatFormatting.AQUA + "Cultivating: " + EnumChatFormatting.YELLOW + format.format(counterInterp) + 11, + EnumChatFormatting.AQUA + "Contest Estimate: " + EnumChatFormatting.YELLOW + + String.format("%,.0f", predInterp) ); } + } + } - if (isJacobTime() && inJacobContest) { - if (jacobPredictionLast == jacobPrediction && jacobPrediction <= 0) { - lineMap.put(11, EnumChatFormatting.AQUA + "Contest Estimate: " + EnumChatFormatting.YELLOW + "N/A"); - } else { - float predInterp = interp(jacobPrediction, jacobPredictionLast); - lineMap.put( - 11, - EnumChatFormatting.AQUA + "Contest Estimate: " + EnumChatFormatting.YELLOW + - String.format("%,.0f", predInterp) - ); - } - } - - float xpInterp = xpGainHour; - if (xpGainHourLast == xpGainHour && xpGainHour <= 0) { - lineMap.put(5, EnumChatFormatting.AQUA + "XP/h: " + EnumChatFormatting.YELLOW + "N/A"); - } else { - xpInterp = interp(xpGainHour, xpGainHourLast); + private void renderLevelAndXP() { + float xpInterp = xpGainHour; + if (xpGainHourLast == xpGainHour && xpGainHour <= 0) { + lineMap.put(5, EnumChatFormatting.AQUA + "XP/h: " + EnumChatFormatting.YELLOW + "N/A"); + } else { + xpInterp = interpolate(xpGainHour, xpGainHourLast); - lineMap.put(5, EnumChatFormatting.AQUA + "XP/h: " + EnumChatFormatting.YELLOW + - format.format(xpInterp) + (isFarming ? "" : EnumChatFormatting.RED + " (PAUSED)")); - } + lineMap.put(5, EnumChatFormatting.AQUA + "XP/h: " + EnumChatFormatting.YELLOW + + format.format(xpInterp) + (isFarming ? "" : EnumChatFormatting.RED + " (PAUSED)")); + } - if (skillInfo != null && skillInfo.level < 60) { - StringBuilder levelStr = new StringBuilder(EnumChatFormatting.AQUA + skillType + ": "); + if (skillInfo != null && skillInfo.level < 60) { + StringBuilder levelStr = new StringBuilder(EnumChatFormatting.AQUA + skillType + ": "); - levelStr.append(EnumChatFormatting.YELLOW) - .append(skillInfo.level) - .append(EnumChatFormatting.GRAY) - .append(" ["); + levelStr.append(EnumChatFormatting.YELLOW) + .append(skillInfo.level) + .append(EnumChatFormatting.GRAY) + .append(" ["); - float progress = skillInfo.currentXp / skillInfo.currentXpMax; - if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { - progress = interp(progress, skillInfoLast.currentXp / skillInfoLast.currentXpMax); - } + float progress = skillInfo.currentXp / skillInfo.currentXpMax; + if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { + progress = interpolate(progress, skillInfoLast.currentXp / skillInfoLast.currentXpMax); + } - float lines = 25; - for (int i = 0; i < lines; i++) { - if (i / lines < progress) { - levelStr.append(EnumChatFormatting.YELLOW); - } else { - levelStr.append(EnumChatFormatting.DARK_GRAY); - } - levelStr.append('|'); + float lines = 25; + for (int i = 0; i < lines; i++) { + if (i / lines < progress) { + levelStr.append(EnumChatFormatting.YELLOW); + } else { + levelStr.append(EnumChatFormatting.DARK_GRAY); } + levelStr.append('|'); + } - levelStr.append(EnumChatFormatting.GRAY) - .append("] ") - .append(EnumChatFormatting.YELLOW) - .append((int) (progress * 100)) - .append("%"); + levelStr.append(EnumChatFormatting.GRAY) + .append("] ") + .append(EnumChatFormatting.YELLOW) + .append((int) (progress * 100)) + .append("%"); - int current = (int) skillInfo.currentXp; - if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { - current = (int) interp(current, skillInfoLast.currentXp); - } + int current = (int) skillInfo.currentXp; + if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { + current = (int) interpolate(current, skillInfoLast.currentXp); + } - int remaining = (int) (skillInfo.currentXpMax - skillInfo.currentXp); - if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { - remaining = (int) interp(remaining, (int) (skillInfoLast.currentXpMax - skillInfoLast.currentXp)); - } + int remaining = (int) (skillInfo.currentXpMax - skillInfo.currentXp); + if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { + remaining = (int) interpolate(remaining, (int) (skillInfoLast.currentXpMax - skillInfoLast.currentXp)); + } - lineMap.put(2, levelStr.toString()); - lineMap.put(3, EnumChatFormatting.AQUA + "Current XP: " + EnumChatFormatting.YELLOW + format.format(current)); - if (remaining < 0) { - lineMap.put(4, EnumChatFormatting.AQUA + "Remaining XP: " + EnumChatFormatting.YELLOW + "MAXED!"); - lineMap.put(7, EnumChatFormatting.AQUA + "ETA: " + EnumChatFormatting.YELLOW + "MAXED!"); + lineMap.put(2, levelStr.toString()); + lineMap.put(3, EnumChatFormatting.AQUA + "Current XP: " + EnumChatFormatting.YELLOW + format.format(current)); + if (remaining < 0) { + lineMap.put(4, EnumChatFormatting.AQUA + "Remaining XP: " + EnumChatFormatting.YELLOW + "MAXED!"); + lineMap.put(7, EnumChatFormatting.AQUA + "ETA: " + EnumChatFormatting.YELLOW + "MAXED!"); + } else { + lineMap.put( + 4, + EnumChatFormatting.AQUA + "Remaining XP: " + EnumChatFormatting.YELLOW + format.format(remaining) + ); + if (xpGainHour < 1000) { + lineMap.put(7, EnumChatFormatting.AQUA + "ETA: " + EnumChatFormatting.YELLOW + "N/A"); } else { lineMap.put( - 4, - EnumChatFormatting.AQUA + "Remaining XP: " + EnumChatFormatting.YELLOW + format.format(remaining) + 7, + EnumChatFormatting.AQUA + "ETA: " + EnumChatFormatting.YELLOW + + Utils.prettyTime((long) (remaining) * 1000 * 60 * 60 / (long) xpInterp) ); - if (xpGainHour < 1000) { - lineMap.put(7, EnumChatFormatting.AQUA + "ETA: " + EnumChatFormatting.YELLOW + "N/A"); - } else { - lineMap.put( - 7, - EnumChatFormatting.AQUA + "ETA: " + EnumChatFormatting.YELLOW + - Utils.prettyTime((long) (remaining) * 1000 * 60 * 60 / (long) xpInterp) - ); - } } - } - if (skillInfo != null && skillInfo.level == 60) { - int current = (int) skillInfo.currentXp; - if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { - current = (int) interp(current, skillInfoLast.currentXp); - } + } - if (foraging == 0) { - lineMap.put( - 2, - EnumChatFormatting.AQUA + "Farming: " + EnumChatFormatting.YELLOW + "60 " + EnumChatFormatting.RED + - "(Maxed)" - ); - } else { - lineMap.put( - 2, - EnumChatFormatting.AQUA + "Foraging: " + EnumChatFormatting.YELLOW + "50 " + EnumChatFormatting.RED + - "(Maxed)" - ); - } - lineMap.put(3, EnumChatFormatting.AQUA + "Current XP: " + EnumChatFormatting.YELLOW + format.format(current)); + if (skillInfo != null && skillInfo.level == 60) { + int current = (int) skillInfo.currentXp; + if (skillInfoLast != null && skillInfo.currentXpMax == skillInfoLast.currentXpMax) { + current = (int) interpolate(current, skillInfoLast.currentXp); + } + if (foraging == 0) { + lineMap.put( + 2, + EnumChatFormatting.AQUA + "Farming: " + EnumChatFormatting.YELLOW + "60 " + EnumChatFormatting.RED + + "(Maxed)" + ); + } else { + lineMap.put( + 2, + EnumChatFormatting.AQUA + "Foraging: " + EnumChatFormatting.YELLOW + "50 " + EnumChatFormatting.RED + + "(Maxed)" + ); } + lineMap.put(3, EnumChatFormatting.AQUA + "Current XP: " + EnumChatFormatting.YELLOW + format.format(current)); - float yaw = Minecraft.getMinecraft().thePlayer.rotationYawHead; - float pitch = Minecraft.getMinecraft().thePlayer.rotationPitch; - yaw %= 360; - if (yaw < 0) yaw += 360; - if (yaw > 180) yaw -= 360; - pitch %= 360; - if (pitch < 0) pitch += 360; - if (pitch > 180) pitch -= 360; + } + } - lineMap.put(6, EnumChatFormatting.AQUA + "Yaw: " + EnumChatFormatting.YELLOW + - String.format("%.2f", yaw) + EnumChatFormatting.BOLD + "\u1D52"); + private void renderYawPitch() { + float yaw = Minecraft.getMinecraft().thePlayer.rotationYawHead; + float pitch = Minecraft.getMinecraft().thePlayer.rotationPitch; + yaw %= 360; + if (yaw < 0) yaw += 360; + if (yaw > 180) yaw -= 360; + pitch %= 360; + if (pitch < 0) pitch += 360; + if (pitch > 180) pitch -= 360; + + lineMap.put(6, EnumChatFormatting.AQUA + "Yaw: " + EnumChatFormatting.YELLOW + + String.format("%.2f", yaw) + EnumChatFormatting.BOLD + "\u1D52"); + + lineMap.put(8, EnumChatFormatting.AQUA + "Pitch: " + EnumChatFormatting.YELLOW + + String.format("%.2f", pitch) + EnumChatFormatting.BOLD + "\u1D52"); + } - lineMap.put(8, EnumChatFormatting.AQUA + "Pitch: " + EnumChatFormatting.YELLOW + - String.format("%.2f", pitch) + EnumChatFormatting.BOLD + "\u1D52"); + private void renderCropsPerSecond() { + float cropsMultiplier = 0; + String unit = null; + switch (NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingCropRateUnit) { + case 0: + cropsMultiplier = 1; + unit = "/s"; + break; + case 1: + cropsMultiplier = 60; + unit = "/m"; + break; + case 2: + cropsMultiplier = 3600; + unit = "/h"; + break; + } - for (int strIndex : NotEnoughUpdates.INSTANCE.config.skillOverlays.farmingText) { - if (lineMap.get(strIndex) != null) { - overlayStrings.add(lineMap.get(strIndex)); - } - } - if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null; + if (cropsPerSecondLast == cropsPerSecond && cropsPerSecond <= 0) { + lineMap.put( + 1, + EnumChatFormatting.AQUA + + (foraging == 1 ? "Logs" + unit + ": " : "Crops" + unit + ": ") + + EnumChatFormatting.YELLOW + "N/A" + ); + } else { + //Don't interpolate at the start + float cropsPerSecond = cropsPerSecondLast != 0 + ? interpolate(this.cropsPerSecond, cropsPerSecondLast) + : this.cropsPerSecond; + float cropsPerUnit = cropsPerSecond * cropsMultiplier; + + lineMap.put( + 1, + EnumChatFormatting.AQUA + (foraging == 1 ? "Logs" + unit + ": " : "Crops" + unit + ": ") + + EnumChatFormatting.YELLOW + + String.format("%,.0f", cropsPerUnit) + ); } } } |