aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/CustomAH.java208
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java79
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java77
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUResourceManager.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java115
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/StreamerMode.java63
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/Utils.java57
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java492
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java138
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java34
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java24
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/Options.java95
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java10
-rw-r--r--src/main/resources/assets/notenoughupdates/ah_item_holder.pngbin0 -> 642 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/ah_item_tab.pngbin0 -> 627 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/item_mask.pngbin856 -> 2800 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/off.pngbin1302 -> 3331 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/order_value.pngbin0 -> 1818 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/order_value_active.pngbin0 -> 1804 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/blit.vsh16
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/grayscale.fsh15
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json17
-rw-r--r--src/main/resources/assets/notenoughupdates/slider_button.pngbin0 -> 666 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/slider_off.pngbin0 -> 765 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/slider_on.pngbin0 -> 767 bytes
-rw-r--r--src/main/resources/mixins.notenoughupdates.json3
31 files changed, 1412 insertions, 128 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/CustomAH.java b/src/main/java/io/github/moulberry/notenoughupdates/CustomAH.java
new file mode 100644
index 00000000..d74d0e5c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/CustomAH.java
@@ -0,0 +1,208 @@
+package io.github.moulberry.notenoughupdates;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.util.TexLoc;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.item.Item;
+import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.opengl.GL11;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static io.github.moulberry.notenoughupdates.GuiTextures.*;
+
+public class CustomAH extends GuiScreen {
+
+ private static final ResourceLocation inventoryBackground = new ResourceLocation("textures/gui/container/inventory.png");
+ private static final ResourceLocation creativeTabSearch = new ResourceLocation("textures/gui/container/creative_inventory/tab_item_search.png");
+ private static final ResourceLocation creativeInventoryTabs = new ResourceLocation("textures/gui/container/creative_inventory/tabs.png");
+
+ private int yScrollInitial = 0;
+ private boolean scrollClicked = false;
+
+
+ private int splits = 2;
+
+ private int ySplit = 35;
+ private int ySplitSize = 18;
+ private int ySize = 136 + ySplitSize*splits;
+ private int xSize = 195;
+
+ private float scrollAmount;
+
+ private int guiLeft = 0;
+ private int guiTop = 0;
+
+ private NEUManager manager;
+ private HashMap<String, JsonObject> auctionItems = new HashMap<>();
+
+ private TexLoc tl = new TexLoc(0, 0, Keyboard.KEY_M);
+
+ public CustomAH(NEUManager manager) {
+ this.manager = manager;
+ updateAuctions();
+ }
+
+ private void updateAuctions() {
+ HashMap<Integer, JsonObject> pages = new HashMap<>();
+
+ HashMap<String, String> args = new HashMap<>();
+ args.put("page", "0");
+ AtomicInteger totalPages = new AtomicInteger(1);
+ AtomicInteger currentPages = new AtomicInteger(0);
+ manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/profiles",
+ args, jsonObject -> {
+ if(jsonObject.get("success").getAsBoolean()) {
+ pages.put(0, jsonObject);
+ totalPages.set(jsonObject.get("totalPages").getAsInt());
+ currentPages.incrementAndGet();
+
+ for(int i=1; i<totalPages.get(); i++) {
+ int j = i;
+ HashMap<String, String> args2 = new HashMap<>();
+ args2.put("page", ""+i);
+ manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/profiles",
+ args2, jsonObject2 -> {
+ if (jsonObject2.get("success").getAsBoolean()) {
+ pages.put(j, jsonObject2);
+ currentPages.incrementAndGet();
+ }
+ }
+ );
+ }
+ }
+ }
+ );
+
+ ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();//1593549115 () 1593631661919
+ long startTime = System.currentTimeMillis();
+ ses.schedule(new Runnable() {
+ public void run() {
+ if(System.currentTimeMillis() - startTime > 20000) return;
+
+ if(currentPages.get() == totalPages.get()) {
+ auctionItems.clear();
+ for(int pageNum : pages.keySet()) {
+ JsonObject page = pages.get(pageNum);
+ JsonArray auctions = page.get("auctions").getAsJsonArray();
+ for(int i=0; i<auctions.size(); i++) {
+ JsonObject auction = auctions.get(i).getAsJsonObject();
+ String auctionUuid = auction.get("uuid").getAsString();
+ String auctioneerUuid = auction.get("auctioneer").getAsString();
+ int end = auction.get("end").getAsInt();
+ String category = auction.get("category").getAsString();
+
+ String item_bytes = auction.get("item_bytes").getAsString();
+
+ try {
+ NBTTagCompound tag = CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes)));
+ tag = tag.getTagList("i", 10).getCompoundTagAt(0);
+ int id = tag.getShort("id");
+ int damage = tag.getShort("Damage");
+ tag = tag.getCompoundTag("tag");
+
+ String internalname = "";
+ if(tag != null && tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+
+ if(ea.hasKey("id", 8)) {
+ internalname = ea.getString("id");
+ }
+ }
+
+ String[] lore = new String[0];
+ NBTTagCompound display = tag.getCompoundTag("display");
+
+ if(display.hasKey("Lore", 9)) {
+ NBTTagList list = display.getTagList("Lore", 8);
+ lore = new String[list.tagCount()];
+ for(int k=0; k<list.tagCount(); k++) {
+ lore[k] = list.getStringTagAt(k);
+ }
+ }
+
+ String itemid = Item.getItemById(id).getRegistryName();
+ String displayname = display.getString("Name");
+ String[] info = new String[0];
+ String clickcommand = "";
+
+ JsonObject item = new JsonObject();
+
+ } catch(IOException e) {}
+ }
+ }
+ return;
+ }
+
+ ses.schedule(this, 1000L, TimeUnit.MILLISECONDS);
+ }
+ }, 5000L, TimeUnit.MILLISECONDS);
+
+ }
+
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+
+ tl.handleKeyboardInput();
+
+ guiLeft = (this.width - xSize)/2;
+ guiTop = (this.height - ySize)/2;
+
+ this.mc.getTextureManager().bindTexture(creativeTabSearch);
+ this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySplit);
+ int y = guiTop+ySplit;
+ for(int i=0; i<splits; i++) {
+ this.drawTexturedModalRect(guiLeft, y, 0, ySplit, xSize, ySplit+ySplitSize);
+ y += ySplitSize;
+ }
+ this.drawTexturedModalRect(guiLeft, y, 0, ySplit, xSize, 136-ySplit);
+
+ this.mc.getTextureManager().bindTexture(creativeInventoryTabs);
+ this.drawTexturedModalRect(guiLeft+175, guiTop+18+(int)((95+ySplitSize*2)*scrollAmount),
+ 256-(scrollClicked?12:24), 0, 12, 15);
+ }
+
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ int y = guiTop+18+(int)((95+ySplitSize*2)*scrollAmount);
+ if(mouseX > guiLeft+175 && mouseX < guiLeft+175+12) {
+ if(mouseY > y && mouseY < y+15) {
+ scrollClicked = true;
+ return;
+ }
+ }
+ scrollClicked = false;
+ }
+
+ @Override
+ protected void mouseReleased(int mouseX, int mouseY, int state) {
+ scrollClicked = false;
+ }
+
+ @Override
+ protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
+ if(scrollClicked) {
+ int yMin = guiTop+18 + 8;
+ int yMax = guiTop+18+(95+ySplitSize*2) + 8;
+
+ scrollAmount = (mouseY-yMin)/(float)yMax;
+ scrollAmount = Math.max(0, Math.min(1, scrollAmount));
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java b/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java
index 148f1bc5..4328eaf4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java
@@ -8,8 +8,8 @@ import net.minecraft.util.EnumChatFormatting;
public class CustomItems {
/**
- * So it has come to this, huh? Snooping through the source to find all my carefully crafted easter eggs. Well
- * guess what, you cheated not only the game, but yourself. You didn't grow. You didn't improve. You took a
+ * So it has come to this, huh? Snooping through the source to find all my carefully crafted easter eggs. You
+ * cheated not only the game, but yourself. You didn't grow. You didn't improve. You took a
* shortcut and gained nothing. You experienced a hollow victory. Nothing was risked and nothing was gained.
* It's sad that you don't know the difference.
*/
@@ -22,7 +22,7 @@ public class CustomItems {
"Dirt, AOTD. Dirt, AOTD.",
"Ooh, Dirt to Midas! Let's shake it up a little.",
"",
- "Also, Did you know that only 10% of the people watching are subscribed?",
+ "Also, did you know that only 8.7% of the people watching are subscribed?",
"It's OK, everyone makes mistakes",
"Also follow -> twitch.tv/nullzeelive",
"Also -> discord.gg/nullzee");
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java b/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java
index 48db19a5..965a7e48 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/GuiTextures.java
@@ -14,12 +14,19 @@ public class GuiTextures {
public static final ResourceLocation item_edit = new ResourceLocation("notenoughupdates:item_edit.png");
public static final ResourceLocation close = new ResourceLocation("notenoughupdates:close.png");
public static final ResourceLocation settings = new ResourceLocation("notenoughupdates:settings.png");
+
public static final ResourceLocation off = new ResourceLocation("notenoughupdates:off.png");
public static final ResourceLocation on = new ResourceLocation("notenoughupdates:on.png");
public static final ResourceLocation help = new ResourceLocation("notenoughupdates:help.png");
+ public static final ResourceLocation slider_off = new ResourceLocation("notenoughupdates:slider_off.png");
+ public static final ResourceLocation slider_on = new ResourceLocation("notenoughupdates:slider_on.png");
+ public static final ResourceLocation slider_button = new ResourceLocation("notenoughupdates:slider_button.png");
public static final ResourceLocation item_mask = new ResourceLocation("notenoughupdates:item_mask.png");
+ public static final ResourceLocation ah_item_holder = new ResourceLocation("notenoughupdates:ah_item_holder.png");
+ public static final ResourceLocation ah_item_tab = new ResourceLocation("notenoughupdates:ah_item_tab.png");
+
public static final ResourceLocation logo = new ResourceLocation("notenoughupdates:logo.png");
public static final ResourceLocation logo_fg = new ResourceLocation("notenoughupdates:logo_fg.png");
public static final ResourceLocation logo_bg = new ResourceLocation("notenoughupdates:logo_bg.png");
@@ -39,8 +46,10 @@ public class GuiTextures {
public static final ResourceLocation order_alphabetical = new ResourceLocation("notenoughupdates:order_alphabetical.png");
public static final ResourceLocation order_rarity = new ResourceLocation("notenoughupdates:order_rarity.png");
+ public static final ResourceLocation order_value = new ResourceLocation("notenoughupdates:order_value.png");
public static final ResourceLocation order_alphabetical_active = new ResourceLocation("notenoughupdates:order_alphabetical_active.png");
public static final ResourceLocation order_rarity_active = new ResourceLocation("notenoughupdates:order_rarity_active.png");
+ public static final ResourceLocation order_value_active = new ResourceLocation("notenoughupdates:order_value_active.png");
public static final ResourceLocation ascending_overlay = new ResourceLocation("notenoughupdates:ascending_overlay.png");
public static final ResourceLocation descending_overlay = new ResourceLocation("notenoughupdates:descending_overlay.png");
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java
index a7c7a1e4..d2190425 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java
@@ -84,13 +84,6 @@ public class NEUIO {
}
}
}
-
- /*for(GHContent content : repo.getDirectoryContent("items")) {
- String oldSha = oldShas.get(content.getName());
- if(!content.getSha().equals(oldSha)) {
- changedFiles.put(content.getName(), content.getSha());
- }
- }*/
} catch(IOException e) {
return null;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index bebd090c..e2c8d928 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -54,7 +54,7 @@ public class NEUManager {
public String viewItemAttemptID = null;
public long viewItemAttemptTime = 0;
- public String currentProfile = "";
+ public String currentProfile = "Papaya";
public final HypixelApi hypixelApi = new HypixelApi();
private ResourceLocation wkZip = new ResourceLocation("notenoughupdates:wkhtmltox.zip");
@@ -180,6 +180,25 @@ public class NEUManager {
public float craftCost = -1;
}
+ public boolean isVanillaItem(String internalname) {
+ //Removes trailing numbers and underscores, eg. LEAVES_2-3 -> LEAVES
+ String vanillaName = internalname.split("-")[0];
+ int sub = 0;
+ for(int i=vanillaName.length()-1; i>1; i--) {
+ char c = vanillaName.charAt(i);
+ if((int)c >= 48 && (int)c <= 57) { //0-9
+ sub++;
+ } else if(c == '_') {
+ sub++;
+ break;
+ } else {
+ break;
+ }
+ }
+ vanillaName = vanillaName.substring(0, vanillaName.length()-sub).toLowerCase();
+ return Item.itemRegistry.getObject(new ResourceLocation(vanillaName)) != null;
+ }
+
/**
* Recursively calculates the cost of crafting an item from raw materials.
*/
@@ -189,24 +208,7 @@ public class NEUManager {
} else {
CraftInfo ci = new CraftInfo();
- //Removes trailing numbers and underscores, eg. LEAVES_2-3 -> LEAVES
- String vanillaName = internalname.split("-")[0];
- int sub = 0;
- for(int i=vanillaName.length()-1; i>1; i--) {
- char c = vanillaName.charAt(i);
- if((int)c >= 48 && (int)c <= 57) { //0-9
- sub++;
- } else if(c == '_') {
- sub++;
- break;
- } else {
- break;
- }
- }
- vanillaName = vanillaName.substring(0, vanillaName.length()-sub);
- if(Item.itemRegistry.getObject(new ResourceLocation(vanillaName)) != null) {
- ci.vanillaItem = true;
- }
+ ci.vanillaItem = isVanillaItem(internalname);
JsonObject auctionInfo = getItemAuctionInfo(internalname);
JsonObject bazaarInfo = getBazaarInfo(internalname);
@@ -657,9 +659,29 @@ public class NEUManager {
public Set<String> search(String query, boolean multi) {
if(multi) {
Set<String> result = new HashSet<>();
- for(String query2 : query.split("\\|")) {
- result.addAll(search(query2));
+
+ StringBuilder query2 = new StringBuilder();
+ char lastOp = '|';
+ for(char c : query.toCharArray()) {
+ if(c == '|' || c == '&') {
+ if(lastOp == '|') {
+ result.addAll(search(query2.toString()));
+ } else if(lastOp == '&') {
+ result.retainAll(search(query2.toString()));
+ }
+
+ query2 = new StringBuilder();
+ lastOp = c;
+ } else {
+ query2.append(c);
+ }
+ }
+ if(lastOp == '|') {
+ result.addAll(search(query2.toString()));
+ } else if(lastOp == '&') {
+ result.retainAll(search(query2.toString()));
}
+
return result;
} else {
return search(query);
@@ -670,6 +692,10 @@ public class NEUManager {
* Returns the name of items which match a certain search query.
*/
public Set<String> search(String query) {
+ query = query.trim();
+ boolean negate = query.startsWith("!");
+ if(negate) query = query.substring(1);
+
LinkedHashSet<String> results = new LinkedHashSet<>();
if(query.startsWith("title:")) {
query = query.substring(6);
@@ -691,7 +717,16 @@ public class NEUManager {
results.addAll(new TreeSet<>(search(query, titleWordMap)));
results.addAll(new TreeSet<>(search(query, loreWordMap)));
}
- return results;
+ if(!negate) {
+ return results;
+ } else {
+ Set<String> negatedResults = new HashSet<>();
+ for(String internalname : itemMap.keySet()) {
+ negatedResults.add(internalname);
+ }
+ negatedResults.removeAll(results);
+ return negatedResults;
+ }
}
/**
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index 59233882..d96be893 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -30,6 +30,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.Matrix4f;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
+import net.minecraftforge.client.ClientCommandHandler;
import org.apache.commons.lang3.StringUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
@@ -62,10 +63,10 @@ public class NEUOverlay extends Gui {
};
private ResourceLocation[] orderIcons = new ResourceLocation[] {
- order_alphabetical, order_rarity
+ order_alphabetical, order_rarity, order_value
};
private ResourceLocation[] orderIconsActive = new ResourceLocation[] {
- order_alphabetical_active, order_rarity_active
+ order_alphabetical_active, order_rarity_active, order_value_active
};
//Various constants used for GUI structure
@@ -74,9 +75,8 @@ public class NEUOverlay extends Gui {
private final int searchBarYSize = 40;
private final int searchBarPadding = 2;
- private static final int BOX_PADDING = 15;
- public static final int ITEM_PADDING = 4;
- public static final int ITEM_SIZE = 16;
+ public static final int ITEM_PADDING = 4;
+ public static final int ITEM_SIZE = 16;
private Color bg = new Color(90, 90, 140, 50);
private Color fg = new Color(100,100,100, 255);
@@ -97,6 +97,9 @@ public class NEUOverlay extends Gui {
private boolean searchMode = false;
private long millisLastLeftClick = 0;
+ private long millisLastMouseMove = 0;
+ private int lastMouseX = 0;
+ private int lastMouseY = 0;
boolean mouseDown = false;
@@ -107,6 +110,7 @@ public class NEUOverlay extends Gui {
private static final int COMPARE_MODE_ALPHABETICAL = 0;
private static final int COMPARE_MODE_RARITY = 1;
+ private static final int COMPARE_MODE_VALUE = 2;
private static final int SORT_MODE_ALL = 0;
private static final int SORT_MODE_MOB = 1;
@@ -177,6 +181,13 @@ public class NEUOverlay extends Gui {
int mouseX = Mouse.getX() / scaledresolution.getScaleFactor();
int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor();
+ if(lastMouseX != mouseX || lastMouseY != mouseY) {
+ millisLastMouseMove = System.currentTimeMillis();
+ }
+
+ lastMouseX = mouseX;
+ lastMouseY = mouseY;
+
if(Mouse.getEventButtonState()) {
mouseDown = true;
} else if(Mouse.getEventButton() != -1) {
@@ -288,8 +299,8 @@ public class NEUOverlay extends Gui {
}
//Clicking on "close info pane" button
- if(mouseX > width*getInfoPaneOffsetFactor()-22 && mouseX < width*getInfoPaneOffsetFactor()-6) {
- if(mouseY > 7 && mouseY < 23) {
+ if(mouseX > width*getInfoPaneOffsetFactor()-getBoxPadding()-8 && mouseX < width*getInfoPaneOffsetFactor()-getBoxPadding()+8) {
+ if(mouseY > getBoxPadding()-8 && mouseY < getBoxPadding()+8) {
if(Mouse.getEventButtonState() && Mouse.getEventButton() < 2) { //Left or right click up
displayInformationPane(null);
return true;
@@ -322,6 +333,9 @@ public class NEUOverlay extends Gui {
if(command.startsWith("/")) {
NotEnoughUpdates.INSTANCE.sendChatMessage(command);
return true;
+ } else {
+ ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command);
+ return true;
}
}
}
@@ -376,6 +390,8 @@ public class NEUOverlay extends Gui {
if(mouseX < width*getInfoPaneOffsetFactor()) {
activeInfoPane.mouseInput(width, height, mouseX, mouseY, mouseDown);
return true;
+ } else if(Mouse.getEventButton() <= 1 && Mouse.getEventButtonState()) { //Left or right click
+ activeInfoPane.mouseInputOutside();
}
}
@@ -627,6 +643,12 @@ public class NEUOverlay extends Gui {
if(rarity1 < rarity2) return mult;
if(rarity1 > rarity2) return -mult;
+ } else if(getCompareMode() == COMPARE_MODE_VALUE) {
+ float cost1 = manager.getCraftCost(o1.get("internalname").getAsString()).craftCost;
+ float cost2 = manager.getCraftCost(o2.get("internalname").getAsString()).craftCost;
+
+ if(cost1 < cost2) return mult;
+ if(cost1 > cost2) return -mult;
}
String i1 = o1.get("internalname").getAsString();
@@ -776,7 +798,8 @@ public class NEUOverlay extends Gui {
}
public int getBoxPadding() {
- return (BOX_PADDING-5)*2/scaledresolution.getScaleFactor()+5;
+ double panePadding = Math.max(0, Math.min(20, manager.config.panePadding.value));
+ return (int)(panePadding*2/scaledresolution.getScaleFactor()+5);
}
private abstract class ItemSlotConsumer {
@@ -1252,7 +1275,7 @@ public class NEUOverlay extends Gui {
//Atomic reference used so that below lambda doesn't complain about non-effectively-final variable
AtomicReference<JsonObject> tooltipToDisplay = new AtomicReference<>(null);
-
+ List<String> textToDisplay = null;
if(itemPaneOffsetFactor.getValue() < 1) {
renderBlurredBackground(width, height,
leftSide+getBoxPadding()-5, getBoxPadding()-5,
@@ -1290,6 +1313,19 @@ public class NEUOverlay extends Gui {
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect(orderIconX, iconTop, scaledITEM_SIZE, scaledITEM_SIZE,0, 1, 0, 1, GL11.GL_NEAREST);
GlStateManager.bindTexture(0);
+
+ if(mouseY > iconTop && mouseY < iconTop+scaledITEM_SIZE) {
+ if(mouseX > orderIconX && mouseX < orderIconX+scaledITEM_SIZE) {
+ if(System.currentTimeMillis() - millisLastMouseMove > 400) {
+ String text = EnumChatFormatting.GRAY+"Order ";
+ if(i == COMPARE_MODE_ALPHABETICAL) text += "Alphabetically";
+ else if(i == COMPARE_MODE_RARITY) text += "by Rarity";
+ else if(i == COMPARE_MODE_VALUE) text += "by Item Worth";
+ else text = null;
+ if(text != null) textToDisplay = Utils.createList(text);
+ }
+ }
+ }
}
for(int i=0; i<sortIcons.length; i++) {
@@ -1299,6 +1335,22 @@ public class NEUOverlay extends Gui {
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect(sortIconX, iconTop, scaledITEM_SIZE, scaledITEM_SIZE, 0, 1, 0, 1, GL11.GL_NEAREST);
GlStateManager.bindTexture(0);
+
+ if(mouseY > iconTop && mouseY < iconTop+scaledITEM_SIZE) {
+ if(mouseX > sortIconX && mouseX < sortIconX+scaledITEM_SIZE) {
+ if(System.currentTimeMillis() - millisLastMouseMove > 400) {
+ String text = EnumChatFormatting.GRAY+"Filter ";
+ if(i == SORT_MODE_ALL) text = EnumChatFormatting.GRAY+"No Filter";
+ else if(i == SORT_MODE_MOB) text += "Mobs";
+ else if(i == SORT_MODE_PET) text += "Pets";
+ else if(i == SORT_MODE_TOOL) text += "Tools";
+ else if(i == SORT_MODE_ARMOR) text += "Armor";
+ else if(i == SORT_MODE_ACCESSORY) text += "Accessories";
+ else text = null;
+ if(text != null) textToDisplay = Utils.createList(text);
+ }
+ }
+ }
}
if(!hoverInv) {
@@ -1355,7 +1407,7 @@ public class NEUOverlay extends Gui {
GlStateManager.color(1f, 1f, 1f, 1f);
Minecraft.getMinecraft().getTextureManager().bindTexture(close);
- Utils.drawTexturedRect(rightSide-22, 7, 16, 16);
+ Utils.drawTexturedRect(rightSide-getBoxPadding()-8, getBoxPadding()-8, 16, 16);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
}
@@ -1567,7 +1619,10 @@ public class NEUOverlay extends Gui {
if(hasClick) text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"LMB/R : View recipe!");
if(hasInfo) text.add(EnumChatFormatting.YELLOW.toString()+EnumChatFormatting.BOLD+"RMB : View additional information!");
- Utils.drawHoveringText(text, mouseX, mouseY, width, height, -1, fr);
+ textToDisplay = text;
+ }
+ if(textToDisplay != null) {
+ Utils.drawHoveringText(textToDisplay, mouseX, mouseY, width, height, -1, fr);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUResourceManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUResourceManager.java
new file mode 100644
index 00000000..41737eda
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUResourceManager.java
@@ -0,0 +1,38 @@
+package io.github.moulberry.notenoughupdates;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.resources.IResource;
+import net.minecraft.client.resources.IResourceManager;
+import net.minecraft.util.ResourceLocation;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+public class NEUResourceManager implements IResourceManager {
+
+ private IResourceManager parentResourceManager;
+
+ public NEUResourceManager(IResourceManager parentResourceManager) {
+ this.parentResourceManager = parentResourceManager;
+ }
+
+ @Override
+ public Set<String> getResourceDomains() {
+ return parentResourceManager.getResourceDomains();
+ }
+
+ @Override
+ public IResource getResource(ResourceLocation location) throws IOException {
+ return parentResourceManager.getResource(forceNeuRL(location));
+ }
+
+ @Override
+ public List<IResource> getAllResources(ResourceLocation location) throws IOException {
+ return parentResourceManager.getAllResources(forceNeuRL(location));
+ }
+
+ private ResourceLocation forceNeuRL(ResourceLocation location) {
+ return new ResourceLocation("notenoughupdates", location.getResourcePath());
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index b4b48db5..ab903227 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -6,14 +6,20 @@ import com.mojang.authlib.Agent;
import com.mojang.authlib.exceptions.AuthenticationException;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
+import io.github.moulberry.notenoughupdates.commands.SimpleCommand;
+import io.github.moulberry.notenoughupdates.infopanes.CollectionLogInfoPane;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.gui.inventory.GuiContainer;
+import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.client.settings.KeyBinding;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.init.Blocks;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
+import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
@@ -23,6 +29,7 @@ import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.Session;
import net.minecraft.util.StatCollector;
+import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.client.event.ClientChatReceivedEvent;
import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.client.event.GuiScreenEvent;
@@ -32,6 +39,7 @@ import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.input.Keyboard;
@@ -83,6 +91,29 @@ public class NotEnoughUpdates {
return s;
}
+ ScheduledExecutorService guiDelaySES = Executors.newScheduledThreadPool(1);
+ SimpleCommand collectionLogCommand = new SimpleCommand("neucl", new SimpleCommand.ProcessCommandRunnable() {
+ public void processCommand(ICommandSender sender, String[] args) {
+ if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) {
+ guiDelaySES.schedule(()->{
+ Minecraft.getMinecraft().displayGuiScreen(new GuiInventory(Minecraft.getMinecraft().thePlayer));
+ }, 10L, TimeUnit.MILLISECONDS);
+ }
+ manager.updatePrices();
+ overlay.displayInformationPane(new CollectionLogInfoPane(overlay, manager));
+ }
+ });
+
+ SimpleCommand neuAhCommand = new SimpleCommand("neuah", new SimpleCommand.ProcessCommandRunnable() {
+ public void processCommand(ICommandSender sender, String[] args) {
+ if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) {
+ guiDelaySES.schedule(()->{
+ Minecraft.getMinecraft().displayGuiScreen(new CustomAH(manager));
+ }, 10L, TimeUnit.MILLISECONDS);
+ }
+ }
+ });
+
/**
* Instantiates NEUIo, NEUManager and NEUOverlay instances. Registers keybinds and adds a shutdown hook to clear tmp folder.
* @param event
@@ -94,6 +125,9 @@ public class NotEnoughUpdates {
File f = new File(event.getModConfigurationDirectory(), "notenoughupdates");
f.mkdirs();
+ ClientCommandHandler.instance.registerCommand(collectionLogCommand);
+ ClientCommandHandler.instance.registerCommand(neuAhCommand);
+
neuio = new NEUIO(getAccessToken());
manager = new NEUManager(this, neuio, f);
manager.loadItemInformation();
@@ -165,16 +199,64 @@ public class NotEnoughUpdates {
}
/**
- * Will send the cached message from #sendChatMessage when at least 200ms has passed since the last message.
+ * 1)Will send the cached message from #sendChatMessage when at least 200ms has passed since the last message.
* This is used in order to prevent the mod spamming messages.
+ * 2)Adds unique items to the collection log
*/
- @EventHandler
+ private HashMap<String, Long> newItemAddMap = new HashMap<>();
+ @SubscribeEvent
public void onTick(TickEvent.ClientTickEvent event) {
if(currChatMessage != null && System.currentTimeMillis() - lastChatMessage > CHAT_MSG_COOLDOWN) {
lastChatMessage = System.currentTimeMillis();
Minecraft.getMinecraft().thePlayer.sendChatMessage(currChatMessage);
currChatMessage = null;
}
+ if(hasSkyblockScoreboard() && manager.currentProfile != null && manager.currentProfile.length() > 0) {
+ HashSet<String> newItem = new HashSet<>();
+ for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) {
+ processUniqueStack(stack, newItem);
+ }
+ boolean usableContainer = true;
+ for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) {
+ if(stack == null) {
+ continue;
+ }
+ if(stack.hasTagCompound()) {
+ NBTTagCompound tag = stack.getTagCompound();
+ if(tag.hasKey("ExtraAttributes", 10)) {
+ continue;
+ }
+ }
+ usableContainer = false;
+ break;
+ }
+ if(usableContainer) {
+ for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) {
+ processUniqueStack(stack, newItem);
+ }
+ }
+ newItemAddMap.keySet().retainAll(newItem);
+ }
+ }
+
+ private void processUniqueStack(ItemStack stack, HashSet<String> newItem) {
+ if(stack != null && stack.hasTagCompound()) {
+ String internalname = manager.getInternalNameForItem(stack);
+ if(internalname != null) {
+ ArrayList<String> log = manager.config.collectionLog.value.computeIfAbsent(
+ manager.currentProfile, k -> new ArrayList<>());
+ if(!log.contains(internalname)) {
+ newItem.add(internalname);
+ if(newItemAddMap.containsKey(internalname)) {
+ if(System.currentTimeMillis() - newItemAddMap.get(internalname) > 1000) {
+ log.add(internalname);
+ }
+ } else {
+ newItemAddMap.put(internalname, System.currentTimeMillis());
+ }
+ }
+ }
+ }
}
/**
@@ -302,8 +384,9 @@ public class NotEnoughUpdates {
/**
* 1) When receiving "You are playing on profile" messages, will set the current profile.
* 2) When a /viewrecipe command fails (i.e. player does not have recipe unlocked, will open the custom recipe GUI)
+ * 3) Replaces lobby join notifications when streamer mode is active
*/
- @SubscribeEvent
+ @SubscribeEvent(priority = EventPriority.LOW)
public void onGuiChat(ClientChatReceivedEvent e) {
String r = null;
String unformatted = e.message.getUnformattedText().replaceAll("(?i)\\u00A7.", "");
@@ -319,12 +402,20 @@ public class NotEnoughUpdates {
EnumChatFormatting.RED+"Invalid recipe ")) {
r = "";
}
- if(r != null) {
+ if(r != null) {
if(manager.failViewItem(r)) {
e.setCanceled(true);
}
missingRecipe.set(true);
}
+ //System.out.println(e.message);
+ if(isOnSkyblock() && manager.config.streamerMode.value && e.message instanceof ChatComponentText) {
+ String m = e.message.getFormattedText();
+ String m2 = StreamerMode.filterChat(e.message.getFormattedText());
+ if(!m.equals(m2)) {
+ e.message = new ChatComponentText(m2);
+ }
+ }
}
/**
@@ -441,6 +532,9 @@ public class NotEnoughUpdates {
JOptionPane.PLAIN_MESSAGE,
null, new String[]{"Enter"}, "Enter");
resInternalname = tf.getText();
+ if(resInternalname.trim().length() == 0) {
+ return;
+ }
JsonObject recipe = new JsonObject();
@@ -536,6 +630,16 @@ public class NotEnoughUpdates {
*/
@SubscribeEvent
public void onItemTooltip(ItemTooltipEvent event) {
+ if(!isOnSkyblock()) return;
+ if(manager.config.hideEmptyPanes.value &&
+ event.itemStack.getItem().equals(Item.getItemFromBlock(Blocks.stained_glass_pane))) {
+ String first = Utils.cleanColour(event.toolTip.get(0));
+ first = first.replaceAll("\\(.*\\)", "").trim();
+ if(first.length() == 0) {
+ event.toolTip.clear();
+ }
+ }
+ //AH prices
if(Minecraft.getMinecraft().currentScreen != null) {
if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
@@ -623,7 +727,10 @@ public class NotEnoughUpdates {
//Stolen from Biscut's SkyblockAddons
public boolean isOnSkyblock() {
if(!manager.config.onlyShowOnSkyblock.value) return true;
+ return hasSkyblockScoreboard();
+ }
+ public boolean hasSkyblockScoreboard() {
Minecraft mc = Minecraft.getMinecraft();
if (mc != null && mc.theWorld != null) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/StreamerMode.java b/src/main/java/io/github/moulberry/notenoughupdates/StreamerMode.java
new file mode 100644
index 00000000..c7d5e8ae
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/StreamerMode.java
@@ -0,0 +1,63 @@
+package io.github.moulberry.notenoughupdates;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StreamerMode {
+
+ private static final Pattern lobbyPattern = Pattern.compile("(mini|mega)([0-9]{1,3}[A-Z])");
+
+ public static String filterLobbyNames(String line) {
+ Matcher matcher = lobbyPattern.matcher(line);
+ if(matcher.find() && matcher.groupCount() == 2) {
+ String lobbyType = matcher.group(1);
+ String lobbyId = matcher.group(2);
+ long lobbyNum = Long.parseLong(lobbyId.substring(0, lobbyId.length()-1));
+
+ long obfLobbyNum = (lobbyNum*9182739 + 11) % 500;
+ char obfLobbyLetter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt((int)(obfLobbyNum%26));
+
+ line = line.replaceAll("(mini|mega)([0-9]{1,3}[A-Z])", lobbyType+obfLobbyNum+obfLobbyLetter);
+ }
+ return line;
+ }
+
+ public static String filterScoreboard(String line) {
+ line = filterLobbyNames(cleanDuplicateColourCodes(line));
+ return line;
+ }
+
+ public static String filterChat(String line) {
+ line = filterLobbyNames(line);
+ return line;
+ }
+
+ private static String cleanDuplicateColourCodes(String line) {
+ StringBuilder sb = new StringBuilder();
+ char currentColourCode = 'r';
+ boolean sectionSymbolLast = false;
+ for(char c : line.toCharArray()) {
+ if((int)c > 50000) continue;
+
+ if(c == '\u00a7') {
+ sectionSymbolLast = true;
+ } else {
+ if(sectionSymbolLast) {
+ if(currentColourCode != c) {
+ sb.append('\u00a7');
+ sb.append(c);
+ currentColourCode = c;
+ }
+ sectionSymbolLast = false;
+ } else {
+ sb.append(c);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/Utils.java
index c08adc94..f850b49d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/Utils.java
@@ -112,6 +112,10 @@ public class Utils {
drawTexturedRect(x, y, width, height, uMin, uMax, vMin , vMax, GL11.GL_LINEAR);
}
+ public static String cleanColour(String in) {
+ return in.replaceAll("(?i)\\u00A7.", "");
+ }
+
public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) {
GlStateManager.enableTexture2D();
GlStateManager.enableBlend();
@@ -137,34 +141,6 @@ public class Utils {
.tex(uMin, vMin).endVertex();
tessellator.draw();
- /*Tessellator tessellator = Tessellator.getInstance();
- WorldRenderer worldrenderer = tessellator.getWorldRenderer();
- worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX);
- worldrenderer
- .pos(x, y + height, 0)
- .tex(uMin, vMax).endVertex();
- worldrenderer
- .pos(x + width, y + height, 0)
- .tex(uMax, vMax).endVertex();
- worldrenderer
- .pos(x + width, y, 0)
- .tex(uMax, vMin).endVertex();
- worldrenderer
- .pos(x, y, 0)
- .tex(uMin, vMin).endVertex();
- tessellator.draw();*/
-
- /*GL11.glBegin(GL11.GL_TRIANGLE_STRIP);
- GL11.glTexCoord2f(uMin, vMin);
- GL11.glVertex3f(x, y, 0.0F);
- GL11.glTexCoord2f(uMin, vMax);
- GL11.glVertex3f(x, y+height, 0.0F);
- GL11.glTexCoord2f(uMax, vMin);
- GL11.glVertex3f(x+width, y, 0.0F);
- GL11.glTexCoord2f(uMax, vMax);
- GL11.glVertex3f(x+width, y+height, 0.0F);
- GL11.glEnd();*/
-
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
@@ -204,7 +180,21 @@ public class Utils {
drawStringScaled(str, fr, x-len/2, y-fontHeight/2, shadow, colour, factor);
}
+ public static void drawStringCenteredYScaled(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) {
+ int strLen = fr.getStringWidth(str);
+ float factor = len/(float)strLen;
+ float fontHeight = 8*factor;
+
+ drawStringScaled(str, fr, x, y-fontHeight/2, shadow, colour, factor);
+ }
+
public static int renderStringTrimWidth(String str, FontRenderer fr, boolean shadow, int x, int y, int len, int colour, int maxLines) {
+ return renderStringTrimWidth(str, fr, shadow, x, y, len, colour, maxLines, 1);
+ }
+
+ public static int renderStringTrimWidth(String str, FontRenderer fr, boolean shadow, int x, int y, int len, int colour, int maxLines, float scale) {
+ len = (int)(len/scale);
+
int yOff = 0;
String excess;
String trimmed = trimToWidth(str, len);
@@ -221,26 +211,27 @@ public class Utils {
int lines = 0;
while((lines++<maxLines) || maxLines<0) {
if(trimmed.length() == str.length()) {
- fr.drawString(trimmed, x, y + yOff, colour, shadow);
+ drawStringScaled(trimmed, fr, x, y+yOff, shadow, colour, scale);
+ //fr.drawString(trimmed, x, y + yOff, colour, shadow);
break;
} else if(trimmed.isEmpty()) {
- yOff -= 12;
+ yOff -= 12*scale;
break;
} else {
if(firstLine) {
- fr.drawString(trimmed, x, y + yOff, colour, shadow);
+ drawStringScaled(trimmed, fr, x, y+yOff, shadow, colour, scale);
firstLine = false;
} else {
if(trimmed.startsWith(" ")) {
trimmed = trimmed.substring(1);
}
- fr.drawString(colourCodes + trimmed, x, y + yOff, colour, shadow);
+ drawStringScaled(colourCodes + trimmed, fr, x, y+yOff, shadow, colour, scale);
}
excess = str.substring(trimmedCharacters);
trimmed = trimToWidth(excess, len);
trimmedCharacters += trimmed.length();
- yOff += 12;
+ yOff += 12*scale;
}
}
return yOff;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java
new file mode 100644
index 00000000..ae27be46
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/SimpleCommand.java
@@ -0,0 +1,36 @@
+package io.github.moulberry.notenoughupdates.commands;
+
+import net.minecraft.command.CommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+
+public class SimpleCommand extends CommandBase {
+
+ private String commandName;
+ private ProcessCommandRunnable runnable;
+
+ public SimpleCommand(String commandName, ProcessCommandRunnable runnable) {
+ this.commandName = commandName;
+ this.runnable = runnable;
+ }
+
+ public abstract static class ProcessCommandRunnable {
+ public abstract void processCommand(ICommandSender sender, String[] args);
+ }
+
+ public boolean canCommandSenderUseCommand(ICommandSender sender) {
+ return true;
+ }
+
+ public String getCommandName() {
+ return commandName;
+ }
+
+ public String getCommandUsage(ICommandSender sender) {
+ return "/" + commandName;
+ }
+
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ runnable.processCommand(sender, args);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java
new file mode 100644
index 00000000..1c21e342
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java
@@ -0,0 +1,492 @@
+package io.github.moulberry.notenoughupdates.infopanes;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NEUOverlay;
+import io.github.moulberry.notenoughupdates.NEUResourceManager;
+import io.github.moulberry.notenoughupdates.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.shader.Framebuffer;
+import net.minecraft.client.shader.Shader;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.Matrix4f;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.text.NumberFormat;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static io.github.moulberry.notenoughupdates.GuiTextures.item_mask;
+
+public class CollectionLogInfoPane extends ScrollableInfoPane {
+
+ private String mobRegex = ".*?((_MONSTER)|(_ANIMAL)|(_MINIBOSS)|(_BOSS)|(_SC))$";
+ private String petRegex = ".*?;[0-4]$";
+
+ TreeSet<String> items = new TreeSet<>(getItemComparator());
+
+ private int buttonHover = -1;
+
+ private static final int FILTER_ALL = 0;
+ private static final int FILTER_WEAPON = 1;
+ private static final int FILTER_ARMOR = 2;
+ private static final int FILTER_ACCESSORY = 3;
+ private static final int FILTER_PET = 4;
+ private static final int FILTER_TOOL = 5;
+ private static final int FILTER_SLAYER_ZOMBIE = 6;
+ private static final int FILTER_SLAYER_WOLF = 7;
+ private static final int FILTER_SLAYER_SPIDER = 8;
+ private int filterMode = FILTER_ALL;
+ private String[] filterPrettyNames = new String[]{"ALL","WEAPON","ARMOR",
+ "ACCESSORY","PET","TOOL","ZOMBIE SLAYER","WOLF SLAYER","SPIDER SLAYER"};
+
+ private Framebuffer itemFramebuffer = null;
+ private Framebuffer itemBGFramebuffer = null;
+ private Framebuffer itemFramebufferGrayscale = null;
+ private Shader grayscaleShader = null;
+
+ public CollectionLogInfoPane(NEUOverlay overlay, NEUManager manager) {
+ super(overlay, manager);
+ refreshItems();
+ }
+
+ private boolean loreContains(JsonArray lore, String str) {
+ for(int i=0; i<lore.size(); i++) {
+ String line = lore.get(i).getAsString();
+ if(line.contains(str)) return true;
+ }
+ return false;
+ }
+
+ private void refreshItems() {
+ items.clear();
+ for(String internalname : manager.getItemInformation().keySet()) {
+ if(!manager.isVanillaItem(internalname) && !internalname.matches(mobRegex)) {
+ JsonArray lore = manager.getItemInformation().get(internalname).get("lore").getAsJsonArray();
+ switch(filterMode) {
+ case FILTER_WEAPON:
+ if(overlay.checkItemType(lore, "SWORD", "BOW", "WAND") < 0) continue;
+ break;
+ case FILTER_ARMOR:
+ if(overlay.checkItemType(lore, "HELMET", "CHESTPLATE", "LEGGINGS", "BOOTS") < 0) continue;
+ break;
+ case FILTER_ACCESSORY:
+ if(overlay.checkItemType(lore, "ACCESSORY") < 0) continue;
+ break;
+ case FILTER_PET:
+ if(!internalname.matches(petRegex)) continue;
+ break;
+ case FILTER_TOOL:
+ if(overlay.checkItemType(lore, "AXE", "PICKAXE", "FISHING ROD", "SHOVEL", "HOE") < 0) continue;
+ break;
+ case FILTER_SLAYER_ZOMBIE:
+ if(!loreContains(lore, "\u00A7c\u2620 \u00A75Requires Zombie")) continue;
+ break;
+ case FILTER_SLAYER_WOLF:
+ if(!loreContains(lore, "\u00A7c\u2620 \u00A75Requires Wolf")) continue;
+ break;
+ case FILTER_SLAYER_SPIDER:
+ if(!loreContains(lore, "\u00A7c\u2620 \u00A75Requires Spider")) continue;
+ break;
+ }
+ items.add(internalname);
+ }
+ }
+ }
+
+ private Map<String, ArrayList<String>> getAcquiredItems() {
+ return manager.config.collectionLog.value;
+ }
+
+ private Comparator<String> getItemComparator() {
+ return (o1, o2) -> {
+ float cost1 = manager.getCraftCost(o1).craftCost;
+ float cost2 = manager.getCraftCost(o2).craftCost;
+
+ if(cost1 < cost2) return 1;
+ if(cost1 > cost2) return -1;
+
+ return o1.compareTo(o2);
+ };
+ }
+
+ public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) {
+ super.mouseInput(width, height, mouseX, mouseY, mouseDown);
+ if(mouseDown) {
+ if(buttonHover == 0) {
+ if(Mouse.getEventButton() == 0) {
+ filterMode++;
+ if(filterMode >= filterPrettyNames.length) {
+ filterMode = 0;
+ }
+ } else if(Mouse.getEventButton() == 1) {
+ filterMode--;
+ if(filterMode < 0) {
+ filterMode = filterPrettyNames.length-1;
+ }
+ }
+ }
+ refreshItems();
+ }
+ }
+
+ public void render(int width, int height, Color bg, Color fg, ScaledResolution scaledresolution, int mouseX, int mouseY) {
+ int paneWidth = (int)(width/3*overlay.getWidthMult());
+ int rightSide = (int)(width*overlay.getInfoPaneOffsetFactor());
+ int leftSide = rightSide - paneWidth;
+ int padding = overlay.getBoxPadding();
+
+ renderDefaultBackground(width, height, bg);
+
+ renderControls(height, padding, leftSide+padding, rightSide-padding, 20, fg);
+ renderCollectionLog(fg, width, height, leftSide+padding, rightSide-padding, padding+25, height-padding);
+ }
+
+ private float getCompletedness() {
+ int total = items.size();
+ int own = 0;
+ for(String item : items) {
+ if(getAcquiredItems() != null &&
+ getAcquiredItems().containsKey(manager.currentProfile) &&
+ getAcquiredItems().get(manager.currentProfile).contains(item)) {
+ own++;
+ }
+
+ }
+ return own/(float)total;
+ }
+
+ private EnumChatFormatting[] rainbow = new EnumChatFormatting[]{
+ EnumChatFormatting.RED,
+ EnumChatFormatting.GOLD,
+ EnumChatFormatting.YELLOW,
+ EnumChatFormatting.GREEN,
+ EnumChatFormatting.AQUA,
+ EnumChatFormatting.LIGHT_PURPLE,
+ EnumChatFormatting.DARK_PURPLE
+ };
+
+ private String getCompletednessString() {
+ float completedness = getCompletedness();
+ String text = (int)(completedness*100)+"% Complete";
+ if(completedness >= 1) {
+ StringBuilder rainbowText = new StringBuilder();
+ for(int i=0; i<text.length(); i++) {
+ char c = text.charAt(i);
+ int index = (int)(i-System.currentTimeMillis()/100)%rainbow.length;
+ if(index < 0) index += rainbow.length;
+ rainbowText.append(rainbow[index]).append(c);
+ }
+ text = rainbowText.toString();
+ }
+ return text;
+ }
+
+ private void renderControls(int height, int top, int left, int right, int ySize, Color fg) {
+ ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
+
+ int mouseX = Mouse.getX() / scaledresolution.getScaleFactor();
+ int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor();
+
+ buttonHover = -1;
+
+ int totalAvailable = right-left;
+ int controlPadding = 3;
+ String[] controls = new String[]{
+ "Filter: "+filterPrettyNames[filterMode],
+ getCompletednessString()};
+ int numControls = controls.length;
+ int available = totalAvailable-(numControls-1)*controlPadding;
+ int controlSize = available/numControls;
+ int extraPadding = (available%controlSize)/2;
+
+ for(int i=0; i<numControls; i++) {
+ int width = controlSize+controlPadding;
+ int x = left+extraPadding+i*width;
+
+ if(mouseX > x && mouseX < x+controlSize) {
+ if(mouseY > top && mouseY < top+ySize) {
+ buttonHover = i;
+ }
+ }
+
+ drawRect(x, top, x+controlSize, top+ySize,
+ new Color(177,177,177).getRGB());
+ drawRect(x+1, top+1, x+controlSize, top+ySize,
+ new Color(50,50,50).getRGB());
+ drawRect(x+1, top+1, x+controlSize-1, top+ySize-1, fg.getRGB());
+ Utils.drawStringCenteredScaledMaxWidth(controls[i], Minecraft.getMinecraft().fontRendererObj,
+ x+width/2f, top+ySize/2f, true, controlSize-4, Color.WHITE.getRGB());
+ }
+ }
+
+ private Matrix4f createProjectionMatrix(int width, int height) {
+ Matrix4f projMatrix = new Matrix4f();
+ projMatrix.setIdentity();
+ projMatrix.m00 = 2.0F / (float)width;
+ projMatrix.m11 = 2.0F / (float)(-height);
+ projMatrix.m22 = -0.0020001999F;
+ projMatrix.m33 = 1.0F;
+ projMatrix.m03 = -1.0F;
+ projMatrix.m13 = 1.0F;
+ projMatrix.m23 = -1.0001999F;
+ return projMatrix;
+ }
+
+ private void renderCollectionLog(Color fg, int width, int height, int left, int right, int top, int bottom) {
+ ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
+
+ int mouseX = Mouse.getX() / scaledresolution.getScaleFactor();
+ int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor();
+
+ if(itemFramebuffer != null && grayscaleShader != null &&
+ (itemFramebuffer.framebufferWidth != width || itemFramebuffer.framebufferHeight != height)) {
+ grayscaleShader.setProjectionMatrix(createProjectionMatrix(
+ width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor()));
+ }
+
+ itemFramebuffer = checkFramebufferSizes(itemFramebuffer, width, height,
+ scaledresolution.getScaleFactor());
+ itemBGFramebuffer = checkFramebufferSizes(itemBGFramebuffer, width, height,
+ scaledresolution.getScaleFactor());
+ itemFramebufferGrayscale = checkFramebufferSizes(itemFramebufferGrayscale, width, height,
+ scaledresolution.getScaleFactor());
+ renderItemsToImage(itemFramebuffer, fg, left+5, right, top+1, bottom);
+ renderItemBGToImage(itemBGFramebuffer, fg, left+5, right, top+1, bottom);
+
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
+ renderFromImage(itemBGFramebuffer, width, height, left, right, top, bottom);
+ renderFromImage(itemFramebuffer, width, height, left, right, top, bottom);
+
+ if(grayscaleShader == null) {
+ try {
+ grayscaleShader = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()),
+ "grayscale",
+ itemFramebuffer, itemFramebufferGrayscale);
+ grayscaleShader.setProjectionMatrix(createProjectionMatrix(
+ width*scaledresolution.getScaleFactor(), height*scaledresolution.getScaleFactor()));
+ } catch(Exception e) {
+ return;
+ }
+ }
+
+ GL11.glPushMatrix();
+ grayscaleShader.loadShader(0);
+ GlStateManager.enableDepth();
+ GL11.glPopMatrix();
+
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
+
+ itemFramebufferGrayscale.bindFramebufferTexture();
+
+ AtomicReference<JsonObject> tooltipToDisplay = new AtomicReference<>(null);
+
+ AtomicBoolean isTop = new AtomicBoolean(false);
+ AtomicInteger lowestY = new AtomicInteger(-1);
+
+ String[] items = getItemList();
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ iterateItemSlots(new ItemSlotConsumer() {
+ @Override
+ public void consume(int x, int y, int id) {
+ String internalname = items[id];
+ if(id == 0) isTop.set(true);
+
+ int leftI = x-1;
+ int rightI = x+17;
+ int topI = y-1;
+ int bottomI = y+17;
+
+ lowestY.set(Math.max(bottomI, lowestY.get()));
+
+ if(mouseX > leftI && mouseX < rightI) {
+ if(mouseY > topI && mouseY < bottomI) {
+ tooltipToDisplay.set(manager.getItemInformation().get(internalname));
+ }
+ }
+
+ if(getAcquiredItems() != null &&
+ getAcquiredItems().containsKey(manager.currentProfile) &&
+ getAcquiredItems().get(manager.currentProfile).contains(internalname)) {
+ return;
+ }
+
+
+ topI = Math.max(topI, top);
+ bottomI = Math.min(bottomI, bottom);
+
+ Utils.drawTexturedRect(leftI, topI, rightI-leftI, bottomI-topI,
+ leftI/(float)width, rightI/(float)width,
+ (height-topI)/(float)height, (height-bottomI)/(float)height);
+ }
+ }, left+5, right, top+1, bottom);
+
+ if(!isTop.get()) {
+ if(lowestY.get() == -1) {
+ scrollHeight.setValue(0);
+ } else {
+ int dist = bottom - lowestY.get() - 10;
+ if(dist > 0) {
+ scrollHeight.setValue(scrollHeight.getValue() - dist);
+ }
+ }
+ }
+
+ itemFramebufferGrayscale.unbindFramebufferTexture();
+
+ JsonObject json = tooltipToDisplay.get();
+ if(json != null) {
+ List<String> text = new ArrayList<>();
+ text.add(json.get("displayname").getAsString());
+ JsonArray lore = json.get("lore").getAsJsonArray();
+
+ for(int i=0; i<lore.size(); i++) {
+ text.add(lore.get(i).getAsString());
+ }
+
+ Utils.drawHoveringText(text, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
+ }
+ }
+
+ private String[] getItemList() {
+ String[] items_arr = new String[items.size()];
+ int i=0;
+ for(String internalname : items) {
+ items_arr[i++] = internalname;
+ }
+ return items_arr;
+ }
+
+ private int limCol(int col) {
+ return Math.min(255, Math.max(0, col));
+ }
+
+ private void renderItems(int left, int right, int top, int bottom) {
+ String[] items = getItemList();
+ iterateItemSlots(new ItemSlotConsumer() {
+ public void consume(int x, int y, int id) {
+ String internalname = items[id];
+
+ ItemStack stack = manager.jsonToStack(manager.getItemInformation().get(internalname));
+ Utils.drawItemStack(stack, x, y);
+ }
+ }, left, right, top, bottom);
+ }
+
+ private void renderItemBackgrounds(Color fg, int left, int right, int top, int bottom) {
+ int opacity = Math.min(255, Math.max(0, manager.config.fgOpacity.value.intValue()));
+ Color fgGold = new Color(limCol(fg.getRed()+100), limCol(fg.getGreen()+50), limCol(fg.getBlue()-50), opacity);
+ Color fgCustomOpacity = new Color((fg.getRGB() & 0x00ffffff) | opacity << 24, true);
+
+ String[] items = getItemList();
+ iterateItemSlots(new ItemSlotConsumer() {
+ public void consume(int x, int y, int id) {
+ String internalname = items[id];
+
+ Color color = fgCustomOpacity;
+ if(getAcquiredItems() != null &&
+ getAcquiredItems().containsKey(manager.currentProfile) &&
+ getAcquiredItems().get(manager.currentProfile).contains(internalname)) {
+ color = fgGold;
+ }
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(item_mask);
+ if(manager.config.itemStyle.value) {
+ GlStateManager.color(color.getRed() / 255f, color.getGreen() / 255f,
+ color.getBlue() / 255f, color.getAlpha() / 255f);
+ Utils.drawTexturedRect(x - 1, y - 1, overlay.ITEM_SIZE + 2, overlay.ITEM_SIZE + 2, GL11.GL_NEAREST);
+ } else {
+ drawRect(x-1, y-1, x+overlay.ITEM_SIZE+1, y+overlay.ITEM_SIZE+1, color.getRGB());
+ }
+ GlStateManager.bindTexture(0);
+ }
+ }, left, right, top, bottom);
+ }
+
+ /**
+ * Checks whether the screen size has changed, if so it reconstructs the itemPane framebuffer and marks that the
+ * itemPane should be redrawn.
+ */
+ private Framebuffer checkFramebufferSizes(Framebuffer framebuffer, int width, int height, int scaleFactor) {
+ int sw = width*scaleFactor;
+ int sh = height*scaleFactor;
+
+ if(framebuffer == null || framebuffer.framebufferWidth != sw || framebuffer.framebufferHeight != sh) {
+ if(framebuffer == null) {
+ framebuffer = new Framebuffer(sw, sh, true);
+ } else {
+ framebuffer.createBindFramebuffer(sw, sh);
+ }
+ framebuffer.setFramebufferFilter(GL11.GL_NEAREST);
+ }
+ return framebuffer;
+ }
+
+ private void renderItemsToImage(Framebuffer framebuffer, Color fg, int left, int right, int top, int bottom) {
+ GL11.glPushMatrix();
+ framebuffer.framebufferClear();
+ framebuffer.bindFramebuffer(false);
+
+ renderItems(left, right, top, bottom);
+
+ framebuffer.unbindFramebuffer();
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
+ GL11.glPopMatrix();
+ }
+
+ private void renderItemBGToImage(Framebuffer framebuffer, Color fg, int left, int right, int top, int bottom) {
+ GL11.glPushMatrix();
+ framebuffer.framebufferClear();
+ framebuffer.bindFramebuffer(false);
+
+ renderItemBackgrounds(fg, left, right, top, bottom);
+
+ framebuffer.unbindFramebuffer();
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
+ GL11.glPopMatrix();
+ }
+
+ private void renderFromImage(Framebuffer framebuffer, int width, int height, int left, int right, int top, int bottom) {
+ framebuffer.bindFramebufferTexture();
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ Utils.drawTexturedRect(left, top, right-left, bottom-top,
+ left/(float)width, right/(float)width,
+ (height-top)/(float)height, (height-bottom)/(float)height);
+ framebuffer.unbindFramebufferTexture();
+ }
+
+ private abstract class ItemSlotConsumer {
+ public abstract void consume(int x, int y, int id);
+ }
+
+ public void iterateItemSlots(ItemSlotConsumer itemSlotConsumer, int left, int right, int top, int bottom) {
+ int scrolledTop = top-scrollHeight.getValue();
+
+ int id = 0;
+ int extraSize = overlay.ITEM_SIZE+overlay.ITEM_PADDING;
+ for(int y=scrolledTop; y<bottom; y+=extraSize) {
+ for(int x=left; x<right-extraSize; x+=extraSize) {
+ if(y > top-extraSize) {
+ itemSlotConsumer.consume(x, y, id);
+ }
+ if(++id >= items.size()) {
+ return;
+ }
+ }
+ }
+ }
+
+ public boolean keyboardInput() {
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java
index 2b87fdbc..60f8ca72 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java
@@ -23,6 +23,7 @@ public abstract class InfoPane extends Gui {
int mouseY);
public abstract void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown);
+ public void mouseInputOutside(){};
public abstract boolean keyboardInput();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java
index 2fccbf9e..090410dd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/SettingsInfoPane.java
@@ -30,6 +30,10 @@ public class SettingsInfoPane extends InfoPane {
private int page = 0;
private int maxPages = 1;
+ private Options.Option clickedSlider = null;
+ private int clickedSliderX = 0;
+ private float clickedSliderMult = 0;
+
public SettingsInfoPane(NEUOverlay overlay, NEUManager manager) {
super(overlay, manager);
}
@@ -59,33 +63,65 @@ public class SettingsInfoPane extends InfoPane {
float mult = tileWidth/90f;
drawRect(x, y, x+tileWidth, y+tileHeight, fg.getRGB());
- if(scaledresolution.getScaleFactor()==4) {
- GL11.glScalef(0.5f,0.5f,1);
- Utils.renderStringTrimWidth(option.displayName, fr, true, (x+(int)(8*mult))*2, (y+(int)(8*mult))*2,
- (tileWidth-(int)(16*mult))*2, new Color(100,255,150).getRGB(), 3);
- GL11.glScalef(2,2,1);
- } else {
- Utils.renderStringTrimWidth(option.displayName, fr, true, x+(int)(8*mult), y+(int)(8*mult),
- tileWidth-(int)(16*mult), new Color(100,255,150).getRGB(), 3);
- }
+
+ if(manager.config.hideApiKey.value && option==manager.config.apiKey) return;
+
+ Utils.renderStringTrimWidth(option.displayName, fr, true, x+(int)(8*mult), y+(int)(8*mult),
+ tileWidth-(int)(16*mult), new Color(100,255,150).getRGB(), 3,
+ 2f/scaledresolution.getScaleFactor());
if(option.value instanceof Boolean) {
GlStateManager.color(1f, 1f, 1f, 1f);
- Minecraft.getMinecraft().getTextureManager().bindTexture(((Boolean)option.value) ? on : off);
- Utils.drawTexturedRect(x+tileWidth/2-(int)(32*mult), y+tileHeight-(int)(20*mult), (int)(48*mult), (int)(16*mult));
+ Minecraft.getMinecraft().getTextureManager().bindTexture(((Boolean) option.value) ? on : off);
+ Utils.drawTexturedRect(x + tileWidth/2f - (int) (32 * mult), y + tileHeight - (int) (20 * mult), (int) (48 * mult), (int) (16 * mult));
Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(x+tileWidth/2+(int)(19*mult), y+tileHeight-(int)(19*mult), (int)(14*mult), (int)(14*mult));
+ Utils.drawTexturedRect(x + tileWidth/2f + (int) (19 * mult), y + tileHeight - (int) (19 * mult), (int) (14 * mult), (int) (14 * mult));
GlStateManager.bindTexture(0);
- if(mouseX > x+tileWidth/2+(int)(19*mult) && mouseX < x+tileWidth/2+(int)(19*mult)+(int)(14*mult)) {
- if(mouseY > y+tileHeight-(int)(19*mult) && mouseY < y+tileHeight-(int)(19*mult)+(int)(14*mult)) {
+ if (mouseX > x + tileWidth / 2 + (int) (19 * mult) && mouseX < x + tileWidth / 2 + (int) (19 * mult) + (int) (14 * mult)) {
+ if (mouseY > y + tileHeight - (int) (19 * mult) && mouseY < y + tileHeight - (int) (19 * mult) + (int) (14 * mult)) {
List<String> textLines = new ArrayList<>();
textLines.add(option.displayName);
- textLines.add(EnumChatFormatting.GRAY+option.desc);
+ textLines.add(EnumChatFormatting.GRAY + option.desc);
textToDisplay.set(textLines);
}
}
+ } else if(option.value instanceof Double) {
+ if(!textConfigMap.containsKey(option)) {
+ textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value),
+ GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE | GuiElementTextField.SCALE_TEXT));
+ }
+ GuiElementTextField tf = textConfigMap.get(option);
+ if(tf.getText().trim().endsWith(".0")) {
+ tf.setText(tf.getText().trim().substring(0, tf.getText().trim().length()-2));
+ }
+ if(tf.getFocus()) {
+ tf.setSize(Math.max((int)(20*mult), fr.getStringWidth(tf.getText())+10), (int)(16*mult));
+ tfTop.set(tf);
+ tfTopX.set(x+(int)(65*mult));
+ tfTopY.set(y+tileHeight-(int)(20*mult));
+ } else {
+ tf.setSize((int)(20*mult), (int)(16*mult));
+ tf.render(x+(int)(65*mult), y+tileHeight-(int)(20*mult));
+ }
+
+ double sliderAmount = (((Options.Option<Double>)option).value-option.minValue)/(option.maxValue-option.minValue);
+ sliderAmount = Math.max(0, Math.min(1, sliderAmount));
+
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on);
+ Utils.drawTexturedRect(x+5*mult, y + tileHeight-20*mult, (float)(54*mult*sliderAmount), 16*mult,
+ 0, (float)sliderAmount, 0, 1);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off);
+ Utils.drawTexturedRect((float)(x+5*mult+54*mult*sliderAmount), y + tileHeight - 20*mult,
+ (float)(54*mult*(1-sliderAmount)), 16*mult,
+ (float)(sliderAmount), 1, 0, 1);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(slider_button);
+ Utils.drawTexturedRect(x+1*mult+(float)(54*sliderAmount*mult), y + tileHeight - 20*mult,
+ 8*mult, 16*mult);
} else {
if(!textConfigMap.containsKey(option)) {
textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0));
@@ -121,6 +157,13 @@ public class SettingsInfoPane extends InfoPane {
}
}
+ @Override
+ public void mouseInputOutside() {
+ for(GuiElementTextField tf : textConfigMap.values()) {
+ tf.otherComponentClick();
+ }
+ }
+
public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) {
iterateSettingTile(new SettingsTileConsumer() {
@Override
@@ -136,13 +179,74 @@ public class SettingsInfoPane extends InfoPane {
}
}
}
+ } else if(option.value instanceof Double) {
+ if(!textConfigMap.containsKey(option)) {
+ textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value),
+ GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE | GuiElementTextField.SCALE_TEXT));
+ }
+
+ GuiElementTextField tf = textConfigMap.get(option);
+ int tfX = x+(int)(65*mult);
+ int tfY = y+tileHeight-(int)(20*mult);
+ int tfWidth = tf.getWidth();
+ int tfHeight = tf.getHeight();
+ if(mouseY > tfY && mouseY < tfY+tfHeight) {
+ if(mouseX > tfX && mouseX < tfX+tfWidth) {
+ if(Mouse.getEventButtonState()) {
+ tf.mouseClicked(mouseX, mouseY, Mouse.getEventButton());
+ onTextfieldChange(tf, option);
+ return;
+ } else if(Mouse.getEventButton() == -1 && mouseDown) {
+ tf.mouseClickMove(mouseX, mouseY, 0, 0); //last 2 values are unused
+ return;
+ }
+ } else if(clickedSlider != option && Mouse.getEventButtonState() && mouseX > x+1*mult && mouseX < x+63*mult) {
+ clickedSlider = option;
+ clickedSliderX = x;
+ clickedSliderMult = mult;
+ }
+ }
+
+ if(clickedSlider == option) {
+ float xMin = clickedSliderX+5*clickedSliderMult;
+ float xMax = clickedSliderX+59*clickedSliderMult;
+
+ float sliderAmount = (mouseX - xMin)/(xMax - xMin);
+ sliderAmount = Math.max(0, Math.min(1, sliderAmount));
+
+ double range = option.maxValue - option.minValue;
+ double value = option.minValue + sliderAmount*range;
+
+ if(range >= 10) {
+ value = Math.round(value);
+ } else if(range >= 1) {
+ value = Math.round(value*10)/10.0;
+ } else {
+ value = Math.round(value*100)/100.0;
+ }
+
+ value = Math.max(option.minValue, Math.min(option.maxValue, value));
+
+ tf.setText(String.valueOf(value));
+ onTextfieldChange(tf, option);
+
+ if(Mouse.getEventButton() == 0 && !Mouse.getEventButtonState()) {
+ clickedSlider = null;
+ }
+ }
+
+ if(Mouse.getEventButtonState()) tf.otherComponentClick();
} else {
if(!textConfigMap.containsKey(option)) {
textConfigMap.put(option, new GuiElementTextField(String.valueOf(option.value), 0));
}
GuiElementTextField tf = textConfigMap.get(option);
- if(mouseX > x+(int)(10*mult) && mouseX < x+(int)(10*mult)+tileWidth-(int)(20*mult)) {
- if(mouseY > y+tileHeight-(int)(20*mult) && mouseY < y+tileHeight-(int)(20*mult)+(int)(16*mult)) {
+ int tfX = x+(int)(10*mult);
+ int tfY = y+tileHeight-(int)(20*mult);
+ int tfWidth = tf.getWidth();
+ int tfHeight = tf.getHeight();
+ if(mouseX > tfX && mouseX < tfX+tfWidth) {
+ if(mouseY > tfY && mouseY < tfY+tfHeight) {
if(Mouse.getEventButtonState()) {
tf.mouseClicked(mouseX, mouseY, Mouse.getEventButton());
onTextfieldChange(tf, option);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java
index 1112a882..9bcc2891 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java
@@ -17,6 +17,7 @@ import java.util.regex.Pattern;
public class GuiElementTextField extends GuiElement {
+ public static final int SCALE_TEXT = 0b100000;
public static final int NUM_ONLY = 0b10000;
public static final int NO_SPACE = 0b01000;
public static final int FORCE_CAPS = 0b00100;
@@ -55,6 +56,10 @@ public class GuiElementTextField extends GuiElement {
return textField.getText();
}
+ public void setText(String text) {
+ textField.setText(text);
+ }
+
public void setSize(int searchBarXSize, int searchBarYSize) {
this.searchBarXSize = searchBarXSize;
this.searchBarYSize = searchBarYSize;
@@ -89,6 +94,22 @@ public class GuiElementTextField extends GuiElement {
return searchBarXSize + paddingUnscaled*2;
}
+ private float getScaleFactor(String str) {
+ return Math.min(1, (searchBarXSize-2)/(float)Minecraft.getMinecraft().fontRendererObj.getStringWidth(str));
+ }
+
+ private boolean isScaling() {
+ return (options & SCALE_TEXT) != 0;
+ }
+
+ private float getStringWidth(String str) {
+ if(isScaling()) {
+ return Minecraft.getMinecraft().fontRendererObj.getStringWidth(str)*getScaleFactor(str);
+ } else {
+ return Minecraft.getMinecraft().fontRendererObj.getStringWidth(str);
+ }
+ }
+
public int getCursorPos(int mouseX, int mouseY) {
int xComp = mouseX - x;
int yComp = mouseY - y;
@@ -302,7 +323,7 @@ public class GuiElementTextField extends GuiElement {
}
}
- if((options & NUM_ONLY) != 0 && textField.getText().matches("[^0-9]")) textField.setText(old);
+ if((options & NUM_ONLY) != 0 && textField.getText().matches("[^0-9.]")) textField.setText(old);
}
}
@@ -364,8 +385,15 @@ public class GuiElementTextField extends GuiElement {
for(int yOffI = 0; yOffI < texts.length; yOffI++) {
int yOff = yOffI*extraSize;
- Minecraft.getMinecraft().fontRendererObj.drawString(Utils.trimToWidth(texts[yOffI], searchBarXSize-10), x + 5,
- y+(searchBarYSize-8)/2+yOff, Color.WHITE.getRGB());
+ if(isScaling() && Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])>searchBarXSize-10) {
+ Utils.drawStringCenteredScaledMaxWidth(texts[yOffI], Minecraft.getMinecraft().fontRendererObj, x+searchBarXSize/2f,
+ y+searchBarYSize/2f+yOff, false,
+ searchBarXSize-2, Color.WHITE.getRGB());
+ } else {
+ Minecraft.getMinecraft().fontRendererObj.drawString(Utils.trimToWidth(texts[yOffI], searchBarXSize-10), x + 5,
+ y+(searchBarYSize-8)/2+yOff, Color.WHITE.getRGB());
+ }
+
}
if(focus && System.currentTimeMillis()%1000>500) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java
new file mode 100644
index 00000000..60361306
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java
@@ -0,0 +1,24 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.StreamerMode;
+import net.minecraft.client.gui.GuiIngame;
+import net.minecraft.scoreboard.ScorePlayerTeam;
+import net.minecraft.scoreboard.Team;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin({GuiIngame.class})
+public class MixinGuiIngame {
+
+ private static final String TARGET = "Lnet/minecraft/scoreboard/ScorePlayerTeam;" +
+ "formatPlayerName(Lnet/minecraft/scoreboard/Team;Ljava/lang/String;)Ljava/lang/String;";
+ @Redirect(method="renderScoreboard", at=@At(value="INVOKE", target=TARGET))
+ public String renderScoreboard_formatPlayerName(Team team, String name) {
+ if(NotEnoughUpdates.INSTANCE.isOnSkyblock() && NotEnoughUpdates.INSTANCE.manager.config.streamerMode.value) {
+ return StreamerMode.filterScoreboard(ScorePlayerTeam.formatPlayerName(team, name));
+ }
+ return ScorePlayerTeam.formatPlayerName(team, name);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java b/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java
index 5eae3886..fdda8c66 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java
@@ -10,7 +10,9 @@ import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class Options {
@@ -23,40 +25,50 @@ public class Options {
false,
"Enable Item Editing",
true,
- "Dev Feature. Please don't use.");
+ "Dev Feature.");
public Option<Boolean> onlyShowOnSkyblock = new Option(
true,
"Only Show On Skyblock",
false,
- "GUI Overlay only appears when you are playing Skyblock.");
+ "NEU Overlay only appears when you are playing Skyblock.");
public Option<Boolean> hidePotionEffect = new Option(
true,
- "Hide Potion Effect",
+ "Hide Potion Effects",
false,
- "If true, the potion effects will not show in the inventory GUI.");
+ "Potion effects are hidden in the inventory GUI. Contrib: All the gamers that play on GUI AUTO");
public Option<Boolean> showQuickCommands = new Option(
true,
"Quick Commands",
false,
- "If true, shows quick commands above search bar.");
+ "Shows QuickCommands™ above search bar.");
public Option<Boolean> advancedPriceInfo = new Option(
false,
- "Advanced Price Information",
+ "Adv. Item Price Info",
false,
- "Shows some extra information about item sales.");
+ "Shows some extra information about item prices.");
public Option<Boolean> cacheRenderedItempane = new Option(
true,
- "Cache Rendered Itempane",
+ "Cache Itempane",
+ false,
+ "Caches the drawn itempane, drastically improving performance. Animated textures will not work.");
+ public Option<Boolean> streamerMode = new Option(
+ false,
+ "Streamer Mode",
+ false,
+ "Hides or randomises some stuff on your screen to prevent sniping.");
+ public Option<Boolean> hideApiKey = new Option(
false,
- "Caches the drawn itempane, drastically improving performance. However, animated textures will not work.");
+ "Hide Apikey Setting",
+ false,
+ "Hides the Apikey setting (please try not to leak Apikey if you're recording)");
public Option<Double> bgBlurFactor = new Option(
- 10.0,
- "Background Blur Factor",
+ 5.0,
+ "Background Blur",
false,
- "Changes the strength of pane background blur. 0-50.");
+ "Changes the strength of pane background blur. 0-50.", 0, 50);
public Option<String> apiKey = new Option(
"",
- "Api key used for certain features.",
+ "Api Key",
false,
"Type /api new to receive key and put it here.");
public Option<Boolean> autoupdate = new Option(
@@ -71,24 +83,34 @@ public class Options {
"If true, the itempane will stay open after the gui is closed.");
public Option<Boolean> itemStyle = new Option(
true,
- "Circular Item BG Style",
+ "Circular Item Style",
+ false,
+ "Uses the circular item background style instead of the square style. Contrib: Calyps0");
+ public Option<Boolean> hideEmptyPanes = new Option(
+ true,
+ "Hide GUI Filler Tooltips",
false,
- "If true, uses the circular item background style instead of the square style.");
+ "Hides the tooltip of glass panes in skyblock GUIs. Contrib: ThatGravyBoat");
public Option<Double> paneWidthMult = new Option(
1.0,
- "Pane Width Multiplier",
+ "Pane Width",
false,
- "Changes how wide the item and info panes are. Value between 0.5-1.5.");
+ "Changes how wide the item and info panes are. Value between 0.5-1.5.", 0.5, 1.5);
public Option<Double> bgOpacity = new Option(
- 50.0,
+ 30.0,
"Pane Background Opacity",
false,
- "Changes the background colour opacity of item and info panes. Value between 0-255.");
+ "Changes the background colour opacity of item and info panes. Value between 0-255.", 0, 255);
public Option<Double> fgOpacity = new Option(
255.0,
"Item Background Opacity",
false,
- "Changes the opacity of item background. Value between 0-255.");
+ "Changes the opacity of item background. Value between 0-255.", 0, 255);
+ public Option<Double> panePadding = new Option(
+ 10.0,
+ "Pane Padding",
+ false,
+ "Changes the padding of the panes. Value between 0-20.", 0, 20);
/**
* OPTIONS THAT DON'T SHOW IN GUI
@@ -109,7 +131,7 @@ public class Options {
false,
"Sort Mode");
public Option<ArrayList<Boolean>> compareAscending = new Option(
- Utils.createList(true, true),
+ Utils.createList(true, true, true),
"Compare Ascending",
false,
"Compare Ascending");
@@ -118,6 +140,11 @@ public class Options {
"Favourites",
false,
"Favourites");
+ public Option<Map<String, ArrayList<String>>> collectionLog = new Option(
+ new HashMap<String, ArrayList<String>>(),
+ "CollectionLog",
+ false,
+ "CollectionLog");
public Option<ArrayList<String>> quickCommands = new Option(
createDefaultQuickCommands(),
"Quick Commands",
@@ -131,31 +158,39 @@ public class Options {
arr.add("/craft:CRAFTING_TABLE");
arr.add("/enderchest:ENDER_CHEST");
arr.add("/wardrobe:LEATHER_CHESTPLATE");
+ arr.add("/collectionlog:MAP");
return arr;
}
public List<Option> getOptions() {
List<Option> options = new ArrayList<>();
+ //Buttons
tryAddOption(enableItemEditing, options);
tryAddOption(onlyShowOnSkyblock, options);
tryAddOption(hidePotionEffect, options);
tryAddOption(advancedPriceInfo, options);
tryAddOption(cacheRenderedItempane, options);
+ tryAddOption(streamerMode, options);
+ tryAddOption(hideApiKey, options);
tryAddOption(autoupdate, options);
tryAddOption(keepopen, options);
tryAddOption(itemStyle, options);
+ tryAddOption(hideEmptyPanes, options);
+ //Sliders
tryAddOption(bgBlurFactor, options);
- tryAddOption(apiKey, options);
tryAddOption(paneWidthMult, options);
tryAddOption(bgOpacity, options);
tryAddOption(fgOpacity, options);
+ tryAddOption(panePadding, options);
+ //Text
+ tryAddOption(apiKey, options);
return options;
}
private void tryAddOption(Option<?> option, List<Option> list) {
- if(!option.secret || dev.value) {
+ if(!option.secret) {// || dev.value) {
list.add(option);
}
}
@@ -166,13 +201,21 @@ public class Options {
public final transient String displayName;
public final transient boolean secret;
public final transient String desc;
+ public final transient double minValue;
+ public final transient double maxValue;
public Option(T defaultValue, String displayName, boolean secret, String desc) {
+ this(defaultValue, displayName, secret, desc, 0, 100);
+ }
+
+ public Option(T defaultValue, String displayName, boolean secret, String desc, double minValue, double maxValue) {
this.value = defaultValue;
this.defaultValue = defaultValue;
this.displayName = displayName;
this.secret = secret;
this.desc = desc;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
}
public void setValue(String value) {
@@ -215,6 +258,12 @@ public class Options {
for(Field f : Options.class.getDeclaredFields()) {
try {
+ if(((Option)f.get(oDefault)).value instanceof List) {
+ //If the default size of the list is greater than the loaded size, use the default value.
+ if(((List<?>)((Option)f.get(oDefault)).value).size() > ((List<?>)((Option)f.get(oLoad)).value).size()) {
+ continue;
+ }
+ }
((Option)f.get(oDefault)).value = ((Option)f.get(oLoad)).value;
} catch (Exception e) { }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java b/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java
index 65e7305a..48eea22d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java
@@ -21,6 +21,8 @@ public class TexLoc {
}
public void handleKeyboardInput() {
+ int mult=1;
+ if(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) mult=10;
if(Keyboard.isKeyDown(toggleKey)) {
if(!pressedLastTick) {
toggled = !toggled;
@@ -31,16 +33,16 @@ public class TexLoc {
}
if(toggled) {
if(Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
- if(!dirPressed) x--;
+ if(!dirPressed) x-=mult;
dirPressed = true;
} else if(Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
- if(!dirPressed) x++;
+ if(!dirPressed) x+=mult;
dirPressed = true;
} else if(Keyboard.isKeyDown(Keyboard.KEY_UP)) {
- if(!dirPressed) y--;
+ if(!dirPressed) y-=mult;
dirPressed = true;
} else if(Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
- if(!dirPressed) y++;
+ if(!dirPressed) y+=mult;
dirPressed = true;
} else {
dirPressed = false;
diff --git a/src/main/resources/assets/notenoughupdates/ah_item_holder.png b/src/main/resources/assets/notenoughupdates/ah_item_holder.png
new file mode 100644
index 00000000..ed396f25
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/ah_item_holder.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/ah_item_tab.png b/src/main/resources/assets/notenoughupdates/ah_item_tab.png
new file mode 100644
index 00000000..c307fa31
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/ah_item_tab.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/item_mask.png b/src/main/resources/assets/notenoughupdates/item_mask.png
index 7a202a33..3b402d7f 100644
--- a/src/main/resources/assets/notenoughupdates/item_mask.png
+++ b/src/main/resources/assets/notenoughupdates/item_mask.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/off.png b/src/main/resources/assets/notenoughupdates/off.png
index 174d1b4f..cfb17e40 100644
--- a/src/main/resources/assets/notenoughupdates/off.png
+++ b/src/main/resources/assets/notenoughupdates/off.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/order_value.png b/src/main/resources/assets/notenoughupdates/order_value.png
new file mode 100644
index 00000000..5526e8f6
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/order_value.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/order_value_active.png b/src/main/resources/assets/notenoughupdates/order_value_active.png
new file mode 100644
index 00000000..3864021c
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/order_value_active.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/blit.vsh b/src/main/resources/assets/notenoughupdates/shaders/program/blit.vsh
new file mode 100644
index 00000000..01a16db5
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/blit.vsh
@@ -0,0 +1,16 @@
+#version 120
+
+attribute vec4 Position;
+
+uniform mat4 ProjMat;
+uniform vec2 OutSize;
+
+varying vec2 texCoord;
+
+void main(){
+ vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0);
+ gl_Position = vec4(outPos.xy, 0.2, 1.0);
+
+ texCoord = Position.xy / OutSize;
+ texCoord.y = 1.0 - texCoord.y;
+}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.fsh b/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.fsh
new file mode 100644
index 00000000..70875510
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.fsh
@@ -0,0 +1,15 @@
+#version 120
+
+uniform sampler2D DiffuseSampler;
+
+varying vec2 texCoord;
+
+void main(){
+ vec3 Gray = vec3(0.3, 0.59, 0.11);
+ vec4 diffuseColor = texture2D(DiffuseSampler, texCoord);
+
+ float Luma = dot(diffuseColor.rgb, Gray);
+ diffuseColor.rgb = vec3(Luma, Luma, Luma);
+
+ gl_FragColor = diffuseColor;
+}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json b/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json
new file mode 100644
index 00000000..048ceb9f
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json
@@ -0,0 +1,17 @@
+{
+ "blend": {
+ "func": "add",
+ "srcrgb": "srcalpha",
+ "dstrgb": "1-srcalpha"
+ },
+ "vertex": "blit",
+ "fragment": "grayscale",
+ "attributes": [ "Position" ],
+ "samplers": [
+ { "name": "DiffuseSampler" }
+ ],
+ "uniforms": [
+ { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
+ { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/slider_button.png b/src/main/resources/assets/notenoughupdates/slider_button.png
new file mode 100644
index 00000000..aeb81b86
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/slider_button.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/slider_off.png b/src/main/resources/assets/notenoughupdates/slider_off.png
new file mode 100644
index 00000000..0f514c41
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/slider_off.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/slider_on.png b/src/main/resources/assets/notenoughupdates/slider_on.png
new file mode 100644
index 00000000..8d2d6680
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/slider_on.png
Binary files differ
diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json
index 6b616e4e..49e37916 100644
--- a/src/main/resources/mixins.notenoughupdates.json
+++ b/src/main/resources/mixins.notenoughupdates.json
@@ -4,6 +4,7 @@
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinItemStack",
- "MixinInventoryEffectRenderer"
+ "MixinInventoryEffectRenderer",
+ "MixinGuiIngame"
]
} \ No newline at end of file