diff options
Diffstat (limited to 'src')
8 files changed, 986 insertions, 72 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUCape.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUCape.java new file mode 100644 index 00000000..1a33a798 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUCape.java @@ -0,0 +1,192 @@ +package io.github.moulberry.notenoughupdates; + +import net.minecraft.client.Minecraft; +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.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Vector3f; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class NEUCape { + + private List<List<Node>> nodes = null; + + int horzNodes = 20; + float targetDist = 1/30f; + + public void createNodes(EntityPlayer player) { + nodes = new ArrayList<>(); + for(int i=0; i<50; i++) { + List<Node> row = new ArrayList<>(); + for(int j=0; j<horzNodes; j++) { + row.add(new Node(-1, 2-i*targetDist, ((double)j)/(horzNodes-1))); + } + + nodes.add(row); + } + for(int y=0; y<nodes.size(); y++) { + for(int x=0; x<nodes.get(y).size(); x++) { + for(Direction dir : Direction.values()) { + for(int i=1; i<=2; i++) { + Offset offset = new Offset(dir, i); + + int xNeighbor = x+offset.getXOffset(); + int yNeighbor = y+offset.getYOffset(); + + if(xNeighbor >= 0 && xNeighbor < nodes.get(y).size() + && yNeighbor >= 0 && yNeighbor < nodes.size()) { + Node neighbor = nodes.get(yNeighbor).get(xNeighbor); + nodes.get(y).get(x).neighbors.put(offset, neighbor); + } + } + } + } + } + } + + public void ensureNodesCreated(EntityPlayer player) { + if(nodes == null) createNodes(player); + } + + public enum Direction { + LEFT(-1, 0), + UP(0, 1), + RIGHT(1, 0), + DOWN(0, -1), + UPLEFT(-1, 1), + UPRIGHT(1, 1), + DOWNLEFT(-1, -1), + DOWNRIGHT(1, -1); + + int xOff; + int yOff; + + Direction(int xOff, int yOff) { + this.xOff = xOff; + this.yOff = yOff; + } + } + + public static class Offset { + Direction direction; + int steps; + + public Offset(Direction direction, int steps) { + this.direction = direction; + this.steps = steps; + } + + public int getXOffset() { + return direction.xOff*steps; + } + + public int getYOffset() { + return direction.yOff*steps; + } + + public boolean equals(Object obj) { + if(obj instanceof Offset) { + Offset other = (Offset) obj; + return other.direction == direction && other.steps == steps; + } + return false; + } + + @Override + public int hashCode() { + return 13*direction.ordinal() + 7*steps; + } + } + + public static class Node { + private Vector3f position; + private Vector3f acceleration = new Vector3f(); + private HashMap<Offset, Node> neighbors = new HashMap<>(); + + public Node(double x, double y, double z) { + this.position = new Vector3f((float)x, (float)y, (float)z); + } + + public void updatePosition() { + + } + + public void renderNode() { + //System.out.println(neighbors.size()); + if(neighbors.containsKey(new Offset(Direction.DOWNRIGHT, 1))) { + //System.out.println("trying to render"); + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.color(1F, 1F, 1F, 1F); + worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION); + + Vector3f node2Pos = neighbors.get(new Offset(Direction.DOWN, 1)).position; + Vector3f node3Pos = neighbors.get(new Offset(Direction.RIGHT, 1)).position; + Vector3f node4Pos = neighbors.get(new Offset(Direction.DOWNRIGHT, 1)).position; + + worldrenderer.pos(position.x, position.y, position.z).endVertex(); + worldrenderer.pos(node2Pos.x, node2Pos.y, node2Pos.z).endVertex(); + worldrenderer.pos(node3Pos.x, node3Pos.y, node3Pos.z).endVertex(); + worldrenderer.pos(node4Pos.x, node4Pos.y, node4Pos.z).endVertex(); + + tessellator.draw(); + } + } + } + + @SubscribeEvent + public void onRenderPlayer(RenderPlayerEvent.Post e) { + EntityPlayer player = e.entityPlayer; + + ensureNodesCreated(player); + if(Keyboard.isKeyDown(Keyboard.KEY_R)) createNodes(player); + + Entity viewer = Minecraft.getMinecraft().getRenderViewEntity(); + double viewerX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * e.partialRenderTick; + double viewerY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * e.partialRenderTick; + double viewerZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * e.partialRenderTick; + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, + GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GlStateManager.disableTexture2D(); + GlStateManager.disableCull(); + + //GL11.glTranslatef(-(float)viewerX, -(float)viewerY, -(float)viewerZ); + + updateCape(player); + renderCape(player); + + //GL11.glTranslatef((float)viewerX, (float)viewerY, (float)viewerZ); + + GL11.glEnable(GL11.GL_CULL_FACE); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + GlStateManager.color(1F, 1F, 1F, 1F); + } + + private void updateCape(EntityPlayer player) { + + } + + private void renderCape(EntityPlayer player) { + for(int y=0; y<nodes.size()-1; y++) { + for(int x=0; x<nodes.get(y).size()-1; x++) { + nodes.get(y).get(x).renderNode(); + } + } + } + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUCape2.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUCape2.java new file mode 100644 index 00000000..4b834cbb --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUCape2.java @@ -0,0 +1,608 @@ +package io.github.moulberry.notenoughupdates; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.command.CommandBase; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.*; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.client.event.RenderPlayerEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class NEUCape2 { + + //private ResourceLocation capeImageLocation = new ResourceLocation(Morus.MODID, "cape.jpg"); + //private SimpleTexture capeTexture; + + private long millisLastRenderUpdate = 0; + + private int horzNodes = 20; + private double targetDist = 1/30.0; + + private EntityPlayer player = null; + + private double vertOffset = 1.4; + private double shoulderLength = 0.3; + private double shoulderWidth = 0.13; + private double crouchWidthOffset = -0.05; + private double maxCrouchOffset = 0.35; + + private double resistance = 0.08; + private double gravity = 0.04; + private int steps = 10; + + private List<List<Node>> nodes = new ArrayList<>(); + + /*private void reloadCapeImage() { + if(capeTexture != null) { + capeTexture.deleteGlTexture(); + } + capeTexture = new SimpleTexture(capeImageLocation); + try { + capeTexture.loadTexture(Minecraft.getMinecraft().getResourceManager()); + } catch(IOException e) { + e.printStackTrace(); + } + }*/ + + private void resetNodes(EntityPlayer player) { + nodes.clear(); + for(int i=0; i<50; i++) { + List<Node> list = new ArrayList<>(); + for(int j=0; j<horzNodes; j++) { + if(horzNodes == 1) { + list.add(new Node(player.posX-1, player.posY+2-i*targetDist, player.posZ, i, j)); + } else if(horzNodes > 1) { + list.add(new Node(player.posX-1, player.posY+2-i*targetDist, player.posZ+((double)j)/(horzNodes-1), i, j)); + } + } + + nodes.add(list); + } + } + + class Node { + public int iIndex; + public int jIndex; + + public boolean fixed = false; + + public double x; + public double y; + public double z; + public double xOld; + public double yOld; + public double zOld; + public double aX; + public double aY; + public double aZ; + + public double normalX; + public double normalY; + public double normalZ; + + public Node(double x, double y, double z, int iIndex, int jIndex) { + this.x = xOld = x; + this.y = xOld = y; + this.z = xOld = z; + this.iIndex = iIndex; + this.jIndex = jIndex; + } + + private void updateNormal(Node up, Node left, Node right, Node down, Node up2, Node left2, Node right2, Node down2) { + Vec3 normal1 = normal(up, left); + Vec3 normal2 = normal(right, up); + Vec3 normal3 = normal(down, right); + Vec3 normal4 = normal(left, down); + Vec3 normal5 = normal(up2, left2); + Vec3 normal6 = normal(right2, up2); + Vec3 normal7 = normal(down2, right2); + Vec3 normal8 = normal(left2, down2); + + Vec3 avgNormal = normal1.add(normal2).add(normal3).add(normal4) + .add(normal5).add(normal6).add(normal7).add(normal8).normalize(); + + normalX = avgNormal.xCoord; + normalY = avgNormal.yCoord; + normalZ = avgNormal.zCoord; + } + + private Vec3 normal(Node node1, Node node2) { + if(node1 == null || node2 == null) { + return new Vec3(0,0,0); + } + Vec3 thisNode = node2vec(this); + Vec3 node1Vec = node2vec(node1); + Vec3 node2Vec = node2vec(node2); + + Vec3 thisTo1 = node1Vec.subtract(thisNode); + Vec3 thisTo2 = node2Vec.subtract(thisNode); + + return thisTo1.crossProduct(thisTo2); + + } + + public void update(double pX, double pY, double pZ, EntityPlayer player) { + if(fixed) { + return; + } + + double xTemp = x; + double yTemp = y; + double zTemp = z; + + double res = resistance; + + BlockPos pos = new BlockPos( + MathHelper.floor_double(x), + MathHelper.floor_double(y), + MathHelper.floor_double(z)); + Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); + if(block.getMaterial().isLiquid()) { + aX /= 5; + aY /= 5; + aZ /= 5; + + res = Math.sqrt(res); + } + + double xDiff = x-xOld; + double yDiff = y-yOld; + double zDiff = z-zOld; + + xDiff = MathHelper.clamp_double(xDiff, -0.5, 0.5); + yDiff = MathHelper.clamp_double(yDiff, -0.5, 0.5); + zDiff = MathHelper.clamp_double(zDiff, -0.5, 0.5); + + x = x + xDiff*(1-res)+aX*0.2; + y = y + yDiff*(1-res)+aY*0.2; + z = z + zDiff*(1-res)+aZ*0.2; + + resolvePlayerCollision(pX, pY, pZ, player); + + if(!checkCollision(xTemp, yTemp, zTemp)) { + xOld = xTemp; + yOld = yTemp; + zOld = zTemp; + } + + if(checkCollision(x, y, z)) { + updateFromBoundingBox(); + } + + aX = 0; + aY = 0; + aZ = 0; + } + + public boolean resolvePlayerCollision(double pX, double pY, double pZ, EntityPlayer player) { + double angle = Math.toRadians(player.renderYawOffset); + + double offset = 0; + + if(player.getCurrentArmor(1) != null) { + if(player.isSneaking()) { + offset += 0.15; + } else { + offset += 0.06; + } + } + + if(player.isSneaking()) { + offset -= crouchWidthOffset; + + double dY = y - player.posY; + + if(dY < 0.65) { + offset += maxCrouchOffset; + } else if(dY < 1.2) { + offset += maxCrouchOffset*(1.2-dY)/0.55; + } + } + + double x1 = pX+Math.cos(angle)*2-Math.cos(angle+Math.PI/2)*(shoulderWidth+offset); + double z1 = pZ+Math.sin(angle)*2-Math.sin(angle+Math.PI/2)*(shoulderWidth+offset); + double x2 = pX-Math.cos(angle)*2-Math.cos(angle+Math.PI/2)*(shoulderWidth+offset); + double z2 = pZ-Math.sin(angle)*2-Math.sin(angle+Math.PI/2)*(shoulderWidth+offset); + + boolean crossed = ((x2 - x1)*(z - z1) < (z2 - z1)*(x - x1)); + + if(crossed) { + double dot1 = ((x-x2)*(x1-x2)+(z-z2)*(z1-z2)); + double dot2 = (x1-x2)*(x1-x2)+(z1-z2)*(z1-z2); + double k = dot1/dot2; + + x = xOld = (x1-x2)*k+x2; + z = zOld = (z1-z2)*k+z2; + + return true; + } + return false; + } + + public void updateFromBoundingBox() { + BlockPos pos = new BlockPos( + MathHelper.floor_double(x), + MathHelper.floor_double(y), + MathHelper.floor_double(z)); + Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); + block.setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, pos); + AxisAlignedBB bb = block.getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, pos); + + Vec3 center = new Vec3((bb.minX + bb.maxX) / 2, (bb.minY + bb.maxY) / 2, (bb.minZ + bb.maxZ) / 2); + MovingObjectPosition mop = bb.calculateIntercept(center.add(new Vec3(x, y, z).subtract(center).normalize()), center); + + if(mop == null) { + return; + } + + Vec3 vec = mop.hitVec; + + if(vec == null) { + return; + } + + double dX = vec.xCoord - x; + double dY = vec.yCoord - y; + double dZ = vec.zCoord - z; + double adX = Math.abs(dX); + double adY = Math.abs(dY); + double adZ = Math.abs(dZ); + + double tot = adX + adY + adZ; + + //Simulate a little bit of friction + if(tot < 0.15 || checkCollision(vec.xCoord, vec.yCoord, vec.zCoord)) { + x = xOld; + y = yOld; + z = zOld; + return; + } + + //>0.3 check reduces the movement at corners a little bit + if(adX/tot > 0.3) x = xOld = vec.xCoord; + if(adY/tot > 0.3) y = yOld = vec.yCoord; + if(adZ/tot > 0.3) z = zOld = vec.zCoord; + } + + public boolean checkCollision(double x, double y, double z) { + BlockPos pos = new BlockPos( + MathHelper.floor_double(x), + MathHelper.floor_double(y), + MathHelper.floor_double(z)); + Block block = Minecraft.getMinecraft().theWorld.getBlockState(pos).getBlock(); + + if(block.getMaterial().isSolid()) { + block.setBlockBoundsBasedOnState(Minecraft.getMinecraft().theWorld, pos); + AxisAlignedBB bb = block.getSelectedBoundingBox(Minecraft.getMinecraft().theWorld, pos); + + return bb.isVecInside(new Vec3(x, y, z)); + } else { + return false; + } + } + } + + @SubscribeEvent + public void onRenderTick(TickEvent.RenderTickEvent e) { + if(Minecraft.getMinecraft().theWorld == null || player == null) { + return; + } + + long delta = System.currentTimeMillis() - millisLastRenderUpdate; + + double lagFactor = delta/(1000/60.0); + if(lagFactor > 3) { + lagFactor = 3; + } + + double playerX = player.lastTickPosX + (player.posX - player.lastTickPosX) * e.renderTickTime; + double playerY = player.lastTickPosY + (player.posY - player.lastTickPosY) * e.renderTickTime; + double playerZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * e.renderTickTime; + + updateFixedNodes(playerX, playerY, playerZ, player); + + for(List<Node> nodes2 : nodes) { + for(Node node : nodes2) { + node.aY -= gravity*lagFactor; + node.update(playerX, playerY, playerZ, player); + } + } + for(int step=0; step<steps*lagFactor; step++) { + for(int i=0; i<nodes.size(); i++) { + for (int j = 0; j < horzNodes; j++) { + Node node = nodes.get(i).get(j); + List<Node> struct = new ArrayList<>(); + List<Node> shear = new ArrayList<>(); + List<Node> bend = new ArrayList<>(); + + if(i+1 < nodes.size()) struct.add(nodes.get(i+1).get(j)); + if(j+1 < horzNodes) struct.add(nodes.get(i).get(j+1)); + if(i-1 >= 0) struct.add(nodes.get(i-1).get(j)); + if(j-1 >= 0) struct.add(nodes.get(i).get(j-1)); + + if(i+1 < nodes.size() && j+1 < horzNodes) shear.add(nodes.get(i+1).get(j+1)); + if(i+1 < nodes.size() && j-1 >= 0) shear.add(nodes.get(i+1).get(j-1)); + if(i-1 >= 0 && j+1 < horzNodes) shear.add(nodes.get(i-1).get(j+1)); + if(i-1 >= 0 && j-1 >= 0) shear.add(nodes.get(i-1).get(j-1)); + + if(i+2 < nodes.size()) bend.add(nodes.get(i+2).get(j)); + if(j+2 < horzNodes) bend.add(nodes.get(i).get(j+2)); + if(i-2 >= 0) bend.add(nodes.get(i-2).get(j)); + if(j-2 >= 0) bend.add(nodes.get(i).get(j-2)); + + try { + updateNode(node, struct, shear, bend); + } catch(Exception ex) { + + } + } + } + } + for(int i=0; i<nodes.size(); i++) { + for (int j = 0; j < horzNodes; j++) { + Node up = null, down = null, left = null, right = null; + Node up2 = null, down2 = null, left2 = null, right2 = null; + + if(i+1 < nodes.size()) down = nodes.get(i+1).get(j); + if(j+1 < horzNodes) right = nodes.get(i).get(j+1); + if(i-1 >= 0) up = nodes.get(i-1).get(j); + if(j-1 >= 0) left = nodes.get(i).get(j-1); + + if(i+2 < nodes.size()) down2 = nodes.get(i+2).get(j); + if(j+2 < horzNodes) right2 = nodes.get(i).get(j+2); + if(i-2 >= 0) up2 = nodes.get(i-2).get(j); + if(j-2 >= 0) left2 = nodes.get(i).get(j-2); + + nodes.get(i).get(j).updateNormal(up, left, right, down, up2, left2, right2, down2); + } + } + + millisLastRenderUpdate = System.currentTimeMillis(); + } + + @SubscribeEvent + public void onRenderPlayer(RenderPlayerEvent.Post e) { + EntityPlayer player = e.entityPlayer; + + if(!player.getName().equalsIgnoreCase("Moulberry")) { + return; + } + + if(nodes.size() == 0) { + resetNodes(player); + } + + this.player = player; + + Entity viewer = Minecraft.getMinecraft().getRenderViewEntity(); + + double viewerX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * e.partialRenderTick; + double viewerY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * e.partialRenderTick; + double viewerZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * e.partialRenderTick; + + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, + GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GL11.glDisable(GL11.GL_CULL_FACE); + GlStateManager.enableTexture2D(); + int currTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + //GL11.glBindTexture(GL11.GL_TEXTURE_2D, capeTexture.getGlTextureId()); + + //ShaderManager shaderManager = ShaderManager.getInstance(); + + //shaderManager.loadShader("cape"); + + for(int i=0; i<nodes.size(); i++) { + for(int j=0; j<horzNodes; j++) { + Node node = nodes.get(i).get(j); + if(i+1 < nodes.size() && j+1 < horzNodes) { + GlStateManager.color(1F, 1F, 1F, 1F); + renderNodeConnection(viewerX, viewerY, viewerZ, node, + nodes.get(i+1).get(j), nodes.get(i).get(j+1), + nodes.get(i+1).get(j+1), true); + GlStateManager.color(0.1F, 0.1F, 0.1F, 1F); + renderNodeConnection(viewerX, viewerY, viewerZ, node, + nodes.get(i+1).get(j), nodes.get(i).get(j+1), + nodes.get(i+1).get(j+1), false); + } + } + } + + GlStateManager.color(0.1F, 0.1F, 0.1F, 1F); + for(int i=0; i<nodes.size(); i++) { + if(i+1 < nodes.size()) { + renderSideConnection(viewerX, viewerY, viewerZ, + nodes.get(i).get(0), nodes.get(i+1).get(0)); + renderSideConnection(viewerX, viewerY, viewerZ, + nodes.get(i).get(horzNodes-1), nodes.get(i+1).get(horzNodes-1)); + } + } + + for(int j=0; j<horzNodes; j++) { + if(j+1 < horzNodes) { + renderSideConnection(viewerX, viewerY, viewerZ, + nodes.get(0).get(j), nodes.get(0).get(j+1)); + renderSideConnection(viewerX, viewerY, viewerZ, + nodes.get(nodes.size()-1).get(j), nodes.get(nodes.size()-1).get(j+1)); + } + } + + GL20.glUseProgram(0); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, currTex); + GL11.glEnable(GL11.GL_CULL_FACE); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + GlStateManager.popMatrix(); + GlStateManager.color(1F, 1F, 1F, 1F); + } + + private Vec3 node2vec(Node node) { + return new Vec3(node.x, node.y, node.z); + } + + private void renderSideConnection(double pX, double pY, double pZ, Node node1, Node node2) { + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + + worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_NORMAL); + + worldrenderer.pos(node1.x-pX, node1.y-pY, node1.z-pZ) + .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); + worldrenderer.pos(node2.x-pX, node2.y-pY, node2.z-pZ) + .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); + worldrenderer.pos(node1.x-pX+node1.normalX/15, node1.y-pY+node1.normalY/15, node1.z-pZ+node1.normalZ/15) + .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); + worldrenderer.pos(node2.x-pX+node2.normalX/15, node2.y-pY+node2.normalY/15, node2.z-pZ+node2.normalZ/15) + .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); + + tessellator.draw(); + } + + private void renderNodeConnection(double pX, double pY, double pZ, Node node1, Node node2, + Node node3, Node node4, boolean offset) { + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + + + //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(node1.normalY + " " + node2.normalY + " " + node3.normalY + " " + node4.normalY)); + + if(offset) { + worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_NORMAL); + + worldrenderer.pos(node1.x-pX+node1.normalX/15, node1.y-pY+node1.normalY/15, node1.z-pZ+node1.normalZ/15) + .tex(((double)node1.jIndex)/(horzNodes-1), ((double)node1.iIndex)/(nodes.size()-1)) + .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); + worldrenderer.pos(node2.x-pX+node2.normalX/15, node2.y-pY+node2.normalY/15, node2.z-pZ+node2.normalZ/15) + .tex(((double)node2.jIndex)/(horzNodes-1), ((double)node2.iIndex)/(nodes.size()-1)) + .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); + worldrenderer.pos(node3.x-pX+node3.normalX/15, node3.y-pY+node3.normalY/15, node3.z-pZ+node3.normalZ/15) + .tex(((double)node3.jIndex)/(horzNodes-1), ((double)node3.iIndex)/(nodes.size()-1)) + .normal((float)node3.normalX, (float)node3.normalY, (float)node3.normalZ).endVertex(); + worldrenderer.pos(node4.x-pX+node4.normalX/15, node4.y-pY+node4.normalY/15, node4.z-pZ+node4.normalZ/15) + .tex(((double)node4.jIndex)/(horzNodes-1), ((double)node4.iIndex)/(nodes.size()-1)) + .normal((float)node4.normalX, (float)node4.normalY, (float)node4.normalZ).endVertex(); + + } else { + worldrenderer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_NORMAL); + + worldrenderer.pos(node1.x-pX, node1.y-pY, node1.z-pZ) + .normal((float)node1.normalX, (float)node1.normalY, (float)node1.normalZ).endVertex(); + worldrenderer.pos(node2.x-pX, node2.y-pY, node2.z-pZ) + .normal((float)node2.normalX, (float)node2.normalY, (float)node2.normalZ).endVertex(); + worldrenderer.pos(node3.x-pX, node3.y-pY, node3.z-pZ) + .normal((float)node3.normalX, (float)node3.normalY, (float)node3.normalZ).endVertex(); + worldrenderer.pos(node4.x-pX, node4.y-pY, node4.z-pZ) + .normal((float)node4.normalX, (float)node4.normalY, (float)node4.normalZ).endVertex(); + } + + tessellator.draw(); + } + + private Vec3 scale(Vec3 vector, double amount) { + return new Vec3(vector.xCoord * amount, vector.yCoord * amount, vector.zCoord * amount); + } + + private void updateNode(Node node, List<Node> struct, List<Node> shear, List<Node> bend) { + double shearDist = 1.414*targetDist; + double bendDist = 2*targetDist; //Potentially differentiate between corners? + + for(Node bendNode : bend) { + resolve(node, bendNode, bendDist); + } + + for(Node shearNode : shear) { + resolve(node, shearNode, shearDist); + } + + for(Node structNode : struct) { + resolve(node, structNode, targetDist); + } + } + + public void resolve(Node node1, Node node2, double targetDist) { + double dX = node1.x - node2.x; + double dY = node1.y - node2.y; + double dZ = node1.z - node2.z; + + double distSq = dX*dX + dY*dY + dZ*dZ; + double dist = Math.sqrt(distSq); + + dX *= (1 - targetDist/dist)*0.5; + dY *= (1 - targetDist/dist)*0.5; + dZ *= (1 - targetDist/dist)*0.5; + + if(node1.fixed || node2.fixed) { + dX *= 2; + dY *= 2; + dZ *= 2; + } + + if(!node1.fixed) { + node1.x -= dX; + node1.y -= dY; + node1.z -= dZ; + } + + if(!node2.fixed) { + node2.x += dX; + node2.y += dY; + node2.z += dZ; + } + } + + private void updateFixedNodes(double pX, double pY, double pZ, EntityPlayer player) { + double angle = Math.toRadians(player.renderYawOffset); + + double shoulderWidth2 = shoulderWidth + (player.isSneaking()?crouchWidthOffset:0); + if(player.getCurrentArmor(1) != null || player.getCurrentArmor(2) != null) { + if(player.isSneaking()) { + shoulderWidth2 += 0.15; + } else { + shoulderWidth2 += 0.06; + } + } + + Node node = nodes.get(0).get(0); + node.x = pX+Math.cos(angle)*shoulderLength-Math.cos(angle+Math.PI/2)*shoulderWidth2; + node.y = pY+vertOffset-(player.isSneaking()?0.2:0); + node.z = pZ+Math.sin(angle)*shoulderLength-Math.sin(angle+Math.PI/2)*shoulderWidth2; + node.fixed = true; + + node = nodes.get(0).get(nodes.get(0).size()-1); + node.x = pX-Math.cos(angle)*shoulderLength-Math.cos(angle+Math.PI/2)*shoulderWidth2; + node.y = pY+vertOffset-(player.isSneaking()?0.2:0); + node.z = pZ-Math.sin(angle)*shoulderLength-Math.sin(angle+Math.PI/2)*shoulderWidth2; + node.fixed = true; + + + + /*for(int i=0; i<horzNodes; i++) { + Node node = nodes.get(0).get(i); + + node.x = pX-1; + node.y = pY+2; + node.z = pZ+((double)i)/(horzNodes-1); + }*/ + } + + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index f3263e0f..77d3be7f 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -223,12 +223,17 @@ public class NEUManager { } } - public JsonObject getAuctionPricesJson() { - return auctionPricesJson; + public boolean hasAuctionInfo(String internalname) { + return auctionPricesJson.has("item_data") && auctionPricesJson.get("item_data").getAsJsonObject().has(internalname); + } + + public boolean hasBazaarInfo(String internalname) { + return auctionPricesJson.has("bazaar") && auctionPricesJson.get("bazaar").getAsJsonObject().has(internalname); } public JsonObject getItemAuctionInfo(String internalname) { - JsonElement e = auctionPricesJson.get("prices").getAsJsonObject().get(internalname); + if(!hasAuctionInfo(internalname)) return null; + JsonElement e = auctionPricesJson.get("item_data").getAsJsonObject().get(internalname); if(e == null) { return null; } @@ -236,6 +241,7 @@ public class NEUManager { } public JsonObject getBazaarInfo(String internalname) { + if(!hasBazaarInfo(internalname)) return null; JsonElement e = auctionPricesJson.get("bazaar").getAsJsonObject().get(internalname); if(e == null) { return null; @@ -463,8 +469,13 @@ public class NEUManager { return; } + if(json.get("itemid") == null) return; + String itemid = json.get("itemid").getAsString(); - itemid = Item.getByNameOrId(itemid).getRegistryName(); + Item mcitem = Item.getByNameOrId(itemid); + if(mcitem != null) { + itemid = mcitem.getRegistryName(); + } json.addProperty("itemid", itemid); itemMap.put(internalName, json); @@ -787,14 +798,36 @@ public class NEUManager { } public String getInternalnameFromNBT(NBTTagCompound tag) { - String internalname = "UNKNOWN"; + String internalname = null; if(tag != null && tag.hasKey("ExtraAttributes", 10)) { NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); if(ea.hasKey("id", 8)) { - internalname = ea.getString("id"); + internalname = ea.getString("id").replaceAll(":", "-"); + } + + if("PET".equals(internalname)) { + String petInfo = ea.getString("petInfo"); + if(petInfo.length() > 0) { + JsonObject petInfoObject = gson.fromJson(petInfo, JsonObject.class); + internalname = petInfoObject.get("type").getAsString(); + String tier = petInfoObject.get("tier").getAsString(); + switch(tier) { + case "COMMON": + internalname += ";0"; break; + case "UNCOMMON": + internalname += ";1"; break; + case "RARE": + internalname += ";2"; break; + case "EPIC": + internalname += ";3"; break; + case "LEGENDARY": + internalname += ";4"; break; + } + } } } + return internalname; } @@ -934,15 +967,7 @@ public class NEUManager { public String getInternalNameForItem(ItemStack stack) { NBTTagCompound tag = stack.getTagCompound(); - //Internal id - if(tag != null && tag.hasKey("ExtraAttributes", 10)) { - NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); - - if(ea.hasKey("id", 8)) { - return ea.getString("id").replaceAll(":", "-"); - } - } - return null; + return getInternalnameFromNBT(tag); } //Currently unused in production. diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java index 1d50daa6..475f6a99 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java @@ -346,7 +346,7 @@ public class NEUOverlay extends Gui { Utils.playPressSound(); return true; } else { - ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command); + ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/"+command); //Need to add '/' because of sk1er's patcher being unbelievably shit Utils.playPressSound(); return true; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index 32cd5980..8d01e9a9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -14,6 +14,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.inventory.*; +import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.settings.KeyBinding; import net.minecraft.command.ICommandSender; import net.minecraft.init.Blocks; @@ -43,7 +44,6 @@ 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.*; @@ -98,11 +98,16 @@ public class NotEnoughUpdates { 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)) { - openGui = new GuiInventory(Minecraft.getMinecraft().thePlayer); + if(!OpenGlHelper.isFramebufferEnabled()) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED+ + "This feature requires FBOs to work. Try disabling Optifine's 'Fast Render'.")); + } else { + if(!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) { + openGui = new GuiInventory(Minecraft.getMinecraft().thePlayer); + } + manager.updatePrices(); + overlay.displayInformationPane(new CollectionLogInfoPane(overlay, manager)); } - manager.updatePrices(); - overlay.displayInformationPane(new CollectionLogInfoPane(overlay, manager)); } }); @@ -131,6 +136,7 @@ public class NotEnoughUpdates { public void preinit(FMLPreInitializationEvent event) { INSTANCE = this; MinecraftForge.EVENT_BUS.register(this); + //MinecraftForge.EVENT_BUS.register(new NEUCape()); File f = new File(event.getModConfigurationDirectory(), "notenoughupdates"); f.mkdirs(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/AuctionManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/AuctionManager.java index 543b4c8e..3f87f774 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/auction/AuctionManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/AuctionManager.java @@ -9,6 +9,8 @@ import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; import net.minecraft.util.EnumChatFormatting; import java.io.ByteArrayInputStream; @@ -222,6 +224,8 @@ public class AuctionManager { lastApiUpdate = lastUpdated; + String[] lvl4Maxes = {"Experience", "Life Steal", "Scavenger", "Looting"}; + String[] categoryItemType = new String[]{"sword","fishingrod","pickaxe","axe", "shovel","petitem","travelscroll","reforgestone","bow"}; String playerUUID = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replaceAll("-",""); @@ -244,68 +248,93 @@ public class AuctionManager { String sbCategory = auction.get("category").getAsString(); String extras = auction.get("extra").getAsString(); String item_name = auction.get("item_name").getAsString(); - String item_lore = auction.get("item_lore").getAsString(); + String item_lore = Utils.fixBrokenAPIColour(auction.get("item_lore").getAsString()); String item_bytes = auction.get("item_bytes").getAsString(); String rarity = auction.get("tier").getAsString(); JsonArray bids = auction.get("bids").getAsJsonArray(); - NBTTagCompound item_tag; + + for(String lvl4Max : lvl4Maxes) { + item_lore = item_lore.replaceAll("\\u00A79("+lvl4Max+" IV)", EnumChatFormatting.DARK_PURPLE+"$1"); + } + item_lore = item_lore.replaceAll("\\u00A79([A-Za-z ]+ VI)", EnumChatFormatting.DARK_PURPLE+"$1"); + item_lore = item_lore.replaceAll("\\u00A79([A-Za-z ]+ VII)", EnumChatFormatting.RED+"$1"); + try { - item_tag = CompressedStreamTools.readCompressed( - new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes))); - } catch(IOException e) { continue; } - - NBTTagCompound tag = item_tag.getTagList("i", 10).getCompoundTagAt(0).getCompoundTag("tag"); - String internalname = manager.getInternalnameFromNBT(tag); - - for(String str : extras.substring(item_name.length()).split(" ")) { - str = Utils.cleanColour(str).toLowerCase(); - if(str.length() > 0) { - HashSet<String> aucids = extrasToAucIdMap.computeIfAbsent(str, k -> new HashSet<>()); - aucids.add(auctionUuid); + NBTTagCompound item_tag; + try { + item_tag = CompressedStreamTools.readCompressed( + new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes))); + } catch(IOException e) { continue; } + + NBTTagCompound tag = item_tag.getTagList("i", 10).getCompoundTagAt(0).getCompoundTag("tag"); + String internalname = manager.getInternalnameFromNBT(tag); + String displayNormal = ""; + if(manager.getItemInformation().containsKey(internalname)) { + displayNormal = Utils.cleanColour(manager.getItemInformation().get(internalname).get("displayname").getAsString()); } - } - for(int j=0; j<bids.size(); j++) { - JsonObject bid = bids.get(j).getAsJsonObject(); - if(bid.get("bidder").getAsString().equalsIgnoreCase(playerUUID)) { - playerBids.add(auctionUuid); + String[] lore = new String[0]; + NBTTagCompound display = tag.getCompoundTag("display"); + if(display.hasKey("Lore", 9)) { + NBTTagList loreList = new NBTTagList(); + for(String line : item_lore.split("\n")) { + loreList.appendTag(new NBTTagString(line)); + } + display.setTag("Lore", loreList); + } + tag.setTag("display", display); + item_tag.getTagList("i", 10).getCompoundTagAt(0).setTag("tag", tag); + + for(String str : extras.replaceAll(displayNormal, "").split(" ")) { + str = Utils.cleanColour(str).toLowerCase(); + if(str.length() > 0) { + HashSet<String> aucids = extrasToAucIdMap.computeIfAbsent(str, k -> new HashSet<>()); + aucids.add(auctionUuid); + } } - } - //Categories - String category = sbCategory; - int itemType = checkItemType(item_lore, "SWORD", "FISHING ROD", "PICKAXE", - "AXE", "SHOVEL", "PET ITEM", "TRAVEL SCROLL", "REFORGE STONE", "BOW"); - if(itemType >= 0 && itemType < categoryItemType.length) { - category = categoryItemType[itemType]; - } - if(extras.startsWith("Enchanted Book")) category = "ebook"; - if(extras.endsWith("Potion")) category = "potion"; - if(extras.contains("Rune")) category = "rune"; - if(item_lore.split("\n")[0].endsWith("Furniture")) category = "furniture"; - if(item_lore.split("\n")[0].endsWith("Pet") || - item_lore.split("\n")[0].endsWith("Mount")) category = "pet"; - - Auction auction1 = new Auction(auctioneerUuid, end, starting_bid, highest_bid_amount, - bid_count, bin, category, rarity, item_tag); - - if(tag.hasKey("ench")) { - auction1.enchLevel = 1; - if(tag.hasKey("ExtraAttributes", 10)) { - NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); - - int hotpotatocount = ea.getInteger("hot_potato_count"); - if(hotpotatocount == 10) { - auction1.enchLevel = 2; + for(int j=0; j<bids.size(); j++) { + JsonObject bid = bids.get(j).getAsJsonObject(); + if(bid.get("bidder").getAsString().equalsIgnoreCase(playerUUID)) { + playerBids.add(auctionUuid); + } + } + + //Categories + String category = sbCategory; + int itemType = checkItemType(item_lore, "SWORD", "FISHING ROD", "PICKAXE", + "AXE", "SHOVEL", "PET ITEM", "TRAVEL SCROLL", "REFORGE STONE", "BOW"); + if(itemType >= 0 && itemType < categoryItemType.length) { + category = categoryItemType[itemType]; + } + if(extras.startsWith("Enchanted Book")) category = "ebook"; + if(extras.endsWith("Potion")) category = "potion"; + if(extras.contains("Rune")) category = "rune"; + if(item_lore.split("\n")[0].endsWith("Furniture")) category = "furniture"; + if(item_lore.split("\n")[0].endsWith("Pet") || + item_lore.split("\n")[0].endsWith("Mount")) category = "pet"; + + Auction auction1 = new Auction(auctioneerUuid, end, starting_bid, highest_bid_amount, + bid_count, bin, category, rarity, item_tag); + + if(tag.hasKey("ench")) { + auction1.enchLevel = 1; + if(tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + int hotpotatocount = ea.getInteger("hot_potato_count"); + if(hotpotatocount == 10) { + auction1.enchLevel = 2; + } } } - } - auction1.lastUpdate = System.currentTimeMillis(); + auction1.lastUpdate = System.currentTimeMillis(); - auctionMap.put(auctionUuid, auction1); - internalnameToAucIdMap.computeIfAbsent(internalname, k -> new HashSet<>()).add(auctionUuid); + auctionMap.put(auctionUuid, auction1); + internalnameToAucIdMap.computeIfAbsent(internalname, k -> new HashSet<>()).add(auctionUuid); + } catch(Exception e) {e.printStackTrace();} } processMillis = (int)(System.currentTimeMillis() - startProcess); } 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 9fad4e99..047ca5af 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/Options.java @@ -38,6 +38,11 @@ public class Options { "Quick Commands", false, "Shows QuickCommands™ above search bar."); + public Option<Boolean> tooltipBorderColours = new Option( + true, + "Coloured Tooltip Borders", + false, + "Makes the border of tooltips coloured. (Only NEU Tooltips)"); public Option<Boolean> advancedPriceInfo = new Option( false, "Adv. Item Price Info", @@ -170,6 +175,8 @@ public class Options { tryAddOption(advancedPriceInfo, options); tryAddOption(cacheRenderedItempane, options); tryAddOption(streamerMode, options); + tryAddOption(showQuickCommands, options); + tryAddOption(tooltipBorderColours, options); tryAddOption(hideApiKey, options); tryAddOption(autoupdate, options); tryAddOption(keepopen, options); 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 2084c609..639449c0 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -3,6 +3,7 @@ package io.github.moulberry.notenoughupdates.util; import com.mojang.authlib.Agent; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.util.TexLoc; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; @@ -21,6 +22,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Session; import org.lwjgl.input.Keyboard; @@ -28,6 +30,7 @@ import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL14; import javax.swing.*; +import java.awt.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -123,7 +126,11 @@ public class Utils { } public static String cleanColour(String in) { - return in.replaceAll("(?i)\\u00A7.", ""); + return in.replaceAll("(?i)\\u00C2\\u00A7.", "").replaceAll("(?i)\\u00A7.", ""); + } + + public static String fixBrokenAPIColour(String in) { + return in.replaceAll("(?i)\\u00C2(\\u00A7.)", "$1"); } public static String prettyCase(String str) { @@ -334,6 +341,10 @@ public class Utils { } public static void drawHoveringText(List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font) { + drawHoveringText(textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, font, true); + } + + 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()) { GlStateManager.disableRescaleNormal(); @@ -438,7 +449,43 @@ public class Utils { drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); drawGradientRect(zLevel, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - final int borderColorStart = 0x505000FF; + //TODO: Coloured Borders + int borderColorStart = 0x505000FF; + if(NotEnoughUpdates.INSTANCE.manager.config.tooltipBorderColours.value) { + if(textLines.size() > 0) { + String first = textLines.get(0); + int lastColourCode = -99; + int currentColour = 0; + int[] mostCommon = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + for(int i=0; i<first.length(); i++) { + char c = first.charAt(i); + if(c == '\u00A7') { + lastColourCode = i; + } else if(lastColourCode == i-1) { + int colIndex = "0123456789abcdef".indexOf(c); + if(colIndex >= 0) { + currentColour = colIndex; + } else { + currentColour = 0; + } + } else if("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(c) >= 0){ + if(currentColour > 0) { + mostCommon[currentColour]++; + } + } + } + int mostCommonCount = 0; + for(int index=0; index<mostCommon.length; index++) { + if(mostCommon[index] > mostCommonCount) { + mostCommonCount = mostCommon[index]; + currentColour = index; + } + } + + int colourInt = font.getColorCode("0123456789abcdef".charAt(currentColour)); + borderColorStart = new Color(colourInt).darker().getRGB() & 0x00FFFFFF | 0x80000000; + } + } final int borderColorEnd = (borderColorStart & 0xFEFEFE) >> 1 | borderColorStart & 0xFF000000; drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); |