aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMark Cockram <kiwiszijncool@gmail.com>2023-07-14 21:25:59 +0200
committerGitHub <noreply@github.com>2023-07-14 21:25:59 +0200
commite05840f4ad02579ae66fb75defbac6f686610e56 (patch)
treeaebadc5c8b94f36556eabee0e2d7058cdf3e3f34 /src/main/java
parent897d727953562d487e9d2f1d77fdb1d83f16da0a (diff)
downloadNotEnoughUpdates-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
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java64
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingSkillOverlay.java712
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)
+ );
}
}
}