diff --git a/src/main/java/noppes/npcs/client/ClientTickHandler.java b/src/main/java/noppes/npcs/client/ClientTickHandler.java index 33e979c89..e66bf90e6 100644 --- a/src/main/java/noppes/npcs/client/ClientTickHandler.java +++ b/src/main/java/noppes/npcs/client/ClientTickHandler.java @@ -11,17 +11,27 @@ import kamkeel.npcs.network.packets.player.InputDevicePacket; import kamkeel.npcs.network.packets.player.ScreenSizePacket; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.ContainerPlayer; import net.minecraft.world.World; import noppes.npcs.CustomNpcs; import noppes.npcs.client.controllers.MusicController; import noppes.npcs.client.controllers.ScriptSoundController; +import noppes.npcs.client.gui.hud.ClientHudManager; +import noppes.npcs.client.gui.hud.CompassHudComponent; +import noppes.npcs.client.gui.hud.EnumHudComponent; +import noppes.npcs.client.gui.hud.HudComponent; import noppes.npcs.client.gui.player.inventory.GuiCNPCInventory; import noppes.npcs.client.renderer.RenderNPCInterface; +import noppes.npcs.constants.MarkType; +import noppes.npcs.controllers.data.MarkData; +import noppes.npcs.entity.EntityNPCInterface; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import tconstruct.client.tabs.InventoryTabCustomNpc; +import java.util.ArrayList; + import static noppes.npcs.client.ClientEventHandler.renderCNPCPlayer; public class ClientTickHandler{ @@ -77,6 +87,13 @@ public class ClientTickHandler{ prevHeight = mc.displayHeight; PacketClient.sendClient(new ScreenSizePacket(mc.displayWidth,mc.displayHeight)); } + + if(mc.theWorld == null) + return; + + if(mc.theWorld.getTotalWorldTime() % 20 == 0) { // Update every second + updateCompassMarks(); + } } @SubscribeEvent @@ -119,4 +136,44 @@ public class ClientTickHandler{ return false; } + + private final int SCAN_RANGE = 128; + private void updateCompassMarks() { + Minecraft mc = Minecraft.getMinecraft(); + EntityPlayer player = mc.thePlayer; + ArrayList marks = new ArrayList<>(); + + // Scan entities in loaded chunks + for(Object entity : mc.theWorld.loadedEntityList) { + if(entity instanceof EntityNPCInterface) { + EntityNPCInterface npc = (EntityNPCInterface) entity; + + // Check distance + if(player.getDistanceToEntity(npc) > SCAN_RANGE) + continue; + + // Get marks + MarkData markData = MarkData.get(npc); + for(MarkData.Mark mark : markData.marks) { + if(mark.getType() != MarkType.NONE && + mark.availability.isAvailable(player)) { + marks.add(new CompassHudComponent.MarkTargetEntry( + (int)npc.posX, + (int)npc.posZ, + mark.getType(), + mark.color + )); + break; // Only show first valid mark per NPC + } + } + } + } + + // Update compass + HudComponent compass = ClientHudManager.getInstance() + .getHudComponents().get(EnumHudComponent.QuestCompass); + if(compass != null) { + ((CompassHudComponent) compass).updateMarkTargets(marks); + } + } } diff --git a/src/main/java/noppes/npcs/client/gui/hud/CompassHudComponent.java b/src/main/java/noppes/npcs/client/gui/hud/CompassHudComponent.java index 87ab0532e..67d1e50d3 100644 --- a/src/main/java/noppes/npcs/client/gui/hud/CompassHudComponent.java +++ b/src/main/java/noppes/npcs/client/gui/hud/CompassHudComponent.java @@ -2,31 +2,37 @@ package noppes.npcs.client.gui.hud; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; import noppes.npcs.config.ConfigClient; +import noppes.npcs.constants.MarkType; import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.List; public class CompassHudComponent extends HudComponent { private final Minecraft mc; - private final List targets = new ArrayList<>(); + private final List markTargets = new ArrayList<>(); private final int BAR_HEIGHT = 20; private final int BASE_ICON_SIZE = 8; private final int MAX_ICON_SIZE = 16; private final int SCALE_DISTANCE_MIN = 10; private final int SCALE_DISTANCE_MAX = 40; private static final int HANDLE_SIZE = 10; + private final int SCAN_RANGE = 128; - public static class TargetEntry { + public static class MarkTargetEntry { public int x, z; + public int type; public int color; - public TargetEntry(int x, int z, int color) { + public MarkTargetEntry(int x, int z, int type, int color) { this.x = x; this.z = z; + this.type = type; this.color = color; } } @@ -40,17 +46,18 @@ public class CompassHudComponent extends HudComponent { @Override public void loadData(NBTTagCompound compound) { - targets.clear(); - NBTTagList list = compound.getTagList("Targets", 10); + markTargets.clear(); + NBTTagList list = compound.getTagList("MarkTargets", 10); for(int i = 0; i < list.tagCount(); i++) { NBTTagCompound entry = list.getCompoundTagAt(i); - targets.add(new TargetEntry( + markTargets.add(new MarkTargetEntry( entry.getInteger("x"), entry.getInteger("z"), + entry.getInteger("type"), entry.getInteger("color") )); } - hasData = !targets.isEmpty(); + hasData = !markTargets.isEmpty(); } @Override @@ -63,7 +70,6 @@ public class CompassHudComponent extends HudComponent { @Override public void save() { - // Save to config ConfigClient.CompassOverlayX = posX; ConfigClient.CompassOverlayY = posY; ConfigClient.CompassOverlayScale = scale; @@ -73,7 +79,7 @@ public class CompassHudComponent extends HudComponent { @Override public void renderOnScreen(float partialTicks) { - if (!hasData || isEditting) return; +// if (!hasData || isEditting) return; ScaledResolution res = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); int actualX = (int)((float) posX / 100F * res.getScaledWidth()); @@ -87,49 +93,92 @@ public class CompassHudComponent extends HudComponent { // Draw background bar drawRect(0, 0, overlayWidth, BAR_HEIGHT, 0x80000000); - // Render all targets - for(TargetEntry target : targets) { - renderTargetIcon(target); + // Render all marks + for(MarkTargetEntry mark : markTargets) { + renderMarkIcon(mark); } GL11.glPopMatrix(); } - private void renderTargetIcon(TargetEntry target) { + private void renderMarkIcon(MarkTargetEntry mark) { if (mc.thePlayer == null) return; - // Calculate position on bar - float iconPos = calculateIconPosition(target.x, target.z); - int barWidth = overlayWidth; + Float iconPos = calculateIconPosition(mark.x, mark.z); + if(iconPos == null) { + // Target is behind the player; don't render. + return; + } - // Calculate dynamic size + int barWidth = overlayWidth; float distance = (float) Math.sqrt( - Math.pow(target.x - mc.thePlayer.posX, 2) + - Math.pow(target.z - mc.thePlayer.posZ, 2) + Math.pow(mark.x - mc.thePlayer.posX, 2) + + Math.pow(mark.z - mc.thePlayer.posZ, 2) ); int iconSize = calculateIconSize(distance); - int iconX = MathHelper.clamp_int((int)iconPos, iconSize/2, barWidth - iconSize/2); - - // Calculate vertical position + int iconX = MathHelper.clamp_int((int)iconPos.floatValue(), iconSize/2, barWidth - iconSize/2); int iconY = (BAR_HEIGHT - iconSize)/2; - // Draw icon - drawRect(iconX - iconSize/2, iconY, - iconX + iconSize/2, iconY + iconSize, target.color); + ResourceLocation texture = getTextureForMark(mark.type); + if(texture != null) { + renderTextureIcon(iconX - iconSize/2, iconY, iconSize, texture, mark.color); + } } - private float calculateIconPosition(double targetX, double targetZ) { + private ResourceLocation getTextureForMark(int type) { + switch(type) { + case MarkType.EXCLAMATION: return new ResourceLocation("customnpcs", "textures/marks/exclamation.png"); + case MarkType.QUESTION: return new ResourceLocation("customnpcs", "textures/marks/question.png"); + case MarkType.POINTER: return new ResourceLocation("customnpcs", "textures/marks/pointer.png"); + case MarkType.CROSS: return new ResourceLocation("customnpcs", "textures/marks/cross.png"); + case MarkType.SKULL: return new ResourceLocation("customnpcs", "textures/marks/skull.png"); + case MarkType.STAR: return new ResourceLocation("customnpcs", "textures/marks/star.png"); + default: return null; + } + } + + private void renderTextureIcon(int x, int y, int size, ResourceLocation texture, int color) { + float red = (color >> 16 & 255) / 255.0F; + float green = (color >> 8 & 255) / 255.0F; + float blue = (color & 255) / 255.0F; + + GL11.glPushMatrix(); + GL11.glColor4f(red, green, blue, 1); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + mc.getTextureManager().bindTexture(texture); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(x, y + size, 0, 0, 1); + tessellator.addVertexWithUV(x + size, y + size, 0, 1, 1); + tessellator.addVertexWithUV(x + size, y, 0, 1, 0); + tessellator.addVertexWithUV(x, y, 0, 0, 0); + tessellator.draw(); + + GL11.glColor4f(1, 1, 1, 1); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopMatrix(); + } + + private Float calculateIconPosition(double targetX, double targetZ) { double dx = targetX - mc.thePlayer.posX; double dz = targetZ - mc.thePlayer.posZ; + double angleToTarget = Math.toDegrees(Math.atan2(dz, dx)); + double adjustedPlayerYaw = mc.thePlayer.rotationYaw + 90; + double relativeAngle = angleToTarget - adjustedPlayerYaw; + while(relativeAngle < -180) relativeAngle += 360; + while(relativeAngle > 180) relativeAngle -= 360; - double angle = Math.toDegrees(Math.atan2(dz, dx)) - 90; - angle = (angle + 360) % 360; + // Only render if the target is within 90° to either side (180° front) + if (Math.abs(relativeAngle) > 90) { + return null; + } - double playerYaw = (mc.thePlayer.rotationYaw % 360 + 360) % 360; - double relativeAngle = (angle - playerYaw + 360) % 360; - - return (float)(relativeAngle / 360.0 * overlayWidth); + // Map -90..90 to 0..overlayWidth so that 0 becomes the left edge and 90 the right edge. + return (float)(overlayWidth / 2.0 + (relativeAngle / 90.0) * (overlayWidth / 2.0)); } private int calculateIconSize(float distance) { @@ -153,50 +202,38 @@ public class CompassHudComponent extends HudComponent { GL11.glTranslatef(actualX, actualY, 0); GL11.glScalef(scaleFactor, scaleFactor, scaleFactor); - // Draw editor background and handles drawRect(0, 0, overlayWidth, overlayHeight, 0x80000000); drawRectOutline(0, 0, overlayWidth, overlayHeight, 0xFF00FF00); - - // Add resize handle (bottom-right corner) drawRect(overlayWidth - HANDLE_SIZE, overlayHeight - HANDLE_SIZE, overlayWidth, overlayHeight, 0xFFCCCCCC); - // Demo targets - renderDemoIcon(overlayWidth * 0.25f, 0xFF0000FF); - renderDemoIcon(overlayWidth * 0.75f, 0xFF00FF00); + // Demo marks + renderDemoIcon(overlayWidth * 0.25f, MarkType.EXCLAMATION, 0xFF00FF00); + renderDemoIcon(overlayWidth * 0.75f, MarkType.QUESTION, 0xFFFF0000); GL11.glPopMatrix(); } - private void renderDemoIcon(float position, int color) { - // Animate size + private void renderDemoIcon(float position, int type, int color) { float pulse = (System.currentTimeMillis() % 1000) / 1000f; int size = (int)(BASE_ICON_SIZE + (MAX_ICON_SIZE - BASE_ICON_SIZE) * pulse); + ResourceLocation texture = getTextureForMark(type); - int iconX = (int)position - size/2; - int iconY = (BAR_HEIGHT - size)/2; - drawRect(iconX, iconY, iconX + size, iconY + size, color); - } - - // Management methods - public void addTarget(int x, int z, int color) { - targets.add(new TargetEntry(x, z, color)); - hasData = true; - } - - public void removeTarget(int index) { - if(index >= 0 && index < targets.size()) { - targets.remove(index); - hasData = !targets.isEmpty(); + if(texture != null) { + GL11.glPushMatrix(); + GL11.glTranslatef(position - size/2, (BAR_HEIGHT - size)/2, 0); + renderTextureIcon(0, 0, size, texture, color); + GL11.glPopMatrix(); } } - public void clearTargets() { - targets.clear(); - hasData = false; + public void updateMarkTargets(List newMarks) { + markTargets.clear(); + markTargets.addAll(newMarks); + hasData = !markTargets.isEmpty(); } - // Helper drawing methods (same as in QuestTrackingComponent) + // Helper drawing methods private void drawRect(int left, int top, int right, int bottom, int color) { net.minecraft.client.gui.Gui.drawRect(left, top, right, bottom, color); }