aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java243
1 files changed, 157 insertions, 86 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
index 3955b35f..71a23ffb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
@@ -1,3 +1,22 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.reflect.TypeToken;
@@ -17,14 +36,26 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -36,11 +67,11 @@ public class GuiPriceGraph extends GuiScreen {
private final ResourceLocation TEXTURE;
private static final int X_SIZE = 364;
private static final int Y_SIZE = 215;
- private Data dataPoints;
- private float highestValue;
+ private ItemData itemData;
+ private double highestValue;
private long firstTime;
private long lastTime;
- private Float lowestValue = null;
+ private Double lowestValue = null;
private String itemName;
private final String itemId;
private int guiLeft;
@@ -117,27 +148,27 @@ public class GuiPriceGraph extends GuiScreen {
Utils.drawStringCentered("Loading...", Minecraft.getMinecraft().fontRendererObj,
guiLeft + 166, guiTop + 116, false, 0xffffff00
);
- else if (dataPoints == null || dataPoints.get() == null || dataPoints.get().size() <= 1)
+ else if (
+ itemData == null || itemData.get() == null || itemData.get().size() <= 1 || lowestValue == null)
Utils.drawStringCentered("No data found.", Minecraft.getMinecraft().fontRendererObj,
guiLeft + 166, guiTop + 116, false, 0xffff0000
);
else {
-
int graphColor = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.ahGraph.graphColor);
int graphColor2 = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.ahGraph.graphColor2);
Integer lowestDist = null;
Long lowestDistTime = null;
HashMap<Integer, Integer> secondLineData = new HashMap<>();
- for (int i = (dataPoints.isBz() ? 1 : 0); i >= 0; i--) {
+ for (int i = (itemData.isBz() ? 1 : 0); i >= 0; i--) {
Utils.drawGradientRect(0, guiLeft + 17, guiTop + 35, guiLeft + 315, guiTop + 198,
changeAlpha(i == 0 ? graphColor : graphColor2, 120), changeAlpha(i == 0 ? graphColor : graphColor2, 10)
);
Integer prevX = null;
Integer prevY = null;
- for (Long time : dataPoints.get().keySet()) {
- float price = dataPoints.isBz()
- ? i == 0 ? dataPoints.bz.get(time).b : dataPoints.bz.get(time).s
- : dataPoints.ah.get(time);
+ for (Long time : itemData.get().keySet()) {
+ double price = itemData.isBz()
+ ? i == 0 ? itemData.bz.get(time).b : itemData.bz.get(time).s
+ : itemData.ah.get(time);
int xPos = (int) map(time, firstTime, lastTime, guiLeft + 17, guiLeft + 315);
int yPos = (int) map(price, highestValue + 10d, lowestValue - 10d, guiTop + 35, guiTop + 198);
if (prevX != null) {
@@ -160,7 +191,7 @@ public class GuiPriceGraph extends GuiScreen {
);
if (i == 0) {
Utils.drawLine(prevX, prevY + 0.5f, xPos, yPos + 0.5f, 2, graphColor);
- if (dataPoints.isBz())
+ if (itemData.isBz())
Utils.drawLine(
prevX,
secondLineData.get(prevX) + 0.5f,
@@ -219,8 +250,8 @@ public class GuiPriceGraph extends GuiScreen {
Utils.drawDottedLine(customStart, guiTop + 197, customEnd, guiTop + 197, 2, 10, 0xFFc6c6c6);
}
if (lowestDist != null && !customSelecting) {
- float price = dataPoints.isBz() ? dataPoints.bz.get(lowestDistTime).b : dataPoints.ah.get(lowestDistTime);
- Float price2 = dataPoints.isBz() ? dataPoints.bz.get(lowestDistTime).s : null;
+ double price = itemData.isBz() ? itemData.bz.get(lowestDistTime).b : itemData.ah.get(lowestDistTime);
+ Float price2 = itemData.isBz() ? itemData.bz.get(lowestDistTime).s : null;
int xPos = (int) map(lowestDistTime, firstTime, lastTime, guiLeft + 17, guiLeft + 315);
int yPos = (int) map(price, highestValue + 10d, lowestValue - 10d, guiTop + 35, guiTop + 198);
int yPos2 = price2 != null
@@ -244,7 +275,7 @@ public class GuiPriceGraph extends GuiScreen {
NumberFormat nf = NumberFormat.getInstance();
ArrayList<String> text = new ArrayList<>();
text.add(displayFormat.format(date));
- if (dataPoints.isBz()) {
+ if (itemData.isBz()) {
text.add(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "Bazaar Insta-Buy: " +
EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + nf.format(price));
text.add(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "Bazaar Insta-Sell: " +
@@ -321,7 +352,7 @@ public class GuiPriceGraph extends GuiScreen {
}
private void loadData() {
- dataPoints = null;
+ itemData = null;
loaded = false;
new Thread(() -> {
File dir = new File("config/notenoughupdates/prices");
@@ -330,46 +361,46 @@ public class GuiPriceGraph extends GuiScreen {
return;
}
File[] files = dir.listFiles();
- Data data = new Data();
+ ItemData itemData = new ItemData();
if (files == null) return;
for (File file : files) {
if (!file.getName().endsWith(".gz")) continue;
- HashMap<String, Data> data2 = load(file);
+ HashMap<String, ItemData> data2 = load(file);
if (data2 == null || !data2.containsKey(itemId)) continue;
if (data2.get(itemId).isBz()) {
- if (data.bz == null) data.bz = data2.get(itemId).bz;
- else data.bz.putAll(data2.get(itemId).bz);
- } else if (data.ah == null) data.ah = data2.get(itemId).ah;
- else data.ah.putAll(data2.get(itemId).ah);
+ if (itemData.bz == null) itemData.bz = data2.get(itemId).bz;
+ else itemData.bz.putAll(data2.get(itemId).bz);
+ } else if (itemData.ah == null) itemData.ah = data2.get(itemId).ah;
+ else itemData.ah.putAll(data2.get(itemId).ah);
}
- if (data.get() != null && !data.get().isEmpty()) {
+ if (itemData.get() != null && !itemData.get().isEmpty()) {
if (mode < 3)
- data = new Data(
- new TreeMap<>(data.get().entrySet().stream()
- .filter(e -> e.getKey() > System.currentTimeMillis() / 1000 -
- (mode == 0 ? 3600 : mode == 1 ? 86400 : 604800))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
- data.isBz()
+ itemData = new ItemData(
+ new TreeMap<>(itemData.get().entrySet().stream()
+ .filter(e -> e.getKey() > System.currentTimeMillis() / 1000 -
+ (mode == 0 ? 3600 : mode == 1 ? 86400 : 604800))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
+ itemData.isBz()
);
else if (mode == 4)
- data = new Data(
- new TreeMap<>(data.get().entrySet().stream()
- .filter(e -> e.getKey() >= customStart && e.getKey() <= customEnd)
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
- data.isBz()
+ itemData = new ItemData(
+ new TreeMap<>(itemData.get().entrySet().stream()
+ .filter(e -> e.getKey() >= customStart && e.getKey() <= customEnd)
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
+ itemData.isBz()
);
- if (data.get() == null || data.get().isEmpty()) {
+ if (itemData.get() == null || itemData.get().isEmpty()) {
loaded = true;
return;
}
- dataPoints = trimData(data);
- firstTime = dataPoints.get().firstKey();
- lastTime = dataPoints.get().lastKey();
+ this.itemData = trimData(itemData);
+ firstTime = this.itemData.get().firstKey();
+ lastTime = this.itemData.get().lastKey();
highestValue = 0;
lowestValue = null;
- for (long key : dataPoints.get().keySet()) {
- float value1 = dataPoints.isBz() ? dataPoints.bz.get(key).b : dataPoints.ah.get(key);
- Float value2 = dataPoints.isBz() ? dataPoints.bz.get(key).s : null;
+ for (long key : this.itemData.get().keySet()) {
+ double value1 = this.itemData.isBz() ? this.itemData.bz.get(key).b : this.itemData.ah.get(key);
+ Float value2 = this.itemData.isBz() ? this.itemData.bz.get(key).s : null;
if (value1 > highestValue) {
highestValue = value1;
}
@@ -380,7 +411,7 @@ public class GuiPriceGraph extends GuiScreen {
lowestValue = value1;
}
if (value2 != null && value2 < lowestValue) {
- lowestValue = value2;
+ lowestValue = Double.valueOf(value2);
}
}
}
@@ -399,37 +430,19 @@ public class GuiPriceGraph extends GuiScreen {
if (!file.getName().endsWith(".gz")) continue;
if (file.lastModified() <
System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.config.ahGraph.dataRetention * 86400000L)
+ //noinspection ResultOfMethodCallIgnored
file.delete();
}
Date date = new Date();
Long epochSecond = date.toInstant().getEpochSecond();
File file = new File(dir, "prices_" + format.format(date) + ".gz");
- HashMap<String, Data> prices = new HashMap<>();
- if (file.exists())
- prices = load(file);
- if (prices == null) return;
+ HashMap<String, ItemData> prices = new HashMap<>();
+ if (file.exists()) {
+ HashMap<String, ItemData> tempPrices = load(file);
+ if (tempPrices != null) prices = tempPrices;
+ }
for (Map.Entry<String, JsonElement> item : items.entrySet()) {
- if (prices.containsKey(item.getKey())) {
- if (bazaar && item.getValue().getAsJsonObject().has("curr_buy") && item.getValue().getAsJsonObject().has(
- "curr_sell"))
- prices.get(item.getKey()).bz.put(epochSecond, new BzData(
- item.getValue().getAsJsonObject().get("curr_buy").getAsFloat(),
- item.getValue().getAsJsonObject().get("curr_sell").getAsFloat()
- ));
- else if (!bazaar)
- prices.get(item.getKey()).ah.put(epochSecond, item.getValue().getAsInt());
- } else {
- TreeMap<Long, Object> mapData = new TreeMap<>();
- if (bazaar && item.getValue().getAsJsonObject().has("curr_buy") && item.getValue().getAsJsonObject().has(
- "curr_sell"))
- mapData.put(epochSecond, new BzData(
- item.getValue().getAsJsonObject().get("curr_buy").getAsFloat(),
- item.getValue().getAsJsonObject().get("curr_sell").getAsFloat()
- ));
- else if (!bazaar)
- mapData.put(epochSecond, item.getValue().getAsLong());
- prices.put(item.getKey(), new Data(mapData, bazaar));
- }
+ addOrUpdateItemPriceInfo(item, prices, epochSecond, bazaar);
}
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
@@ -446,16 +459,71 @@ public class GuiPriceGraph extends GuiScreen {
}
}
- private Data trimData(Data data) {
- long first = data.get().firstKey();
- long last = data.get().lastKey();
- Data trimmed = new Data();
- if (data.isBz())
+ private static void addOrUpdateItemPriceInfo(
+ Map.Entry<String, JsonElement> item,
+ HashMap<String, ItemData> prices,
+ long timestamp,
+ boolean bazaar
+ ) {
+ String itemName = item.getKey();
+ ItemData existingItemData = null;
+ if (prices.containsKey(itemName)) {
+ existingItemData = prices.get(itemName);
+ }
+
+ // Handle transitions from ah to bz (the other direction typically doesn't happen)
+ if (existingItemData != null) {
+ if (existingItemData.isBz() && !bazaar) {
+ return;
+ }
+
+ if (!existingItemData.isBz() && bazaar) {
+ prices.remove(itemName);
+ existingItemData = null;
+ }
+ }
+
+ if (bazaar) {
+ if (!item.getValue().getAsJsonObject().has("curr_buy") ||
+ !item.getValue().getAsJsonObject().has("curr_sell")
+ ) {
+ return;
+ }
+
+ BzData bzData = new BzData(
+ item.getValue().getAsJsonObject().get("curr_buy").getAsFloat(),
+ item.getValue().getAsJsonObject().get("curr_sell").getAsFloat()
+ );
+
+ if (existingItemData != null) {
+ existingItemData.bz.put(timestamp, bzData);
+ } else {
+ TreeMap<Long, Object> mapData = new TreeMap<>();
+ mapData.put(timestamp, bzData);
+ prices.put(item.getKey(), new ItemData(mapData, true));
+ }
+ } else {
+ if (existingItemData != null) {
+ prices.get(item.getKey()).ah.put(timestamp, item.getValue().getAsBigDecimal().longValue());
+ } else {
+ TreeMap<Long, Object> mapData = new TreeMap<>();
+ mapData.put(timestamp, item.getValue().getAsLong());
+ prices.put(item.getKey(), new ItemData(mapData, false));
+ }
+ }
+ }
+
+ private ItemData trimData(ItemData itemData) {
+ long first = itemData.get().firstKey();
+ long last = itemData.get().lastKey();
+ ItemData trimmed = new ItemData();
+ if (itemData.isBz())
trimmed.bz = new TreeMap<>();
else
trimmed.ah = new TreeMap<>();
int zones = NotEnoughUpdates.INSTANCE.config.ahGraph.graphZones;
- Long[] dataArray = !data.isBz() ? data.ah.keySet().toArray(new Long[0]) : data.bz.keySet().toArray(new Long[0]);
+ Long[] dataArray =
+ !itemData.isBz() ? itemData.ah.keySet().toArray(new Long[0]) : itemData.bz.keySet().toArray(new Long[0]);
int prev = 0;
for (int i = 0; i < zones; i++) {
long lowest = (long) map(i, 0, zones, first, last);
@@ -466,24 +534,24 @@ public class GuiPriceGraph extends GuiScreen {
for (int l = prev; l < dataArray.length; l++) {
if (dataArray[l] >= lowest && dataArray[l] <= highest) {
amount++;
- sumBuy += data.isBz() ? data.bz.get(dataArray[l]).b : data.ah.get(dataArray[l]);
- if (data.isBz()) sumSell += data.bz.get(dataArray[l]).s;
+ sumBuy += itemData.isBz() ? itemData.bz.get(dataArray[l]).b : itemData.ah.get(dataArray[l]);
+ if (itemData.isBz()) sumSell += itemData.bz.get(dataArray[l]).s;
prev = l + 1;
} else if (dataArray[l] > highest)
break;
}
if (amount > 0) {
- if (data.isBz())
+ if (itemData.isBz())
trimmed.bz.put(lowest, new BzData((float) (sumBuy / amount), (float) (sumSell / amount)));
else
- trimmed.ah.put(lowest, (int) (sumBuy / amount));
+ trimmed.ah.put(lowest, (long) (sumBuy / amount));
}
}
return trimmed;
}
- private static HashMap<String, Data> load(File file) {
- Type type = new TypeToken<HashMap<String, Data>>() {
+ private static HashMap<String, ItemData> load(File file) {
+ Type type = new TypeToken<HashMap<String, ItemData>>() {
}.getType();
if (file.exists()) {
try (
@@ -493,7 +561,10 @@ public class GuiPriceGraph extends GuiScreen {
))
) {
return GSON.fromJson(reader, type);
- } catch (Exception ignored) {
+ } catch (Exception e) {
+ System.out.println("Deleting " + file.getName() + " because it is probably corrupted.");
+ //noinspection ResultOfMethodCallIgnored
+ file.delete();
}
}
return null;
@@ -521,18 +592,18 @@ public class GuiPriceGraph extends GuiScreen {
}
}
-class Data {
- public TreeMap<Long, Integer> ah = null;
+class ItemData {
+ public TreeMap<Long, Long> ah = null;
public TreeMap<Long, BzData> bz = null;
- public Data() {
+ public ItemData() {
}
- public Data(TreeMap<Long, ?> map, boolean bz) {
+ public ItemData(TreeMap<Long, ?> map, boolean bz) {
if (bz)
this.bz = (TreeMap<Long, BzData>) map;
else
- this.ah = (TreeMap<Long, Integer>) map;
+ this.ah = (TreeMap<Long, Long>) map;
}
public TreeMap<Long, ?> get() {