aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorMoulberry <james.jenour@student.scotch.wa.edu.au>2020-08-19 12:16:12 +1000
committerMoulberry <james.jenour@student.scotch.wa.edu.au>2020-08-19 12:16:12 +1000
commitea1391e0c6f0db863bbb61511eb6e9acb57a5968 (patch)
tree16e0b8a76055838b6cc1963f56c1327cd8850c66 /src/main
parent0c23f52d2be811d74a3b6ef598dd9de7ccb763ab (diff)
downloadNotEnoughUpdates-ea1391e0c6f0db863bbb61511eb6e9acb57a5968.tar.gz
NotEnoughUpdates-ea1391e0c6f0db863bbb61511eb6e9acb57a5968.tar.bz2
NotEnoughUpdates-ea1391e0c6f0db863bbb61511eb6e9acb57a5968.zip
1.1.5
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java244
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java8
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java39
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java175
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java517
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java24
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java83
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java11
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java77
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java26
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java69
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/Options.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java29
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java24
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/contrib.png (renamed from src/main/resources/assets/notenoughupdates/contrib.png)bin189394 -> 189394 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/fade.png (renamed from src/main/resources/assets/notenoughupdates/fade.png)bin18572 -> 18572 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/gravy.png (renamed from src/main/resources/assets/notenoughupdates/gravy.png)bin58330 -> 58330 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/nullzee.png (renamed from src/main/resources/assets/notenoughupdates/nullzee.png)bin108263 -> 108263 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/patreon1.png (renamed from src/main/resources/assets/notenoughupdates/patreon1.png)bin46767 -> 46767 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/patreon2.png (renamed from src/main/resources/assets/notenoughupdates/patreon2.png)bin45479 -> 45479 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/testcape.png (renamed from src/main/resources/assets/notenoughupdates/testcape.png)bin21571 -> 21571 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/cosmetics_fg.pngbin0 -> 1607 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_elements.pngbin2567 -> 4636 bytes
-rw-r--r--src/main/resources/mixins.notenoughupdates.json5
29 files changed, 1216 insertions, 176 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java b/src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java
new file mode 100644
index 00000000..500587f5
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/CustomItemEffects.java
@@ -0,0 +1,244 @@
+package io.github.moulberry.notenoughupdates;
+
+import net.minecraft.block.Block;
+import net.minecraft.block.material.Material;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.ActiveRenderInfo;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraftforge.client.event.DrawBlockHighlightEvent;
+import net.minecraftforge.client.event.EntityViewRenderEvent;
+import net.minecraftforge.client.event.RenderBlockOverlayEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.util.vector.Vector3f;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+
+public class CustomItemEffects {
+
+ public static final CustomItemEffects INSTANCE = new CustomItemEffects();
+
+ public int aoteUseTicks = 0;
+ public int aoteTeleportationTicks = 0;
+ public Vector3f aoteTeleportationLast = null;
+ public Vector3f aoteTeleportationCurr = null;
+ public boolean teleported = false;
+ public float partialTicks;
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if(aoteTeleportationTicks > 7) aoteTeleportationTicks = 7;
+
+ if(aoteUseTicks > 20 && aoteTeleportationCurr != null && !teleported) {
+ aoteTeleportationCurr = null;
+ aoteTeleportationTicks = 0;
+ }
+
+ if(aoteTeleportationCurr != null && aoteTeleportationTicks > 0) {
+ aoteUseTicks++;
+ if(teleported) {
+ float factor = 1f/aoteTeleportationTicks;
+
+ aoteTeleportationLast = new Vector3f(aoteTeleportationCurr);
+
+ float dX = aoteTeleportationCurr.x - (float)Minecraft.getMinecraft().thePlayer.posX;
+ float dY = aoteTeleportationCurr.y - (float)Minecraft.getMinecraft().thePlayer.posY;
+ float dZ = aoteTeleportationCurr.z - (float)Minecraft.getMinecraft().thePlayer.posZ;
+
+ aoteTeleportationCurr.x -= dX*factor;
+ aoteTeleportationCurr.y -= dY*factor;
+ aoteTeleportationCurr.z -= dZ*factor;
+
+ aoteTeleportationTicks--;
+ } else {
+ aoteTeleportationCurr.x = (float) Minecraft.getMinecraft().thePlayer.posX;
+ aoteTeleportationCurr.y = (float) Minecraft.getMinecraft().thePlayer.posY;
+ aoteTeleportationCurr.z = (float) Minecraft.getMinecraft().thePlayer.posZ;
+ aoteTeleportationLast = new Vector3f(aoteTeleportationCurr);
+ }
+ } else {
+ aoteTeleportationCurr = null;
+ aoteUseTicks = 0;
+ teleported = false;
+ }
+ }
+
+ public Vector3f getCurrentPosition() {
+ if(!teleported || aoteTeleportationLast == null || aoteTeleportationCurr == null) return null;
+ return new Vector3f(aoteTeleportationLast.x + (aoteTeleportationCurr.x - aoteTeleportationLast.x) * partialTicks,
+ aoteTeleportationLast.y + (aoteTeleportationCurr.y - aoteTeleportationLast.y) * partialTicks,
+ aoteTeleportationLast.z + (aoteTeleportationCurr.z - aoteTeleportationLast.z) * partialTicks);
+ }
+
+ @SubscribeEvent
+ public void renderBlockOverlay(DrawBlockHighlightEvent event) {
+ if(aoteTeleportationCurr != null && aoteTeleportationTicks > 0 && teleported) {
+ event.setCanceled(true);
+ }
+ ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem();
+ String heldInternal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held);
+ if(heldInternal != null) {
+ if(heldInternal.equals("JUNGLE_AXE") || heldInternal.equals("TREECAPITATOR_AXE")) {
+ int maxWood = 10;
+ if(heldInternal.equals("TREECAPITATOR_AXE")) maxWood = 35;
+
+ if (event.target.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
+ GlStateManager.enableBlend();
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+ GlStateManager.color(0.0F, 0.0F, 0.0F, 0.4F);
+ GL11.glLineWidth(2.0F);
+ GlStateManager.disableTexture2D();
+ GlStateManager.depthMask(false);
+ float f = 0.002F;
+ //BlockPos blockpos = ;
+ //Block block = Minecraft.getMinecraft().theWorld.getBlockState(blockpos).getBlock();
+
+ if(Minecraft.getMinecraft().theWorld.getBlockState(event.target.getBlockPos()).getBlock() == Blocks.log ||
+ Minecraft.getMinecraft().theWorld.getBlockState(event.target.getBlockPos()).getBlock() == Blocks.log2) {
+ EntityPlayer player = event.player;
+
+ int woods = 0;
+
+ HashSet<BlockPos> candidatesOld = new HashSet<>();
+ LinkedList<BlockPos> candidates = new LinkedList<>();
+ LinkedList<BlockPos> candidatesNew = new LinkedList<>();
+
+ candidatesNew.add(event.target.getBlockPos());
+
+ while(woods < maxWood) {
+ if(candidatesNew.isEmpty()) {
+ break;
+ }
+
+ candidates.addAll(candidatesNew);
+ candidatesNew.clear();
+
+ woods += candidates.size();
+ boolean random = woods > maxWood;
+
+ while(!candidates.isEmpty()) {
+ BlockPos candidate = candidates.pop();
+ Block block = Minecraft.getMinecraft().theWorld.getBlockState(candidate).getBlock();
+
+ candidatesOld.add(candidate);
+
+ for(int x = -1; x <= 1; x++) {
+ for(int y = -1; y <= 1; y++) {
+ for(int z = -1; z <= 1; z++) {
+ if(x != 0 || y != 0 || z != 0) {
+ BlockPos posNew = candidate.add(x, y, z);
+ if(!candidatesOld.contains(posNew) && !candidates.contains(posNew) && !candidatesNew.contains(posNew)) {
+ Block blockNew = Minecraft.getMinecraft().theWorld.getBlockState(posNew).getBlock();
+ if(blockNew == Blocks.log || blockNew == Blocks.log2) {
+ candidatesNew.add(posNew);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ block.setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, candidate);
+ double d0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * (double)partialTicks;
+ double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double)partialTicks;
+ double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double)partialTicks;
+
+ drawSelectionBoundingBox(block.getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, candidate)
+ .expand(0.001D, 0.001D, 0.001D).offset(-d0, -d1, -d2),
+ random ? 0.1f : 0.2f);
+ }
+ }
+ }
+
+ GlStateManager.depthMask(true);
+ GlStateManager.enableTexture2D();
+ GlStateManager.disableBlend();
+ }
+ }
+ }
+ }
+
+ public static void drawSelectionBoundingBox(AxisAlignedBB p_181561_0_, float alpha) {
+ GlStateManager.color(64/255f, 224/255f, 208/255f, alpha);
+
+ Tessellator tessellator = Tessellator.getInstance();
+ WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+ //vertical
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex();
+ tessellator.draw();
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex();
+ tessellator.draw();
+ //x
+
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex();
+ tessellator.draw();
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex();
+ tessellator.draw();
+
+ //z
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.minZ).endVertex();
+ tessellator.draw();
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION);
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.minY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.maxX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex();
+ worldrenderer.pos(p_181561_0_.minX, p_181561_0_.maxY, p_181561_0_.maxZ).endVertex();
+ tessellator.draw();
+
+ }
+
+ @SubscribeEvent
+ public void onPlayerInteract(PlayerInteractEvent event) {
+ if(event.action == PlayerInteractEvent.Action.RIGHT_CLICK_AIR || event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
+ ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem();
+ if(held != null) {
+ String internal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held);
+ if(internal != null && internal.equals("ASPECT_OF_THE_END")) {
+ aoteTeleportationTicks += 5;
+
+ if(aoteTeleportationCurr == null) {
+ aoteTeleportationCurr = new Vector3f();
+ aoteTeleportationCurr.x = (float) Minecraft.getMinecraft().thePlayer.posX;
+ aoteTeleportationCurr.y = (float) Minecraft.getMinecraft().thePlayer.posY;
+ aoteTeleportationCurr.z = (float) Minecraft.getMinecraft().thePlayer.posZ;
+ }
+
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java
index fc7db07b..af23787a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java
@@ -2,6 +2,7 @@ package io.github.moulberry.notenoughupdates;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.auction.CustomAHGui;
+import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
import io.github.moulberry.notenoughupdates.gamemodes.SBGamemodes;
import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
@@ -33,6 +34,7 @@ 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;
+import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import javax.swing.*;
@@ -131,6 +133,7 @@ public class NEUEventListener {
}
if(longUpdate) {
neu.updateSkyblockScoreboard();
+ CapeManager.getInstance().tick();
if(neu.hasSkyblockScoreboard()) {
lastSkyblockScoreboard = currentTime;
if(!joinedSB) {
@@ -657,6 +660,9 @@ public class NEUEventListener {
*/
@SubscribeEvent
public void onGuiScreenMouse(GuiScreenEvent.MouseInputEvent.Pre event) {
+ if(!event.isCanceled()) {
+ Utils.scrollTooltip(Mouse.getEventDWheel());
+ }
if(event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView()) {
event.setCanceled(true);
neu.manager.auctionManager.customAH.handleMouseInput();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index 2cfe9d91..2ae298e2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -464,8 +464,8 @@ public class NEUManager {
}
URL url = new URL(dlUrl+name);
URLConnection urlConnection = url.openConnection();
- urlConnection.setConnectTimeout(3000);
- urlConnection.setReadTimeout(3000);
+ urlConnection.setConnectTimeout(5000);
+ urlConnection.setReadTimeout(5000);
try (BufferedInputStream inStream = new BufferedInputStream(urlConnection.getInputStream());
FileOutputStream fileOutputStream = new FileOutputStream(item)) {
byte dataBuffer[] = new byte[1024];
@@ -503,8 +503,8 @@ public class NEUManager {
}
URL url = new URL(dlUrl);
URLConnection urlConnection = url.openConnection();
- urlConnection.setConnectTimeout(3000);
- urlConnection.setReadTimeout(3000);
+ urlConnection.setConnectTimeout(15000);
+ urlConnection.setReadTimeout(20000);
try (BufferedInputStream inStream = new BufferedInputStream(urlConnection.getInputStream());
FileOutputStream fileOutputStream = new FileOutputStream(itemsZip)) {
byte dataBuffer[] = new byte[1024];
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index 6e01e409..aa604854 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -9,10 +9,10 @@ import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
import io.github.moulberry.notenoughupdates.auction.CustomAHGui;
import io.github.moulberry.notenoughupdates.commands.SimpleCommand;
import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
+import io.github.moulberry.notenoughupdates.cosmetics.GuiCosmetics;
import io.github.moulberry.notenoughupdates.gamemodes.GuiGamemodes;
import io.github.moulberry.notenoughupdates.gamemodes.SBGamemodes;
import io.github.moulberry.notenoughupdates.infopanes.CollectionLogInfoPane;
-import io.github.moulberry.notenoughupdates.infopanes.CosmeticsInfoPane;
import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.questing.GuiQuestLine;
@@ -40,8 +40,6 @@ import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
-import net.minecraftforge.fml.relauncher.Side;
-import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.StringUtils;
import javax.swing.*;
@@ -128,6 +126,37 @@ public class NotEnoughUpdates {
}
});
+ SimpleCommand peekCommand = new SimpleCommand("peek", new SimpleCommand.ProcessCommandRunnable() {
+ public void processCommand(ICommandSender sender, String[] args) {
+ profileViewer.getProfileByName(args[0], profile -> {
+ if (profile != null) {
+ profile.resetCache();
+
+ float overallScore = 0;
+
+ JsonObject profileInfo = profile.getProfileInformation(null);
+
+ JsonObject skill = profile.getSkillInfo(null);
+ }
+ });
+ }
+ }, new SimpleCommand.TabCompleteRunnable() {
+ @Override
+ public List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos) {
+ if (args.length != 1) return null;
+
+ String lastArg = args[args.length - 1];
+ List<String> playerMatches = new ArrayList<>();
+ for (EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) {
+ String playerName = player.getName();
+ if (playerName.toLowerCase().startsWith(lastArg.toLowerCase())) {
+ playerMatches.add(playerName);
+ }
+ }
+ return playerMatches;
+ }
+ });
+
public static ProfileViewer profileViewer;
SimpleCommand.ProcessCommandRunnable viewProfileRunnable = new SimpleCommand.ProcessCommandRunnable() {
@@ -252,10 +281,7 @@ public class NotEnoughUpdates {
SimpleCommand cosmeticsCommand = new SimpleCommand("neucosmetics", new SimpleCommand.ProcessCommandRunnable() {
public void processCommand(ICommandSender sender, String[] args) {
- if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) {
- openGui = new GuiInventory(Minecraft.getMinecraft().thePlayer);
- }
- overlay.displayInformationPane(new CosmeticsInfoPane(overlay, manager));
+ openGui = new GuiCosmetics();
}
});
@@ -288,6 +314,7 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(new NEUEventListener(this));
MinecraftForge.EVENT_BUS.register(CapeManager.getInstance());
MinecraftForge.EVENT_BUS.register(new SBGamemodes());
+ MinecraftForge.EVENT_BUS.register(CustomItemEffects.INSTANCE);
File f = new File(event.getModConfigurationDirectory(), "notenoughupdates");
f.mkdirs();
@@ -425,6 +452,7 @@ public class NotEnoughUpdates {
long currentTime = System.currentTimeMillis();
if (openGui != null) {
+ Minecraft.getMinecraft().thePlayer.closeScreen();
Minecraft.getMinecraft().displayGuiScreen(openGui);
openGui = null;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
index de03baa9..457c06d0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
@@ -309,7 +309,7 @@ public class APIManager {
getPageFromAPI(0);
}
- manager.hypixelApi.getApiGZIPAsync("http://moulberry.codes/auction.json.gz", jsonObject -> {
+ manager.hypixelApi.getMyApiGZIPAsync("auction.json.gz", jsonObject -> {
if(jsonObject.get("success").getAsBoolean()) {
long apiUpdate = (long)jsonObject.get("time").getAsFloat();
if(lastApiUpdate == apiUpdate) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java
index 3780db3d..817c9e96 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java
@@ -1,6 +1,7 @@
package io.github.moulberry.notenoughupdates.auction;
import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -405,13 +406,12 @@ public class CustomAH extends Gui {
return -1;
}
- public String findEndsInStr(ItemStack stack) {
+ public String findStrStart(ItemStack stack, String toFind) {
if(stack.hasTagCompound()) {
//ยง7Ends in:
- String endsIn = EnumChatFormatting.GRAY+"Ends in: ";
for(String line : manager.getLoreFromNBT(stack.getTagCompound())) {
- if(line.trim().startsWith(endsIn)) {
- return line.substring(endsIn.length());
+ if(line.trim().startsWith(toFind)) {
+ return line.substring(toFind.length());
}
}
}
@@ -419,6 +419,10 @@ public class CustomAH extends Gui {
return null;
}
+ public String findEndsInStr(ItemStack stack) {
+ return findStrStart(stack, EnumChatFormatting.GRAY+"Ends in: ");
+ }
+
public void drawScreen(int mouseX, int mouseY) {
if(System.currentTimeMillis() - lastOpen < 1000) Mouse.setGrabbed(false);
@@ -522,7 +526,11 @@ public class CustomAH extends Gui {
if(mouseX > auctionViewLeft+31 && mouseX <auctionViewLeft+31+16) {
if(mouseY > guiTop+35 && mouseY < guiTop+35+16) {
- if(topStack != null) tooltipToRender = topStack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ if(topStack != null) {
+ tooltipToRender = topStack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ tooltipToRender.add("");
+ tooltipToRender.add(EnumChatFormatting.YELLOW+"Click to copy seller name!");
+ }
} else if(mouseY > guiTop+100 && mouseY < guiTop+100+16) {
if(leftStack != null) tooltipToRender = leftStack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
} else if(mouseY > guiTop+61 && mouseY < guiTop+61+16) {
@@ -916,11 +924,13 @@ public class CustomAH extends Gui {
mouseClickMove(mouseX, mouseY, this.eventButton, l);
}
- int dWheel = Mouse.getEventDWheel();
- dWheel = Math.max(-1, Math.min(1, dWheel));
+ if(!manager.config.disableAhScroll.value) {
+ int dWheel = Mouse.getEventDWheel();
+ dWheel = Math.max(-1, Math.min(1, dWheel));
- scrollAmount = scrollAmount - dWheel/(float)(auctionIds.size()/9-(5+splits));
- scrollAmount = Math.max(0, Math.min(1, scrollAmount));
+ scrollAmount = scrollAmount - dWheel/(float)(auctionIds.size()/9-(5+splits));
+ scrollAmount = Math.max(0, Math.min(1, scrollAmount));
+ }
}
private String niceAucId(String aucId) {
@@ -1362,7 +1372,16 @@ public class CustomAH extends Gui {
if(containerName.trim().equals("Auction View") || containerName.trim().equals("BIN Auction View")) {
if(mouseX > guiLeft+getXSize()+4+31 && mouseX < guiLeft+getXSize()+4+31+16) {
boolean leftFiller = isGuiFiller(auctionView.inventorySlots.getSlot(29).getStack());//isBin
- if(mouseY > guiTop+100 && mouseY < guiTop+100+16) {
+ if(mouseY > guiTop+35 && mouseY < guiTop+35+16) {
+ ItemStack topStack = auctionView.inventorySlots.getSlot(13).getStack();
+ if(topStack != null) {
+ String line = findStrStart(topStack, EnumChatFormatting.GRAY+"Seller: ");
+ String[] split = line.split(" ");
+ String seller = split[split.length-1];
+ StringSelection selection = new StringSelection(seller);
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
+ }
+ } else if(mouseY > guiTop+100 && mouseY < guiTop+100+16) {
int slotClick = leftFiller ? 31 : 29;
Minecraft.getMinecraft().playerController.windowClick(auctionView.inventorySlots.windowId,
slotClick, 2, 3, Minecraft.getMinecraft().thePlayer);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
index e78d078c..906ccda4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
@@ -1,7 +1,10 @@
package io.github.moulberry.notenoughupdates.cosmetics;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.HypixelApi;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.client.event.RenderPlayerEvent;
@@ -11,6 +14,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
+import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
@@ -18,28 +22,94 @@ import java.util.Set;
public class CapeManager {
public static final CapeManager INSTANCE = new CapeManager();
+ public long lastCapeUpdate = 0;
+ public long lastCapeSynced = 0;
+ public Pair<NEUCape, String> localCape = null;
private HashMap<String, Pair<NEUCape, String>> capeMap = new HashMap<>();
- private String[] capes = new String[]{"patreon1", "patreon2", "gravy", "fade", "contrib"};
+
+ private boolean allAvailable = false;
+ private HashSet<String> availableCapes = new HashSet<>();
+
+ private String[] capes = new String[]{"patreon1", "patreon2", "fade", "contrib", "nullzee", "gravy" };
+ public Boolean[] specialCapes = new Boolean[]{ true, true, false, true, true, true };
public static CapeManager getInstance() {
return INSTANCE;
}
- public void setCape(String player, String capename) {
- if(capename == null) {
- NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value = "";
- capeMap.remove(player);
- return;
+ public void tick() {
+ long currentTime = System.currentTimeMillis();
+ if(currentTime - lastCapeUpdate > 60*1000) {
+ lastCapeUpdate = currentTime;
+ updateCapes();
}
- if(player.equalsIgnoreCase(Minecraft.getMinecraft().thePlayer.getName())) {
- NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value = capename;
+ }
+
+ private void updateCapes() {
+ NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("cgi-bin/getactivecape.py", (jsonObject) -> {
+ if(jsonObject.get("success").getAsBoolean()) {
+ lastCapeSynced = System.currentTimeMillis();
+ for(JsonElement active : jsonObject.get("active").getAsJsonArray()) {
+ if(active.isJsonObject()) {
+ JsonObject activeObj = (JsonObject) active;
+ setCape(activeObj.get("_id").getAsString(), activeObj.get("capeType").getAsString(), false);
+ }
+ }
+ }
+ }, () -> {
+ System.out.println("[MBAPI] Update capes errored");
+ });
+ if(Minecraft.getMinecraft().thePlayer != null) {
+ NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("cgi-bin/getpermscape.py?uuid="+
+ Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""), (jsonObject) -> {
+ if(jsonObject.get("success").getAsBoolean()) {
+ availableCapes.clear();
+ for(JsonElement perm : jsonObject.get("perms").getAsJsonObject().get("perms").getAsJsonArray()) {
+ if(perm.isJsonPrimitive()) {
+ String cape = perm.getAsString();
+ if(cape.equals("*")) {
+ allAvailable = true;
+ } else {
+ availableCapes.add(cape);
+ }
+ }
+ }
+ }
+ }, () -> {
+ System.out.println("[MBAPI] Update capes errored - perms");
+ });
}
- if(capeMap.containsKey(player)) {
- Pair<NEUCape, String> capePair = capeMap.get(player);
- capePair.setValue(capename);
- } else {
- capeMap.put(player, new MutablePair<>(new NEUCape(capename), capename));
+ }
+
+ public HashSet<String> getAvailableCapes() {
+ return allAvailable ? availableCapes : availableCapes;
+ }
+
+ public void setCape(String playerUUID, String capename, boolean updateConfig) {
+ boolean none = capename == null || capename.equals("null");
+
+ updateConfig = updateConfig && playerUUID.equals(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""));
+ if(updateConfig) {
+ NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value = String.valueOf(capename);
+ try { NotEnoughUpdates.INSTANCE.manager.saveConfig(); } catch(IOException ignored) {}
+ }
+
+ if(updateConfig) {
+ if(none) {
+ localCape = null;
+ } else {
+ localCape = new MutablePair<>(new NEUCape(capename), capename);
+ }
+ } else if(capeMap.containsKey(playerUUID)) {
+ if(none) {
+ capeMap.remove(playerUUID);
+ } else {
+ Pair<NEUCape, String> capePair = capeMap.get(playerUUID);
+ capePair.setValue(capename);
+ }
+ } else if(!none) {
+ capeMap.put(playerUUID, new MutablePair<>(new NEUCape(capename), capename));
}
}
@@ -50,10 +120,10 @@ public class CapeManager {
return null;
}
- public EntityPlayer getPlayerForName(String name) {
+ public EntityPlayer getPlayerForUUID(String uuid) {
if(Minecraft.getMinecraft().theWorld != null) {
for(EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) {
- if(player.getName().equals(name)) {
+ if(player.getUniqueID().toString().replace("-", "").equals(uuid)) {
return player;
}
}
@@ -63,38 +133,55 @@ public class CapeManager {
@SubscribeEvent
public void onRenderPlayer(RenderPlayerEvent.Post e) {
- //if(e.partialRenderTick == 1.0F) return; //rendering in inventory
- if(Minecraft.getMinecraft().thePlayer != null &&
- e.entityPlayer.getName().equals(Minecraft.getMinecraft().thePlayer.getName())) {
- if(NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value != null &&
- !NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value.isEmpty()) {
- setCape(Minecraft.getMinecraft().thePlayer.getName(),
- NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value);
+ if(e.partialRenderTick == 1.0F) return; //rendering in inventory
+
+ String uuid = e.entityPlayer.getUniqueID().toString().replace("-", "");
+ String clientUuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "");
+
+ if(Minecraft.getMinecraft().thePlayer != null && uuid.equals(clientUuid)) {
+ String selCape = NotEnoughUpdates.INSTANCE.manager.config.selectedCape.value;
+ if(selCape != null && !selCape.isEmpty()) {
+ if(localCape == null) {
+ localCape = new MutablePair<>(new NEUCape(selCape), selCape);
+ } else {
+ localCape.setValue(selCape);
+ }
}
}
- if(e.entityPlayer.getName().equals("Moulberry")) setCape(e.entityPlayer.getName(), "fade");
- if(capeMap.containsKey(e.entityPlayer.getName())) {
- capeMap.get(e.entityPlayer.getName()).getLeft().onRenderPlayer(e);
+ if(uuid.equals(clientUuid) && localCape != null && localCape.getRight() != null && !localCape.getRight().equals("null")) {
+ localCape.getLeft().onRenderPlayer(e);
+ } else if(capeMap.containsKey(uuid)) {
+ capeMap.get(uuid).getLeft().onRenderPlayer(e);
}
}
@SubscribeEvent
public void onTick(TickEvent.ClientTickEvent event) {
+ String clientUuid = null;
+ if(Minecraft.getMinecraft().thePlayer != null) {
+ clientUuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "");
+ }
+
Set<String> toRemove = new HashSet<>();
- for(String playerName : capeMap.keySet()) {
- EntityPlayer player = getPlayerForName(playerName);
- if(player == null) {
- toRemove.add(playerName);
- } else {
- String capeName = capeMap.get(playerName).getRight();
- if(capeName != null) {
- capeMap.get(playerName).getLeft().setCapeTexture(capeName);
- capeMap.get(playerName).getLeft().onTick(event, player);
+ for(String playerUUID : capeMap.keySet()) {
+ EntityPlayer player = getPlayerForUUID(playerUUID);
+ if(player != null) {
+ String capeName = capeMap.get(playerUUID).getRight();
+ if(capeName != null && !capeName.equals("null")) {
+ if(playerUUID.equals(clientUuid) && localCape != null && localCape.getRight() != null && !localCape.getRight().equals("null")) {
+ continue;
+ }
+ capeMap.get(playerUUID).getLeft().setCapeTexture(capeName);
+ capeMap.get(playerUUID).getLeft().onTick(event, player);
} else {
- toRemove.add(playerName);
+ toRemove.add(playerUUID);
}
}
}
+ if(localCape != null) {
+ localCape.getLeft().setCapeTexture(localCape.getValue());
+ localCape.getLeft().onTick(event, Minecraft.getMinecraft().thePlayer);
+ }
for(String playerName : toRemove) {
capeMap.remove(playerName);
}
@@ -104,22 +191,6 @@ public class CapeManager {
return capes;
}
- private String[] contributors = new String[]{"thatgravyboat", "twasnt", "traxyrr", "some1sm", "meguminqt", "marethyu_77"};
-
- public boolean getPermissionForCape(String player, String capename) {
- if(capename == null) {
- return false;
- } else if(player.equalsIgnoreCase("Moulberry")) {
- return true; //Oh yeah gimme gimme
- } else {
- switch(capename) {
- case "nullzee": return player.equalsIgnoreCase("Nullzee");
- case "gravy": return player.equalsIgnoreCase("ThatGravyBoat");
- case "contrib": return ArrayUtils.contains(contributors, player.toLowerCase());
- case "fade": return true;
- }
- }
- return false;
- }
+ //private String[] contributors = new String[]{"thatgravyboat", "twasnt", "traxyrr", "some1sm", "meguminqt", "marethyu_77"};
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java
new file mode 100644
index 00000000..f9c4995e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java
@@ -0,0 +1,517 @@
+package io.github.moulberry.notenoughupdates.cosmetics;
+
+import com.google.common.base.Splitter;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.minecraft.MinecraftProfileTexture;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.SBAIntegration;
+import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.Panorama;
+import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.questing.SBScoreboardData;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityOtherPlayerMP;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.OpenGlHelper;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.client.renderer.entity.RenderManager;
+import net.minecraft.client.resources.DefaultPlayerSkin;
+import net.minecraft.client.resources.SkinManager;
+import net.minecraft.client.shader.Framebuffer;
+import net.minecraft.client.shader.Shader;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EnumPlayerModelParts;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagByteArray;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTTagString;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.Matrix4f;
+import net.minecraft.util.ResourceLocation;
+import org.apache.commons.lang3.text.WordUtils;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+import org.lwjgl.opengl.GL20;
+
+import java.awt.*;
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.util.List;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class GuiCosmetics extends GuiScreen {
+
+ public static final ResourceLocation pv_bg = new ResourceLocation("notenoughupdates:pv_bg.png");
+ public static final ResourceLocation pv_dropdown = new ResourceLocation("notenoughupdates:pv_dropdown.png");
+ public static final ResourceLocation cosmetics_fg = new ResourceLocation("notenoughupdates:cosmetics_fg.png");
+ public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png");
+
+ private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
+
+ private CosmeticsPage currentPage = CosmeticsPage.CAPES;
+ private int sizeX;
+ private int sizeY;
+ private int guiLeft;
+ private int guiTop;
+
+ private String wantToEquipCape = null;
+ private long lastCapeEquip = 0;
+
+ private List<String> tooltipToDisplay = null;
+
+ public enum CosmeticsPage {
+ CAPES(new ItemStack(Items.chainmail_chestplate));
+
+ public final ItemStack stack;
+
+ CosmeticsPage(ItemStack stack) {
+ this.stack = stack;
+ }
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ this.sizeX = 431;
+ this.sizeY = 202;
+ this.guiLeft = (this.width-this.sizeX)/2;
+ this.guiTop = (this.height-this.sizeY)/2;
+
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ drawDefaultBackground();
+
+ blurBackground();
+ renderBlurredBackground(width, height, guiLeft+2, guiTop+2, sizeX-4, sizeY-4);
+
+ GlStateManager.enableDepth();
+ GlStateManager.translate(0, 0, 5);
+ renderTabs(true);
+ GlStateManager.translate(0, 0, -3);
+
+ GlStateManager.disableDepth();
+ GlStateManager.translate(0, 0, -2);
+ renderTabs(false);
+ GlStateManager.translate(0, 0, 2);
+
+ GlStateManager.disableLighting();
+ GlStateManager.enableDepth();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_bg);
+ Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
+
+ GlStateManager.color(1, 1, 1, 1);
+ switch (currentPage) {
+ case CAPES:
+ drawCapesPage(mouseX, mouseY, partialTicks);
+ break;
+ }
+
+ if(tooltipToDisplay != null) {
+ List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size());
+ for(String line : tooltipToDisplay) {
+ grayTooltip.add(EnumChatFormatting.GRAY + line);
+ }
+ Utils.drawHoveringText(grayTooltip, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
+ tooltipToDisplay = null;
+ }
+
+ StringBuilder statusMsg = new StringBuilder("Last Sync: ");
+ if(CapeManager.INSTANCE.lastCapeSynced == 0) {
+ statusMsg.append("Not Synced");
+ } else {
+ statusMsg.append((System.currentTimeMillis() - CapeManager.INSTANCE.lastCapeSynced)/1000).append("s ago");
+ }
+ statusMsg.append(" - Next Sync: ");
+ if(CapeManager.INSTANCE.lastCapeUpdate == 0) {
+ statusMsg.append("ASAP");
+ } else {
+ statusMsg.append(60 - (System.currentTimeMillis() - CapeManager.INSTANCE.lastCapeUpdate)/1000).append("s");
+ }
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(EnumChatFormatting.AQUA+statusMsg.toString(),
+ guiLeft+sizeX-Minecraft.getMinecraft().fontRendererObj.getStringWidth(statusMsg.toString()), guiTop-12, 0, true);
+
+ if(currentPage == CosmeticsPage.CAPES && wantToEquipCape != null) {
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown);
+ Utils.drawTexturedRect(guiLeft+sizeX/2f-50, guiTop+sizeY+5, 100, 20, 0, 100/200f, 0, 20/185f, GL11.GL_NEAREST);
+
+ String equipMsg = EnumChatFormatting.GREEN + "Equip Cape";
+ if(System.currentTimeMillis() - lastCapeEquip < 20*1000) {
+ equipMsg += " - " + (20 - (System.currentTimeMillis() - lastCapeEquip)/1000) + "s";
+ }
+
+ Utils.drawStringCenteredScaledMaxWidth(equipMsg, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft+sizeX/2f, guiTop+sizeY+5+10, false, 90, 0);
+ }
+ }
+
+ private void renderTabs(boolean renderPressed) {
+ int ignoredTabs = 0;
+ for(int i = 0; i< CosmeticsPage.values().length; i++) {
+ CosmeticsPage page = CosmeticsPage.values()[i];
+ if(page.stack == null) {
+ ignoredTabs++;
+ continue;
+ }
+ boolean pressed = page == currentPage;
+ if(pressed == renderPressed) {
+ renderTab(page.stack, i-ignoredTabs, pressed);
+ }
+ }
+ }
+
+ private void renderTab(ItemStack stack, int xIndex, boolean pressed) {
+ GlStateManager.disableLighting();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ int x = guiLeft+xIndex*28;
+ int y = guiTop-28;
+
+ float uMin = 0;
+ float uMax = 28/256f;
+ float vMin = 20/256f;
+ float vMax = 51/256f;
+ if(pressed) {
+ vMin = 52/256f;
+ vMax = 84/256f;
+
+ if(xIndex != 0) {
+ uMin = 28/256f;
+ uMax = 56/256f;
+ }
+
+ renderBlurredBackground(width, height, x+2, y+2, 28-4, 28-4);
+ } else {
+ renderBlurredBackground(width, height, x+2, y+4, 28-4, 28-4);
+ }
+
+ GlStateManager.disableLighting();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(x, y, 28, pressed?32:31, uMin, uMax, vMin, vMax, GL11.GL_NEAREST);
+
+ GlStateManager.enableDepth();
+ Utils.drawItemStack(stack, x+6, y+9);
+ }
+
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
+ for (int i = 0; i < CosmeticsPage.values().length; i++) {
+ CosmeticsPage page = CosmeticsPage.values()[i];
+ int x = guiLeft + i * 28;
+ int y = guiTop - 28;
+
+ if (mouseX > x && mouseX < x + 28) {
+ if (mouseY > y && mouseY < y + 32) {
+ if (currentPage != page) Utils.playPressSound();
+ currentPage = page;
+ return;
+ }
+ }
+ }
+ if(mouseY > guiTop+177 && mouseY < guiTop+177+12) {
+ if(mouseX > guiLeft+15+371*scroll && mouseX < guiLeft+15+371*scroll+32) {
+ scrollClickedX = mouseX - (int)(guiLeft+15+371*scroll);
+ return;
+ }
+ }
+
+ int index = 0;
+ int displayingCapes = 0;
+ for(String cape : CapeManager.INSTANCE.getCapes()) {
+ boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape);
+ if (!CapeManager.INSTANCE.specialCapes[index++] || equipable) {
+ displayingCapes++;
+ }
+ }
+
+ float totalNeeded = 91*displayingCapes;
+ float totalAvail = sizeX-20;
+ float xOffset = scroll*(totalNeeded-totalAvail);
+
+ index = 0;
+ int displayIndex = 0;
+ for(String cape : CapeManager.INSTANCE.getCapes()) {
+ boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape);
+ if(CapeManager.INSTANCE.specialCapes[index++] && !equipable) continue;
+
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 20 + 91 * displayIndex - xOffset, guiTop + 123, 81, 20,
+ 0, 81 / 256f, 216 / 256f, 236 / 256f, GL11.GL_NEAREST);
+
+ if(mouseX > guiLeft + 20 + 91 * displayIndex - xOffset && mouseX < guiLeft + 20 + 91 * displayIndex - xOffset+81) {
+ if(mouseY > guiTop + 123 && mouseY < guiTop + 123 + 20) {
+ if(CapeManager.INSTANCE.localCape != null && CapeManager.INSTANCE.localCape.getRight().equals(cape)) {
+ CapeManager.INSTANCE.setCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""),
+ "null", true);
+ } else {
+ CapeManager.INSTANCE.setCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""),
+ cape, true);
+ }
+
+ return;
+ } else if(equipable && mouseY > guiTop + 149 && mouseY < guiTop + 149 + 20) {
+ wantToEquipCape = cape;
+ return;
+ }
+ }
+
+ displayIndex++;
+ }
+
+ if(currentPage == CosmeticsPage.CAPES && wantToEquipCape != null) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown);
+ Utils.drawTexturedRect(guiLeft+sizeX/2f-50, guiTop+sizeY+5, 100, 20, 0, 100/200f, 0, 20/185f, GL11.GL_NEAREST);
+
+ if(mouseX > guiLeft+sizeX/2f-50 && mouseX < guiLeft+sizeX/2f+50) {
+ if(mouseY > guiTop+sizeY+5 && mouseY < guiTop+sizeY+25) {
+ if(System.currentTimeMillis() - lastCapeEquip > 20*1000) {
+ lastCapeEquip = System.currentTimeMillis();
+ NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("cgi-bin/changecape.py?capeType="+wantToEquipCape+"&accessToken="+
+ Minecraft.getMinecraft().getSession().getToken(), (jsonObject) -> {}, () -> {});
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void mouseReleased(int mouseX, int mouseY, int state) {
+ super.mouseReleased(mouseX, mouseY, state);
+
+ scrollClickedX = -1;
+ }
+
+ @Override
+ protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
+ super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
+
+ if(scrollClickedX >= 0) {
+ float scrollStartX = mouseX - scrollClickedX;
+ scroll = (scrollStartX-(guiLeft+15))/371f;
+ scroll = Math.max(0, Math.min(1, scroll));
+ }
+ }
+
+ private HashMap<String, ResourceLocation> capesLocation = new HashMap<>();
+ private float scroll = 0f;
+ private int scrollClickedX = -1;
+ private void drawCapesPage(int mouseX, int mouseY, float partialTicks) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(cosmetics_fg);
+ Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(guiLeft+15+371*scroll, guiTop+177, 32, 12,
+ 0, 32/256f, 192/256f, 204/256f, GL11.GL_NEAREST);
+
+ GL11.glEnable(GL11.GL_SCISSOR_TEST);
+ GL11.glScissor(Minecraft.getMinecraft().displayWidth*(guiLeft+3)/width, 0,
+ Minecraft.getMinecraft().displayWidth*(sizeX-6)/width, Minecraft.getMinecraft().displayHeight);
+
+ int index = 0;
+ int displayingCapes = 0;
+ for(String cape : CapeManager.INSTANCE.getCapes()) {
+ boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape);
+ if (!CapeManager.INSTANCE.specialCapes[index++] || equipable) {
+ displayingCapes++;
+ }
+ }
+
+ float totalNeeded = 91*displayingCapes;
+ float totalAvail = sizeX-20;
+ float xOffset = scroll*(totalNeeded-totalAvail);
+
+ index = 0;
+ int displayIndex = 0;
+ for(String cape : CapeManager.INSTANCE.getCapes()) {
+ boolean equipable = CapeManager.INSTANCE.getAvailableCapes() == null || CapeManager.INSTANCE.getAvailableCapes().contains(cape);
+ if(CapeManager.INSTANCE.specialCapes[index++] && !equipable) continue;
+
+ if(cape.equals(CapeManager.INSTANCE.getCape(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "")))) {
+ GlStateManager.color(250 / 255f, 200 / 255f, 0 / 255f, 1);
+ Utils.drawGradientRect(guiLeft + 20 + 91 * displayIndex - (int) xOffset, guiTop + 10,
+ guiLeft + 20 + 91 * displayIndex - (int) xOffset + 81, guiTop + 10 + 108,
+ new Color(150, 100, 0, 40).getRGB(), new Color(250, 200, 0, 40).getRGB());
+ } else if(cape.equals(wantToEquipCape)) {
+ GlStateManager.color(0, 200 / 255f, 250 / 255f, 1);
+ Utils.drawGradientRect(guiLeft + 20 + 91 * displayIndex - (int) xOffset, guiTop + 10,
+ guiLeft + 20 + 91 * displayIndex - (int) xOffset + 81, guiTop + 10 + 108,
+ new Color(0, 100, 150, 40).getRGB(), new Color(0, 200, 250, 40).getRGB());
+ } else if(CapeManager.INSTANCE.localCape != null && CapeManager.INSTANCE.localCape.getRight().equals(cape)) {
+ GlStateManager.color(100/255f, 250/255f, 150/255f, 1);
+ Utils.drawGradientRect(guiLeft+20+91*displayIndex-(int)xOffset, guiTop+10,
+ guiLeft+20+91*displayIndex-(int)xOffset+81, guiTop+10+108,
+ new Color(50, 100, 75, 40).getRGB(), new Color(100, 250, 150, 40).getRGB());
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(guiLeft+20+91*displayIndex-xOffset, guiTop+10, 81, 108,
+ 0, 81/256f, 84/256f, 192/256f, GL11.GL_NEAREST);
+ GlStateManager.color(1, 1, 1, 1);
+
+ Utils.drawTexturedRect(guiLeft+20+91*displayIndex-xOffset, guiTop+123, 81, 20,
+ 0, 81/256f, 216/256f, 236/256f, GL11.GL_NEAREST);
+
+ boolean equipPressed = cape.equals(wantToEquipCape);
+ if(!equipable) GlStateManager.color(1, 1, 1, 0.5f);
+ Utils.drawTexturedRect(guiLeft+20+91*displayIndex-xOffset, guiTop+149, 81, 20,
+ equipPressed?81/256f:0, equipPressed?0:81/256f, equipPressed?236/256f:216/256f, equipPressed?216/256f:236/256f, GL11.GL_NEAREST);
+
+ Utils.drawStringCenteredScaledMaxWidth("Try it out", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft+20+91*displayIndex+81/2f-xOffset, guiTop+123+10, false, 75, new Color(100, 250, 150).getRGB());
+ if(equipable) {
+ Utils.drawStringCenteredScaledMaxWidth("Equip", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft+20+91*displayIndex+81/2f-xOffset, guiTop+149+10, false, 75, new Color(100, 250, 150).getRGB());
+ } else {
+ Utils.drawStringCenteredScaledMaxWidth("Not Unlocked", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft+20+91*displayIndex+81/2f-xOffset, guiTop+149+10, false, 75, new Color(200, 50, 50, 100).getRGB());
+ }
+ GlStateManager.color(1, 1, 1, 1);
+
+ ResourceLocation capeTexture = capesLocation.computeIfAbsent(cape, k -> new ResourceLocation("notenoughupdates", "capes/"+cape+".png"));
+ Minecraft.getMinecraft().getTextureManager().bindTexture(capeTexture);
+ Utils.drawTexturedRect(guiLeft+31+91*displayIndex-xOffset, guiTop+24, 59, 84,
+ 0, 293/1024f, 0, 420/1024f, GL11.GL_NEAREST);
+
+ displayIndex++;
+ }
+
+ GL11.glScissor(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight);
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ }
+
+ Shader blurShaderHorz = null;
+ Framebuffer blurOutputHorz = null;
+ Shader blurShaderVert = null;
+ Framebuffer blurOutputVert = null;
+
+ /**
+ * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate
+ * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis).
+ *
+ * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to
+ * apply scales and translations manually.
+ */
+ 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;
+ }
+
+ /**
+ * Renders whatever is currently in the Minecraft framebuffer to our two framebuffers, applying a horizontal
+ * and vertical blur separately in order to significantly save computation time.
+ * This is only possible if framebuffers are supported by the system, so this method will exit prematurely
+ * if framebuffers are not available. (Apple machines, for example, have poor framebuffer support).
+ */
+ private double lastBgBlurFactor = -1;
+ private void blurBackground() {
+ int width = Minecraft.getMinecraft().displayWidth;
+ int height = Minecraft.getMinecraft().displayHeight;
+
+ if(blurOutputHorz == null) {
+ blurOutputHorz = new Framebuffer(width, height, false);
+ blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST);
+ }
+ if(blurOutputVert == null) {
+ blurOutputVert = new Framebuffer(width, height, false);
+ blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST);
+ }
+ if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) {
+ blurOutputHorz.createBindFramebuffer(width, height);
+ blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
+ }
+ if(blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) {
+ blurOutputVert.createBindFramebuffer(width, height);
+ blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
+ }
+
+ if(blurShaderHorz == null) {
+ try {
+ blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
+ Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz);
+ blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0);
+ blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
+ } catch(Exception e) { }
+ }
+ if(blurShaderVert == null) {
+ try {
+ blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
+ blurOutputHorz, blurOutputVert);
+ blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1);
+ blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
+ } catch(Exception e) { }
+ }
+ if(blurShaderHorz != null && blurShaderVert != null) {
+ if(15 != lastBgBlurFactor) {
+ blurShaderHorz.getShaderManager().getShaderUniform("Radius").set((float)15);
+ blurShaderVert.getShaderManager().getShaderUniform("Radius").set((float)15);
+ lastBgBlurFactor = 15;
+ }
+ GL11.glPushMatrix();
+ blurShaderHorz.loadShader(0);
+ blurShaderVert.loadShader(0);
+ GlStateManager.enableDepth();
+ GL11.glPopMatrix();
+
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
+ }
+ }
+
+ /**
+ * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen.
+ * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight]
+ */
+ public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) {
+ float uMin = x/(float)width;
+ float uMax = (x+blurWidth)/(float)width;
+ float vMin = (height-y)/(float)height;
+ float vMax = (height-y-blurHeight)/(float)height;
+
+ blurOutputVert.bindFramebufferTexture();
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ //Utils.setScreen(width*f, height*f, f);
+ Utils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax);
+ //Utils.setScreen(width, height, f);
+ blurOutputVert.unbindFramebufferTexture();
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java
index 9848f495..985bc14c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java
@@ -62,7 +62,7 @@ public class NEUCape {
} else {
shaderName = "cape";
}
- capeTex = new ResourceLocation("notenoughupdates:"+capeName+".png");
+ capeTex = new ResourceLocation("notenoughupdates:capes/"+capeName+".png");
startTime = System.currentTimeMillis();
}
}
@@ -229,8 +229,6 @@ public class NEUCape {
if(currentPlayer != null && currentPlayer != player) return;
- if(e.partialRenderTick == 1) return;
-
if(player.getActivePotionEffect(Potion.invisibility) != null) return;
if(player.isSpectator() || player.isInvisible()) return;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java
index cdda9957..de8fe562 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java
@@ -231,17 +231,19 @@ public class SBGamemodes {
if(!"Your Island".equals(SBScoreboardData.getInstance().location)) return;
- if(event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
- if(Math.abs(event.pos.getX()) > 40 || Math.abs(event.pos.getZ()) > 40) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW+"[NPC] Builder"+
- EnumChatFormatting.WHITE+": Sorry, "+Minecraft.getMinecraft().thePlayer.getName()+
- ", due to budget cuts your skyblock island is now only 80 blocks wide."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.AQUA+"(Use "+EnumChatFormatting.YELLOW+"/neugamemodes"+
- EnumChatFormatting.AQUA+" if you would like to build further out)"));
-
- event.setCanceled(true);
+ if((getGamemode().gamemodeModifiers & MODIFIER_SMALLISLAND) != 0) {
+ if(event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
+ if(Math.abs(event.pos.getX()) > 40 || Math.abs(event.pos.getZ()) > 40) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.YELLOW+"[NPC] Builder"+
+ EnumChatFormatting.WHITE+": Sorry, "+Minecraft.getMinecraft().thePlayer.getName()+
+ ", due to budget cuts your skyblock island is now only 80 blocks wide."));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.AQUA+"(Use "+EnumChatFormatting.YELLOW+"/neugamemodes"+
+ EnumChatFormatting.AQUA+" if you would like to build further out)"));
+
+ event.setCanceled(true);
+ }
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java
deleted file mode 100644
index 707968e3..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CosmeticsInfoPane.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package io.github.moulberry.notenoughupdates.infopanes;
-
-import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
-import io.github.moulberry.notenoughupdates.NEUManager;
-import io.github.moulberry.notenoughupdates.NEUOverlay;
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.FontRenderer;
-import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.util.ResourceLocation;
-
-import java.awt.*;
-import java.util.HashMap;
-
-public class CosmeticsInfoPane extends InfoPane {
-
- public CosmeticsInfoPane(NEUOverlay overlay, NEUManager manager) {
- super(overlay, manager);
- }
-
- private HashMap<String, ResourceLocation> capeTextures = new HashMap<>();
-
- private String selectedCape = null;
-
- public void render(int width, int height, Color bg, Color fg, ScaledResolution scaledresolution, int mouseX,
- int mouseY) {
- super.renderDefaultBackground(width, height, bg);
-
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
- int currentY = overlay.getBoxPadding()+10;
- fr.drawString("NEU Capes", overlay.getBoxPadding()+10, currentY, Color.WHITE.getRGB(), true); currentY += 10;
-
- selectedCape = null;
- for(String cape : CapeManager.getInstance().getCapes()) {
- if(CapeManager.getInstance().getPermissionForCape(Minecraft.getMinecraft().thePlayer.getName(), cape)) {
- currentY += renderCapeSelector(cape, currentY, mouseX, mouseY);
- currentY += 5;
- }
- }
- }
-
- public int renderCapeSelector(String capename, int y, int mouseX, int mouseY) {
- if(mouseX > overlay.getBoxPadding()+5 && mouseX < overlay.getBoxPadding()+75) {
- if(mouseY > y && mouseY < y+100) {
- selectedCape = capename;
- }
- }
- boolean selected = capename.equals(CapeManager.getInstance().getCape(Minecraft.getMinecraft().thePlayer.getName()));
-
- if(selected) {
- drawRect(overlay.getBoxPadding()+5, y, overlay.getBoxPadding()+75, y+100, Color.YELLOW.getRGB());
- drawGradientRect(overlay.getBoxPadding()+10, y+5, overlay.getBoxPadding()+70, y+95, Color.GRAY.darker().getRGB(), Color.GRAY.getRGB());
- } else {
- drawGradientRect(overlay.getBoxPadding()+5, y, overlay.getBoxPadding()+75, y+100, Color.GRAY.darker().getRGB(), Color.GRAY.getRGB());
- }
-
- GlStateManager.color(1, 1, 1, 1);
-
- ResourceLocation capeTex = capeTextures.computeIfAbsent(capename, k -> new ResourceLocation("notenoughupdates:"+capename+".png"));
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(capeTex);
- Utils.drawTexturedRect(overlay.getBoxPadding()+10, y+10, 60, 80, 0, 300/1024f, 0, 425/1024f);
- return 100;
- }
-
- public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) {
- if(mouseDown && selectedCape != null) {
- if(selectedCape.equals(CapeManager.getInstance().getCape(Minecraft.getMinecraft().thePlayer.getName()))) {
- CapeManager.getInstance().setCape(Minecraft.getMinecraft().thePlayer.getName(), null);
- } else {
- CapeManager.getInstance().setCape(Minecraft.getMinecraft().thePlayer.getName(), selectedCape);
- }
- }
- }
-
- @Override
- public boolean keyboardInput() {
- return false;
- }
-
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java
index 3e9cdb3f..234d06a8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java
@@ -136,6 +136,10 @@ public class HTMLInfoPane extends TextInfoPane {
return new HTMLInfoPane(overlay, manager, name, filename, html);
}
+ private String spaceEscape(String str) {
+ return str.replace(" ", "\\ ");
+ }
+
/**
* Uses the wkhtmltoimage command-line tool to generate an image from the HTML code. This
* generation is done asynchronously as sometimes it can take up to 10 seconds for more
@@ -190,9 +194,12 @@ public class HTMLInfoPane extends TextInfoPane {
EnumChatFormatting.GRAY+"), please wait...";
Runtime runtime = Runtime.getRuntime();
- Process p = runtime.exec("\""+wkHtmlToImage.getAbsolutePath() + "\" --width "+
+ Process p = runtime.exec(spaceEscape(wkHtmlToImage.getAbsolutePath()) + " --width "+
+ IMAGE_WIDTH*ZOOM_FACTOR+" --transparent --zoom "+ZOOM_FACTOR + " " + spaceEscape(input.getAbsolutePath()) +
+ " " + spaceEscape(output.getAbsolutePath()));
+ /*Process p = runtime.exec("\""+wkHtmlToImage.getAbsolutePath() + "\" --width "+
IMAGE_WIDTH*ZOOM_FACTOR+" --transparent --zoom "+ZOOM_FACTOR+" \"" + input.getAbsolutePath() +
- "\" \"" + output.getAbsolutePath() + "\"");
+ "\" \"" + output.getAbsolutePath() + "\"");*/
/*Process p2 = runtime.exec("\""+wkHtmlToImage.getAbsolutePath() + "\" --width "+
(IMAGE_WIDTH+EXT_WIDTH)*ZOOM_FACTOR+" --transparent --zoom "+ZOOM_FACTOR+" \"" + input.getAbsolutePath() +
"\" \"" + outputExt.getAbsolutePath() + "\"");*/
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java
new file mode 100644
index 00000000..de86198e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java
@@ -0,0 +1,77 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import io.github.moulberry.notenoughupdates.CustomItemEffects;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraft.client.renderer.EntityRenderer;
+import org.lwjgl.util.vector.Vector3f;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(EntityRenderer.class)
+public class MixinEntityRenderer {
+
+ //orientCamera
+ @ModifyVariable(method="orientCamera", at=@At(value="STORE"), ordinal = 0)
+ public double orientCamera_d0(double d0) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.x;
+ }
+ return d0;
+ }
+
+ @ModifyVariable(method="orientCamera", at=@At(value="STORE"), ordinal = 1)
+ public double orientCamera_d1(double d1) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.y;
+ }
+ return d1;
+ }
+
+ @ModifyVariable(method="orientCamera", at=@At(value="STORE"), ordinal = 2)
+ public double orientCamera_d2(double d2) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.z;
+ }
+ return d2;
+ }
+
+ //renderWorldPass
+ @Inject(method="renderWorldPass", at=@At("HEAD"))
+ public void renderWorldPass(int pass, float partialTicks, long finishTimeNano, CallbackInfo ci) {
+ CustomItemEffects.INSTANCE.partialTicks = partialTicks;
+ }
+
+ @ModifyVariable(method="renderWorldPass", at=@At(value="STORE"), ordinal = 0)
+ public double renderWorldPass_d0(double d0) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.x;
+ }
+ return d0;
+ }
+
+ @ModifyVariable(method="renderWorldPass", at=@At(value="STORE"), ordinal = 1)
+ public double renderWorldPass_d1(double d1) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.y;
+ }
+ return d1;
+ }
+
+ @ModifyVariable(method="renderWorldPass", at=@At(value="STORE"), ordinal = 2, print = true)
+ public double renderWorldPass_d2(double d2) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.z;
+ }
+ return d2;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java
new file mode 100644
index 00000000..2337aa8b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java
@@ -0,0 +1,26 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import io.github.moulberry.notenoughupdates.CustomItemEffects;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.StreamerMode;
+import net.minecraft.client.network.NetHandlerPlayClient;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.scoreboard.ScorePlayerTeam;
+import net.minecraft.scoreboard.Team;
+import org.lwjgl.util.vector.Vector3f;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(NetHandlerPlayClient.class)
+public class MixinNetHandlerPlayClient {
+
+ private static final String TARGET = "Lnet/minecraft/entity/player/EntityPlayer;" +
+ "setPositionAndRotation(DDDFF)V";
+ @Redirect(method="handlePlayerPosLook", at=@At(value="INVOKE", target=TARGET))
+ public void handlePlayerPosLook_setPositionAndRotation(EntityPlayer player, double x, double y, double z, float yaw, float pitch) {
+ CustomItemEffects.INSTANCE.teleported = true;
+ player.setPositionAndRotation(x, y, z, yaw, pitch);
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java
new file mode 100644
index 00000000..2bb5503b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java
@@ -0,0 +1,69 @@
+package io.github.moulberry.notenoughupdates.mixins;
+
+import io.github.moulberry.notenoughupdates.CustomItemEffects;
+import net.minecraft.client.renderer.RenderGlobal;
+import org.lwjgl.util.vector.Vector3f;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
+
+@Mixin(RenderGlobal.class)
+public class MixinRenderGlobal {
+
+ //setupTerrain
+ @ModifyVariable(method="setupTerrain", at=@At(value="STORE"), ordinal = 4)
+ public double setupTerrain_d0(double d3) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.x;
+ }
+ return d3;
+ }
+
+ @ModifyVariable(method="setupTerrain", at=@At(value="STORE"), ordinal = 5)
+ public double setupTerrain_d1(double d4) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.y;
+ }
+ return d4;
+ }
+
+ @ModifyVariable(method="setupTerrain", at=@At(value="STORE"), ordinal = 6)
+ public double setupTerrain_d2(double d5) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.z;
+ }
+ return d5;
+ }
+
+ //renderEntities
+ @ModifyVariable(method="renderEntities", at=@At(value="STORE"), ordinal = 3)
+ public double renderEntities_d0(double d3) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.x;
+ }
+ return d3;
+ }
+
+ @ModifyVariable(method="renderEntities", at=@At(value="STORE"), ordinal = 4)
+ public double renderEntities_d1(double d4) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.y;
+ }
+ return d4;
+ }
+
+ @ModifyVariable(method="renderEntities", at=@At(value="STORE"), ordinal = 5)
+ public double renderEntities_d2(double d5) {
+ Vector3f currentPosition = CustomItemEffects.INSTANCE.getCurrentPosition();
+ if(currentPosition != null) {
+ return currentPosition.z;
+ }
+ return d5;
+ }
+
+}
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 88165d08..4906fa4d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java
@@ -58,6 +58,11 @@ public class Options {
"Coloured Tooltip Borders",
false,
"Makes the border of tooltips coloured. (Only NEU Tooltips)");
+ public Option<Boolean> disableAhScroll = new Option(
+ false,
+ "No NeuAH Scroll",
+ false,
+ "Disables Scrolling in NeuAH");
public Option<Boolean> advancedPriceInfo = new Option(
false,
"Adv. Item Price Info",
@@ -292,6 +297,7 @@ public class Options {
//tryAddOption(advancedPriceInfo, options);
tryAddOption(showUpdateMsg, options);
tryAddOption(tooltipBorderColours, options);
+ tryAddOption(disableAhScroll, options);
tryAddOption(hideApiKey, options);
tryAddOption(streamerMode, options);
tryAddOption(autoupdate, options);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
index e8432d63..14966b2f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -1695,6 +1695,7 @@ public class GuiProfileViewer extends GuiScreen {
for(Map.Entry<String, JsonElement> entry : skillInfo.entrySet()) {
if(entry.getKey().startsWith("level_skill")) {
if(entry.getKey().contains("runecrafting")) continue;
+ if(entry.getKey().contains("carpentry")) continue;
totalSkillLVL += entry.getValue().getAsFloat();
totalSkillCount++;
} else if(entry.getKey().startsWith("level_slayer")) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
index ca6c30af..b925f6da 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
@@ -23,6 +23,9 @@ public class HypixelApi {
private Gson gson = new Gson();
private ExecutorService es = Executors.newFixedThreadPool(3);
+ private int myApiErrors = 0;
+ private String[] myApiURLs = {"https://moulberry.codes/", "https://51.89.22.3/", "http://moulberry.codes/", "http://51.89.22.3/"};
+
public void getHypixelApiAsync(String apiKey, String method, HashMap<String, String> args, Consumer<JsonObject> consumer) {
getHypixelApiAsync(apiKey, method, args, consumer, () -> {});
}
@@ -31,6 +34,10 @@ public class HypixelApi {
getApiAsync(generateApiUrl(apiKey.trim(), method, args), consumer, error);
}
+ private String getMyApiURL() {
+ return myApiURLs[myApiErrors%myApiURLs.length];
+ }
+
public void getApiAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
es.submit(() -> {
try {
@@ -41,6 +48,28 @@ public class HypixelApi {
});
}
+ public void getMyApiAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
+ es.submit(() -> {
+ try {
+ consumer.accept(getApiSync(getMyApiURL()+urlS));
+ } catch(IOException e) {
+ myApiErrors++;
+ error.run();
+ }
+ });
+ }
+
+ public void getMyApiGZIPAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
+ es.submit(() -> {
+ try {
+ consumer.accept(getApiGZIPSync(getMyApiURL()+urlS));
+ } catch(IOException e) {
+ myApiErrors++;
+ error.run();
+ }
+ });
+ }
+
public void getApiGZIPAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
es.submit(() -> {
try {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
index 73c15a7b..428a43b2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -619,7 +619,12 @@ public class Utils {
return new Color(colourInt).darker();
}
- //private static List<String>
+ public static void scrollTooltip(int dY) {
+ scrollY.setTarget(scrollY.getTarget()+dY/10f);
+ scrollY.resetTimer();
+ }
+
+ private static LerpingFloat scrollY = new LerpingFloat(0, 100);
public static void drawHoveringText(List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font, boolean coloured) {
if (!textLines.isEmpty())
{
@@ -713,9 +718,24 @@ public class Utils {
}
}
+ //Scrollable tooltips
+ if(tooltipHeight + 6 > screenHeight) {
+ if(scrollY.getTarget() < 0) {
+ scrollY.setTarget(0);
+ scrollY.resetTimer();
+ } else if(screenHeight - tooltipHeight - 12 + (int)scrollY.getTarget() > 0) {
+ scrollY.setTarget(-screenHeight + tooltipHeight + 12);
+ scrollY.resetTimer();
+ }
+ } else {
+ scrollY.setValue(0);
+ scrollY.resetTimer();
+ }
+ scrollY.tick();
+
if (tooltipY + tooltipHeight + 6 > screenHeight)
{
- tooltipY = screenHeight - tooltipHeight - 6;
+ tooltipY = screenHeight - tooltipHeight - 6 + (int)scrollY.getValue();
}
final int zLevel = 300;
diff --git a/src/main/resources/assets/notenoughupdates/contrib.png b/src/main/resources/assets/notenoughupdates/capes/contrib.png
index 51699e6e..51699e6e 100644
--- a/src/main/resources/assets/notenoughupdates/contrib.png
+++ b/src/main/resources/assets/notenoughupdates/capes/contrib.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/fade.png b/src/main/resources/assets/notenoughupdates/capes/fade.png
index d898ec4d..d898ec4d 100644
--- a/src/main/resources/assets/notenoughupdates/fade.png
+++ b/src/main/resources/assets/notenoughupdates/capes/fade.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/gravy.png b/src/main/resources/assets/notenoughupdates/capes/gravy.png
index e43ba7d2..e43ba7d2 100644
--- a/src/main/resources/assets/notenoughupdates/gravy.png
+++ b/src/main/resources/assets/notenoughupdates/capes/gravy.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/nullzee.png b/src/main/resources/assets/notenoughupdates/capes/nullzee.png
index 5939034b..5939034b 100644
--- a/src/main/resources/assets/notenoughupdates/nullzee.png
+++ b/src/main/resources/assets/notenoughupdates/capes/nullzee.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/patreon1.png b/src/main/resources/assets/notenoughupdates/capes/patreon1.png
index aba027bc..aba027bc 100644
--- a/src/main/resources/assets/notenoughupdates/patreon1.png
+++ b/src/main/resources/assets/notenoughupdates/capes/patreon1.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/patreon2.png b/src/main/resources/assets/notenoughupdates/capes/patreon2.png
index 1c5a848a..1c5a848a 100644
--- a/src/main/resources/assets/notenoughupdates/patreon2.png
+++ b/src/main/resources/assets/notenoughupdates/capes/patreon2.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/testcape.png b/src/main/resources/assets/notenoughupdates/capes/testcape.png
index 4b8ba499..4b8ba499 100644
--- a/src/main/resources/assets/notenoughupdates/testcape.png
+++ b/src/main/resources/assets/notenoughupdates/capes/testcape.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/cosmetics_fg.png b/src/main/resources/assets/notenoughupdates/cosmetics_fg.png
new file mode 100644
index 00000000..445753ac
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/cosmetics_fg.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_elements.png b/src/main/resources/assets/notenoughupdates/pv_elements.png
index 0020478e..d742301e 100644
--- a/src/main/resources/assets/notenoughupdates/pv_elements.png
+++ b/src/main/resources/assets/notenoughupdates/pv_elements.png
Binary files differ
diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json
index 8f07f5cc..f797c921 100644
--- a/src/main/resources/mixins.notenoughupdates.json
+++ b/src/main/resources/mixins.notenoughupdates.json
@@ -6,6 +6,9 @@
"MixinItemStack",
"MixinInventoryEffectRenderer",
"MixinGuiIngame",
- "MixinRenderItem"
+ "MixinRenderItem",
+ "MixinEntityRenderer",
+ "MixinRenderGlobal",
+ "MixinNetHandlerPlayClient"
]
} \ No newline at end of file