From 5cf9b26a2ebb0a031491ba7957ef80f2403142ab Mon Sep 17 00:00:00 2001 From: Kam Date: Wed, 11 Mar 2026 17:39:21 -0400 Subject: [PATCH 01/38] Add Changelog --- CHANGELOG.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..873018f92 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,98 @@ +# CustomNPC+ 1.11 Changelog + +## Ability System +- Phase-based abilities (Wind-up, Active, Dazed) with configurable cooldowns, targeting, range, interrupts, invulnerability, and magic damage +- **Melee:** Slam, Heavy Hit, Cutter +- **Energy Projectiles:** Orb, Disc, Beam, Laser Shot with variant system, homing, hit types (Single/Pierce/Multi), size interpolation, explosions +- **Barriers:** Dome, Wall, Shield with HP, reflection, damage absorption +- **Defensive:** Guard, Counter, Dodge +- **Movement:** Charge, Dash, Teleport +- **AOE:** Shockwave, Sweeper, Vortex +- **Hazards & Traps:** Persistent zones and proximity triggers with visual presets +- **Effect:** Healing, buffs, debuffs with target filtering (Allies/Enemies/All) +- **Custom Ability:** Blank-slate type with full script hooks and toggle modes +- Burst system, chained ability combos with concurrency, telegraph system (6 shapes) +- Per-phase animations and sound events +- Ability conditions: HP Threshold, Hit Count, Has Item, Quest Completed, Has Effect +- 12-slot player ability hotbar with HUD editor +- Full scripting API for ability and energy projectile lifecycle events +- Ability Extender system for custom hooks +- Live preview in editor +- Commands: `/kam ability list|types|prebuilts|info|delete|reload|give|remove|giveChain|removeChain|player` + +## Auction House +- Global marketplace with bidding, buyout, and snipe protection +- Built-in currency system (configurable, profile-persistent, Vault support) +- Listing fees, sales tax, minimum prices +- My Trades panel with claim management (20-day expiry) +- Search/sort, notifications (online + offline summary) +- Trade slots (default 8, expandable via permissions) +- Item blacklist (by item, wildcard, mod, NBT; soulbound always blocked) +- Auctioneer NPC role +- Admin GUI and logging +- Cancelable scripting events: Create, Bid, Buyout, Cancel, Claim + +## Script Editor +- Full code editor with syntax highlighting, autocomplete, error detection, and hover tooltips +- Go to Line, Search/Replace, Go to Definition, Fullscreen +- Undo/Redo, Duplicate Line, Comment Toggle, Rename, Move Lines +- Line numbers, smooth scrolling, indent guides, brace matching, smart brackets + +## Java Scripting +- Write scripts in Java via Janino compiler with automatic hook resolution +- Per-tab language selector (mix Java and JavaScript) +- External `.java` file support + +## Client-Side Scripting +- Server-controlled client script execution with auto-sync (off by default) + +## Addon API Support +- Ship `.d.ts` type definitions for automatic script editor autocomplete +- Patch support for extending CNPC+ types, hot reload + +## Traders +- Stock system: Global or Per-Player modes with configurable restock timers +- Currency trades (items + coins) +- Client-side balance preview + +## Cloner +- Folder and subfolder organization for all categories +- Full-width directory browser, improved tabs, tag-based filtering + +## Animations +- Data store for passing data across events/frames +- Consumer-based task system +- Expanded scripting API + +## Animated Textures +- Frame-based animation for items, effect icons, ability hotbar, scripted GUIs + +## NPC API +- `IHitboxData` (width/height scaling), `ITintData` (hurt tint, persistent tints) +- Scriptable behavior: sprint, swim, doors, fire reactions, tactical chance, walking range +- `ISound` (volume, pitch, repeat, position) +- Skin overlay `getColor()`/`setColor()`, knockback API +- Six overlays in singleplayer, script error reporting to console + +## NPC Combat & Behavior +- Attack speed enforcement, passive faction protection +- Improved track speed, invalid texture fallback + +## Other Changes +- Player Dialog Events match NPC Dialog Events +- Linked Item attack speed and scripting API +- Right-click cycling on multi-option buttons +- Legacy quest import (1.6.4), fullscreen/pannable GUIs, unified menu background +- Textfield CTRL shortcuts, `java.lang.reflect` banned in scripts +- Entity packet loss fix (invisible NPCs) +- Natural spawn GUI, runtime control, and despawn improvements + +## Bug Fixes +- Script config sync, Bukkit integration +- Quest cooldown for MC/RL Custom timers, quest/dialog saving and categories +- Bard music restart on dialog open +- Spawner yaw, biome spawn persistence, NPC invisibility +- Track speed, set speed edge cases, spawn data, block waypoints, job spawner +- Hitbox scaling and collision +- Animation offsets, lookup failures, syncing, resync on teleport, registration names, double loading +- Mount movement jitter, dismount edge cases From 15749c8ad7ed6bcd0ed2830e18bf7ae3fb5999b1 Mon Sep 17 00:00:00 2001 From: Kam Date: Wed, 11 Mar 2026 21:42:27 -0400 Subject: [PATCH 02/38] Profile Sync Quest Data Crash Fix --- .../npcs/controllers/ProfileController.java | 11 ++++ .../npcs/controllers/SyncController.java | 2 + .../kamkeel/npcs/network/PacketHandler.java | 1 + .../npcs/network/enums/EnumDataPacket.java | 3 + .../data/ProfileSharedQuestPacket.java | 57 +++++++++++++++++++ .../npcs/client/ClientCacheHandler.java | 1 + .../npcs/client/ProfileClientConfig.java | 41 +++++++++++++ .../controllers/PlayerQuestController.java | 16 +++++- .../npcs/controllers/ProfileConfigSync.java | 34 +++++++++++ .../noppes/npcs/controllers/data/Quest.java | 21 +++++-- 10 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java create mode 100644 src/main/java/noppes/npcs/client/ProfileClientConfig.java create mode 100644 src/main/java/noppes/npcs/controllers/ProfileConfigSync.java diff --git a/src/main/java/kamkeel/npcs/controllers/ProfileController.java b/src/main/java/kamkeel/npcs/controllers/ProfileController.java index fcb3436af..c4be7322e 100644 --- a/src/main/java/kamkeel/npcs/controllers/ProfileController.java +++ b/src/main/java/kamkeel/npcs/controllers/ProfileController.java @@ -7,7 +7,9 @@ import kamkeel.npcs.controllers.data.profile.Profile; import kamkeel.npcs.controllers.data.profile.ProfileInfoEntry; import kamkeel.npcs.controllers.data.profile.ProfileOperation; import kamkeel.npcs.controllers.data.profile.Slot; +import kamkeel.npcs.network.packets.data.ProfileSharedQuestPacket; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.CustomNpcs; @@ -453,6 +455,9 @@ public class ProfileController implements IProfileHandler { PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player); verifySlotQuests(profile.player); save(profile.player, profile); + if (profile.player instanceof EntityPlayerMP) { + ProfileSharedQuestPacket.sendToPlayer((EntityPlayerMP) profile.player); + } IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player); EventHooks.onProfileCreate(handler, scriptPlayer, profile, newSlotId, true); @@ -524,6 +529,9 @@ public class ProfileController implements IProfileHandler { saveSlotData(profile.player, profile, prevSlot); loadSlotData(profile.player, profile, newSlotId); syncSharedQuestsToPlayer(profile.player); + if (profile.player instanceof EntityPlayerMP) { + ProfileSharedQuestPacket.sendToPlayer((EntityPlayerMP) profile.player); + } EventHooks.onProfileChange(handler, scriptPlayer, profile, newSlotId, prevSlot, true); } else { @@ -901,5 +909,8 @@ public class ProfileController implements IProfileHandler { profile.sharedQuestTimestamps.put(questId, completeTime); } save(player, profile); + if (player instanceof EntityPlayerMP) { + ProfileSharedQuestPacket.sendToPlayer((EntityPlayerMP) player); + } } } diff --git a/src/main/java/kamkeel/npcs/controllers/SyncController.java b/src/main/java/kamkeel/npcs/controllers/SyncController.java index d0ee7b16c..57b111404 100644 --- a/src/main/java/kamkeel/npcs/controllers/SyncController.java +++ b/src/main/java/kamkeel/npcs/controllers/SyncController.java @@ -12,6 +12,7 @@ import kamkeel.npcs.network.PacketHandler; import kamkeel.npcs.network.enums.EnumSyncAction; import kamkeel.npcs.network.enums.EnumSyncType; import kamkeel.npcs.network.packets.data.LoginPacket; +import kamkeel.npcs.network.packets.data.ProfileSharedQuestPacket; import kamkeel.npcs.network.packets.data.ability.AbilityCooldownSyncPacket; import kamkeel.npcs.network.packets.data.ability.AbilityHotbarSyncPacket; import kamkeel.npcs.network.packets.data.ability.PlayerAbilitySyncPacket; @@ -184,6 +185,7 @@ public class SyncController { DBCAddon.instance.syncPlayer(player); syncPlayerData(player, false); PartyInfoPacket.sendPartyData(player); + ProfileSharedQuestPacket.sendToPlayer(player); // Sync skin overlays after full handshake to ensure the client is ready. // Overlays are not part of getSyncNBTFull(), and packets sent during diff --git a/src/main/java/kamkeel/npcs/network/PacketHandler.java b/src/main/java/kamkeel/npcs/network/PacketHandler.java index ef71ba967..06bffe6a7 100644 --- a/src/main/java/kamkeel/npcs/network/PacketHandler.java +++ b/src/main/java/kamkeel/npcs/network/PacketHandler.java @@ -586,6 +586,7 @@ public class PacketHandler { DATA_PACKET.registerPacket(new UpdateAnimationsPacket()); DATA_PACKET.registerPacket(new VillagerListPacket()); DATA_PACKET.registerPacket(new PlayerDataInfoPacket()); + DATA_PACKET.registerPacket(new ProfileSharedQuestPacket()); // Data | GUI Packets DATA_PACKET.registerPacket(new GuiClosePacket()); diff --git a/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java b/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java index 1a24ac2ef..598126a2d 100644 --- a/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java +++ b/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java @@ -67,6 +67,9 @@ public enum EnumDataPacket { ABILITY_HOTBAR_SYNC, ABILITY_COOLDOWN_SYNC, + // Profile System + PROFILE_SHARED_QUEST, + // Auction System AUCTION_DATA, diff --git a/src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java b/src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java new file mode 100644 index 000000000..6fa6187c9 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java @@ -0,0 +1,57 @@ +package kamkeel.npcs.network.packets.data; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import kamkeel.npcs.network.AbstractPacket; +import kamkeel.npcs.network.PacketChannel; +import kamkeel.npcs.network.PacketHandler; +import kamkeel.npcs.network.enums.EnumDataPacket; +import kamkeel.npcs.util.ByteBufUtils; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.client.ProfileClientConfig; +import noppes.npcs.controllers.ProfileConfigSync; + +import java.io.IOException; + +public final class ProfileSharedQuestPacket extends AbstractPacket { + public static final String packetName = "Data|ProfileSharedQuest"; + + private NBTTagCompound compound; + + public ProfileSharedQuestPacket() { + } + + public ProfileSharedQuestPacket(NBTTagCompound compound) { + this.compound = compound; + } + + @Override + public Enum getType() { + return EnumDataPacket.PROFILE_SHARED_QUEST; + } + + @Override + public PacketChannel getChannel() { + return PacketHandler.DATA_PACKET; + } + + @Override + public void sendData(ByteBuf out) throws IOException { + ByteBufUtils.writeNBT(out, this.compound); + } + + @SideOnly(Side.CLIENT) + @Override + public void receiveData(ByteBuf in, EntityPlayer player) throws IOException { + NBTTagCompound nbt = ByteBufUtils.readNBT(in); + ProfileClientConfig.readFromNBT(nbt); + } + + public static void sendToPlayer(EntityPlayerMP player) { + NBTTagCompound compound = ProfileConfigSync.writeToNBT(player); + PacketHandler.Instance.sendToPlayer(new ProfileSharedQuestPacket(compound), player); + } +} diff --git a/src/main/java/noppes/npcs/client/ClientCacheHandler.java b/src/main/java/noppes/npcs/client/ClientCacheHandler.java index 30b14be83..3386ffb43 100644 --- a/src/main/java/noppes/npcs/client/ClientCacheHandler.java +++ b/src/main/java/noppes/npcs/client/ClientCacheHandler.java @@ -124,6 +124,7 @@ public class ClientCacheHandler { ClientCacheHandler.customOverlays.clear(); ClientCacheHandler.skinOverlays.clear(); ClientCacheHandler.playerAnimations.clear(); + ProfileClientConfig.reset(); // Clear Texture Caches GuiSoundSelection.cachedDomains.clear(); diff --git a/src/main/java/noppes/npcs/client/ProfileClientConfig.java b/src/main/java/noppes/npcs/client/ProfileClientConfig.java new file mode 100644 index 000000000..66c85a3d7 --- /dev/null +++ b/src/main/java/noppes/npcs/client/ProfileClientConfig.java @@ -0,0 +1,41 @@ +package noppes.npcs.client; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import java.util.HashMap; +import java.util.Map; + +public class ProfileClientConfig { + private static volatile Map sharedQuestTimestamps = new HashMap<>(); + + public static void readFromNBT(NBTTagCompound compound) { + if (compound == null) return; + + Map timestamps = new HashMap<>(); + if (compound.hasKey("SharedQuestTimestamps")) { + NBTTagList list = compound.getTagList("SharedQuestTimestamps", 10); + for (int i = 0; i < list.tagCount(); i++) { + NBTTagCompound entry = list.getCompoundTagAt(i); + timestamps.put(entry.getInteger("Quest"), entry.getLong("Date")); + } + } + sharedQuestTimestamps = timestamps; + } + + public static void reset() { + sharedQuestTimestamps = new HashMap<>(); + } + + public static Map getSharedQuestTimestamps() { + return sharedQuestTimestamps; + } + + public static boolean hasSharedQuest(int questId) { + return sharedQuestTimestamps.containsKey(questId); + } + + public static Long getSharedQuestTimestamp(int questId) { + return sharedQuestTimestamps.get(questId); + } +} diff --git a/src/main/java/noppes/npcs/controllers/PlayerQuestController.java b/src/main/java/noppes/npcs/controllers/PlayerQuestController.java index 288c24f79..a02808c33 100644 --- a/src/main/java/noppes/npcs/controllers/PlayerQuestController.java +++ b/src/main/java/noppes/npcs/controllers/PlayerQuestController.java @@ -2,6 +2,8 @@ package noppes.npcs.controllers; import kamkeel.npcs.controllers.ProfileController; import kamkeel.npcs.controllers.data.profile.Profile; +import noppes.npcs.client.ClientCacheHandler; +import noppes.npcs.client.ProfileClientConfig; import kamkeel.npcs.network.packets.data.AchievementPacket; import kamkeel.npcs.network.packets.data.ChatAlertPacket; import net.minecraft.entity.player.EntityPlayer; @@ -131,9 +133,17 @@ public class PlayerQuestController { boolean finishedLocally = data.finishedQuests.containsKey(quest.id); boolean completedShared = false; boolean hasCooldownShared = false; - if (ConfigMain.ProfilesEnabled && quest.profileOptions.enableOptions) { - Profile profile = ProfileController.Instance.getProfile(player); - if (profile != null && profile.sharedQuestTimestamps.containsKey(quest.id)) { + if (quest.profileOptions.enableOptions) { + boolean hasSharedTimestamp = false; + if (ProfileController.Instance != null) { + if (ConfigMain.ProfilesEnabled) { + Profile profile = ProfileController.Instance.getProfile(player); + hasSharedTimestamp = profile != null && profile.sharedQuestTimestamps.containsKey(quest.id); + } + } else if (ClientCacheHandler.allowProfiles) { + hasSharedTimestamp = ProfileClientConfig.hasSharedQuest(quest.id); + } + if (hasSharedTimestamp) { if (quest.profileOptions.completeControl == EnumProfileSync.Shared) completedShared = true; if (quest.profileOptions.cooldownControl == EnumProfileSync.Shared) diff --git a/src/main/java/noppes/npcs/controllers/ProfileConfigSync.java b/src/main/java/noppes/npcs/controllers/ProfileConfigSync.java new file mode 100644 index 000000000..5291ff1fd --- /dev/null +++ b/src/main/java/noppes/npcs/controllers/ProfileConfigSync.java @@ -0,0 +1,34 @@ +package noppes.npcs.controllers; + +import kamkeel.npcs.controllers.ProfileController; +import kamkeel.npcs.controllers.data.profile.Profile; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import noppes.npcs.config.ConfigMain; + +import java.util.Map; + +public class ProfileConfigSync { + public static NBTTagCompound writeToNBT(EntityPlayer player) { + NBTTagCompound compound = new NBTTagCompound(); + if (!ConfigMain.ProfilesEnabled || ProfileController.Instance == null) { + return compound; + } + + Profile profile = ProfileController.Instance.getProfile(player); + if (profile == null) { + return compound; + } + + NBTTagList questList = new NBTTagList(); + for (Map.Entry entry : profile.sharedQuestTimestamps.entrySet()) { + NBTTagCompound questEntry = new NBTTagCompound(); + questEntry.setInteger("Quest", entry.getKey()); + questEntry.setLong("Date", entry.getValue()); + questList.appendTag(questEntry); + } + compound.setTag("SharedQuestTimestamps", questList); + return compound; + } +} diff --git a/src/main/java/noppes/npcs/controllers/data/Quest.java b/src/main/java/noppes/npcs/controllers/data/Quest.java index c2b9ac397..a547743e4 100644 --- a/src/main/java/noppes/npcs/controllers/data/Quest.java +++ b/src/main/java/noppes/npcs/controllers/data/Quest.java @@ -2,6 +2,8 @@ package noppes.npcs.controllers.data; import kamkeel.npcs.controllers.ProfileController; import kamkeel.npcs.controllers.data.profile.Profile; +import noppes.npcs.client.ClientCacheHandler; +import noppes.npcs.client.ProfileClientConfig; import kamkeel.npcs.network.packets.data.QuestCompletionPacket; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; @@ -176,13 +178,22 @@ public class Quest implements ICompatibilty, IQuest { } public long getTimeUntilRepeat(EntityPlayer player) { - if (ConfigMain.ProfilesEnabled && profileOptions.enableOptions && profileOptions.cooldownControl == EnumProfileSync.Shared) { - Profile profile = ProfileController.Instance.getProfile(player); - if (profile != null) { - Long questTime = profile.sharedQuestTimestamps.get(this.id); - if (questTime == null) return 0L; + if (profileOptions.enableOptions && profileOptions.cooldownControl == EnumProfileSync.Shared) { + Long questTime = null; + if (ProfileController.Instance != null) { + if (ConfigMain.ProfilesEnabled) { + Profile profile = ProfileController.Instance.getProfile(player); + if (profile != null) { + questTime = profile.sharedQuestTimestamps.get(this.id); + } + } + } else if (ClientCacheHandler.allowProfiles) { + questTime = ProfileClientConfig.getSharedQuestTimestamp(this.id); + } + if (questTime != null) { return calculateRemainingCooldown(player, questTime); } + return 0L; } IPlayerQuestData questData = PlayerData.get(player).getQuestData(); return getTimeUntilRepeatQuestData(player, questData); From b231f65bfbd20ee950668d245fdd3cf94619f1aa Mon Sep 17 00:00:00 2001 From: Kam Date: Wed, 11 Mar 2026 21:57:56 -0400 Subject: [PATCH 03/38] Profile Sync Quest Data Crash Fix --- .../npcs/client/ProfileClientConfig.java | 31 ++++++++++++++++--- .../controllers/PlayerQuestController.java | 24 ++++---------- .../noppes/npcs/controllers/data/Quest.java | 19 ++---------- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/main/java/noppes/npcs/client/ProfileClientConfig.java b/src/main/java/noppes/npcs/client/ProfileClientConfig.java index 66c85a3d7..8a23cc5ca 100644 --- a/src/main/java/noppes/npcs/client/ProfileClientConfig.java +++ b/src/main/java/noppes/npcs/client/ProfileClientConfig.java @@ -1,7 +1,11 @@ package noppes.npcs.client; +import kamkeel.npcs.controllers.ProfileController; +import kamkeel.npcs.controllers.data.profile.Profile; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import noppes.npcs.config.ConfigMain; import java.util.HashMap; import java.util.Map; @@ -27,15 +31,34 @@ public class ProfileClientConfig { sharedQuestTimestamps = new HashMap<>(); } - public static Map getSharedQuestTimestamps() { - return sharedQuestTimestamps; + /** + * Whether profiles are enabled, checking the correct source for each side. + */ + public static boolean isProfilesEnabled() { + if (ProfileController.Instance != null) + return ConfigMain.ProfilesEnabled; + return ClientCacheHandler.allowProfiles; } - public static boolean hasSharedQuest(int questId) { + /** + * Check if a quest has a shared timestamp, resolving from server or client cache. + */ + public static boolean hasSharedQuest(EntityPlayer player, int questId) { + if (ProfileController.Instance != null) { + Profile profile = ProfileController.Instance.getProfile(player); + return profile != null && profile.sharedQuestTimestamps.containsKey(questId); + } return sharedQuestTimestamps.containsKey(questId); } - public static Long getSharedQuestTimestamp(int questId) { + /** + * Get the shared quest timestamp, resolving from server or client cache. + */ + public static Long getSharedQuestTimestamp(EntityPlayer player, int questId) { + if (ProfileController.Instance != null) { + Profile profile = ProfileController.Instance.getProfile(player); + return profile != null ? profile.sharedQuestTimestamps.get(questId) : null; + } return sharedQuestTimestamps.get(questId); } } diff --git a/src/main/java/noppes/npcs/controllers/PlayerQuestController.java b/src/main/java/noppes/npcs/controllers/PlayerQuestController.java index a02808c33..cb3fce39f 100644 --- a/src/main/java/noppes/npcs/controllers/PlayerQuestController.java +++ b/src/main/java/noppes/npcs/controllers/PlayerQuestController.java @@ -1,8 +1,6 @@ package noppes.npcs.controllers; import kamkeel.npcs.controllers.ProfileController; -import kamkeel.npcs.controllers.data.profile.Profile; -import noppes.npcs.client.ClientCacheHandler; import noppes.npcs.client.ProfileClientConfig; import kamkeel.npcs.network.packets.data.AchievementPacket; import kamkeel.npcs.network.packets.data.ChatAlertPacket; @@ -133,22 +131,12 @@ public class PlayerQuestController { boolean finishedLocally = data.finishedQuests.containsKey(quest.id); boolean completedShared = false; boolean hasCooldownShared = false; - if (quest.profileOptions.enableOptions) { - boolean hasSharedTimestamp = false; - if (ProfileController.Instance != null) { - if (ConfigMain.ProfilesEnabled) { - Profile profile = ProfileController.Instance.getProfile(player); - hasSharedTimestamp = profile != null && profile.sharedQuestTimestamps.containsKey(quest.id); - } - } else if (ClientCacheHandler.allowProfiles) { - hasSharedTimestamp = ProfileClientConfig.hasSharedQuest(quest.id); - } - if (hasSharedTimestamp) { - if (quest.profileOptions.completeControl == EnumProfileSync.Shared) - completedShared = true; - if (quest.profileOptions.cooldownControl == EnumProfileSync.Shared) - hasCooldownShared = true; - } + if (ProfileClientConfig.isProfilesEnabled() && quest.profileOptions.enableOptions + && ProfileClientConfig.hasSharedQuest(player, quest.id)) { + if (quest.profileOptions.completeControl == EnumProfileSync.Shared) + completedShared = true; + if (quest.profileOptions.cooldownControl == EnumProfileSync.Shared) + hasCooldownShared = true; } boolean isFinished = finishedLocally || completedShared; diff --git a/src/main/java/noppes/npcs/controllers/data/Quest.java b/src/main/java/noppes/npcs/controllers/data/Quest.java index a547743e4..c7e63ec1f 100644 --- a/src/main/java/noppes/npcs/controllers/data/Quest.java +++ b/src/main/java/noppes/npcs/controllers/data/Quest.java @@ -1,8 +1,5 @@ package noppes.npcs.controllers.data; -import kamkeel.npcs.controllers.ProfileController; -import kamkeel.npcs.controllers.data.profile.Profile; -import noppes.npcs.client.ClientCacheHandler; import noppes.npcs.client.ProfileClientConfig; import kamkeel.npcs.network.packets.data.QuestCompletionPacket; import net.minecraft.entity.player.EntityPlayer; @@ -24,7 +21,6 @@ import noppes.npcs.api.handler.data.IQuestCategory; import noppes.npcs.api.handler.data.IQuestInterface; import noppes.npcs.api.handler.data.IQuestObjective; import noppes.npcs.api.handler.data.ISlot; -import noppes.npcs.config.ConfigMain; import noppes.npcs.constants.EnumProfileSync; import noppes.npcs.constants.EnumQuestCompletion; import noppes.npcs.constants.EnumQuestRepeat; @@ -178,18 +174,9 @@ public class Quest implements ICompatibilty, IQuest { } public long getTimeUntilRepeat(EntityPlayer player) { - if (profileOptions.enableOptions && profileOptions.cooldownControl == EnumProfileSync.Shared) { - Long questTime = null; - if (ProfileController.Instance != null) { - if (ConfigMain.ProfilesEnabled) { - Profile profile = ProfileController.Instance.getProfile(player); - if (profile != null) { - questTime = profile.sharedQuestTimestamps.get(this.id); - } - } - } else if (ClientCacheHandler.allowProfiles) { - questTime = ProfileClientConfig.getSharedQuestTimestamp(this.id); - } + if (ProfileClientConfig.isProfilesEnabled() && profileOptions.enableOptions + && profileOptions.cooldownControl == EnumProfileSync.Shared) { + Long questTime = ProfileClientConfig.getSharedQuestTimestamp(player, this.id); if (questTime != null) { return calculateRemainingCooldown(player, questTime); } From 88d496137a860004c058b3cc375a26b13dcbf957 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 12 Mar 2026 04:53:27 +0200 Subject: [PATCH 04/38] SCRIPT EDITOR COLOR SCHEMES (W.I.P --- .../client/CustomNpcResourceListener.java | 10 +- .../client/gui/util/GuiScriptTextArea.java | 15 +- .../util/script/interpreter/ScriptLine.java | 2 +- .../interpreter/hover/GutterIconRenderer.java | 2 +- .../interpreter/hover/TokenHoverRenderer.java | 2 +- .../interpreter/token/ScriptColorScheme.java | 295 ++++++++++++++++++ .../script/interpreter/token/TokenType.java | 95 +++--- .../colorscheme/script_editor_scheme.json | 167 ++++++++++ 8 files changed, 538 insertions(+), 50 deletions(-) create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java create mode 100644 src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json diff --git a/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java b/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java index 14bb52e71..c856cbea3 100644 --- a/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java +++ b/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java @@ -10,12 +10,12 @@ import net.minecraft.util.StatCollector; import noppes.npcs.CustomNpcs; import noppes.npcs.LogWriter; import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSTypeRegistry; +import noppes.npcs.client.gui.util.script.interpreter.token.ScriptColorScheme; import javax.imageio.ImageIO; import java.awt.Graphics; import java.awt.image.BufferedImage; -import java.io.File; -import java.io.InputStream; +import java.io.*; public class CustomNpcResourceListener implements IResourceManagerReloadListener { @@ -30,8 +30,14 @@ public class CustomNpcResourceListener implements SimpleReloadableResourceManager simplemanager = (SimpleReloadableResourceManager) var1; FolderResourcePack pack = new FolderResourcePack(CustomNpcs.Dir); + LogWriter.info("[ResourceListener] Adding FolderResourcePack: " + CustomNpcs.Dir.getAbsolutePath()); + File schemeInFolder = new File(CustomNpcs.Dir, "assets/customnpcs/colorscheme/script_editor_scheme.json"); + LogWriter.info("[ResourceListener] Colorscheme in customnpcs folder: " + schemeInFolder.exists() + + " (" + schemeInFolder.getAbsolutePath() + ")"); simplemanager.reloadResourcePack(pack); + ScriptColorScheme.reloadColorScheme(var1); + // Reload scripting .d.ts files JSTypeRegistry registry = JSTypeRegistry.getInstance(); registry.clear(); diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java index d98eae47d..dac50d743 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java @@ -19,6 +19,7 @@ import noppes.npcs.client.gui.util.script.interpreter.field.FieldAccessInfo; import noppes.npcs.client.gui.util.script.interpreter.method.MethodCallInfo; import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; import noppes.npcs.client.gui.util.script.interpreter.token.Token; +import noppes.npcs.client.gui.util.script.interpreter.token.ScriptColorScheme; import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; import noppes.npcs.client.gui.util.script.interpreter.hover.GutterIconRenderer; import noppes.npcs.client.gui.util.script.interpreter.hover.HoverState; @@ -597,18 +598,18 @@ public class GuiScriptTextArea extends GuiNpcTextField { // Draw outer border around entire area int offset = fullscreen() ? 2 : 1; drawRect(x - offset, y - offset - searchBar.getTotalHeight(), x + width + offset, y + height + offset, - 0xffa0a0a0); + ScriptColorScheme.getBackgroundStyle().getBorderColor()); int searchHeight = searchBar.getTotalHeight(); // Draw line number gutter background int viewportX = x + LINE_NUMBER_GUTTER_WIDTH; - drawRect(x, y, x + LINE_NUMBER_GUTTER_WIDTH, y + height, 0xff000000); + drawRect(x, y, x + LINE_NUMBER_GUTTER_WIDTH, y + height, ScriptColorScheme.getBackgroundStyle().getGutterColor()); // Draw text viewport background (starts after gutter) - drawRect(x + LINE_NUMBER_GUTTER_WIDTH, y, x + width, y + height, 0xff000000); + drawRect(x + LINE_NUMBER_GUTTER_WIDTH, y, x + width, y + height, ScriptColorScheme.getBackgroundStyle().getBackgroundColor()); // Draw separator line between gutter and text area - drawRect(x + LINE_NUMBER_GUTTER_WIDTH-1, y, x + LINE_NUMBER_GUTTER_WIDTH, y + height, 0xff3c3f41); + drawRect(x + LINE_NUMBER_GUTTER_WIDTH-1, y, x + LINE_NUMBER_GUTTER_WIDTH, y + height, ScriptColorScheme.getBackgroundStyle().getGutterSeparatorColor()); // Enable scissor test to clip drawing to the TEXT viewport rectangle (excludes gutter) GL11.glEnable(GL11.GL_SCISSOR_TEST); @@ -833,13 +834,13 @@ public class GuiScriptTextArea extends GuiNpcTextField { int lineNumX = x + LINE_NUMBER_GUTTER_WIDTH - lineNumWidth - 5 - GutterIconRenderer.ICON_GUTTER_WIDTH; // right-align before icon space int lineNumY = posY + 1; // Highlight current line number - int lineNumColor = 0xFF606366; + int lineNumColor = ScriptColorScheme.getBackgroundStyle().getLineNumberColor(); if (active && isEnabled()) { for (int li = 0; li < list.size(); li++) { LineData ld = list.get(li); if (selection.getCursorPosition() >= ld.start && selection.getCursorPosition() < ld.end || (li == list.size() - 1 && selection.getCursorPosition() == text.length())) { if (li == i) { - lineNumColor = 0xFFb9c7d6; + lineNumColor = ScriptColorScheme.getBackgroundStyle().getLineNumberActiveColor(); break; } } @@ -1078,7 +1079,7 @@ public class GuiScriptTextArea extends GuiNpcTextField { double linesCount = (double) effLines; int posY = (int) (y + 1f * scroll.getScrollPos() / linesCount * (height - 4)) + 1; - drawRect(posX, posY, posX + 5, posY + sbSize + 2, 0xFFe0e0e0); + drawRect(posX, posY, posX + 5, posY + sbSize + 2, ScriptColorScheme.getBackgroundStyle().getScrollbarColor()); } if (parent != null) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java index 28dea5e08..983018edd 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java @@ -333,7 +333,7 @@ public class ScriptLine { // Get the width of everything before this segment String prefix = fullText.substring(0, seg.startPos); int prefixWidth = ClientProxy.Font.width(prefix); - int color = (seg.color & 0xFF000000) == 0 ? (0xFF000000 | seg.color) : seg.color; + int color = seg.color; // Draw this segment at the correct position ClientProxy.Font.drawString(seg.text, x + prefixWidth, y, color); diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/GutterIconRenderer.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/GutterIconRenderer.java index 3c5087533..69014acc9 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/GutterIconRenderer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/GutterIconRenderer.java @@ -282,7 +282,7 @@ public class GutterIconRenderer { int currentY = y + PADDING; for (TextSegment segment : segments) { - ClientProxy.Font.drawString(segment.text, currentX, currentY, 0xFF000000 | segment.color); + ClientProxy.Font.drawString(segment.text, currentX, currentY, segment.color); currentX += ClientProxy.Font.width(segment.text); } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java index f3215b1a9..aed5d4391 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java @@ -437,7 +437,7 @@ public class TokenHoverRenderer { for (TokenHoverInfo.TextSegment segment : segments) { String text = segment.text; - int color = 0xFF000000 | segment.color; + int color = segment.color; // Split segment into words for wrapping String[] words = text.split("(?<=\\s)|(?=\\s)"); // Keep whitespace as separate tokens diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java new file mode 100644 index 000000000..c8f377645 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java @@ -0,0 +1,295 @@ +package noppes.npcs.client.gui.util.script.interpreter.token; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import noppes.npcs.LogWriter; + +import java.io.*; +import java.util.List; + +/** + * Manages reloadable style overrides (color, priority, bold, italic) for {@link TokenType}, + * plus editor background/gutter/scrollbar colors via {@link BackgroundStyleEntry}. + *

+ * Loaded from {@code assets/customnpcs/colorscheme/script_editor_scheme.json} on resource reload. + * Styles are cached in a flat array indexed by {@link TokenType#ordinal()} for zero-cost lookups. + */ +public final class ScriptColorScheme { + + // Volatile array reference swapped atomically — all tokens update at once + static volatile StyleEntry[] styles = buildDefaults(); + + // Background/gutter/scrollbar colors — volatile for same atomic-swap pattern + private static volatile BackgroundStyleEntry background = BackgroundStyleEntry.DEFAULT; + + private ScriptColorScheme() {} + + /** Returns the current background style (never null). */ + public static BackgroundStyleEntry getBackgroundStyle() { + return background; + } + + /** + * Reload the color scheme from the resource pack's JSON file. + * Uses {@code getAllResources()} to find the highest-priority version + * (the last entry in the list, which is the latest resource pack override). + * Falls back to defaults if the file is missing or malformed. + */ + public static void reloadColorScheme(IResourceManager resourceManager) { + ResourceLocation loc = new ResourceLocation("customnpcs", "colorscheme/script_editor_scheme.json"); + try { + List allResources = resourceManager.getAllResources(loc); + + if (allResources.isEmpty()) { + LogWriter.info("[ColorScheme] No script_editor_scheme.json found in any resource pack, using defaults"); + resetToDefaults(); + return; + } + + int count = allResources.size(); + LogWriter.info("[ColorScheme] Found " + count + " script_editor_scheme.json resource(s):"); + for (int i = 0; i < count; i++) { + IResource res = allResources.get(i); + String preview = peekResourceContent(res); + LogWriter.info("[ColorScheme] [" + i + "] id=@" + Integer.toHexString(System.identityHashCode(res)) + + " preview: " + preview); + } + LogWriter.info("[ColorScheme] Using highest-priority resource (last in list, index " + (count - 1) + ")"); + + // Re-fetch the resource list to get a fresh InputStream for the last entry, + // because peekResourceContent consumed the original streams. + List freshResources = resourceManager.getAllResources(loc); + IResource bestResource = freshResources.get(freshResources.size() - 1); + + try (InputStream is = bestResource.getInputStream(); + InputStreamReader reader = new InputStreamReader(is, "UTF-8")) { + loadFromJson(reader); + LogWriter.info("[ColorScheme] Loaded script_editor_scheme.json successfully"); + logLoadedSample(); + } + } catch (FileNotFoundException e) { + LogWriter.info("[ColorScheme] No script_editor_scheme.json found, using defaults"); + resetToDefaults(); + } catch (Exception e) { + LogWriter.error("[ColorScheme] Failed to load script_editor_scheme.json: " + e.getMessage()); + resetToDefaults(); + } + } + + private static String peekResourceContent(IResource res) { + try (InputStream peekIs = res.getInputStream()) { + byte[] buf = new byte[120]; + int read = peekIs.read(buf); + if (read > 0) { + return new String(buf, 0, read, "UTF-8").replaceAll("\\s+", " ").trim(); + } + } catch (Exception ignored) {} + return ""; + } + + private static void logLoadedSample() { + StyleEntry[] current = styles; + TokenType[] samples = { TokenType.COMMENT, TokenType.KEYWORD, TokenType.STRING, TokenType.METHOD_CALL, TokenType.DEFAULT }; + for (TokenType tt : samples) { + StyleEntry e = current[tt.ordinal()]; + LogWriter.info("[ColorScheme] " + tt.name() + " -> color=#" + String.format("%08X", e.hexColor) + + ", priority=" + e.priority + ", bold=" + e.bold + ", italic=" + e.italic); + } + + BackgroundStyleEntry bg = background; + LogWriter.info("[ColorScheme] background -> bg=#" + String.format("%08X", bg.getBackgroundColor()) + + ", gutter=#" + String.format("%08X", bg.getGutterColor())); + } + + /** + * Parse a color scheme JSON and install it as the active scheme. + * Expected format: {@code { "TOKEN_NAME": { "color": "#RRGGBB", "priority": int, "bold": bool, "italic": bool }, ... }} + * Missing properties per token fall back to the enum default. Parse errors are logged per-token. + */ + public static void loadFromJson(Reader reader) { + try { + JsonParser parser = new JsonParser(); + JsonElement root = parser.parse(reader); + if (!root.isJsonObject()) { + LogWriter.error("[ColorScheme] script_editor_scheme.json root is not a JSON object, using defaults"); + return; + } + + JsonObject obj = root.getAsJsonObject(); + + background = parseBackground(obj); + + TokenType[] all = TokenType.values(); + StyleEntry[] next = new StyleEntry[all.length]; + for (TokenType tt : all) { + next[tt.ordinal()] = parseEntry(obj, tt); + } + styles = next; + } catch (Exception e) { + LogWriter.error("[ColorScheme] Failed to parse script_editor_scheme.json, using defaults: " + e.getMessage()); + } + } + + public static void resetToDefaults() { + styles = buildDefaults(); + background = BackgroundStyleEntry.DEFAULT; + } + + private static StyleEntry parseEntry(JsonObject root, TokenType tt) { + if (!root.has(tt.name())) { + return defaultEntry(tt); + } + try { + JsonElement elem = root.get(tt.name()); + if (!elem.isJsonObject()) { + LogWriter.error("[ColorScheme] Entry for " + tt.name() + " is not an object, skipping"); + return defaultEntry(tt); + } + JsonObject entry = elem.getAsJsonObject(); + + int defaultColor = tt.getDefaultHexColor(); + if ((defaultColor & 0xFF000000) == 0) { + defaultColor |= 0xFF000000; + } + + int color = entry.has("color") + ? parseColor(entry.get("color"), defaultColor, tt.name()) + : defaultColor; + int priority = entry.has("priority") ? entry.get("priority").getAsInt() : tt.getDefaultPriority(); + boolean bold = entry.has("bold") ? entry.get("bold").getAsBoolean() : tt.getDefaultBold(); + boolean italic = entry.has("italic") ? entry.get("italic").getAsBoolean() : tt.getDefaultItalic(); + + return new StyleEntry(color, priority, bold, italic); + } catch (Exception e) { + LogWriter.error("[ColorScheme] Error parsing token " + tt.name() + ", using defaults: " + e.getMessage()); + return defaultEntry(tt); + } + } + + private static StyleEntry defaultEntry(TokenType tt) { + int color = tt.getDefaultHexColor(); + if ((color & 0xFF000000) == 0) { + color |= 0xFF000000; + } + return new StyleEntry(color, tt.getDefaultPriority(), tt.getDefaultBold(), tt.getDefaultItalic()); + } + + private static BackgroundStyleEntry parseBackground(JsonObject root) { + if (!root.has("background")) { + return BackgroundStyleEntry.DEFAULT; + } + try { + JsonElement elem = root.get("background"); + if (!elem.isJsonObject()) { + LogWriter.error("[ColorScheme] 'background' is not an object, using defaults"); + return BackgroundStyleEntry.DEFAULT; + } + JsonObject bg = elem.getAsJsonObject(); + BackgroundStyleEntry d = BackgroundStyleEntry.DEFAULT; + + int backgroundColor = bg.has("backgroundColor") ? parseColor(bg.get("backgroundColor"), d.getBackgroundColor(), "background.backgroundColor") : d.getBackgroundColor(); + int gutterColor = bg.has("gutterColor") ? parseColor(bg.get("gutterColor"), d.getGutterColor(), "background.gutterColor") : d.getGutterColor(); + int gutterSeparatorColor = bg.has("gutterSeparatorColor") ? parseColor(bg.get("gutterSeparatorColor"), d.getGutterSeparatorColor(), "background.gutterSeparatorColor") : d.getGutterSeparatorColor(); + int lineNumberColor = bg.has("lineNumberColor") ? parseColor(bg.get("lineNumberColor"), d.getLineNumberColor(), "background.lineNumberColor") : d.getLineNumberColor(); + int lineNumberActiveColor = bg.has("lineNumberActiveColor") ? parseColor(bg.get("lineNumberActiveColor"), d.getLineNumberActiveColor(), "background.lineNumberActiveColor") : d.getLineNumberActiveColor(); + int scrollbarColor = bg.has("scrollbarColor") ? parseColor(bg.get("scrollbarColor"), d.getScrollbarColor(), "background.scrollbarColor") : d.getScrollbarColor(); + int borderColor = bg.has("borderColor") ? parseColor(bg.get("borderColor"), d.getBorderColor(), "background.borderColor") : d.getBorderColor(); + + return new BackgroundStyleEntry(backgroundColor, gutterColor, gutterSeparatorColor, + lineNumberColor, lineNumberActiveColor, scrollbarColor, borderColor); + } catch (Exception e) { + LogWriter.error("[ColorScheme] Error parsing 'background', using defaults: " + e.getMessage()); + return BackgroundStyleEntry.DEFAULT; + } + } + + private static StyleEntry[] buildDefaults() { + TokenType[] all = TokenType.values(); + StyleEntry[] defaults = new StyleEntry[all.length]; + for (TokenType tt : all) { + defaults[tt.ordinal()] = defaultEntry(tt); + } + return defaults; + } + + private static int parseColor(JsonElement element, int fallback, String tokenName) { + try { + if (element.isJsonPrimitive()) { + if (element.getAsJsonPrimitive().isString()) { + String s = element.getAsString().trim(); + if (s.startsWith("#")) { + s = s.substring(1); + } + int color = (int) Long.parseLong(s, 16); + if (s.length() <= 6) { + color |= 0xFF000000; + } + return color; + } else if (element.getAsJsonPrimitive().isNumber()) { + return element.getAsInt(); + } + } + } catch (NumberFormatException e) { + LogWriter.error("[ColorScheme] Invalid color for " + tokenName + ": " + element + ", using default"); + } + return fallback; + } + + static final class StyleEntry { + final int hexColor; + final int priority; + final boolean bold; + final boolean italic; + + StyleEntry(int hexColor, int priority, boolean bold, boolean italic) { + this.hexColor = hexColor; + this.priority = priority; + this.bold = bold; + this.italic = italic; + } + } + + public static final class BackgroundStyleEntry { + static final BackgroundStyleEntry DEFAULT = new BackgroundStyleEntry( + 0xff000000, // backgroundColor (text viewport) + 0xff000000, // gutterColor (line-number gutter) + 0xff3c3f41, // gutterSeparatorColor + 0xFF606366, // lineNumberColor (inactive) + 0xFFb9c7d6, // lineNumberActiveColor (current line) + 0xFFe0e0e0, // scrollbarColor + 0xffa0a0a0 // borderColor (outer border) + ); + + private final int backgroundColor; + private final int gutterColor; + private final int gutterSeparatorColor; + private final int lineNumberColor; + private final int lineNumberActiveColor; + private final int scrollbarColor; + private final int borderColor; + + BackgroundStyleEntry(int backgroundColor, int gutterColor, int gutterSeparatorColor, + int lineNumberColor, int lineNumberActiveColor, + int scrollbarColor, int borderColor) { + this.backgroundColor = backgroundColor; + this.gutterColor = gutterColor; + this.gutterSeparatorColor = gutterSeparatorColor; + this.lineNumberColor = lineNumberColor; + this.lineNumberActiveColor = lineNumberActiveColor; + this.scrollbarColor = scrollbarColor; + this.borderColor = borderColor; + } + + public int getBackgroundColor() { return backgroundColor; } + public int getGutterColor() { return gutterColor; } + public int getGutterSeparatorColor() { return gutterSeparatorColor; } + public int getLineNumberColor() { return lineNumberColor; } + public int getLineNumberActiveColor() { return lineNumberActiveColor; } + public int getScrollbarColor() { return scrollbarColor; } + public int getBorderColor() { return borderColor; } + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java index 9306a3c67..e3f5c6470 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java @@ -6,81 +6,100 @@ import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; * Defines all token types for syntax highlighting with hex colors and priorities. * Priority determines which token type wins when marks overlap. * Higher priority = wins conflicts. + * + * Style properties (color, priority, bold, italic) can be overridden at runtime + * via {@link ScriptColorScheme}. The enum constructor values serve as compile-time defaults. */ public enum TokenType { // Comments and strings have highest priority - they override everything inside them - COMMENT(0x777777, 140), - STRING(0xCC8855, 130), + COMMENT(0xFF777777, 140), + STRING(0xFFCC8855, 130), // JSDoc elements - lower priority but will fill gaps left by fragmented comment marking - JSDOC_TAG(0xCC9933, 125), // @param, @type, @return etc. (gold/orange) - JSDOC_TYPE(0x00AAAA, 124), // {TypeName} in JSDoc (aqua like types) + JSDOC_TAG(0xFFCC9933, 125), // @param, @type, @return etc. (gold/orange) + JSDOC_TYPE(0xFF00AAAA, 124), // {TypeName} in JSDoc (aqua like types) - UNUSED_IMPORT(0x666666, 119), // unused import statements (gray) + UNUSED_IMPORT(0xFF666666, 119), // unused import statements (gray) // Keywords and modifiers - CLASS_KEYWORD(0xFF5555, 115), // 'class', 'interface', 'enum' keywords - IMPORT_KEYWORD(0xFFAA00, 110), // 'import' keyword - KEYWORD(0xFF5555, 100), // control flow: if, else, for, while, etc. - MODIFIER(0xFFAA00, 90), // public, private, static, final, etc. + CLASS_KEYWORD(0xFFFF5555, 115), // 'class', 'interface', 'enum' keywords + IMPORT_KEYWORD(0xFFFFAA00, 110), // 'import' keyword + KEYWORD(0xFFFF5555, 100), // control flow: if, else, for, while, etc. + MODIFIER(0xFFFFAA00, 90), // public, private, static, final, etc. // Type declarations and references - INTERFACE_DECL(0x55FFFF, 85), // interface names (aqua) - ENUM_DECL(0xFF55FF, 85), // enum names (magenta) - ENUM_CONSTANT(0x55FFFF, 84, true, false), // enum constant values (blue, bold+italic) - like IntelliJ - CLASS_DECL(0x00AAAA, 85), // class names in declarations - IMPORTED_CLASS(0x00AAAA, 75), // imported class usages - GENERIC_TYPE_PARAM(0x00FA9A, 76), // generic type parameters like T, E, K, V (light green) - TYPE_DECL(0x00AAAA, 70), // package paths, type references + INTERFACE_DECL(0xFF55FFFF, 85), // interface names (aqua) + ENUM_DECL(0xFFFF55FF, 85), // enum names (magenta) + ENUM_CONSTANT(0xFF55FFFF, 84, true, false), // enum constant values (blue, bold+italic) - like IntelliJ + CLASS_DECL(0xFF00AAAA, 85), // class names in declarations + IMPORTED_CLASS(0xFF00AAAA, 75), // imported class usages + GENERIC_TYPE_PARAM(0xFF00FA9A, 76), // generic type parameters like T, E, K, V (light green) + TYPE_DECL(0xFF00AAAA, 70), // package paths, type references // Methods - METHOD_DECL(0x00AA00, 60), // method declarations (green) - METHOD_CALL(0x55FF55, 50), // method calls (bright green) + METHOD_DECL(0xFF00AA00, 60), // method declarations (green) + METHOD_CALL(0xFF55FF55, 50), // method calls (bright green) // Variables and fields - UNDEFINED_VAR(0xAA0000, 20), // unresolved variables (dark red) - high priority - PARAMETER(0x5555FF, 36), // method parameters (blue) - GLOBAL_FIELD(0x55FFFF, 35), // class-level fields (aqua) - LOCAL_FIELD(0xFFFF55, 25), // local variables (yellow) - STATIC_FINAL_FIELD(0xFF55FF, 36, false, true), // static final fields (magenta, italic) + UNDEFINED_VAR(0xFFAA0000, 20), // unresolved variables (dark red) - high priority + PARAMETER(0xFF5555FF, 36), // method parameters (blue) + GLOBAL_FIELD(0xFF55FFFF, 35), // class-level fields (aqua) + LOCAL_FIELD(0xFFFFFF55, 25), // local variables (yellow) + STATIC_FINAL_FIELD(0xFFFF55FF, 36, false, true), // static final fields (magenta, italic) // Literals - LITERAL(0x777777, 40), // numeric and boolean literals + LITERAL(0xFF777777, 40), // numeric and boolean literals // Default - VARIABLE(0xFFFFFF, 30), // generic variables - DEFAULT(0xFFFFFF, 0); // default text color (white) + VARIABLE(0xFFFFFFFF, 30), // generic variables + DEFAULT(0xFFFFFFFF, 0); // default text color (white) - private final int hexColor; - private final int priority; - private final boolean bold; - private final boolean italic; + private final int defaultHexColor; + private final int defaultPriority; + private final boolean defaultBold; + private final boolean defaultItalic; TokenType(int hexColor, int priority) { this(hexColor, priority, false, false); } TokenType(int hexColor, int priority, boolean bold, boolean italic) { - this.hexColor = hexColor; - this.priority = priority; - this.bold = bold; - this.italic = italic; + this.defaultHexColor = hexColor; + this.defaultPriority = priority; + this.defaultBold = bold; + this.defaultItalic = italic; } public int getHexColor() { - return hexColor; + return ScriptColorScheme.styles[ordinal()].hexColor; } public int getPriority() { - return priority; + return ScriptColorScheme.styles[ordinal()].priority; } public boolean isBold() { - return bold; + return ScriptColorScheme.styles[ordinal()].bold; } public boolean isItalic() { - return italic; + return ScriptColorScheme.styles[ordinal()].italic; + } + + int getDefaultHexColor() { + return defaultHexColor; + } + + int getDefaultPriority() { + return defaultPriority; + } + + boolean getDefaultBold() { + return defaultBold; + } + + boolean getDefaultItalic() { + return defaultItalic; } public static TokenType getByType(TypeInfo typeInfo) { diff --git a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json new file mode 100644 index 000000000..86dd81927 --- /dev/null +++ b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json @@ -0,0 +1,167 @@ +{ + "background": { + "backgroundColor": "#FF000000", + "gutterColor": "#FF000000", + "gutterSeparatorColor": "#FF3C3F41", + "lineNumberColor": "#FF606366", + "lineNumberActiveColor": "#FFB9C7D6", + "scrollbarColor": "#FFE0E0E0", + "borderColor": "#FFA0A0A0" + }, + "COMMENT": { + "color": "#FF777777", + "priority": 140, + "bold": false, + "italic": false + }, + "STRING": { + "color": "#FFCC8855", + "priority": 130, + "bold": false, + "italic": false + }, + "JSDOC_TAG": { + "color": "#FFCC9933", + "priority": 125, + "bold": false, + "italic": false + }, + "JSDOC_TYPE": { + "color": "#FF00AAAA", + "priority": 124, + "bold": false, + "italic": false + }, + "UNUSED_IMPORT": { + "color": "#FF666666", + "priority": 119, + "bold": false, + "italic": false + }, + "CLASS_KEYWORD": { + "color": "#FFFF5555", + "priority": 115, + "bold": false, + "italic": false + }, + "IMPORT_KEYWORD": { + "color": "#FFFFAA00", + "priority": 110, + "bold": false, + "italic": false + }, + "KEYWORD": { + "color": "#FFFF5555", + "priority": 100, + "bold": false, + "italic": false + }, + "MODIFIER": { + "color": "#FFFFAA00", + "priority": 90, + "bold": false, + "italic": false + }, + "INTERFACE_DECL": { + "color": "#FF55FFFF", + "priority": 85, + "bold": false, + "italic": false + }, + "ENUM_DECL": { + "color": "#FFFF55FF", + "priority": 85, + "bold": false, + "italic": false + }, + "ENUM_CONSTANT": { + "color": "#FF55FFFF", + "priority": 84, + "bold": true, + "italic": false + }, + "CLASS_DECL": { + "color": "#FF00AAAA", + "priority": 85, + "bold": false, + "italic": false + }, + "IMPORTED_CLASS": { + "color": "#FF00AAAA", + "priority": 75, + "bold": false, + "italic": false + }, + "GENERIC_TYPE_PARAM": { + "color": "#FF00FA9A", + "priority": 76, + "bold": false, + "italic": false + }, + "TYPE_DECL": { + "color": "#FF00AAAA", + "priority": 70, + "bold": false, + "italic": false + }, + "METHOD_DECL": { + "color": "#FF00AA00", + "priority": 60, + "bold": false, + "italic": false + }, + "METHOD_CALL": { + "color": "#FF55FF55", + "priority": 50, + "bold": false, + "italic": false + }, + "UNDEFINED_VAR": { + "color": "#FFAA0000", + "priority": 20, + "bold": false, + "italic": false + }, + "PARAMETER": { + "color": "#FF5555FF", + "priority": 36, + "bold": false, + "italic": false + }, + "GLOBAL_FIELD": { + "color": "#FF55FFFF", + "priority": 35, + "bold": false, + "italic": false + }, + "LOCAL_FIELD": { + "color": "#FFFFFF55", + "priority": 25, + "bold": false, + "italic": false + }, + "STATIC_FINAL_FIELD": { + "color": "#FFFF55FF", + "priority": 36, + "bold": false, + "italic": true + }, + "LITERAL": { + "color": "#FF777777", + "priority": 40, + "bold": false, + "italic": false + }, + "VARIABLE": { + "color": "#FFFFFFFF", + "priority": 30, + "bold": false, + "italic": false + }, + "DEFAULT": { + "color": "#FFFFFFFF", + "priority": 0, + "bold": false, + "italic": false + } +} From 6f2288c81ff4dcfb9d02d4067804e6c572fcb7da Mon Sep 17 00:00:00 2001 From: somehussar <148253652+somehussar@users.noreply.github.com> Date: Thu, 12 Mar 2026 04:58:45 +0100 Subject: [PATCH 05/38] Simplify this. Issue was with wrongly packaged ZIPs --- .../interpreter/token/ScriptColorScheme.java | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java index c8f377645..05bd1e4af 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java @@ -9,6 +9,7 @@ import net.minecraft.util.ResourceLocation; import noppes.npcs.LogWriter; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -42,31 +43,10 @@ public final class ScriptColorScheme { public static void reloadColorScheme(IResourceManager resourceManager) { ResourceLocation loc = new ResourceLocation("customnpcs", "colorscheme/script_editor_scheme.json"); try { - List allResources = resourceManager.getAllResources(loc); + IResource resource = resourceManager.getResource(loc); - if (allResources.isEmpty()) { - LogWriter.info("[ColorScheme] No script_editor_scheme.json found in any resource pack, using defaults"); - resetToDefaults(); - return; - } - - int count = allResources.size(); - LogWriter.info("[ColorScheme] Found " + count + " script_editor_scheme.json resource(s):"); - for (int i = 0; i < count; i++) { - IResource res = allResources.get(i); - String preview = peekResourceContent(res); - LogWriter.info("[ColorScheme] [" + i + "] id=@" + Integer.toHexString(System.identityHashCode(res)) - + " preview: " + preview); - } - LogWriter.info("[ColorScheme] Using highest-priority resource (last in list, index " + (count - 1) + ")"); - - // Re-fetch the resource list to get a fresh InputStream for the last entry, - // because peekResourceContent consumed the original streams. - List freshResources = resourceManager.getAllResources(loc); - IResource bestResource = freshResources.get(freshResources.size() - 1); - - try (InputStream is = bestResource.getInputStream(); - InputStreamReader reader = new InputStreamReader(is, "UTF-8")) { + try (InputStream is = resource.getInputStream(); + InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { loadFromJson(reader); LogWriter.info("[ColorScheme] Loaded script_editor_scheme.json successfully"); logLoadedSample(); From 05c27c5d20cb0e6c6a4f1fb45f9133faba094a41 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 12 Mar 2026 06:57:38 +0200 Subject: [PATCH 06/38] Added cursor caret color to editor color scheme --- .../noppes/npcs/client/CustomNpcResourceListener.java | 3 --- .../npcs/client/gui/util/GuiScriptTextArea.java | 2 +- .../script/interpreter/token/ScriptColorScheme.java | 11 ++++++++--- .../customnpcs/colorscheme/script_editor_scheme.json | 4 +++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java b/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java index c856cbea3..cb39c40c2 100644 --- a/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java +++ b/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java @@ -31,9 +31,6 @@ public class CustomNpcResourceListener implements FolderResourcePack pack = new FolderResourcePack(CustomNpcs.Dir); LogWriter.info("[ResourceListener] Adding FolderResourcePack: " + CustomNpcs.Dir.getAbsolutePath()); - File schemeInFolder = new File(CustomNpcs.Dir, "assets/customnpcs/colorscheme/script_editor_scheme.json"); - LogWriter.info("[ResourceListener] Colorscheme in customnpcs folder: " + schemeInFolder.exists() - + " (" + schemeInFolder.getAbsolutePath() + ")"); simplemanager.reloadResourcePack(pack); ScriptColorScheme.reloadColorScheme(var1); diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java index dac50d743..74a2432b6 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java @@ -1053,7 +1053,7 @@ public class GuiScriptTextArea extends GuiNpcTextField { if (active && isEnabled() && (recentInput || (cursorCounter / 10) % 2 == 0) && (selection.getCursorPosition() >= data.start && selection.getCursorPosition() < data.end || (i == list.size() - 1 && selection.getCursorPosition() == text.length()))) { int posX = x + LINE_NUMBER_GUTTER_WIDTH + ClientProxy.Font.width( line.substring(0, Math.min(selection.getCursorPosition() - data.start, line.length()))); - drawRect(posX + 1, posY, posX + 2, posY + container.lineHeight, 0xffffffff); + drawRect(posX + 1, posY, posX + 2, posY + container.lineHeight, ScriptColorScheme.getBackgroundStyle().getCaretColor()); } } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java index 05bd1e4af..e38aae462 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java @@ -178,9 +178,10 @@ public final class ScriptColorScheme { int lineNumberActiveColor = bg.has("lineNumberActiveColor") ? parseColor(bg.get("lineNumberActiveColor"), d.getLineNumberActiveColor(), "background.lineNumberActiveColor") : d.getLineNumberActiveColor(); int scrollbarColor = bg.has("scrollbarColor") ? parseColor(bg.get("scrollbarColor"), d.getScrollbarColor(), "background.scrollbarColor") : d.getScrollbarColor(); int borderColor = bg.has("borderColor") ? parseColor(bg.get("borderColor"), d.getBorderColor(), "background.borderColor") : d.getBorderColor(); + int caretColor = bg.has("caretColor") ? parseColor(bg.get("caretColor"), d.getCaretColor(), "background.caretColor") : d.getCaretColor(); return new BackgroundStyleEntry(backgroundColor, gutterColor, gutterSeparatorColor, - lineNumberColor, lineNumberActiveColor, scrollbarColor, borderColor); + lineNumberColor, lineNumberActiveColor, scrollbarColor, borderColor, caretColor); } catch (Exception e) { LogWriter.error("[ColorScheme] Error parsing 'background', using defaults: " + e.getMessage()); return BackgroundStyleEntry.DEFAULT; @@ -241,7 +242,8 @@ public final class ScriptColorScheme { 0xFF606366, // lineNumberColor (inactive) 0xFFb9c7d6, // lineNumberActiveColor (current line) 0xFFe0e0e0, // scrollbarColor - 0xffa0a0a0 // borderColor (outer border) + 0xffa0a0a0, // borderColor (outer border) + 0xffffffff // caretColor (cursor) ); private final int backgroundColor; @@ -251,10 +253,11 @@ public final class ScriptColorScheme { private final int lineNumberActiveColor; private final int scrollbarColor; private final int borderColor; + private final int caretColor; BackgroundStyleEntry(int backgroundColor, int gutterColor, int gutterSeparatorColor, int lineNumberColor, int lineNumberActiveColor, - int scrollbarColor, int borderColor) { + int scrollbarColor, int borderColor, int caretColor) { this.backgroundColor = backgroundColor; this.gutterColor = gutterColor; this.gutterSeparatorColor = gutterSeparatorColor; @@ -262,6 +265,7 @@ public final class ScriptColorScheme { this.lineNumberActiveColor = lineNumberActiveColor; this.scrollbarColor = scrollbarColor; this.borderColor = borderColor; + this.caretColor = caretColor; } public int getBackgroundColor() { return backgroundColor; } @@ -271,5 +275,6 @@ public final class ScriptColorScheme { public int getLineNumberActiveColor() { return lineNumberActiveColor; } public int getScrollbarColor() { return scrollbarColor; } public int getBorderColor() { return borderColor; } + public int getCaretColor() { return caretColor; } } } diff --git a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json index 86dd81927..61b0b82d4 100644 --- a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json +++ b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json @@ -6,7 +6,9 @@ "lineNumberColor": "#FF606366", "lineNumberActiveColor": "#FFB9C7D6", "scrollbarColor": "#FFE0E0E0", - "borderColor": "#FFA0A0A0" + "borderColor": "#FFA0A0A0", + "caretColor": "#FFFFFFFF" + }, "COMMENT": { "color": "#FF777777", From 4b9f2e3b478a4ee9625f2a636ec2644158891e57 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 12 Mar 2026 08:54:50 +0200 Subject: [PATCH 07/38] MASSIVE FONT RENDERING FIX, HUGE HUGE HUGE --- .../java/noppes/npcs/config/GlyphCache.java | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/main/java/noppes/npcs/config/GlyphCache.java b/src/main/java/noppes/npcs/config/GlyphCache.java index 86f34d433..ef204e798 100644 --- a/src/main/java/noppes/npcs/config/GlyphCache.java +++ b/src/main/java/noppes/npcs/config/GlyphCache.java @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; import java.awt.AlphaComposite; import java.awt.Color; @@ -43,13 +44,13 @@ public class GlyphCache { * The width in pixels of every texture used for caching pre-rendered glyph images. Used by GlyphCache when calculating * floating point 0.0-1.0 texture coordinates. Must be a power of two for mip-mapping to work. */ - private static final int TEXTURE_WIDTH = 256; + private static final int TEXTURE_WIDTH = 512; /** * The height in pixels of every texture used for caching pre-rendered glyph images. Used by GlyphCache when calculating * floating point 0.0-1.0 texture coordinates. Must be a power of two for mip-mapping to work. */ - private static final int TEXTURE_HEIGHT = 256; + private static final int TEXTURE_HEIGHT = 512; /** * Initial width in pixels of the stringImage buffer used to extract individual glyph images. @@ -66,7 +67,14 @@ public class GlyphCache { * glyphs from "bleeding through" when the scaled GUI resolution is not pixel aligned and sometimes results in off-by-one * sampling of the glyph cache textures. */ - private static final int GLYPH_BORDER = 1; + private static final int GLYPH_BORDER = 2; + + /** + * Extra padding (in pixels) added around each glyph's reported pixel bounds before blitting into the atlas. + * Font hinting (especially GASP-aware rendering) can cause rendered pixels to extend beyond the bounds + * reported by GlyphVector.getGlyphPixelBounds(). This padding ensures those overflow pixels are captured. + */ + private static final int GLYPH_PADDING = 2; /** * Transparent (alpha zero) white background color for use with BufferedImage.clearRect(). @@ -282,6 +290,11 @@ public class GlyphCache { return (int) (font.getLineMetrics(s, this.fontRenderContext).getHeight()); } + java.awt.font.LineMetrics getLineMetrics(String s) { + Font font = lookupFont(s.toCharArray(), 0, s.length(), 0); + return font.getLineMetrics(s, this.fontRenderContext); + } + /** * Given a single OpenType font, perform full text layout and create a new GlyphVector for a string. * @@ -422,6 +435,9 @@ public class GlyphCache { */ vectorBounds = vector.getPixelBounds(fontRenderContext, 0, 0); + /* Expand bounds to account for hinting overflow */ + vectorBounds.grow(GLYPH_PADDING, GLYPH_PADDING); + /* Enlage the stringImage if it is too small to store the entire rendered string */ if (stringImage == null || vectorBounds.width > stringImage.getWidth() || vectorBounds.height > stringImage.getHeight()) { int width = Math.max(vectorBounds.width, stringImage.getWidth()); @@ -429,7 +445,7 @@ public class GlyphCache { allocateStringImage(width, height); } - /* Erase the upper-left corner where the string will get drawn*/ + /* Erase the region where the string will get drawn (expanded for hinting overflow) */ stringGraphics.clearRect(0, 0, vectorBounds.width, vectorBounds.height); /* Draw string with opaque white color and baseline adjustment so the upper-left corner of the image is at (0,0) */ @@ -441,8 +457,12 @@ public class GlyphCache { * by this method is positioned around the origin of each individual glyph." However, the actual * bounds are all relative to the start of the entire GlyphVector, which is actually more useful * for extracting the glyph's image from the rendered string. + * + * Passing fontRenderContext ensures bounds match the GASP-aware rendering hints. + * The rect is then grown by GLYPH_PADDING to capture any hinting overflow pixels. */ - Rectangle rect = vector.getGlyphPixelBounds(index, null, -vectorBounds.x, -vectorBounds.y); + Rectangle rect = vector.getGlyphPixelBounds(index, fontRenderContext, -vectorBounds.x, -vectorBounds.y); + rect.grow(GLYPH_PADDING, GLYPH_PADDING); /* If the current line in cache image is full, then advance to the next line */ if (cachePosX + rect.width + GLYPH_BORDER > TEXTURE_WIDTH) { @@ -573,10 +593,20 @@ public class GlyphCache { private void setRenderingHints() { stringGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAliasEnabled ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); - stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - antiAliasEnabled ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + + if (antiAliasEnabled) { + stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); + stringGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + } else { + stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + } stringGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + + fontRenderContext = stringGraphics.getFontRenderContext(); } /** @@ -608,8 +638,10 @@ public class GlyphCache { GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, imageBuffer); /* Explicitely disable mipmap support becuase updateTexture() will only update the base level 0 */ - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); } /** From be4aa2592a80911299101fde803f89ab43ce9c80 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 12 Mar 2026 10:39:02 +0200 Subject: [PATCH 08/38] MASSIVE FONT RENDERING FIX, HUGE HUGE HUGE --- .../java/noppes/npcs/config/GlyphCache.java | 71 +++++++-- .../java/noppes/npcs/config/StringCache.java | 145 +++++++++++++----- 2 files changed, 168 insertions(+), 48 deletions(-) diff --git a/src/main/java/noppes/npcs/config/GlyphCache.java b/src/main/java/noppes/npcs/config/GlyphCache.java index 86f34d433..5379cb1b9 100644 --- a/src/main/java/noppes/npcs/config/GlyphCache.java +++ b/src/main/java/noppes/npcs/config/GlyphCache.java @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; import java.awt.AlphaComposite; import java.awt.Color; @@ -43,13 +44,13 @@ public class GlyphCache { * The width in pixels of every texture used for caching pre-rendered glyph images. Used by GlyphCache when calculating * floating point 0.0-1.0 texture coordinates. Must be a power of two for mip-mapping to work. */ - private static final int TEXTURE_WIDTH = 256; + private static final int TEXTURE_WIDTH = 512; /** * The height in pixels of every texture used for caching pre-rendered glyph images. Used by GlyphCache when calculating * floating point 0.0-1.0 texture coordinates. Must be a power of two for mip-mapping to work. */ - private static final int TEXTURE_HEIGHT = 256; + private static final int TEXTURE_HEIGHT = 512; /** * Initial width in pixels of the stringImage buffer used to extract individual glyph images. @@ -66,7 +67,14 @@ public class GlyphCache { * glyphs from "bleeding through" when the scaled GUI resolution is not pixel aligned and sometimes results in off-by-one * sampling of the glyph cache textures. */ - private static final int GLYPH_BORDER = 1; + private static final int GLYPH_BORDER = 2; + + /** + * Extra padding (in pixels) added around each glyph's reported pixel bounds before blitting into the atlas. + * Font hinting (especially GASP-aware rendering) can cause rendered pixels to extend beyond the bounds + * reported by GlyphVector.getGlyphPixelBounds(). This padding ensures those overflow pixels are captured. + */ + private static final int GLYPH_PADDING = 2; /** * Transparent (alpha zero) white background color for use with BufferedImage.clearRect(). @@ -107,9 +115,23 @@ public class GlyphCache { /** * Needed for all text layout operations that create GlyphVectors (maps point size to pixel size). + * Rebuilt after setRenderingHints() so layout FRC matches rendering FRC (especially for GASP hinting). */ private FontRenderContext fontRenderContext = glyphCacheGraphics.getFontRenderContext(); + /** + * Return the current FontRenderContext used for glyph layout and rendering. + * StringCache must use this same FRC when computing glyph pixel bounds for positioning, + * so that layout positions match the GASP-aware hinting used during rasterization. + */ + FontRenderContext getFontRenderContext() { + return fontRenderContext; + } + + int getGlyphPadding() { + return GLYPH_PADDING; + } + /** * Intermediate data array for use with textureImage.getRgb(). @@ -282,6 +304,11 @@ public class GlyphCache { return (int) (font.getLineMetrics(s, this.fontRenderContext).getHeight()); } + java.awt.font.LineMetrics getLineMetrics(String s) { + Font font = lookupFont(s.toCharArray(), 0, s.length(), 0); + return font.getLineMetrics(s, this.fontRenderContext); + } + /** * Given a single OpenType font, perform full text layout and create a new GlyphVector for a string. * @@ -386,6 +413,14 @@ public class GlyphCache { boolean vectorRendered = false; /* True if entire GlyphVector was rendered into stringImage */ for (int index = 0; index < numGlyphs; index++) { + int charIndex = start + vector.getGlyphCharIndex(index); + if (charIndex >= start && charIndex < limit) { + char c = text[charIndex]; + if (c == '\n' || c == '\r') { + continue; + } + } + /* If this glyph code is already in glyphCache, then there is no reason to pre-render it again */ int glyphCode = vector.getGlyphCode(index); if (glyphCache.containsKey(fontKey | glyphCode)) { @@ -422,6 +457,9 @@ public class GlyphCache { */ vectorBounds = vector.getPixelBounds(fontRenderContext, 0, 0); + /* Expand bounds to account for hinting overflow */ + vectorBounds.grow(GLYPH_PADDING, GLYPH_PADDING); + /* Enlage the stringImage if it is too small to store the entire rendered string */ if (stringImage == null || vectorBounds.width > stringImage.getWidth() || vectorBounds.height > stringImage.getHeight()) { int width = Math.max(vectorBounds.width, stringImage.getWidth()); @@ -429,7 +467,7 @@ public class GlyphCache { allocateStringImage(width, height); } - /* Erase the upper-left corner where the string will get drawn*/ + /* Erase the region where the string will get drawn (expanded for hinting overflow) */ stringGraphics.clearRect(0, 0, vectorBounds.width, vectorBounds.height); /* Draw string with opaque white color and baseline adjustment so the upper-left corner of the image is at (0,0) */ @@ -441,8 +479,11 @@ public class GlyphCache { * by this method is positioned around the origin of each individual glyph." However, the actual * bounds are all relative to the start of the entire GlyphVector, which is actually more useful * for extracting the glyph's image from the rendered string. + * + * Passing fontRenderContext ensures bounds match the GASP-aware rendering hints. */ - Rectangle rect = vector.getGlyphPixelBounds(index, null, -vectorBounds.x, -vectorBounds.y); + Rectangle rect = vector.getGlyphPixelBounds(index, fontRenderContext, -vectorBounds.x, -vectorBounds.y); + rect.grow(GLYPH_PADDING, GLYPH_PADDING); /* If the current line in cache image is full, then advance to the next line */ if (cachePosX + rect.width + GLYPH_BORDER > TEXTURE_WIDTH) { @@ -573,10 +614,20 @@ public class GlyphCache { private void setRenderingHints() { stringGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAliasEnabled ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); - stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - antiAliasEnabled ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + + if (antiAliasEnabled) { + stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); + stringGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + } else { + stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + } stringGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + + fontRenderContext = stringGraphics.getFontRenderContext(); } /** @@ -608,8 +659,10 @@ public class GlyphCache { GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, imageBuffer); /* Explicitely disable mipmap support becuase updateTexture() will only update the base level 0 */ - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); } /** diff --git a/src/main/java/noppes/npcs/config/StringCache.java b/src/main/java/noppes/npcs/config/StringCache.java index c40d59f1c..773e0680c 100644 --- a/src/main/java/noppes/npcs/config/StringCache.java +++ b/src/main/java/noppes/npcs/config/StringCache.java @@ -3,11 +3,13 @@ package noppes.npcs.config; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Tessellator; import net.minecraft.util.ResourceLocation; +import noppes.npcs.LogWriter; import org.lwjgl.opengl.GL11; import java.awt.Font; -import java.awt.Point; +import java.awt.Rectangle; import java.awt.font.GlyphVector; +import java.awt.geom.Point2D; import java.lang.ref.WeakReference; import java.text.Bidi; import java.util.ArrayList; @@ -71,6 +73,31 @@ public class StringCache { */ private static final int STRIKETHROUGH_THICKNESS = 2; + // BetterFonts renders glyphs at 2x internal resolution; this scale converts to GUI coords + private static final float RENDER_SCALE = 0.5F; + private static final boolean FONT_DEBUG_LOG = Boolean.getBoolean("cnpc.font.debug"); + private static final boolean FONT_DEBUG_DISABLE_INK_OFFSET = Boolean.getBoolean("cnpc.font.debug.disableInkOffset"); + + private static boolean isLineBreak(char c) { + return c == '\n' || c == '\r'; + } + + private static boolean isSpacingDebugGlyph(char c) { + return c == '(' || c == '"' || c == 't' || c == '.'; + } + + private static String debugGlyphLabel(char c) { + return c == '"' ? "\\\"" : String.valueOf(c); + } + + private static float pixelSnap(float coord) { + return (float) Math.floor(coord * 2.0F + 0.5F) * RENDER_SCALE; + } + + private int baselineOffset = BASELINE_OFFSET; + private int underlineOffset = UNDERLINE_OFFSET; + private int strikethroughOffset = STRIKETHROUGH_OFFSET; + /** * Reference to the unicode.FontRenderer class. Needed for creating GlyphVectors and retrieving glyph texture coordinates. */ @@ -319,31 +346,21 @@ public class StringCache { * the string to which this Glyph object belongs. */ static private class Glyph implements Comparable { - /** - * The index into the original string (i.e. with color codes) for the character that generated this glyph. - */ public int stringIndex; - - /** - * Texture ID and position/size of the glyph's pre-rendered image within the cache texture. - */ public GlyphCache.Entry texture; - /** - * Glyph's horizontal position (in pixels) relative to the entire string's baseline - */ + /** Logical horizontal position from getGlyphPosition() — used for spacing/advance */ public int x; - /** - * Glyph's vertical position (in pixels) relative to the entire string's baseline - */ + /** Ink vertical position from getGlyphPixelBounds() — used for texture quad placement */ public int y; - /** - * Glyph's horizontal advance (in pixels) used for strikethrough and underline effects - */ + /** Horizontal advance (logical) used for strikethrough and underline effects */ public int advance; + /** Ink X offset from logical position (inkBoundsX - logicalX) for texture quad placement */ + public int inkOffsetX; + /** * Allows arrays of Glyph objects to be sorted. Performs numeric comparison on stringIndex. * @@ -452,6 +469,17 @@ public class StringCache { maxY = g.y; } fontHeight = (int) ((maxY + height) / 2.0F - minY / 2.0F); + updateFontMetrics(); + } + + private void updateFontMetrics() { + java.awt.font.LineMetrics lm = glyphCache.getLineMetrics("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + float ascent = lm.getAscent(); + float descent = lm.getDescent(); + + baselineOffset = (int) (ascent * RENDER_SCALE + 0.5f); + underlineOffset = (int) (descent * 0.25f + 0.5f); + strikethroughOffset = -(int) (ascent * 0.35f + 0.5f); } /** @@ -495,7 +523,7 @@ public class StringCache { Entry entry = cacheString(str); /* Adjust the baseline of the string because the startY coordinate in Minecraft is for the top of the string */ - startY += BASELINE_OFFSET; + startY += baselineOffset; /* Color currently selected by color code; reapplied to Tessellator instance after glBindTexture() */ @@ -548,7 +576,7 @@ public class StringCache { /* Select the current glyph's texture information and horizontal layout position within this string */ Glyph glyph = entry.glyphs[glyphIndex]; GlyphCache.Entry texture = glyph.texture; - int glyphX = glyph.x; + int glyphX = glyph.x + glyph.inkOffsetX; /* * Replace ASCII digits in the string with their respective glyphs; strings differing by digits are only cached once. @@ -557,6 +585,10 @@ public class StringCache { * of the width mismatch. */ char c = str.charAt(glyph.stringIndex); + if (isLineBreak(c)) { + continue; + } + if (c >= '0' && c <= '9') { int oldWidth = texture.width; texture = digitGlyphs[fontStyle][c - '0'].texture; @@ -580,10 +612,20 @@ public class StringCache { } /* The divide by 2.0F is needed to align with the scaled GUI coordinate system; startX/startY are already scaled */ - float x1 = startX + (glyphX) / 2.0F; - float x2 = startX + (glyphX + texture.width) / 2.0F; - float y1 = startY + (glyph.y) / 2.0F; - float y2 = startY + (glyph.y + texture.height) / 2.0F; + if (FONT_DEBUG_DISABLE_INK_OFFSET) { + glyphX = glyph.x; + } + float x1 = pixelSnap(startX + (glyphX) * RENDER_SCALE); + float x2 = pixelSnap(startX + (glyphX + texture.width) * RENDER_SCALE); + float y1 = pixelSnap(startY + (glyph.y) * RENDER_SCALE); + float y2 = pixelSnap(startY + (glyph.y + texture.height) * RENDER_SCALE); + + if (FONT_DEBUG_LOG && isSpacingDebugGlyph(c)) { + LogWriter.info("[StringCache glyph-debug] char='" + debugGlyphLabel(c) + "' idx=" + glyph.stringIndex + + " x=" + glyph.x + " advance=" + glyph.advance + " texW=" + texture.width + + " inkOffsetX=" + glyph.inkOffsetX + " quadX1=" + x1 + " quadX2=" + x2 + + " y=" + glyph.y + " tex=" + texture.textureName); + } tessellator.addVertexWithUV(x1, y1, 0, texture.u1, texture.v1); tessellator.addVertexWithUV(x1, y2, 0, texture.u1, texture.v2); @@ -625,10 +667,10 @@ public class StringCache { /* Draw underline under glyph if the style is enabled */ if ((renderStyle & ColorCode.UNDERLINE) != 0) { /* The divide by 2.0F is needed to align with the scaled GUI coordinate system; startX/startY are already scaled */ - float x1 = startX + (glyph.x - glyphSpace) / 2.0F; - float x2 = startX + (glyph.x + glyph.advance) / 2.0F; - float y1 = startY + (UNDERLINE_OFFSET) / 2.0F; - float y2 = startY + (UNDERLINE_OFFSET + UNDERLINE_THICKNESS) / 2.0F; + float x1 = pixelSnap(startX + (glyph.x - glyphSpace) * RENDER_SCALE); + float x2 = pixelSnap(startX + (glyph.x + glyph.advance) * RENDER_SCALE); + float y1 = pixelSnap(startY + (underlineOffset) * RENDER_SCALE); + float y2 = pixelSnap(startY + (underlineOffset + UNDERLINE_THICKNESS) * RENDER_SCALE); tessellator.addVertex(x1, y1, 0); tessellator.addVertex(x1, y2, 0); @@ -639,10 +681,10 @@ public class StringCache { /* Draw strikethrough in the middle of glyph if the style is enabled */ if ((renderStyle & ColorCode.STRIKETHROUGH) != 0) { /* The divide by 2.0F is needed to align with the scaled GUI coordinate system; startX/startY are already scaled */ - float x1 = startX + (glyph.x - glyphSpace) / 2.0F; - float x2 = startX + (glyph.x + glyph.advance) / 2.0F; - float y1 = startY + (STRIKETHROUGH_OFFSET) / 2.0F; - float y2 = startY + (STRIKETHROUGH_OFFSET + STRIKETHROUGH_THICKNESS) / 2.0F; + float x1 = pixelSnap(startX + (glyph.x - glyphSpace) * RENDER_SCALE); + float x2 = pixelSnap(startX + (glyph.x + glyph.advance) * RENDER_SCALE); + float y1 = pixelSnap(startY + (strikethroughOffset) * RENDER_SCALE); + float y2 = pixelSnap(startY + (strikethroughOffset + STRIKETHROUGH_THICKNESS) * RENDER_SCALE); tessellator.addVertex(x1, y1, 0); tessellator.addVertex(x1, y2, 0); @@ -1125,6 +1167,11 @@ public class StringCache { /* Break the string up into segments, where each segment can be displayed using a single font */ while (start < limit) { + if (isLineBreak(text[start])) { + start++; + continue; + } + Font font = glyphCache.lookupFont(text, start, limit, style); int next = font.canDisplayUpTo(text, start, limit); @@ -1177,20 +1224,41 @@ public class StringCache { /* Creating a GlyphVector takes care of all language specific OpenType glyph substitutions and positionings */ GlyphVector vector = glyphCache.layoutGlyphVector(font, text, start, limit, layoutFlags); + /* + * Use the same GASP-aware FontRenderContext that was used to rasterize glyphs into the atlas. + * Passing null here would use a default FRC that can produce different pixel bounds for hinted + * glyphs, causing position mismatches and visible spacing gaps (especially on punctuation). + */ + java.awt.font.FontRenderContext frc = glyphCache.getFontRenderContext(); + /* * Extract all needed information for each glyph from the GlyphVector so it won't be needed for actual rendering. * Note that initially, glyph.start holds the character index into the stripped text array. But after the entire * string is layed out, this field will be adjusted on every Glyph object to correctly index the original unstripped * string. + * + * Use getGlyphPosition() (logical font metrics) for horizontal placement and advance calculation. + * Use getGlyphPixelBounds() only for the Y position and to compute the ink X offset from the logical X. + * This separation ensures proper inter-glyph spacing (from logical metrics) while keeping correct + * texture quad alignment (from ink bounds). Under GASP hinting, ink bounds can be tighter than + * logical positions, causing glyphs to visually touch or overlap if used for spacing. */ Glyph glyph = null; int numGlyphs = vector.getNumGlyphs(); + int glyphPadding = glyphCache.getGlyphPadding(); for (int index = 0; index < numGlyphs; index++) { - Point position = vector.getGlyphPixelBounds(index, null, advance, 0).getLocation(); + int charIndex = start + vector.getGlyphCharIndex(index); + if (charIndex >= start && charIndex < limit && isLineBreak(text[charIndex])) { + continue; + } - /* Compute horizontal advance for the previous glyph based on this glyph's position */ + Point2D logicalPos = vector.getGlyphPosition(index); + int logicalX = advance + (int) logicalPos.getX(); + Rectangle inkBounds = vector.getGlyphPixelBounds(index, frc, advance, 0); + + /* Compute horizontal advance for the previous glyph based on logical positions */ if (glyph != null) { - glyph.advance = position.x - glyph.x; + glyph.advance = logicalX - glyph.x; } /* @@ -1198,10 +1266,11 @@ public class StringCache { * it will be corrected later to account for the color codes that have been stripped out. */ glyph = new Glyph(); - glyph.stringIndex = start + vector.getGlyphCharIndex(index); + glyph.stringIndex = charIndex; glyph.texture = glyphCache.lookupGlyph(font, vector.getGlyphCode(index)); - glyph.x = position.x; - glyph.y = position.y; + glyph.x = logicalX; + glyph.y = inkBounds.y - glyphPadding; + glyph.inkOffsetX = (inkBounds.x - logicalX) - glyphPadding; glyphList.add(glyph); } @@ -1215,5 +1284,3 @@ public class StringCache { return advance; } } - - From 28d7b02350afab88c44103fdaf70236ff28e7ddd Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 12 Mar 2026 17:26:26 +0200 Subject: [PATCH 09/38] OMG BEST FONT RENDERING EVER FUUUUCK --- .../java/noppes/npcs/config/GlyphCache.java | 90 ++++++++++++++++--- .../java/noppes/npcs/config/StringCache.java | 84 ++++++++++++----- 2 files changed, 139 insertions(+), 35 deletions(-) diff --git a/src/main/java/noppes/npcs/config/GlyphCache.java b/src/main/java/noppes/npcs/config/GlyphCache.java index 5379cb1b9..76e74fb2d 100644 --- a/src/main/java/noppes/npcs/config/GlyphCache.java +++ b/src/main/java/noppes/npcs/config/GlyphCache.java @@ -1,6 +1,7 @@ package noppes.npcs.config; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; @@ -91,6 +92,21 @@ public class GlyphCache { */ private boolean antiAliasEnabled = false; + /** + * The current Minecraft GUI scale factor (1-4). Glyphs are rasterized at fontSize * guiScaleFactor + * so the atlas has enough texel density for the actual display resolution. This prevents + * GL_LINEAR texture filtering from diluting alpha values at high resolutions. + */ + private int guiScaleFactor = 1; + + /** + * Return the GUI scale factor used for glyph rasterization. StringCache uses this + * to compute an effective render scale that compensates for the larger atlas images. + */ + int getGuiScaleFactor() { + return guiScaleFactor; + } + /** * Temporary image for rendering a string to and then extracting the glyph images from. @@ -103,6 +119,7 @@ public class GlyphCache { private Graphics2D stringGraphics; + /** * All font glyphs are packed inside this image and are then loaded from here into an OpenGL texture. */ @@ -280,6 +297,7 @@ public class GlyphCache { fontSize = size; antiAliasEnabled = antiAlias; + guiScaleFactor = queryGuiScaleFactor(); setRenderingHints(); } @@ -295,10 +313,50 @@ public class GlyphCache { fontSize = size; antiAliasEnabled = antiAlias; + guiScaleFactor = queryGuiScaleFactor(); setRenderingHints(); } } + private static int queryGuiScaleFactor() { + try { + Minecraft mc = Minecraft.getMinecraft(); + if (mc != null && mc.displayWidth > 0 && mc.displayHeight > 0) { + ScaledResolution sr = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + return Math.max(1, sr.getScaleFactor()); + } + } catch (Exception ignored) { + } + return 1; + } + + /** + * Check if the GUI scale factor has changed (e.g. due to window resize) and invalidate the glyph + * cache if so. Glyphs must be re-rasterized at the new density to prevent GL_LINEAR filtering + * from diluting alpha at high display resolutions. + * + * @return true if the scale factor changed and glyphs were invalidated + */ + boolean checkAndUpdateScaleFactor() { + int newScale = queryGuiScaleFactor(); + if (newScale != guiScaleFactor) { + guiScaleFactor = newScale; + invalidateGlyphCache(); + return true; + } + return false; + } + + private void invalidateGlyphCache() { + glyphCache.clear(); + fontCache.clear(); + cachePosX = GLYPH_BORDER; + cachePosY = GLYPH_BORDER; + cacheLineHeight = 0; + allocateGlyphCacheTexture(); + allocateStringImage(STRING_WIDTH, STRING_HEIGHT); + } + int fontHeight(String s) { Font font = lookupFont(s.toCharArray(), 0, s.length(), 0); return (int) (font.getLineMetrics(s, this.fontRenderContext).getHeight()); @@ -338,6 +396,9 @@ public class GlyphCache { * @return an OpenType font capable of displaying at least the first character at the start position in text */ Font lookupFont(char text[], int start, int limit, int style) { + /* Rasterize at scaled size so atlas texel density matches display resolution */ + int renderSize = fontSize * guiScaleFactor; + /* Try using an already known base font; the first font in usedFonts list is the one set with setDefaultFont() */ Iterator iterator = usedFonts.iterator(); while (iterator.hasNext()) { @@ -345,7 +406,7 @@ public class GlyphCache { Font font = iterator.next(); if (font.canDisplayUpTo(text, start, limit) != start) { /* Return a font instance of the proper point size and style; usedFonts has only 1pt sized plain style fonts */ - return font.deriveFont(style, fontSize); + return font.deriveFont(style, renderSize); } } @@ -360,7 +421,7 @@ public class GlyphCache { usedFonts.add(font); /* Return a font instance of the proper point size and style; allFonts has only 1pt sized plain style fonts */ - return font.deriveFont(style, fontSize); + return font.deriveFont(style, renderSize); } } @@ -368,7 +429,7 @@ public class GlyphCache { Font font = usedFonts.get(0); /* Return a font instance of the proper point size and style; usedFonts only 1pt sized plain style fonts */ - return font.deriveFont(style, fontSize); + return font.deriveFont(style, renderSize); } /** @@ -460,7 +521,7 @@ public class GlyphCache { /* Expand bounds to account for hinting overflow */ vectorBounds.grow(GLYPH_PADDING, GLYPH_PADDING); - /* Enlage the stringImage if it is too small to store the entire rendered string */ + /* Enlarge the stringImage if it is too small to store the entire rendered string */ if (stringImage == null || vectorBounds.width > stringImage.getWidth() || vectorBounds.height > stringImage.getHeight()) { int width = Math.max(vectorBounds.width, stringImage.getWidth()); int height = Math.max(vectorBounds.height, stringImage.getHeight()); @@ -615,16 +676,19 @@ public class GlyphCache { stringGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAliasEnabled ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); - if (antiAliasEnabled) { - stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); - stringGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY); - } else { - stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - } +// if (antiAliasEnabled) { +// stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, +// RenderingHints.VALUE_TEXT_ANTIALIAS_ON); +// stringGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, +// RenderingHints.VALUE_RENDER_QUALITY); +// } else { +// stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, +// RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); +// } + stringGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + stringGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); stringGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); fontRenderContext = stringGraphics.getFontRenderContext(); diff --git a/src/main/java/noppes/npcs/config/StringCache.java b/src/main/java/noppes/npcs/config/StringCache.java index 773e0680c..e8d67ee32 100644 --- a/src/main/java/noppes/npcs/config/StringCache.java +++ b/src/main/java/noppes/npcs/config/StringCache.java @@ -73,8 +73,9 @@ public class StringCache { */ private static final int STRIKETHROUGH_THICKNESS = 2; - // BetterFonts renders glyphs at 2x internal resolution; this scale converts to GUI coords - private static final float RENDER_SCALE = 0.5F; + // BetterFonts base scale: maps internal 2x glyph coords to GUI coords. + // With scale-aware rasterization, the effective scale becomes BASE_RENDER_SCALE / guiScaleFactor. + private static final float BASE_RENDER_SCALE = 0.5F; private static final boolean FONT_DEBUG_LOG = Boolean.getBoolean("cnpc.font.debug"); private static final boolean FONT_DEBUG_DISABLE_INK_OFFSET = Boolean.getBoolean("cnpc.font.debug.disableInkOffset"); @@ -90,8 +91,14 @@ public class StringCache { return c == '"' ? "\\\"" : String.valueOf(c); } - private static float pixelSnap(float coord) { - return (float) Math.floor(coord * 2.0F + 0.5F) * RENDER_SCALE; + private float renderScale() { + return BASE_RENDER_SCALE / glyphCache.getGuiScaleFactor(); + } + + private float pixelSnap(float coord) { + float scale = renderScale(); + float invScale = 1.0F / scale; + return (float) Math.floor(coord * invScale + 0.5F) * scale; } private int baselineOffset = BASELINE_OFFSET; @@ -468,7 +475,8 @@ public class StringCache { if (g.y > maxY) maxY = g.y; } - fontHeight = (int) ((maxY + height) / 2.0F - minY / 2.0F); + int scaleFactor = glyphCache.getGuiScaleFactor(); + fontHeight = (int) (((maxY + height) - minY) / 2.0F / scaleFactor); updateFontMetrics(); } @@ -477,11 +485,36 @@ public class StringCache { float ascent = lm.getAscent(); float descent = lm.getDescent(); - baselineOffset = (int) (ascent * RENDER_SCALE + 0.5f); + /* + * baselineOffset is added directly to startY (GUI pixels) at render time, so it must be a + * scale-invariant GUI-pixel value. The constant BASELINE_OFFSET (7) is correct for the default + * 18pt font and remains stable across all GUI scale factors because it operates in GUI coordinate + * space — independent of the glyph rasterization scale. + * + * A dynamic formula like (ascent - padding) * renderScale is fragile: ascent comes from the + * scaled font (fontSize * scaleFactor) and rounding/font-metric variations across scales can + * produce values 1-2 pixels too large, visibly shifting text down within its highlight box. + */ + baselineOffset = BASELINE_OFFSET; + + /* + * underlineOffset and strikethroughOffset are multiplied by renderScale() at draw time + * (same as glyph.x/glyph.y), so they must be in glyph-space pixels. These scale correctly + * because ascent/descent are proportional to the rasterization size. + */ underlineOffset = (int) (descent * 0.25f + 0.5f); strikethroughOffset = -(int) (ascent * 0.35f + 0.5f); } + private void checkForScaleChange() { + if (glyphCache.checkAndUpdateScaleFactor()) { + weakRefCache.clear(); + stringCache.clear(); + cacheDightGlyphs(); + updateHeight(); + } + } + /** * Pre-cache the ASCII digits to allow for fast glyph substitution. Called once from the constructor and called any time the font selection * changes at runtime via setDefaultFont(). @@ -518,6 +551,8 @@ public class StringCache { return 0; } + /* Detect window resize: if GUI scale factor changed, invalidate all caches and re-rasterize */ + checkForScaleChange(); /* Make sure the entire string is cached before rendering and return its glyph representation */ Entry entry = cacheString(str); @@ -615,10 +650,11 @@ public class StringCache { if (FONT_DEBUG_DISABLE_INK_OFFSET) { glyphX = glyph.x; } - float x1 = pixelSnap(startX + (glyphX) * RENDER_SCALE); - float x2 = pixelSnap(startX + (glyphX + texture.width) * RENDER_SCALE); - float y1 = pixelSnap(startY + (glyph.y) * RENDER_SCALE); - float y2 = pixelSnap(startY + (glyph.y + texture.height) * RENDER_SCALE); + float rs = renderScale(); + float x1 = pixelSnap(startX + (glyphX) * rs); + float x2 = pixelSnap(startX + (glyphX + texture.width) * rs); + float y1 = pixelSnap(startY + (glyph.y) * rs); + float y2 = pixelSnap(startY + (glyph.y + texture.height) * rs); if (FONT_DEBUG_LOG && isSpacingDebugGlyph(c)) { LogWriter.info("[StringCache glyph-debug] char='" + debugGlyphLabel(c) + "' idx=" + glyph.stringIndex + @@ -667,10 +703,11 @@ public class StringCache { /* Draw underline under glyph if the style is enabled */ if ((renderStyle & ColorCode.UNDERLINE) != 0) { /* The divide by 2.0F is needed to align with the scaled GUI coordinate system; startX/startY are already scaled */ - float x1 = pixelSnap(startX + (glyph.x - glyphSpace) * RENDER_SCALE); - float x2 = pixelSnap(startX + (glyph.x + glyph.advance) * RENDER_SCALE); - float y1 = pixelSnap(startY + (underlineOffset) * RENDER_SCALE); - float y2 = pixelSnap(startY + (underlineOffset + UNDERLINE_THICKNESS) * RENDER_SCALE); + float urs = renderScale(); + float x1 = pixelSnap(startX + (glyph.x - glyphSpace) * urs); + float x2 = pixelSnap(startX + (glyph.x + glyph.advance) * urs); + float y1 = pixelSnap(startY + (underlineOffset) * urs); + float y2 = pixelSnap(startY + (underlineOffset + UNDERLINE_THICKNESS) * urs); tessellator.addVertex(x1, y1, 0); tessellator.addVertex(x1, y2, 0); @@ -681,10 +718,11 @@ public class StringCache { /* Draw strikethrough in the middle of glyph if the style is enabled */ if ((renderStyle & ColorCode.STRIKETHROUGH) != 0) { /* The divide by 2.0F is needed to align with the scaled GUI coordinate system; startX/startY are already scaled */ - float x1 = pixelSnap(startX + (glyph.x - glyphSpace) * RENDER_SCALE); - float x2 = pixelSnap(startX + (glyph.x + glyph.advance) * RENDER_SCALE); - float y1 = pixelSnap(startY + (strikethroughOffset) * RENDER_SCALE); - float y2 = pixelSnap(startY + (strikethroughOffset + STRIKETHROUGH_THICKNESS) * RENDER_SCALE); + float srs = renderScale(); + float x1 = pixelSnap(startX + (glyph.x - glyphSpace) * srs); + float x2 = pixelSnap(startX + (glyph.x + glyph.advance) * srs); + float y1 = pixelSnap(startY + (strikethroughOffset) * srs); + float y2 = pixelSnap(startY + (strikethroughOffset + STRIKETHROUGH_THICKNESS) * srs); tessellator.addVertex(x1, y1, 0); tessellator.addVertex(x1, y2, 0); @@ -700,7 +738,7 @@ public class StringCache { /* Return total horizontal advance (slightly wider than the bounding box, but close enough for centering strings) */ - return entry.advance / 2; + return (int) (entry.advance * renderScale()); } /** @@ -715,11 +753,13 @@ public class StringCache { return 0; } + checkForScaleChange(); + /* Make sure the entire string is cached and rendered since it will probably be used again in a renderString() call */ Entry entry = cacheString(str); /* Return total horizontal advance (slightly wider than the bounding box, but close enough for centering strings) */ - return entry.advance / 2; + return (int) (entry.advance * renderScale()); } /** @@ -738,8 +778,8 @@ public class StringCache { return 0; } - /* Convert the width from GUI coordinate system to pixels */ - width += width; + /* Convert the width from GUI coordinate system to internal glyph pixels */ + width = (int) (width / renderScale()); /* The glyph array for a string is sorted by the string's logical character position */ Glyph glyphs[] = cacheString(str).glyphs; From 8119515705e6f80bb36d5aa4c9b0ab0f1693d8b6 Mon Sep 17 00:00:00 2001 From: Kam Date: Thu, 12 Mar 2026 15:47:56 -0400 Subject: [PATCH 10/38] Add Script Optimizations / Caching --- src/main/java/noppes/npcs/EventHooks.java | 19 ++++++++++-- .../npcs/controllers/ScriptContainer.java | 31 +++++++++++++------ .../npcs/controllers/data/DataScript.java | 11 +++++-- .../controllers/data/ForgeDataScript.java | 18 +++++++++++ .../npcs/controllers/data/IScriptUnit.java | 7 +++++ .../java/noppes/npcs/scripted/NpcAPI.java | 3 ++ 6 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/main/java/noppes/npcs/EventHooks.java b/src/main/java/noppes/npcs/EventHooks.java index 92475f8b3..e07facff0 100644 --- a/src/main/java/noppes/npcs/EventHooks.java +++ b/src/main/java/noppes/npcs/EventHooks.java @@ -92,6 +92,7 @@ import noppes.npcs.scripted.item.ScriptItemStack; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; +import java.util.HashMap; public class EventHooks { public EventHooks() { @@ -1053,12 +1054,24 @@ public class EventHooks { NpcAPI.EVENT_BUS.post(event); } + private static final HashMap, String> forgeEventNameCache = new HashMap<>(); + + private static String getForgeEventName(Event event) { + Class clazz = event.getClass(); + String cached = forgeEventNameCache.get(clazz); + if (cached != null) + return cached; + String eventName = clazz.getName(); + int i = eventName.lastIndexOf("."); + eventName = StringUtils.uncapitalize(eventName.substring(i + 1).replace("$", "")); + forgeEventNameCache.put(clazz, eventName); + return eventName; + } + public static void onForgeEvent(ForgeEvent ev, Event event) { ForgeDataScript handler = ScriptController.Instance.forgeScripts; if (handler.isEnabled()) { - String eventName = event.getClass().getName(); - int i = eventName.lastIndexOf("."); - eventName = StringUtils.uncapitalize(eventName.substring(i + 1).replace("$", "")); + String eventName = getForgeEventName(event); if (event.isCancelable()) { ev.setCanceled(event.isCanceled()); } diff --git a/src/main/java/noppes/npcs/controllers/ScriptContainer.java b/src/main/java/noppes/npcs/controllers/ScriptContainer.java index 57c0a0ca1..77f25efd0 100644 --- a/src/main/java/noppes/npcs/controllers/ScriptContainer.java +++ b/src/main/java/noppes/npcs/controllers/ScriptContainer.java @@ -46,6 +46,7 @@ public class ScriptContainer implements IScriptUnit { private static Method luaCall; private CompiledScript compScript = null; private final HashMap cachedFunctions = new HashMap<>(); + private long lastGlobalsVersion = -1; /** * Persisted per-container language. Null means inherit from handler default. @@ -224,6 +225,7 @@ public class ScriptContainer implements IScriptUnit { if (ScriptController.Instance.lastLoaded > this.lastCreated) { this.lastCreated = ScriptController.Instance.lastLoaded; evaluated = false; + lastGlobalsVersion = -1; } synchronized (lock) { @@ -236,18 +238,24 @@ public class ScriptContainer implements IScriptUnit { engine.getContext().setWriter(pw); engine.getContext().setErrorWriter(pw); - // Populate bindings with API objects + // Populate bindings with API objects (skip if globals unchanged) + long currentGlobalsVersion = NpcAPI.engineObjectsVersion; + boolean globalsChanged = lastGlobalsVersion != currentGlobalsVersion; if (instanceBindings != null) { - instanceBindings.put("API", NpcAPI.Instance()); - HashMap engineEntries = new HashMap<>(NpcAPI.engineObjects); - for (Map.Entry objectEntry : engineEntries.entrySet()) { - instanceBindings.put(objectEntry.getKey(), objectEntry.getValue()); + if (globalsChanged) { + instanceBindings.put("API", NpcAPI.Instance()); + for (Map.Entry objectEntry : NpcAPI.engineObjects.entrySet()) { + instanceBindings.put(objectEntry.getKey(), objectEntry.getValue()); + } + lastGlobalsVersion = currentGlobalsVersion; } } else { - engine.put("API", NpcAPI.Instance()); - HashMap engineEntries = new HashMap<>(NpcAPI.engineObjects); - for (Map.Entry objectEntry : engineEntries.entrySet()) { - engine.put(objectEntry.getKey(), objectEntry.getValue()); + if (globalsChanged) { + engine.put("API", NpcAPI.Instance()); + for (Map.Entry objectEntry : NpcAPI.engineObjects.entrySet()) { + engine.put(objectEntry.getKey(), objectEntry.getValue()); + } + lastGlobalsVersion = currentGlobalsVersion; } } @@ -328,6 +336,11 @@ public class ScriptContainer implements IScriptUnit { return !this.getFullCode().isEmpty(); } + @Override + public boolean isUnknownFunction(String type) { + return unknownFunctions.contains(type); + } + public void setEngine(String scriptLanguage) { if (!Objects.equals(scriptLanguage, this.currentScriptLanguage)) { // Instance scopes share the template's engine — never create a new one diff --git a/src/main/java/noppes/npcs/controllers/data/DataScript.java b/src/main/java/noppes/npcs/controllers/data/DataScript.java index 7d9fb5c3a..1d98933ef 100644 --- a/src/main/java/noppes/npcs/controllers/data/DataScript.java +++ b/src/main/java/noppes/npcs/controllers/data/DataScript.java @@ -45,6 +45,7 @@ public class DataScript implements IScriptHandlerPacket { public String scriptLanguage = "ECMAScript"; private EntityNPCInterface npc; public boolean enabled = false; + private long lastGlobalsVersion = -1; public ICustomNpc dummyNpc; public IWorld dummyWorld; @@ -271,9 +272,13 @@ public class DataScript implements IScriptHandlerPacket { engine.put(entry.getKey(), entry.getValue().value); } - engine.put("API", NpcAPI.Instance()); - for (Map.Entry engineObjects : NpcAPI.engineObjects.entrySet()) { - engine.put(engineObjects.getKey(), engineObjects.getValue()); + long currentGlobalsVersion = NpcAPI.engineObjectsVersion; + if (lastGlobalsVersion != currentGlobalsVersion) { + engine.put("API", NpcAPI.Instance()); + for (Map.Entry engineObjects : NpcAPI.engineObjects.entrySet()) { + engine.put(engineObjects.getKey(), engineObjects.getValue()); + } + lastGlobalsVersion = currentGlobalsVersion; } } diff --git a/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java b/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java index 26685aee8..067474a0f 100644 --- a/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java +++ b/src/main/java/noppes/npcs/controllers/data/ForgeDataScript.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; public class ForgeDataScript extends MultiScriptHandler { @@ -32,6 +33,7 @@ public class ForgeDataScript extends MultiScriptHandler { private static List cachedHooks; private long lastForgeUpdate = -1L; + private final HashSet globalUnknownEvents = new HashSet<>(); public ForgeDataScript() { } @@ -59,6 +61,7 @@ public class ForgeDataScript extends MultiScriptHandler { protected void reInitScripts() { lastInited = ScriptController.Instance.lastLoaded; lastForgeUpdate = ScriptController.Instance.lastForgeUpdate; + globalUnknownEvents.clear(); for (IScriptUnit script : this.scripts) { if (script instanceof ScriptContainer) @@ -79,10 +82,25 @@ public class ForgeDataScript extends MultiScriptHandler { } } + // Skip events that no script tab handles + if (globalUnknownEvents.contains(type)) { + return; + } + + boolean anyHandled = false; for (IScriptUnit script : this.scripts) { if (script == null || script.hasErrored() || !script.hasCode()) continue; + boolean wasUnknown = script.isUnknownFunction(type); script.run(type, event); + if (!wasUnknown || !script.isUnknownFunction(type)) { + anyHandled = true; + } + } + + // If no script tab handled this event type, cache it globally + if (!anyHandled) { + globalUnknownEvents.add(type); } } diff --git a/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java b/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java index 2e4b25bad..5cdd58e04 100644 --- a/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java +++ b/src/main/java/noppes/npcs/controllers/data/IScriptUnit.java @@ -168,6 +168,13 @@ public interface IScriptUnit { */ IScriptUnit createInstanceScope(IScriptHandler instanceHandler); + /** + * Check if the given function name is known to be absent from this script unit. + */ + default boolean isUnknownFunction(String type) { + return false; + } + // ==================== EXECUTION ==================== /** diff --git a/src/main/java/noppes/npcs/scripted/NpcAPI.java b/src/main/java/noppes/npcs/scripted/NpcAPI.java index 1b0d392b2..1a0b7edf1 100644 --- a/src/main/java/noppes/npcs/scripted/NpcAPI.java +++ b/src/main/java/noppes/npcs/scripted/NpcAPI.java @@ -160,6 +160,7 @@ public class NpcAPI extends AbstractNpcAPI { private static final Map worldCache = new LRUHashMap<>(10); private static final CacheHashMap> scriptItemCache = new CacheHashMap<>(60 * 1000); public static final HashMap engineObjects = new HashMap<>(); + public static volatile long engineObjectsVersion = 0; public static final EventBus EVENT_BUS = new EventBus(); private static AbstractNpcAPI instance = null; @@ -255,10 +256,12 @@ public class NpcAPI extends AbstractNpcAPI { public void addGlobalObject(String key, Object obj) { NpcAPI.engineObjects.put(key, obj); + NpcAPI.engineObjectsVersion++; } public void removeGlobalObject(String key) { NpcAPI.engineObjects.remove(key); + NpcAPI.engineObjectsVersion++; } public boolean hasGlobalObject(String key) { From 71f0ee1973c7a4b9b38c5fc2e952324926621f8e Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Thu, 12 Mar 2026 21:48:16 +0200 Subject: [PATCH 11/38] FONT SO PRETTY IT GOT ME ACTING FONTOSEXUAL --- src/main/java/noppes/npcs/config/GlyphCache.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/config/GlyphCache.java b/src/main/java/noppes/npcs/config/GlyphCache.java index 76e74fb2d..f978f52f5 100644 --- a/src/main/java/noppes/npcs/config/GlyphCache.java +++ b/src/main/java/noppes/npcs/config/GlyphCache.java @@ -77,6 +77,15 @@ public class GlyphCache { */ private static final int GLYPH_PADDING = 2; + /** + * Spacing (in pixels) inserted between adjacent glyphs in the temporary string image during rasterization. + * Each glyph is shifted right by GLYPH_SPACING * glyphIndex to prevent kerning from merging adjacent glyphs. + * This must be >= 2 * GLYPH_PADDING + 1 so that when padded bounding boxes are extracted for adjacent glyphs, + * they never overlap. Without sufficient spacing, bold/italic glyphs (which have wider ink bounds) can bleed + * fragments of neighbouring glyphs into each other's cached texture regions. + */ + private static final int GLYPH_SPACING = 2 * GLYPH_PADDING + 1; + /** * Transparent (alpha zero) white background color for use with BufferedImage.clearRect(). */ @@ -506,7 +515,7 @@ public class GlyphCache { */ for (int i = 0; i < numGlyphs; i++) { Point2D pos = vector.getGlyphPosition(i); - pos.setLocation(pos.getX() + 2 * i, pos.getY()); + pos.setLocation(pos.getX() + GLYPH_SPACING * i, pos.getY()); vector.setGlyphPosition(i, pos); } From c797fbec8031f8e84ede542a4cc9239ab99f4fe6 Mon Sep 17 00:00:00 2001 From: Kam Date: Thu, 12 Mar 2026 20:29:05 -0400 Subject: [PATCH 12/38] Fix Base Directory for Category Manager System for NEW WORLDs --- .../noppes/npcs/controllers/AnimationController.java | 1 - .../java/noppes/npcs/controllers/CategoryManager.java | 9 ++++++++- .../noppes/npcs/controllers/CustomEffectController.java | 1 - .../noppes/npcs/controllers/LinkedItemController.java | 1 - 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/noppes/npcs/controllers/AnimationController.java b/src/main/java/noppes/npcs/controllers/AnimationController.java index ae9012b75..cf1bd2c95 100644 --- a/src/main/java/noppes/npcs/controllers/AnimationController.java +++ b/src/main/java/noppes/npcs/controllers/AnimationController.java @@ -166,7 +166,6 @@ public class AnimationController implements IAnimationHandler { File dir = getDir(); if (!dir.exists()) { dir.mkdir(); - return; } categoryManager.loadCategories(dir); diff --git a/src/main/java/noppes/npcs/controllers/CategoryManager.java b/src/main/java/noppes/npcs/controllers/CategoryManager.java index a4d14def4..80da9768d 100644 --- a/src/main/java/noppes/npcs/controllers/CategoryManager.java +++ b/src/main/java/noppes/npcs/controllers/CategoryManager.java @@ -67,6 +67,10 @@ public class CategoryManager { itemCategoryMap.remove(itemId); } + public boolean isLoaded() { + return baseDir != null; + } + public File getItemDir(int itemId) { int catId = itemCategoryMap.getOrDefault(itemId, UNCATEGORIZED_ID); return getCategoryDir(catId); @@ -86,6 +90,7 @@ public class CategoryManager { // ========== Category CRUD ========== public Category createCategory(String name) { + if (baseDir == null) return null; while (hasCategoryName(name)) name += "_"; lastUsedCatID++; Category cat = new Category(lastUsedCatID, name); @@ -96,7 +101,7 @@ public class CategoryManager { } public void saveCategory(Category cat) { - if (cat.id <= 0) return; + if (cat.id <= 0 || baseDir == null) return; Category existing = categories.get(cat.id); if (existing != null && !existing.title.equals(cat.title)) { String newTitle = cat.title; @@ -116,6 +121,7 @@ public class CategoryManager { } public boolean removeCategory(int catId, Set allItemIds) { + if (baseDir == null) return false; if (catId <= UNCATEGORIZED_ID) return false; Category cat = categories.get(catId); if (cat == null) return false; @@ -149,6 +155,7 @@ public class CategoryManager { } public void moveItem(int itemId, String fileName, int destCatId) { + if (baseDir == null) return; int oldCatId = itemCategoryMap.getOrDefault(itemId, UNCATEGORIZED_ID); if (oldCatId == destCatId) return; diff --git a/src/main/java/noppes/npcs/controllers/CustomEffectController.java b/src/main/java/noppes/npcs/controllers/CustomEffectController.java index f6338ab53..640f544c4 100644 --- a/src/main/java/noppes/npcs/controllers/CustomEffectController.java +++ b/src/main/java/noppes/npcs/controllers/CustomEffectController.java @@ -328,7 +328,6 @@ public class CustomEffectController implements ICustomEffectHandler { File dir = getDir(); if (!dir.exists()) { dir.mkdir(); - return; } categoryManager.loadCategories(dir); diff --git a/src/main/java/noppes/npcs/controllers/LinkedItemController.java b/src/main/java/noppes/npcs/controllers/LinkedItemController.java index fb461f272..f4e994c2c 100644 --- a/src/main/java/noppes/npcs/controllers/LinkedItemController.java +++ b/src/main/java/noppes/npcs/controllers/LinkedItemController.java @@ -126,7 +126,6 @@ public class LinkedItemController implements ILinkedItemHandler { File dir = getDir(); if (!dir.exists()) { dir.mkdir(); - return; } categoryManager.loadCategories(dir); From 26ae7adac578496363c2a61d3bac130fdf6ffb94 Mon Sep 17 00:00:00 2001 From: Kam Date: Thu, 12 Mar 2026 20:33:43 -0400 Subject: [PATCH 13/38] Fix Sound Selection --- .../java/noppes/npcs/client/gui/select/GuiSoundSelection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/client/gui/select/GuiSoundSelection.java b/src/main/java/noppes/npcs/client/gui/select/GuiSoundSelection.java index aba735970..220833f2b 100644 --- a/src/main/java/noppes/npcs/client/gui/select/GuiSoundSelection.java +++ b/src/main/java/noppes/npcs/client/gui/select/GuiSoundSelection.java @@ -145,7 +145,8 @@ public class GuiSoundSelection extends SubGuiInterface implements ICustomScrollL scrollSounds.resetScroll(); getTextField(66).setText(""); soundSearch = ""; - initGui(); + scrollSounds.setList(domains.get(selectedDomain)); + getButton(1).enabled = false; } if (guiCustomScroll.id == 1) { selectedResource = new ResourceLocation(selectedDomain, guiCustomScroll.getSelected()); From 254655cb1de0d4b696d641395fbcecca50f6e63e Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 02:46:16 +0200 Subject: [PATCH 14/38] Improved <> formatting and auto insertion --- .../client/gui/util/GuiScriptTextArea.java | 108 ++++++++++++++++++ .../client/gui/util/script/FormatHelper.java | 37 +++++- 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java index 74a2432b6..a37f0b4b6 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java @@ -2571,6 +2571,34 @@ public class GuiScriptTextArea extends GuiNpcTextField { String after = getSelectionAfterText(); int cursorPos = selection.getCursorPosition(); + // Diamond/generic angle bracket handling + if (c == '<') { + if (!container.getDocument().isExcludedInclusive(cursorPos) && isGenericContext(before)) { + if (hasUnmatchedCloserAhead(after, '<', '>')) { + // There's already an unmatched '>' ahead — just insert '<' + setText(before + "<" + after, true); + selection.reset(before.length() + 1); + } else { + setText(before + "<>" + after, true); + selection.reset(before.length() + 1); + } + scrollToCursor(); + autocompleteManager.onCharTyped(c, text, cursorPos); + return true; + } + } + + if (c == '>') { + if (after.length() > 0 && after.charAt(0) == '>') { + if (shouldSkipAngleBracketClose(before)) { + selection.reset(before.length() + 1); + scrollToCursor(); + autocompleteManager.onCharTyped(c, text, cursorPos); + return true; + } + } + } + if ((c == ')' || c == ']' || c == '}') && after.length() > 0 && after.charAt(0) == c) { selection.reset(before.length() + 1); scrollToCursor(); @@ -2689,6 +2717,86 @@ public class GuiScriptTextArea extends GuiNpcTextField { return (backslashes % 2) == 1; } + private boolean isGenericContext(String before) { + if (before == null || before.isEmpty()) return false; + + int i = before.length() - 1; + while (i >= 0 && (before.charAt(i) == ' ' || before.charAt(i) == '\t')) { + i--; + } + if (i < 0) return false; + + char last = before.charAt(i); + + if (last == '>' || last == ')' || last == ']') return true; + if (last == ',') return true; + + if (Character.isJavaIdentifierPart(last)) { + int end = i + 1; + while (i >= 0 && Character.isJavaIdentifierPart(before.charAt(i))) { + i--; + } + String word = before.substring(i + 1, end); + + if (isComparisonKeyword(word)) return false; + if (isNumericLiteral(word)) return false; + + return true; + } + + return false; + } + + private boolean isComparisonKeyword(String word) { + return "if".equals(word) || "while".equals(word) || "for".equals(word) + || "return".equals(word) || "else".equals(word) || "case".equals(word) + || "assert".equals(word) || "throw".equals(word) || "true".equals(word) + || "false".equals(word) || "null".equals(word); + } + + private boolean isNumericLiteral(String word) { + if (word.isEmpty()) return false; + char first = word.charAt(0); + return first >= '0' && first <= '9'; + } + + private boolean shouldSkipAngleBracketClose(String before) { + if (before == null || before.isEmpty()) return false; + int depth = 0; + boolean inLineComment = false; + boolean inBlockComment = false; + boolean inString = false; + boolean escape = false; + char stringDelimiter = 0; + + for (int i = 0; i < before.length(); i++) { + char c = before.charAt(i); + char next = i + 1 < before.length() ? before.charAt(i + 1) : 0; + + if (inString) { + if (escape) { escape = false; } + else if (c == '\\') { escape = true; } + else if (c == stringDelimiter || c == '\n') { inString = false; } + continue; + } + if (inBlockComment) { + if (c == '*' && next == '/') { inBlockComment = false; i++; } + continue; + } + if (inLineComment) { + if (c == '\n') { inLineComment = false; } + continue; + } + if (c == '/' && next == '/') { inLineComment = true; i++; continue; } + if (c == '/' && next == '*') { inBlockComment = true; i++; continue; } + if (c == '"' || c == '\'') { inString = true; stringDelimiter = c; escape = false; continue; } + + if (c == '<') depth++; + else if (c == '>') depth--; + } + return depth > 0; + } + private boolean hasUnmatchedCloserAhead(String after, char opener, char closer) { int balance = 0; int len = after.length(); diff --git a/src/main/java/noppes/npcs/client/gui/util/script/FormatHelper.java b/src/main/java/noppes/npcs/client/gui/util/script/FormatHelper.java index 989656ddf..5877c5a13 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/FormatHelper.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/FormatHelper.java @@ -1181,13 +1181,15 @@ public class FormatHelper { return settings.spaceBeforeSemicolon ? " " : ""; } - // ---- COLON spacing (ternary : always gets space, label : uses settings) ---- + // ---- COLON spacing (ternary : always gets space, enhanced-for : always gets space, label : uses settings) ---- if (prev.type == TokenType.COLON) { if (isTernaryColon(allTokens, currIdx - 1)) return " "; + if (isEnhancedForLoopColon(allTokens, currIdx - 1)) return " "; return settings.spaceAfterColon ? " " : ""; } if (curr.type == TokenType.COLON) { if (isTernaryColon(allTokens, currIdx)) return " "; + if (isEnhancedForLoopColon(allTokens, currIdx)) return " "; return settings.spaceBeforeColon ? " " : ""; } @@ -1398,6 +1400,39 @@ public class FormatHelper { return false; } + /** + * Check if a colon at the given index is the separator in an enhanced for-loop + * ({@code for (Type var : collection)}) by scanning backwards from the colon + * for an opening paren preceded by the {@code for} keyword. + */ + private boolean isEnhancedForLoopColon(List tokens, int colonIdx) { + int depth = 0; + for (int i = colonIdx - 1; i >= 0; i--) { + Token t = tokens.get(i); + if (t.type == TokenType.PAREN_CLOSE) depth++; + else if (t.type == TokenType.PAREN_OPEN) { + if (depth > 0) { + depth--; + } else { + // Found the opening paren at our depth — check if preceded by 'for' + for (int j = i - 1; j >= 0; j--) { + if (tokens.get(j).type != TokenType.WHITESPACE) { + return tokens.get(j).type == TokenType.KEYWORD + && tokens.get(j).value.equals("for"); + } + } + return false; + } + } + // Stop at statement boundaries + if (t.type == TokenType.SEMICOLON || t.type == TokenType.BRACE_OPEN || + t.type == TokenType.BRACE_CLOSE) { + return false; + } + } + return false; + } + private boolean isAssignmentOperator(String op) { switch (op) { case "=": case "+=": case "-=": case "*=": case "/=": case "%=": From f1f3b17402f1b25b2e3606af4f5c4f6a070d81ac Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:00:54 +0200 Subject: [PATCH 15/38] Correctly calculated new font width throughout script editor endpoints (for italics/bold) --- .../java/noppes/npcs/client/ClientProxy.java | 22 ++++ .../client/gui/util/GuiScriptTextArea.java | 57 ++++---- .../interpreter/ErrorUnderlineRenderer.java | 60 +++++++-- .../util/script/interpreter/ScriptLine.java | 122 ++++++++++++------ .../script/interpreter/hover/HoverState.java | 16 +-- .../java/noppes/npcs/config/StringCache.java | 37 ++++++ 6 files changed, 228 insertions(+), 86 deletions(-) diff --git a/src/main/java/noppes/npcs/client/ClientProxy.java b/src/main/java/noppes/npcs/client/ClientProxy.java index 481e6ada8..71a5b7967 100644 --- a/src/main/java/noppes/npcs/client/ClientProxy.java +++ b/src/main/java/noppes/npcs/client/ClientProxy.java @@ -930,6 +930,28 @@ public class ClientProxy extends CommonProxy { return Minecraft.getMinecraft().fontRenderer.getStringWidth(text); } + /** + * Return the width of a string when rendered with the specified font style (bold/italic). + * + * @param text the string to measure + * @param fontStyle combination of {@link java.awt.Font#BOLD} and {@link java.awt.Font#ITALIC}, + * or {@link java.awt.Font#PLAIN} for normal style + * @return the width in pixels + */ + public int width(String text, int fontStyle) { + if (useCustomFont) + return textFont.getStringWidth(text, fontStyle); + if (fontStyle == java.awt.Font.PLAIN) + return Minecraft.getMinecraft().fontRenderer.getStringWidth(text); + StringBuilder sb = new StringBuilder(); + if ((fontStyle & java.awt.Font.BOLD) != 0) + sb.append('\u00A7').append('l'); + if ((fontStyle & java.awt.Font.ITALIC) != 0) + sb.append('\u00A7').append('o'); + sb.append(text); + return Minecraft.getMinecraft().fontRenderer.getStringWidth(sb.toString()); + } + public FontContainer copy() { FontContainer font = new FontContainer(); font.textFont = textFont; diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java index a37f0b4b6..acf13e760 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java @@ -557,9 +557,13 @@ public class GuiScriptTextArea extends GuiNpcTextField { int cursorCol = 0; if (container != null && container.lines != null && cursorLine < container.lines.size()) { LineData ld = container.lines.get(cursorLine); - String lineText = ld.text; int cursorOffset = selection.getCursorPosition() - ld.start; - cursorCol = ClientProxy.Font.width(lineText.substring(0, Math.min(cursorOffset, lineText.length()))); + ScriptLine sl = container.getDocument() != null ? container.getDocument().getLine(cursorLine) : null; + if (sl != null) { + cursorCol = sl.getRenderedWidth(0, Math.min(cursorOffset, ld.text.length())); + } else { + cursorCol = ClientProxy.Font.width(ld.text.substring(0, Math.min(cursorOffset, ld.text.length()))); + } } int screenX = GuiScriptTextArea.this.x + LINE_NUMBER_GUTTER_WIDTH + 1 + cursorCol; @@ -861,13 +865,13 @@ public class GuiScriptTextArea extends GuiNpcTextField { //Highlight braces the cursor position is on if (startBracket != endBracket) { if (startBracket >= data.start && startBracket < data.end) { - int s = ClientProxy.Font.width(line.substring(0, startBracket - data.start)); - int e = ClientProxy.Font.width(line.substring(0, startBracket - data.start + 1)) + 1; + int s = scriptLine.getRenderedWidth(0, startBracket - data.start); + int e = scriptLine.getRenderedWidth(0, startBracket - data.start + 1) + 1; drawRect(x + LINE_NUMBER_GUTTER_WIDTH + 1 + s, posY, x + LINE_NUMBER_GUTTER_WIDTH + 1 + e, posY + container.lineHeight + 0, 0x9900cc00); } if (endBracket >= data.start && endBracket < data.end) { - int s = ClientProxy.Font.width(line.substring(0, endBracket - data.start)); - int e = ClientProxy.Font.width(line.substring(0, endBracket - data.start + 1)) + 1; + int s = scriptLine.getRenderedWidth(0, endBracket - data.start); + int e = scriptLine.getRenderedWidth(0, endBracket - data.start + 1) + 1; drawRect(x + LINE_NUMBER_GUTTER_WIDTH + 1 + s, posY, x + LINE_NUMBER_GUTTER_WIDTH + 1 + e, posY + container.lineHeight + 0, 0x9900cc00); } } @@ -877,8 +881,8 @@ public class GuiScriptTextArea extends GuiNpcTextField { for (int ubPos : unmatchedBraces) { if (ubPos >= data.start && ubPos < data.end) { int rel = ubPos - data.start; - int s = ClientProxy.Font.width(line.substring(0, rel)); - int e = ClientProxy.Font.width(line.substring(0, rel + 1)) + 1; + int s = scriptLine.getRenderedWidth(0, rel); + int e = scriptLine.getRenderedWidth(0, rel + 1) + 1; drawRect(x + LINE_NUMBER_GUTTER_WIDTH + 1 + s, posY, x + LINE_NUMBER_GUTTER_WIDTH + 1 + e, posY + container.lineHeight, 0xffcc0000); } } @@ -888,8 +892,8 @@ public class GuiScriptTextArea extends GuiNpcTextField { Matcher m = container.regexWord.matcher(line); while (m.find()) { if (line.substring(m.start(), m.end()).equals(highlightedWord)) { - int s = ClientProxy.Font.width(line.substring(0, m.start())); - int e = ClientProxy.Font.width(line.substring(0, m.end())) + 1; + int s = scriptLine.getRenderedWidth(0, m.start()); + int e = scriptLine.getRenderedWidth(0, m.end()) + 1; drawRect(x + LINE_NUMBER_GUTTER_WIDTH + 1 + s, posY, x + LINE_NUMBER_GUTTER_WIDTH + 1 + e, posY + container.lineHeight, 0x99004c00); } } @@ -906,8 +910,8 @@ public class GuiScriptTextArea extends GuiNpcTextField { int matchStart = Math.max(match[0] - data.start, 0); int matchEnd = Math.min(match[1] - data.start, line.length()); if (matchStart < matchEnd) { - int s = ClientProxy.Font.width(line.substring(0, matchStart)); - int e = ClientProxy.Font.width(line.substring(0, matchEnd)) + 1; + int s = scriptLine.getRenderedWidth(0, matchStart); + int e = scriptLine.getRenderedWidth(0, matchEnd) + 1; boolean isExcluded = searchBar.isMatchExcluded(mi); // Current match gets brighter highlight, others get dimmer int highlightColor = (mi == currentMatchIdx) ? 0xBB4488ff : 0x662266aa; @@ -941,9 +945,9 @@ public class GuiScriptTextArea extends GuiNpcTextField { boolean isEmpty = (occ[0] == occ[1]); if (occStart <= occEnd) { // Changed from < to <= to handle empty case - int s = ClientProxy.Font.width(line.substring(0, occStart)); - int e = isEmpty ? s + 2 : ClientProxy.Font.width( - line.substring(0, occEnd)) + 1; // 2px wide for empty + int s = scriptLine.getRenderedWidth(0, occStart); + int e = isEmpty ? s + 2 : scriptLine.getRenderedWidth( + 0, occEnd) + 1; // 2px wide for empty int occX = x + LINE_NUMBER_GUTTER_WIDTH + s; int occEndX = x + LINE_NUMBER_GUTTER_WIDTH + 2 + e; boolean isPrimary = renameHandler.isPrimaryOccurrence(occ[0]); @@ -975,7 +979,7 @@ public class GuiScriptTextArea extends GuiNpcTextField { if (currentWord != null && cursorInWord >= 0 && cursorInWord <= currentWord.length()) { String beforeCursor = currentWord.substring(0, Math.min(cursorInWord, currentWord.length())); - int cursorX = occX + ClientProxy.Font.width(beforeCursor); + int cursorX = occX + scriptLine.getRenderedWidth(occStart, occStart + beforeCursor.length()); // drawRect(cursorX, posY + 1, cursorX + 1, posY + container.lineHeight - 1, // 0xFFFFFFFF); } @@ -993,10 +997,10 @@ public class GuiScriptTextArea extends GuiNpcTextField { // Highlight selection if (selection.hasSelection() && selection.getEndSelection() > data.start && selection.getStartSelection() <= data.end) { if (selection.getStartSelection() < data.end) { - int s = ClientProxy.Font.width( - line.substring(0, Math.max(selection.getStartSelection() - data.start, 0))); - int e = ClientProxy.Font.width( - line.substring(0, Math.min(selection.getEndSelection() - data.start, w))) + 1; + int s = scriptLine.getRenderedWidth( + 0, Math.max(selection.getStartSelection() - data.start, 0)); + int e = scriptLine.getRenderedWidth( + 0, Math.min(selection.getEndSelection() - data.start, w)) + 1; drawRect(x + LINE_NUMBER_GUTTER_WIDTH + 1 + s, posY, x + LINE_NUMBER_GUTTER_WIDTH + 1 + e, posY + container.lineHeight, 0x992172ff); } } @@ -1051,8 +1055,8 @@ public class GuiScriptTextArea extends GuiNpcTextField { // Draw cursor: pause blinking while user is active recently boolean recentInput = selection.hadRecentInput(); if (active && isEnabled() && (recentInput || (cursorCounter / 10) % 2 == 0) && (selection.getCursorPosition() >= data.start && selection.getCursorPosition() < data.end || (i == list.size() - 1 && selection.getCursorPosition() == text.length()))) { - int posX = x + LINE_NUMBER_GUTTER_WIDTH + ClientProxy.Font.width( - line.substring(0, Math.min(selection.getCursorPosition() - data.start, line.length()))); + int posX = x + LINE_NUMBER_GUTTER_WIDTH + scriptLine.getRenderedWidth( + 0, Math.min(selection.getCursorPosition() - data.start, line.length())); drawRect(posX + 1, posY, posX + 2, posY + container.lineHeight, ScriptColorScheme.getBackgroundStyle().getCaretColor()); } } @@ -1144,11 +1148,14 @@ public class GuiScriptTextArea extends GuiNpcTextField { if (i >= scroll.getScrolledLine() && i <= scroll.getScrolledLine() + this.container.visibleLines +1) { double yPos = (i - scroll.getScrolledLine()) * this.container.lineHeight; if (yMouseD >= yPos && yMouseD < yPos + this.container.lineHeight) { + ScriptLine scriptLine = container.getDocument() != null ? container.getDocument().getLine(i) : null; int lineWidth = 0; char[] chars = data.text.toCharArray(); for (int j = 1; j <= chars.length; ++j) { - int w = ClientProxy.Font.width(data.text.substring(0, j)); + int w = scriptLine != null + ? scriptLine.getRenderedWidth(0, j) + : ClientProxy.Font.width(data.text.substring(0, j)); if (xMouse < lineWidth + (w - lineWidth) / 2) { return data.start + j - 1; } @@ -1226,9 +1233,9 @@ public class GuiScriptTextArea extends GuiNpcTextField { tokenLocalStart = Math.max(0, Math.min(tokenLocalStart, lineText.length())); tokenLocalEnd = Math.max(0, Math.min(tokenLocalEnd, lineText.length())); - int tokenScreenX = viewportX + ClientProxy.Font.width(lineText.substring(0, tokenLocalStart)); + int tokenScreenX = viewportX + lineData.getRenderedWidth(0, tokenLocalStart); int tokenScreenY = y + (lineIdx - scroll.getScrolledLine()) * container.lineHeight - (int)fracPixels; - int tokenWidth = ClientProxy.Font.width(lineText.substring(tokenLocalStart, tokenLocalEnd)); + int tokenWidth = lineData.getRenderedWidth(tokenLocalStart, tokenLocalEnd); return new Object[] { token, tokenScreenX, tokenScreenY, tokenWidth }; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ErrorUnderlineRenderer.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ErrorUnderlineRenderer.java index e56e08c7f..bec08df8b 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ErrorUnderlineRenderer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ErrorUnderlineRenderer.java @@ -44,19 +44,32 @@ public class ErrorUnderlineRenderer { ScriptDocument doc, int lineStartX, int baselineY, String lineText, int lineStart, int lineEnd) { + drawErrorUnderlines(doc, null, lineStartX, baselineY, lineText, lineStart, lineEnd); + } + + /** + * Draw error underlines for all validation errors in the document that intersect the given line. + * When a ScriptLine is provided, uses style-aware width calculation so underlines align + * correctly under bold/italic tokens. + */ + public static void drawErrorUnderlines( + ScriptDocument doc, ScriptLine line, + int lineStartX, int baselineY, + String lineText, int lineStart, int lineEnd) { if (doc == null) return; for (DocumentError error : doc.getErrors()) { drawUnderlineForSpan(error.getStartPos(), error.getEndPos(), - lineStartX, baselineY, lineText, lineStart, lineEnd, ERROR_COLOR); + lineStartX, baselineY, lineText, lineStart, lineEnd, ERROR_COLOR, line); } } /** * Calculate underline position for a span of text within a line. * Handles clipping to line boundaries and pixel width calculation. + * When a ScriptLine is provided, uses style-aware width calculation. * * @param spanStart Global offset where the span starts * @param spanEnd Global offset where the span ends @@ -64,11 +77,13 @@ public class ErrorUnderlineRenderer { * @param lineText The text content of the line * @param lineStart Global offset where this line starts * @param lineEnd Global offset where this line ends + * @param line Optional ScriptLine for style-aware width; null falls back to plain width * @return UnderlinePosition with x and width, or null if span doesn't intersect line */ private static UnderlinePosition calculateUnderlinePosition( int spanStart, int spanEnd, - int lineStartX, String lineText, int lineStart, int lineEnd) { + int lineStartX, String lineText, int lineStart, int lineEnd, + ScriptLine line) { // Skip if span doesn't intersect this line if (spanEnd < lineStart || spanStart > lineEnd) @@ -89,18 +104,24 @@ public class ErrorUnderlineRenderer { if (lineLocalStart < 0 || lineLocalStart >= lineText.length()) return null; - // Compute pixel position - String beforeSpan = lineText.substring(0, lineLocalStart); - int beforeWidth = ClientProxy.Font.width(beforeSpan); - + // Compute pixel position using style-aware width when available + int beforeWidth; int spanWidth; - if (lineLocalEnd > lineText.length()) { - // Span extends past line end - spanWidth = ClientProxy.Font.width(lineText.substring(lineLocalStart)); + + if (line != null) { + beforeWidth = line.getRenderedWidth(0, lineLocalStart); + int clampedEnd = Math.min(lineLocalEnd, lineText.length()); + spanWidth = line.getRenderedWidth(lineLocalStart, clampedEnd); } else { - // Span is fully on this line (or clipped) - String spanTextOnLine = lineText.substring(lineLocalStart, lineLocalEnd); - spanWidth = ClientProxy.Font.width(spanTextOnLine); + String beforeSpan = lineText.substring(0, lineLocalStart); + beforeWidth = ClientProxy.Font.width(beforeSpan); + + if (lineLocalEnd > lineText.length()) { + spanWidth = ClientProxy.Font.width(lineText.substring(lineLocalStart)); + } else { + String spanTextOnLine = lineText.substring(lineLocalStart, lineLocalEnd); + spanWidth = ClientProxy.Font.width(spanTextOnLine); + } } return new UnderlinePosition(lineStartX + beforeWidth, spanWidth); @@ -123,9 +144,22 @@ public class ErrorUnderlineRenderer { int lineStartX, int baselineY, String lineText, int lineStart, int lineEnd, int color) { + drawUnderlineForSpan(spanStart, spanEnd, lineStartX, baselineY, + lineText, lineStart, lineEnd, color, null); + } + + /** + * Draw an underline for a simple span if it intersects the line. + * When a ScriptLine is provided, uses style-aware width calculation. + */ + public static void drawUnderlineForSpan( + int spanStart, int spanEnd, + int lineStartX, int baselineY, + String lineText, int lineStart, int lineEnd, + int color, ScriptLine line) { UnderlinePosition pos = calculateUnderlinePosition( - spanStart, spanEnd, lineStartX, lineText, lineStart, lineEnd); + spanStart, spanEnd, lineStartX, lineText, lineStart, lineEnd, line); if (pos != null && pos.isValid()) { drawCurlyUnderline(pos.x, baselineY, pos.width, color); diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java index 983018edd..1265aa582 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptLine.java @@ -132,15 +132,22 @@ public class ScriptLine { clearTokens(); int cursor = globalStart; + /* + * globalEnd includes the newline character position (lineEnd = lineStart + text.length() + 1), + * but the line's text field does NOT include the newline. We must clamp all token boundaries + * to the displayable text end so that '\n' never leaks into rendered token text. + */ + int displayEnd = Math.min(globalStart + text.length(), fullText.length()); + for (Mark mark : marks) { - // Skip marks that don't overlap this line - if (mark.end <= globalStart || mark.start >= globalEnd) { + // Skip marks that don't overlap the displayable portion of this line + if (mark.end <= globalStart || mark.start >= displayEnd) { continue; } - // Clamp mark to line boundaries + // Clamp mark to displayable line boundaries (excludes trailing newline) int tokenStart = Math.max(mark.start, globalStart); - int tokenEnd = Math.min(mark.end, globalEnd); + int tokenEnd = Math.min(mark.end, displayEnd); // Validate bounds tokenStart = Math.max(0, Math.min(tokenStart, fullText.length())); @@ -168,13 +175,10 @@ public class ScriptLine { cursor = tokenEnd; } - // Add trailing default token if needed - if (cursor < globalEnd) { - int end = Math.min(globalEnd, fullText.length()); - if (cursor < end) { - String trailingText = fullText.substring(cursor, end); - addToken(Token.defaultToken(trailingText, cursor, end)); - } + // Add trailing default token if needed (clamped to displayable text, excluding newline) + if (cursor < displayEnd) { + String trailingText = fullText.substring(cursor, displayEnd); + addToken(Token.defaultToken(trailingText, cursor, displayEnd)); } } @@ -183,12 +187,7 @@ public class ScriptLine { token.setTypeInfo((TypeInfo) metadata); } else if (metadata instanceof TypeParamInfo) { TypeParamInfo typeParam = (TypeParamInfo) metadata; - TypeInfo boundType = typeParam.getBoundTypeInfo(); - if (boundType != null) { - token.setTypeInfo(TypeInfo.typeParameter(typeParam.getName(), boundType)); - } else { - token.setTypeInfo(TypeInfo.typeParameter(typeParam.getName())); - } + token.setTypeInfo(TypeInfo.typeParameter(typeParam.getName(), typeParam)); } else if (metadata instanceof MethodCallInfo) { MethodCallInfo callInfo = (MethodCallInfo) metadata; if (callInfo.isConstructor()) { @@ -234,6 +233,59 @@ public class ScriptLine { // ==================== RENDERING ==================== + /** + * Compute the rendered pixel width of a substring of this line, accounting for + * bold/italic token styles. Characters covered by bold or italic tokens will be + * measured with the appropriate font style, producing the same widths as the + * actual rendered output. + * + * @param localStart start index within the line text (inclusive) + * @param localEnd end index within the line text (exclusive) + * @return pixel width matching the rendered output + */ + public int getRenderedWidth(int localStart, int localEnd) { + localStart = Math.max(0, Math.min(localStart, text.length())); + localEnd = Math.max(localStart, Math.min(localEnd, text.length())); + if (localStart >= localEnd) return 0; + + int width = 0; + int cursor = localStart; + + for (Token t : tokens) { + if (cursor >= localEnd) break; + + int tokenLocalStart = t.getGlobalStart() - globalStart; + int tokenLocalEnd = tokenLocalStart + t.getText().length(); + + // Gap before this token (rendered as plain text) + if (cursor < tokenLocalStart) { + int gapEnd = Math.min(tokenLocalStart, localEnd); + if (gapEnd > cursor) { + width += ClientProxy.Font.width(text.substring(cursor, gapEnd)); + cursor = gapEnd; + } + } + + if (cursor >= localEnd) break; + + // Token overlap with [localStart, localEnd) + int overlapStart = Math.max(cursor, tokenLocalStart); + int overlapEnd = Math.min(tokenLocalEnd, localEnd); + if (overlapEnd > overlapStart) { + String substr = text.substring(overlapStart, overlapEnd); + width += ClientProxy.Font.width(substr, t.getFontStyle()); + cursor = overlapEnd; + } + } + + // Trailing text after last token (plain) + if (cursor < localEnd) { + width += ClientProxy.Font.width(text.substring(cursor, localEnd)); + } + + return width; + } + /** * Draw this line with syntax highlighting using Minecraft color codes. * Compatible with the existing rendering system. @@ -249,7 +301,7 @@ public class ScriptLine { for (Token t : tokens) { int tokenStart = t.getGlobalStart() - globalStart; // relative position in line - int tokenWidth = ClientProxy.Font.width(t.getText()); + int tokenWidth = ClientProxy.Font.width(t.getText(), t.getFontStyle()); // Calculate gap width before this token if (tokenStart > lastIndex && tokenStart <= text.length()) { @@ -293,12 +345,9 @@ public class ScriptLine { * Also draws wavy underlines for tokens with errors. */ public void drawStringHex(int x, int y) { - // Build the complete text with all tokens and gaps, draw it as ONE string - // to match the spacing behavior of drawString which draws everything at once - StringBuilder fullText = new StringBuilder(); int lastIndex = 0; - - // Build segments with token position info + + // Build segments with token position info and compute positions using style-aware widths java.util.List segments = new java.util.ArrayList<>(); for (Token t : tokens) { @@ -307,37 +356,29 @@ public class ScriptLine { // Add any gap before this token if (tokenStart > lastIndex && tokenStart <= text.length()) { String gap = text.substring(lastIndex, tokenStart); - segments.add(new TextSegment(fullText.length(), gap, 0xFFFFFFFF, false)); - fullText.append(gap); + segments.add(new TextSegment(lastIndex, gap, 0xFFFFFFFF, false)); } - // Add the colored token + // Add the colored token (with style prefix for rendering) String styledText = t.getStylePrefix() + t.getText(); - segments.add(new TextSegment(fullText.length(), styledText, t.getHexColor(), true)); - fullText.append(styledText); - - lastIndex = tokenStart + styledText.length(); + segments.add(new TextSegment(tokenStart, styledText, t.getHexColor(), true)); + + lastIndex = tokenStart + t.getText().length(); } // Add any remaining text after the last token if (lastIndex < text.length()) { String remaining = text.substring(lastIndex); - segments.add(new TextSegment(fullText.length(), remaining, 0xFFFFFFFF, false)); - fullText.append(remaining); + segments.add(new TextSegment(lastIndex, remaining, 0xFFFFFFFF, false)); } - // Draw each segment at the correct position - // Calculate positions based on the full string to match drawString's spacing + // Draw each segment at the correct position using style-aware width for (TextSegment seg : segments) { if (!seg.text.isEmpty()) { - // Get the width of everything before this segment - String prefix = fullText.substring(0, seg.startPos); - int prefixWidth = ClientProxy.Font.width(prefix); - int color = seg.color; + int prefixWidth = getRenderedWidth(0, seg.startPos); + int color = seg.color; - // Draw this segment at the correct position ClientProxy.Font.drawString(seg.text, x + prefixWidth, y, color); - // Minecraft.getMinecraft().fontRenderer.drawString(seg.text, x + prefixWidth, y, color); } } @@ -354,6 +395,7 @@ public class ScriptLine { ErrorUnderlineRenderer.drawErrorUnderlines( parent, + this, lineStartX, baselineY, getText(), diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java index 7618561c5..2aaf8eed4 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java @@ -302,6 +302,7 @@ public class HoverState { /** * Get the character index within a line at the given X pixel position. + * Uses style-aware width calculation to account for bold/italic tokens. */ private int getCharacterIndexAtX(ScriptLine line, int x) { String text = line.getText(); @@ -309,7 +310,7 @@ public class HoverState { int accumWidth = 0; for (int i = 0; i < text.length(); i++) { - int charWidth = noppes.npcs.client.ClientProxy.Font.width(String.valueOf(text.charAt(i))); + int charWidth = line.getRenderedWidth(i, i + 1); if (accumWidth + charWidth / 2 > x) { return i; } @@ -324,20 +325,19 @@ public class HoverState { private void calculateTokenPosition(ScriptLine line, Token token, int viewportX, int viewportY, float scrollOffset, int lineHeight) { - // X position: calculate width of text before the token - String lineText = line.getText(); + // X position: calculate width of text before the token (style-aware) int tokenLocalStart = token.getGlobalStart() - line.getGlobalStart(); - tokenLocalStart = Math.max(0, Math.min(tokenLocalStart, lineText.length())); + tokenLocalStart = Math.max(0, Math.min(tokenLocalStart, line.getText().length())); - String textBefore = lineText.substring(0, tokenLocalStart); - tokenScreenX = viewportX + noppes.npcs.client.ClientProxy.Font.width(textBefore); + tokenScreenX = viewportX + line.getRenderedWidth(0, tokenLocalStart); // Y position: line position minus scroll int lineY = line.getLineIndex(); tokenScreenY = viewportY + (int) ((lineY - scrollOffset) * lineHeight); - // Token width - tokenWidth = noppes.npcs.client.ClientProxy.Font.width(token.getText()); + // Token width (style-aware) + int tokenLocalEnd = tokenLocalStart + token.getText().length(); + tokenWidth = line.getRenderedWidth(tokenLocalStart, tokenLocalEnd); } public void setTooltipBounds(int x, int y, int width, int height) { diff --git a/src/main/java/noppes/npcs/config/StringCache.java b/src/main/java/noppes/npcs/config/StringCache.java index e8d67ee32..dcf3ecadb 100644 --- a/src/main/java/noppes/npcs/config/StringCache.java +++ b/src/main/java/noppes/npcs/config/StringCache.java @@ -762,6 +762,43 @@ public class StringCache { return (int) (entry.advance * renderScale()); } + /** + * Return the width of a string in pixels when rendered with the specified font style. + * This is needed when measuring text that will be rendered with bold/italic formatting, + * since bold glyphs are wider than plain glyphs. + * + *

The font style is applied by prepending the appropriate Minecraft formatting codes + * (§l for bold, §o for italic) to the string before measuring. This causes cacheString() + * to lay out the entire string using the specified font style. + * + * @param str compute the width of this string + * @param fontStyle combination of {@link java.awt.Font#BOLD} and {@link java.awt.Font#ITALIC} + * @return the width in pixels (in the scaled GUI coordinate system) + */ + public int getStringWidth(String str, int fontStyle) { + /* Check for invalid arguments */ + if (str == null || str.isEmpty()) { + return 0; + } + + /* If plain style, delegate to the normal method (no prefix needed) */ + if (fontStyle == Font.PLAIN) { + return getStringWidth(str); + } + + /* Build the style prefix: §l for bold, §o for italic */ + StringBuilder sb = new StringBuilder(); + if ((fontStyle & Font.BOLD) != 0) { + sb.append('\u00A7').append('l'); + } + if ((fontStyle & Font.ITALIC) != 0) { + sb.append('\u00A7').append('o'); + } + sb.append(str); + + return getStringWidth(sb.toString()); + } + /** * Return the number of characters in a string that will completly fit inside the specified width when rendered, with * or without prefering to break the line at whitespace instead of breaking in the middle of a word. This private provides From b7c3c53dc903dd565d90ad937535f9e8a4aa66ad Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:03:39 +0200 Subject: [PATCH 16/38] Fixed ScriptColorScheme not respecting resourcepack priority --- .../npcs/client/CustomNpcResourceListener.java | 2 +- .../interpreter/token/ScriptColorScheme.java | 16 +++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java b/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java index cb39c40c2..ed186d9cd 100644 --- a/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java +++ b/src/main/java/noppes/npcs/client/CustomNpcResourceListener.java @@ -30,7 +30,7 @@ public class CustomNpcResourceListener implements SimpleReloadableResourceManager simplemanager = (SimpleReloadableResourceManager) var1; FolderResourcePack pack = new FolderResourcePack(CustomNpcs.Dir); - LogWriter.info("[ResourceListener] Adding FolderResourcePack: " + CustomNpcs.Dir.getAbsolutePath()); + LogWriter.info("[ResourceListener] Adding FolderResourcePack (as fallback): " + CustomNpcs.Dir.getAbsolutePath()); simplemanager.reloadResourcePack(pack); ScriptColorScheme.reloadColorScheme(var1); diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java index e38aae462..d0b6df162 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java @@ -43,9 +43,10 @@ public final class ScriptColorScheme { public static void reloadColorScheme(IResourceManager resourceManager) { ResourceLocation loc = new ResourceLocation("customnpcs", "colorscheme/script_editor_scheme.json"); try { - IResource resource = resourceManager.getResource(loc); + List resources = resourceManager.getAllResources(loc); + IResource top = resources.get(resources.size() - 1); - try (InputStream is = resource.getInputStream(); + try (InputStream is = top.getInputStream(); InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { loadFromJson(reader); LogWriter.info("[ColorScheme] Loaded script_editor_scheme.json successfully"); @@ -60,17 +61,6 @@ public final class ScriptColorScheme { } } - private static String peekResourceContent(IResource res) { - try (InputStream peekIs = res.getInputStream()) { - byte[] buf = new byte[120]; - int read = peekIs.read(buf); - if (read > 0) { - return new String(buf, 0, read, "UTF-8").replaceAll("\\s+", " ").trim(); - } - } catch (Exception ignored) {} - return ""; - } - private static void logLoadedSample() { StyleEntry[] current = styles; TokenType[] samples = { TokenType.COMMENT, TokenType.KEYWORD, TokenType.STRING, TokenType.METHOD_CALL, TokenType.DEFAULT }; From 4ccec31efa559f1ff2d34b6e592dd3e00d7204a2 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:22:46 +0200 Subject: [PATCH 17/38] Removed MODIFIER, IMPORT_KEYWORD and CLASS_IMPORT token types, all replaced with KEYWORD --- .../script/autocomplete/AutocompleteMenu.java | 2 +- .../script/interpreter/ScriptDocument.java | 12 +-- .../interpreter/ScriptTextContainer.java | 3 - .../interpreter/hover/TokenHoverInfo.java | 82 ++++++++++--------- .../util/script/interpreter/token/Token.java | 19 +++-- .../script/interpreter/token/TokenType.java | 9 +- 6 files changed, 63 insertions(+), 64 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java index d62fbe48d..5912b5980 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java @@ -419,7 +419,7 @@ public class AutocompleteMenu extends Gui { GL11.glPushMatrix(); float scale = 0.5f; GL11.glScalef(scale, scale, scale); - int col = TokenType.MODIFIER.getHexColor(); + int col = TokenType.KEYWORD.getHexColor(); if (isStatic) font.drawString("s", (int) (textX / scale), (int) (textY / scale), col); diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index 69ddd4547..a6ea09ac3 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -4586,7 +4586,7 @@ public class ScriptDocument { // Modifiers - Java only if (!isJavaScript()) { - addPatternMarks(marks, MODIFIER_PATTERN, TokenType.MODIFIER); + addPatternMarks(marks, MODIFIER_PATTERN, TokenType.KEYWORD); } // Type declarations and usages - Java only (JS doesn't have explicit types) @@ -5297,7 +5297,7 @@ public class ScriptDocument { continue; // Mark 'import' keyword - marks.add(new ScriptLine.Mark(imp.getStartOffset(), imp.getStartOffset() + 6, TokenType.IMPORT_KEYWORD, imp)); + marks.add(new ScriptLine.Mark(imp.getStartOffset(), imp.getStartOffset() + 6, TokenType.KEYWORD, imp)); // Parse path tokens int pathStart = imp.getPathStartOffset(); @@ -5477,7 +5477,7 @@ public class ScriptDocument { if (isExcluded(m.start())) continue; - marks.add(new ScriptLine.Mark(m.start(1), m.end(1), TokenType.CLASS_KEYWORD)); + marks.add(new ScriptLine.Mark(m.start(1), m.end(1), TokenType.KEYWORD)); String kind = m.group(1); TokenType nameType; @@ -5541,7 +5541,7 @@ public class ScriptDocument { int extIdx = indexOfAtDepthZero(betweenParamsAndBrace, "extends"); if (extIdx >= 0) { int extendsAbsStart = scanPos + extIdx; - marks.add(new ScriptLine.Mark(extendsAbsStart, extendsAbsStart + 7, TokenType.IMPORT_KEYWORD)); + marks.add(new ScriptLine.Mark(extendsAbsStart, extendsAbsStart + 7, TokenType.KEYWORD)); // Extract parent name after 'extends ' String afterExtends = betweenParamsAndBrace.substring(extIdx + 7).trim(); @@ -5574,7 +5574,7 @@ public class ScriptDocument { int implIdx = indexOfAtDepthZero(betweenParamsAndBrace, "implements"); if (implIdx >= 0) { int implAbsStart = scanPos + implIdx; - marks.add(new ScriptLine.Mark(implAbsStart, implAbsStart + 10, TokenType.IMPORT_KEYWORD)); + marks.add(new ScriptLine.Mark(implAbsStart, implAbsStart + 10, TokenType.KEYWORD)); String afterImpl = betweenParamsAndBrace.substring(implIdx + 10).trim(); int implListStart = implAbsStart + 10; @@ -8201,7 +8201,7 @@ for (ScriptTypeInfo type:scriptTypes.values()) { superClass, parentConstructor, false).setConstructor(true); callInfo.validate(); methodCalls.add(callInfo); - marks.add(new ScriptLine.Mark(nameStart, nameEnd, TokenType.IMPORT_KEYWORD, + marks.add(new ScriptLine.Mark(nameStart, nameEnd, TokenType.KEYWORD, errorMsg != null ? errorMsg : callInfo)); } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptTextContainer.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptTextContainer.java index 05da45227..7a712ae6c 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptTextContainer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptTextContainer.java @@ -210,10 +210,7 @@ public class ScriptTextContainer extends JavaTextContainer { noppes.npcs.client.gui.util.script.interpreter.token.TokenType type) { if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.COMMENT) return JavaTextContainer.TokenType.COMMENT; if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.STRING) return JavaTextContainer.TokenType.STRING; - if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.CLASS_KEYWORD) return JavaTextContainer.TokenType.CLASS_KEYWORD; - if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.IMPORT_KEYWORD) return JavaTextContainer.TokenType.IMPORT_KEYWORD; if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.KEYWORD) return JavaTextContainer.TokenType.KEYWORD; - if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.MODIFIER) return JavaTextContainer.TokenType.MODIFIER; if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.INTERFACE_DECL) return JavaTextContainer.TokenType.INTERFACE_DECL; if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.ENUM_DECL) return JavaTextContainer.TokenType.ENUM_DECL; if (type == noppes.npcs.client.gui.util.script.interpreter.token.TokenType.CLASS_DECL) return JavaTextContainer.TokenType.CLASS_DECL; diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java index b45688807..fb3567223 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java @@ -17,6 +17,7 @@ import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; import noppes.npcs.client.gui.util.script.interpreter.token.Token; import noppes.npcs.client.gui.util.script.interpreter.token.TokenErrorMessage; import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; +import noppes.npcs.client.gui.util.script.interpreter.type.IntersectionTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.ScriptTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; @@ -266,17 +267,17 @@ public class TokenHoverInfo { int mods = clazz.getModifiers(); // Modifiers - if (Modifier.isPublic(mods)) addSegment("public ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isAbstract(mods) && !clazz.isInterface()) addSegment("abstract ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isFinal(mods) && !isEnum) addSegment("final ", TokenType.MODIFIER.getHexColor()); + if (Modifier.isPublic(mods)) addSegment("public ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isAbstract(mods) && !clazz.isInterface()) addSegment("abstract ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isFinal(mods) && !isEnum) addSegment("final ", TokenType.KEYWORD.getHexColor()); // Class type keyword if (clazz.isInterface()) { - addSegment("interface ", TokenType.MODIFIER.getHexColor()); + addSegment("interface ", TokenType.KEYWORD.getHexColor()); } else if (isEnum) { - addSegment("enum ", TokenType.MODIFIER.getHexColor()); + addSegment("enum ", TokenType.KEYWORD.getHexColor()); } else { - addSegment("class ", TokenType.MODIFIER.getHexColor()); + addSegment("class ", TokenType.KEYWORD.getHexColor()); } // Class name - use proper color based on type @@ -290,7 +291,7 @@ public class TokenHoverInfo { // Extends Class superclass = clazz.getSuperclass(); if (superclass != null && superclass != Object.class && !isEnum) { - addSegment(" extends ", TokenType.MODIFIER.getHexColor()); + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); addSegment(superclass.getSimpleName(), getColorForClass(superclass)); } @@ -299,7 +300,7 @@ public class TokenHoverInfo { // Implements Class[] interfaces = clazz.getInterfaces(); if (interfaces.length > 0) { - addSegment(clazz.isInterface() ? " extends " : " implements ", TokenType.MODIFIER.getHexColor()); + addSegment(clazz.isInterface() ? " extends " : " implements ", TokenType.KEYWORD.getHexColor()); for (int i = 0; i < Math.min(interfaces.length, 3); i++) { if (i > 0) addSegment(", ", TokenType.DEFAULT.getHexColor()); addSegment(interfaces[i].getSimpleName(), TokenType.INTERFACE_DECL.getHexColor()); @@ -325,19 +326,19 @@ public class TokenHoverInfo { int mods = scriptType.getModifiers(); // Modifiers - if (Modifier.isPublic(mods)) addSegment("public ", TokenType.MODIFIER.getHexColor()); + if (Modifier.isPublic(mods)) addSegment("public ", TokenType.KEYWORD.getHexColor()); if (Modifier.isAbstract(mods) && scriptType.getKind() != TypeInfo.Kind.INTERFACE) - addSegment("abstract ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isFinal(mods)) addSegment("final ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isStatic(mods)) addSegment("static ", TokenType.MODIFIER.getHexColor()); + addSegment("abstract ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isFinal(mods)) addSegment("final ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isStatic(mods)) addSegment("static ", TokenType.KEYWORD.getHexColor()); // Class type keyword if (scriptType.getKind() == TypeInfo.Kind.INTERFACE) { - addSegment("interface ", TokenType.MODIFIER.getHexColor()); + addSegment("interface ", TokenType.KEYWORD.getHexColor()); } else if (scriptType.getKind() == TypeInfo.Kind.ENUM) { - addSegment("enum ", TokenType.MODIFIER.getHexColor()); + addSegment("enum ", TokenType.KEYWORD.getHexColor()); } else { - addSegment("class ", TokenType.MODIFIER.getHexColor()); + addSegment("class ", TokenType.KEYWORD.getHexColor()); } // Class name @@ -347,7 +348,7 @@ public class TokenHoverInfo { addTypeSegments(typeInfo); addDeclaredTypeParamSegments(typeInfo); if (scriptType.hasSuperClass()) { - addSegment(" extends ", TokenType.MODIFIER.getHexColor()); + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); TypeInfo superClass = scriptType.getSuperClass(); if (superClass != null && superClass.isResolved()) { // Color based on resolved type @@ -370,7 +371,7 @@ public class TokenHoverInfo { // Already showed extends, so use comma addSegment(", ", TokenType.DEFAULT.getHexColor()); } else { - addSegment(keyword, TokenType.MODIFIER.getHexColor()); + addSegment(keyword, TokenType.KEYWORD.getHexColor()); } List interfaceNames = scriptType.getImplementedInterfaceNames(); @@ -414,12 +415,12 @@ public class TokenHoverInfo { JSTypeInfo jsType = typeInfo.getJSTypeInfo(); iconIndicator = "I"; - addSegment("interface ", TokenType.MODIFIER.getHexColor()); + addSegment("interface ", TokenType.KEYWORD.getHexColor()); addTypeSegments(typeInfo); addDeclaredTypeParamSegments(typeInfo); if (jsType.getExtendsType() != null) { - addSegment(" extends ", TokenType.MODIFIER.getHexColor()); + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); addSegment(jsType.getExtendsType(), TokenType.INTERFACE_DECL.getHexColor()); } @@ -451,7 +452,7 @@ public class TokenHoverInfo { iconIndicator = "T"; String paramName = typeInfo.getTypeParameterName(); - addSegment("type parameter ", TokenType.MODIFIER.getHexColor()); + addSegment("type parameter ", TokenType.KEYWORD.getHexColor()); addSegment("<", TokenType.DEFAULT.getHexColor()); addSegment(paramName, TokenType.GENERIC_TYPE_PARAM.getHexColor()); @@ -796,13 +797,14 @@ public class TokenHoverInfo { TypeParamInfo param = params.get(i); addSegment(param.getName(), TokenType.GENERIC_TYPE_PARAM.getHexColor()); if (param.getBoundTypeName() != null && !"Object".equals(param.getBoundTypeName())) { - addSegment(" extends ", TokenType.MODIFIER.getHexColor()); + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); TypeInfo boundType = param.getBoundTypeInfo(); if (boundType != null && boundType.isResolved()) { addTypeSegments(boundType); } else { addSegment(param.getBoundTypeName(), TokenType.IMPORTED_CLASS.getHexColor()); } + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); } } addSegment(">", TokenType.DEFAULT.getHexColor()); @@ -844,9 +846,9 @@ public class TokenHoverInfo { // Modifiers (public, private, etc.) declaration.clear(); int mods = constructor.getModifiers(); - if (Modifier.isPublic(mods)) addSegment("public ", TokenType.MODIFIER.getHexColor()); - else if (Modifier.isProtected(mods)) addSegment("protected ", TokenType.MODIFIER.getHexColor()); - else if (Modifier.isPrivate(mods)) addSegment("private ", TokenType.MODIFIER.getHexColor()); + if (Modifier.isPublic(mods)) addSegment("public ", TokenType.KEYWORD.getHexColor()); + else if (Modifier.isProtected(mods)) addSegment("protected ", TokenType.KEYWORD.getHexColor()); + else if (Modifier.isPrivate(mods)) addSegment("private ", TokenType.KEYWORD.getHexColor()); // Constructor name (same as class name) addSegment(constructor.getName(), containingType.getTokenType().getHexColor()); @@ -890,14 +892,14 @@ public class TokenHoverInfo { // Skip for now - could add later // Modifiers - if (Modifier.isPublic(mods)) addSegment("public ", TokenType.MODIFIER.getHexColor()); - else if (Modifier.isProtected(mods)) addSegment("protected ", TokenType.MODIFIER.getHexColor()); - else if (Modifier.isPrivate(mods)) addSegment("private ", TokenType.MODIFIER.getHexColor()); + if (Modifier.isPublic(mods)) addSegment("public ", TokenType.KEYWORD.getHexColor()); + else if (Modifier.isProtected(mods)) addSegment("protected ", TokenType.KEYWORD.getHexColor()); + else if (Modifier.isPrivate(mods)) addSegment("private ", TokenType.KEYWORD.getHexColor()); - if (Modifier.isStatic(mods)) addSegment("static ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isFinal(mods)) addSegment("final ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isAbstract(mods)) addSegment("abstract ", TokenType.MODIFIER.getHexColor()); - if (Modifier.isSynchronized(mods)) addSegment("synchronized ", TokenType.MODIFIER.getHexColor()); + if (Modifier.isStatic(mods)) addSegment("static ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isFinal(mods)) addSegment("final ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isAbstract(mods)) addSegment("abstract ", TokenType.KEYWORD.getHexColor()); + if (Modifier.isSynchronized(mods)) addSegment("synchronized ", TokenType.KEYWORD.getHexColor()); // Return type - check for actual type color (handle array suffix coloring) TypeInfo returnType = methodInfo.getReturnType(); @@ -932,12 +934,12 @@ public class TokenHoverInfo { if (methodInfo.isDeclaration() && methodInfo.getDeclarationOffset() >= 0) { String modifiers = extractModifiersAtPosition(methodInfo.getDeclarationOffset()); if (modifiers != null && !modifiers.isEmpty()) { - addSegment(modifiers + " ", TokenType.MODIFIER.getHexColor()); + addSegment(modifiers + " ", TokenType.KEYWORD.getHexColor()); } } else { // Fallback: show static if we know it if (methodInfo.isStatic()) { - addSegment("static ", TokenType.MODIFIER.getHexColor()); + addSegment("static ", TokenType.KEYWORD.getHexColor()); } } @@ -1395,20 +1397,20 @@ public class TokenHoverInfo { */ private void addFieldModifiers(int mods) { if (Modifier.isPublic(mods)) - addSegment("public ", TokenType.MODIFIER.getHexColor()); + addSegment("public ", TokenType.KEYWORD.getHexColor()); else if (Modifier.isProtected(mods)) - addSegment("protected ", TokenType.MODIFIER.getHexColor()); + addSegment("protected ", TokenType.KEYWORD.getHexColor()); else if (Modifier.isPrivate(mods)) - addSegment("private ", TokenType.MODIFIER.getHexColor()); + addSegment("private ", TokenType.KEYWORD.getHexColor()); if (Modifier.isStatic(mods)) - addSegment("static ", TokenType.MODIFIER.getHexColor()); + addSegment("static ", TokenType.KEYWORD.getHexColor()); if (Modifier.isFinal(mods)) - addSegment("final ", TokenType.MODIFIER.getHexColor()); + addSegment("final ", TokenType.KEYWORD.getHexColor()); if (Modifier.isVolatile(mods)) - addSegment("volatile ", TokenType.MODIFIER.getHexColor()); + addSegment("volatile ", TokenType.KEYWORD.getHexColor()); if (Modifier.isTransient(mods)) - addSegment("transient ", TokenType.MODIFIER.getHexColor()); + addSegment("transient ", TokenType.KEYWORD.getHexColor()); } /** diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/Token.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/Token.java index b7b81af9e..7e12ee0c4 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/Token.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/Token.java @@ -58,10 +58,6 @@ public class Token { return new Token(text, start, end, TokenType.KEYWORD); } - public static Token modifier(String text, int start, int end) { - return new Token(text, start, end, TokenType.MODIFIER); - } - public static Token comment(String text, int start, int end) { return new Token(text, start, end, TokenType.COMMENT); } @@ -196,8 +192,7 @@ public class Token { // ==================== TYPE CHECKS ==================== public boolean isKeyword() { - return type == TokenType.KEYWORD || type == TokenType.MODIFIER || - type == TokenType.CLASS_KEYWORD || type == TokenType.IMPORT_KEYWORD; + return type == TokenType.KEYWORD; } public boolean isTypeReference() { @@ -264,6 +259,18 @@ public class Token { return sb.toString(); } + /** + * Get the java.awt.Font style bitmask for this token. + * Returns a combination of {@link java.awt.Font#PLAIN}, {@link java.awt.Font#BOLD}, + * and {@link java.awt.Font#ITALIC}. + */ + public int getFontStyle() { + int style = java.awt.Font.PLAIN; + if (type.isBold()) style |= java.awt.Font.BOLD; + if (type.isItalic()) style |= java.awt.Font.ITALIC; + return style; + } + @Override public String toString() { return "Token{'" + text + "', " + type + ", [" + globalStart + "-" + globalEnd + "]}"; diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java index e3f5c6470..9f4b5ac69 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java @@ -22,10 +22,7 @@ public enum TokenType { UNUSED_IMPORT(0xFF666666, 119), // unused import statements (gray) // Keywords and modifiers - CLASS_KEYWORD(0xFFFF5555, 115), // 'class', 'interface', 'enum' keywords - IMPORT_KEYWORD(0xFFFFAA00, 110), // 'import' keyword - KEYWORD(0xFFFF5555, 100), // control flow: if, else, for, while, etc. - MODIFIER(0xFFFFAA00, 90), // public, private, static, final, etc. + KEYWORD(0xFFFF5555, 100,true, false), // control flow: if, else, for, while, etc. // Type declarations and references INTERFACE_DECL(0xFF55FFFF, 85), // interface names (aqua) @@ -133,12 +130,8 @@ public enum TokenType { return '6'; // gold case JSDOC_TYPE: return '3'; // dark aqua (like types) - case CLASS_KEYWORD: case KEYWORD: return 'c'; // red - case IMPORT_KEYWORD: - case MODIFIER: - return '6'; // gold case ENUM_DECL: case STATIC_FINAL_FIELD: return 'd'; // magenta From f6f19c0e485a6189df1e42789fc4fd10d820309d Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:26:06 +0200 Subject: [PATCH 18/38] Improved font rendering for ITALIC and BOLD to remove glyph artifacts --- .../java/noppes/npcs/config/GlyphCache.java | 95 +++++++++++++++++-- .../java/noppes/npcs/config/StringCache.java | 8 +- 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/src/main/java/noppes/npcs/config/GlyphCache.java b/src/main/java/noppes/npcs/config/GlyphCache.java index f978f52f5..8cc890869 100644 --- a/src/main/java/noppes/npcs/config/GlyphCache.java +++ b/src/main/java/noppes/npcs/config/GlyphCache.java @@ -78,13 +78,13 @@ public class GlyphCache { private static final int GLYPH_PADDING = 2; /** - * Spacing (in pixels) inserted between adjacent glyphs in the temporary string image during rasterization. - * Each glyph is shifted right by GLYPH_SPACING * glyphIndex to prevent kerning from merging adjacent glyphs. - * This must be >= 2 * GLYPH_PADDING + 1 so that when padded bounding boxes are extracted for adjacent glyphs, - * they never overlap. Without sufficient spacing, bold/italic glyphs (which have wider ink bounds) can bleed - * fragments of neighbouring glyphs into each other's cached texture regions. + * Minimum spacing (in pixels) inserted between adjacent glyphs in the temporary string image during + * rasterization. Each glyph is shifted right by glyphSpacing * glyphIndex to prevent kerning from + * merging adjacent glyphs. This base value is used for plain/bold styles. For italic fonts, the + * spacing is increased dynamically by {@link #computeGlyphSpacing(Font)} to account for the + * horizontal overhang caused by the italic slant. */ - private static final int GLYPH_SPACING = 2 * GLYPH_PADDING + 1; + private static final int GLYPH_SPACING_BASE = 2 * GLYPH_PADDING + 1; /** * Transparent (alpha zero) white background color for use with BufferedImage.clearRect(). @@ -158,6 +158,36 @@ public class GlyphCache { return GLYPH_PADDING; } + /** + * Compute the inter-glyph spacing needed for a given font when rasterizing into the temporary + * string image. For plain and bold fonts, the base spacing (2*GLYPH_PADDING+1) is sufficient. + * For italic fonts, the slant causes the top of each glyph to lean horizontally, and at large + * raster sizes (e.g. 54pt at scale 3) this overhang can be 8+ pixels — far exceeding the base + * spacing's 1-pixel effective gap. Without adequate spacing, adjacent italic glyphs' rendered + * pixels overlap in the string image, and narrow glyphs like 'I'/'i' capture neighboring + * fragments as visible dot artifacts in their cached texture. + * + * The italic overhang is computed as: lineHeight * |italicAngle|. Java2D's standard italic + * angle is ~0.2 (approx 12°). A safety factor of 1.5× is applied since antialiasing can + * produce faint alpha slightly beyond the geometric slant boundary. + */ + private int computeGlyphSpacing(Font font) { + float italicAngle = font.getItalicAngle(); + if (italicAngle == 0 && font.isItalic()) { + italicAngle = -0.2f; // Java2D synthetic italic default shear + } + + if (italicAngle == 0) { + return GLYPH_SPACING_BASE; + } + + java.awt.font.LineMetrics lm = font.getLineMetrics("I", fontRenderContext); + float lineHeight = lm.getAscent() + lm.getDescent(); + int italicOverhang = (int) Math.ceil(lineHeight * Math.abs(italicAngle) * 1.5f); + + return Math.max(GLYPH_SPACING_BASE, 2 * GLYPH_PADDING + italicOverhang + 1); + } + /** * Intermediate data array for use with textureImage.getRgb(). @@ -481,6 +511,7 @@ public class GlyphCache { int numGlyphs = vector.getNumGlyphs(); /* Length of the GlyphVector */ Rectangle dirty = null; /* Total area within texture that needs to be updated with glTexSubImage2D() */ boolean vectorRendered = false; /* True if entire GlyphVector was rendered into stringImage */ + int glyphSpacing = computeGlyphSpacing(font); for (int index = 0; index < numGlyphs; index++) { int charIndex = start + vector.getGlyphCharIndex(index); @@ -497,6 +528,20 @@ public class GlyphCache { continue; } + /* + * Skip whitespace glyphs that have no visible ink (spaces, tabs, etc.). These characters + * contribute only advance width, not visible pixels. Without this check, GLYPH_PADDING + * expansion would create a small non-zero rect for the empty glyph, and the blit from + * stringImage could capture stray antialiased fringe pixels from neighboring glyphs, + * causing whitespace to render as visible dots. + */ + { + Rectangle glyphBounds = vector.getGlyphPixelBounds(index, fontRenderContext, 0, 0); + if (glyphBounds.width == 0 || glyphBounds.height == 0) { + continue; + } + } + /* * The only way to get glyph shapes with font hinting is to draw the entire glyph vector into a * temporary BufferedImage, and then bit blit the individual glyphs based on their bounding boxes @@ -515,7 +560,7 @@ public class GlyphCache { */ for (int i = 0; i < numGlyphs; i++) { Point2D pos = vector.getGlyphPosition(i); - pos.setLocation(pos.getX() + GLYPH_SPACING * i, pos.getY()); + pos.setLocation(pos.getX() + glyphSpacing * i, pos.getY()); vector.setGlyphPosition(i, pos); } @@ -537,8 +582,16 @@ public class GlyphCache { allocateStringImage(width, height); } - /* Erase the region where the string will get drawn (expanded for hinting overflow) */ - stringGraphics.clearRect(0, 0, vectorBounds.width, vectorBounds.height); + /* + * Clear the ENTIRE stringImage, not just the vectorBounds area. The stringImage is reused + * across calls and may be larger than the current vectorBounds. Individual glyph pixel bounds + * (from getGlyphPixelBounds()) can differ slightly from the aggregate vector bounds + * (from getPixelBounds()) due to integer rounding. After GLYPH_PADDING expansion, a glyph's + * padded rect could extend 1-2 pixels beyond the vectorBounds area, capturing stale pixels + * from a previous render. This caused tiny dot artifacts above capital letters whose ink + * extends to the top of the line bounds. Clearing the full image eliminates this class of bugs. + */ + stringGraphics.clearRect(0, 0, stringImage.getWidth(), stringImage.getHeight()); /* Draw string with opaque white color and baseline adjustment so the upper-left corner of the image is at (0,0) */ stringGraphics.drawGlyphVector(vector, -vectorBounds.x, -vectorBounds.y); @@ -555,6 +608,30 @@ public class GlyphCache { Rectangle rect = vector.getGlyphPixelBounds(index, fontRenderContext, -vectorBounds.x, -vectorBounds.y); rect.grow(GLYPH_PADDING, GLYPH_PADDING); + /* + * Clamp the padded rect to the stringImage bounds. Due to rounding differences between + * getPixelBounds() and getGlyphPixelBounds(), a padded glyph rect can occasionally extend + * beyond the image edge. Reading pixels outside the image would cause an exception or + * capture garbage data. + */ + if (rect.x < 0) { + rect.width += rect.x; // shrink width by the overshoot + rect.x = 0; + } + if (rect.y < 0) { + rect.height += rect.y; // shrink height by the overshoot + rect.y = 0; + } + if (rect.x + rect.width > stringImage.getWidth()) { + rect.width = stringImage.getWidth() - rect.x; + } + if (rect.y + rect.height > stringImage.getHeight()) { + rect.height = stringImage.getHeight() - rect.y; + } + if (rect.width <= 0 || rect.height <= 0) { + continue; + } + /* If the current line in cache image is full, then advance to the next line */ if (cachePosX + rect.width + GLYPH_BORDER > TEXTURE_WIDTH) { cachePosX = GLYPH_BORDER; diff --git a/src/main/java/noppes/npcs/config/StringCache.java b/src/main/java/noppes/npcs/config/StringCache.java index dcf3ecadb..63c0b6a91 100644 --- a/src/main/java/noppes/npcs/config/StringCache.java +++ b/src/main/java/noppes/npcs/config/StringCache.java @@ -611,6 +611,12 @@ public class StringCache { /* Select the current glyph's texture information and horizontal layout position within this string */ Glyph glyph = entry.glyphs[glyphIndex]; GlyphCache.Entry texture = glyph.texture; + + /* Skip glyphs with no cached texture (whitespace characters like spaces and tabs) */ + if (texture == null) { + continue; + } + int glyphX = glyph.x + glyph.inkOffsetX; /* @@ -698,7 +704,7 @@ public class StringCache { Glyph glyph = entry.glyphs[glyphIndex]; /* The strike/underlines are drawn beyond the glyph's width to include the extra space between glyphs */ - int glyphSpace = glyph.advance - glyph.texture.width; + int glyphSpace = glyph.texture != null ? glyph.advance - glyph.texture.width : 0; /* Draw underline under glyph if the style is enabled */ if ((renderStyle & ColorCode.UNDERLINE) != 0) { From 547989a6d431a6097c9b3f1ac09f98cbab602dc7 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:32:27 +0200 Subject: [PATCH 19/38] Smoothened script editor scrolling again (now that we have proper fonts) --- .../noppes/npcs/client/gui/util/script/ScrollState.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/ScrollState.java b/src/main/java/noppes/npcs/client/gui/util/script/ScrollState.java index f8c92d64a..ecbe29c35 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/ScrollState.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/ScrollState.java @@ -23,9 +23,9 @@ public class ScrollState { private boolean clickScrolling = false; // Animation parameters - private static final double TAU = 0.15; // Time constant (~55ms feels snappy) - private static final double SNAP_THRESHOLD = 0.1; // Snap to target when this close (increased to avoid microstutters) - private static final double MAX_DT = 0.1; // Max delta time for stability + private static final double TAU = 0.1; // Time constant (~55ms feels snappy) + private static final double SNAP_THRESHOLD = 0.01; // Snap to target when this close (increased to avoid microstutters) + private static final double MAX_DT = 0.05; // Max delta time for stability /** * Reset scroll state to initial values From eae5a08932372dfa174d1dc392d1c02be896d57c Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:43:39 +0200 Subject: [PATCH 20/38] Made TokenType priority internal --- .../interpreter/token/ScriptColorScheme.java | 18 ++++++------- .../script/interpreter/token/TokenType.java | 19 ++++++-------- .../colorscheme/script_editor_scheme.json | 26 ------------------- 3 files changed, 17 insertions(+), 46 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java index d0b6df162..f5d6a9cb9 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/ScriptColorScheme.java @@ -13,9 +13,12 @@ import java.nio.charset.StandardCharsets; import java.util.List; /** - * Manages reloadable style overrides (color, priority, bold, italic) for {@link TokenType}, + * Manages reloadable style overrides (color, bold, italic) for {@link TokenType}, * plus editor background/gutter/scrollbar colors via {@link BackgroundStyleEntry}. *

+ * Priority is always determined internally by {@link TokenType#getPriority()} ()} + * and is never exposed to or loaded from user-facing JSON files. + *

* Loaded from {@code assets/customnpcs/colorscheme/script_editor_scheme.json} on resource reload. * Styles are cached in a flat array indexed by {@link TokenType#ordinal()} for zero-cost lookups. */ @@ -67,7 +70,7 @@ public final class ScriptColorScheme { for (TokenType tt : samples) { StyleEntry e = current[tt.ordinal()]; LogWriter.info("[ColorScheme] " + tt.name() + " -> color=#" + String.format("%08X", e.hexColor) - + ", priority=" + e.priority + ", bold=" + e.bold + ", italic=" + e.italic); + + ", bold=" + e.bold + ", italic=" + e.italic); } BackgroundStyleEntry bg = background; @@ -77,7 +80,7 @@ public final class ScriptColorScheme { /** * Parse a color scheme JSON and install it as the active scheme. - * Expected format: {@code { "TOKEN_NAME": { "color": "#RRGGBB", "priority": int, "bold": bool, "italic": bool }, ... }} + * Expected format: {@code { "TOKEN_NAME": { "color": "#RRGGBB", "bold": bool, "italic": bool }, ... }} * Missing properties per token fall back to the enum default. Parse errors are logged per-token. */ public static void loadFromJson(Reader reader) { @@ -129,11 +132,10 @@ public final class ScriptColorScheme { int color = entry.has("color") ? parseColor(entry.get("color"), defaultColor, tt.name()) : defaultColor; - int priority = entry.has("priority") ? entry.get("priority").getAsInt() : tt.getDefaultPriority(); boolean bold = entry.has("bold") ? entry.get("bold").getAsBoolean() : tt.getDefaultBold(); boolean italic = entry.has("italic") ? entry.get("italic").getAsBoolean() : tt.getDefaultItalic(); - return new StyleEntry(color, priority, bold, italic); + return new StyleEntry(color, bold, italic); } catch (Exception e) { LogWriter.error("[ColorScheme] Error parsing token " + tt.name() + ", using defaults: " + e.getMessage()); return defaultEntry(tt); @@ -145,7 +147,7 @@ public final class ScriptColorScheme { if ((color & 0xFF000000) == 0) { color |= 0xFF000000; } - return new StyleEntry(color, tt.getDefaultPriority(), tt.getDefaultBold(), tt.getDefaultItalic()); + return new StyleEntry(color, tt.getDefaultBold(), tt.getDefaultItalic()); } private static BackgroundStyleEntry parseBackground(JsonObject root) { @@ -212,13 +214,11 @@ public final class ScriptColorScheme { static final class StyleEntry { final int hexColor; - final int priority; final boolean bold; final boolean italic; - StyleEntry(int hexColor, int priority, boolean bold, boolean italic) { + StyleEntry(int hexColor, boolean bold, boolean italic) { this.hexColor = hexColor; - this.priority = priority; this.bold = bold; this.italic = italic; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java index 9f4b5ac69..7b6be3444 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java @@ -6,8 +6,9 @@ import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; * Defines all token types for syntax highlighting with hex colors and priorities. * Priority determines which token type wins when marks overlap. * Higher priority = wins conflicts. - * - * Style properties (color, priority, bold, italic) can be overridden at runtime + *

+ * Priority is defined exclusively by the enum and never stored elsewhere. + * Visual style properties (color, bold, italic) can be overridden at runtime * via {@link ScriptColorScheme}. The enum constructor values serve as compile-time defaults. */ public enum TokenType { @@ -16,7 +17,7 @@ public enum TokenType { STRING(0xFFCC8855, 130), // JSDoc elements - lower priority but will fill gaps left by fragmented comment marking - JSDOC_TAG(0xFFCC9933, 125), // @param, @type, @return etc. (gold/orange) + JSDOC_TAG(0xFFCC9933, 125,true, true), // @param, @type, @return etc. (gold/orange) JSDOC_TYPE(0xFF00AAAA, 124), // {TypeName} in JSDoc (aqua like types) UNUSED_IMPORT(0xFF666666, 119), // unused import statements (gray) @@ -52,7 +53,7 @@ public enum TokenType { DEFAULT(0xFFFFFFFF, 0); // default text color (white) private final int defaultHexColor; - private final int defaultPriority; + private final int priority; private final boolean defaultBold; private final boolean defaultItalic; @@ -62,7 +63,7 @@ public enum TokenType { TokenType(int hexColor, int priority, boolean bold, boolean italic) { this.defaultHexColor = hexColor; - this.defaultPriority = priority; + this.priority = priority; this.defaultBold = bold; this.defaultItalic = italic; } @@ -72,7 +73,7 @@ public enum TokenType { } public int getPriority() { - return ScriptColorScheme.styles[ordinal()].priority; + return priority; } public boolean isBold() { @@ -86,11 +87,7 @@ public enum TokenType { int getDefaultHexColor() { return defaultHexColor; } - - int getDefaultPriority() { - return defaultPriority; - } - + boolean getDefaultBold() { return defaultBold; } diff --git a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json index 61b0b82d4..8b41acc3f 100644 --- a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json +++ b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json @@ -12,157 +12,131 @@ }, "COMMENT": { "color": "#FF777777", - "priority": 140, "bold": false, "italic": false }, "STRING": { "color": "#FFCC8855", - "priority": 130, "bold": false, "italic": false }, "JSDOC_TAG": { "color": "#FFCC9933", - "priority": 125, "bold": false, "italic": false }, "JSDOC_TYPE": { "color": "#FF00AAAA", - "priority": 124, "bold": false, "italic": false }, "UNUSED_IMPORT": { "color": "#FF666666", - "priority": 119, "bold": false, "italic": false }, "CLASS_KEYWORD": { "color": "#FFFF5555", - "priority": 115, "bold": false, "italic": false }, "IMPORT_KEYWORD": { "color": "#FFFFAA00", - "priority": 110, "bold": false, "italic": false }, "KEYWORD": { "color": "#FFFF5555", - "priority": 100, "bold": false, "italic": false }, "MODIFIER": { "color": "#FFFFAA00", - "priority": 90, "bold": false, "italic": false }, "INTERFACE_DECL": { "color": "#FF55FFFF", - "priority": 85, "bold": false, "italic": false }, "ENUM_DECL": { "color": "#FFFF55FF", - "priority": 85, "bold": false, "italic": false }, "ENUM_CONSTANT": { "color": "#FF55FFFF", - "priority": 84, "bold": true, "italic": false }, "CLASS_DECL": { "color": "#FF00AAAA", - "priority": 85, "bold": false, "italic": false }, "IMPORTED_CLASS": { "color": "#FF00AAAA", - "priority": 75, "bold": false, "italic": false }, "GENERIC_TYPE_PARAM": { "color": "#FF00FA9A", - "priority": 76, "bold": false, "italic": false }, "TYPE_DECL": { "color": "#FF00AAAA", - "priority": 70, "bold": false, "italic": false }, "METHOD_DECL": { "color": "#FF00AA00", - "priority": 60, "bold": false, "italic": false }, "METHOD_CALL": { "color": "#FF55FF55", - "priority": 50, "bold": false, "italic": false }, "UNDEFINED_VAR": { "color": "#FFAA0000", - "priority": 20, "bold": false, "italic": false }, "PARAMETER": { "color": "#FF5555FF", - "priority": 36, "bold": false, "italic": false }, "GLOBAL_FIELD": { "color": "#FF55FFFF", - "priority": 35, "bold": false, "italic": false }, "LOCAL_FIELD": { "color": "#FFFFFF55", - "priority": 25, "bold": false, "italic": false }, "STATIC_FINAL_FIELD": { "color": "#FFFF55FF", - "priority": 36, "bold": false, "italic": true }, "LITERAL": { "color": "#FF777777", - "priority": 40, "bold": false, "italic": false }, "VARIABLE": { "color": "#FFFFFFFF", - "priority": 30, "bold": false, "italic": false }, "DEFAULT": { "color": "#FFFFFFFF", - "priority": 0, "bold": false, "italic": false } From 3b7798338f8a3b494179622013cb26f75c5320fc Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 03:53:05 +0200 Subject: [PATCH 21/38] Proper TypeInfo.typeParam overload that is much needed + IntersectionTypeInfo for type parameter > --- .../script/interpreter/ScriptDocument.java | 9 +- .../interpreter/type/GenericContext.java | 17 +- .../type/IntersectionTypeInfo.java | 160 ++++++++++++++++++ .../script/interpreter/type/TypeInfo.java | 62 +++++++ 4 files changed, 229 insertions(+), 19 deletions(-) create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/IntersectionTypeInfo.java diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index a6ea09ac3..a602fce6a 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -4343,14 +4343,7 @@ public class ScriptDocument { // Check if the name is a declared type parameter on this class (e.g., E in class Box) TypeParamInfo typeParam = enclosing.getDeclaredTypeParam(baseTypeName); if (typeParam != null) { - TypeInfo boundType = typeParam.getBoundTypeInfo(); - if (boundType == null) { - typeParam.resolveBoundType(); - boundType = typeParam.getBoundTypeInfo(); - } - TypeInfo result = (boundType != null && boundType.isResolved()) - ? TypeInfo.typeParameter(baseTypeName, boundType) - : TypeInfo.typeParameter(baseTypeName); + TypeInfo result = TypeInfo.typeParameter(baseTypeName, typeParam); for (int i = 0; i < arrayDims; i++) result = TypeInfo.arrayOf(result); return result; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java index e657e4c07..394000384 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java @@ -73,8 +73,9 @@ public final class GenericContext { if (declared == null) continue; String name = declared.getName(); if (name == null || name.isEmpty()) continue; - TypeInfo bound = declared.getBoundTypeInfo(); - bounds.put(name, (bound != null && bound.isResolved()) ? bound : TypeInfo.OBJECT); + TypeInfo tp = TypeInfo.typeParameter(name, declared); + TypeInfo effectiveBound = tp.getBoundType(); + bounds.put(name, effectiveBound != null ? effectiveBound : TypeInfo.OBJECT); } return new GenericContext(applied, bounds); @@ -125,15 +126,9 @@ public final class GenericContext { if (declared == null) continue; String name = declared.getName(); if (name == null || name.isEmpty()) continue; - TypeInfo bound = declared.getBoundTypeInfo(); - TypeInfo effectiveBound = (bound != null && bound.isResolved()) ? bound : TypeInfo.OBJECT; - - // TODO: Goatee not sure what this was for -// List additionalBounds = declared.getAdditionalBoundTypes(); -// if (additionalBounds != null && !additionalBounds.isEmpty()) { -// effectiveBound = IntersectionTypeInfo.of(effectiveBound, additionalBounds); -// } - bounds.put(name, effectiveBound); + TypeInfo tp = TypeInfo.typeParameter(name, declared); + TypeInfo effectiveBound = tp.getBoundType(); + bounds.put(name, effectiveBound != null ? effectiveBound : TypeInfo.OBJECT); } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/IntersectionTypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/IntersectionTypeInfo.java new file mode 100644 index 000000000..74e039559 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/IntersectionTypeInfo.java @@ -0,0 +1,160 @@ +package noppes.npcs.client.gui.util.script.interpreter.type; + +import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; +import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * Represents an intersection type from multiple bounds on a type parameter. + * For example, {@code >} creates an intersection + * of Number and Comparable. + * + *

The primary bound determines the display name and main type identity. + * Member lookup (hasMethod, getMethodInfo, hasField, getFieldInfo, getAllMethodOverloads) + * delegates to ALL constituent types, so methods from any bound are accessible.

+ * + *

This is used by {@link GenericContext} when building bound fallbacks for type + * parameters with additional interface bounds.

+ */ +public class IntersectionTypeInfo extends TypeInfo { + + /** The primary (first) bound type — used for display and as the "main" type. */ + private final TypeInfo primaryBound; + + /** Additional interface bounds (everything after {@code &}). */ + private final List additionalBounds; + + private IntersectionTypeInfo(TypeInfo primaryBound, List additionalBounds) { + super(primaryBound.getSimpleName(), primaryBound.getFullName(), "", + primaryBound.getKind(), primaryBound.getJavaClass(), true, null, true); + this.primaryBound = primaryBound; + this.additionalBounds = additionalBounds; + } + + /** + * Create an intersection type from a primary bound and additional interface bounds. + * If there are no additional bounds, returns the primary bound directly (no wrapper). + * + * @param primary the primary (first) bound type + * @param additional the additional interface bounds (may be empty) + * @return an IntersectionTypeInfo if there are additional bounds, otherwise the primary itself + */ + public static TypeInfo of(TypeInfo primary, List additional) { + if (additional == null || additional.isEmpty()) { + return primary; + } + return new IntersectionTypeInfo(primary, new ArrayList<>(additional)); + } + + @Override + public boolean hasMethod(String methodName) { + if (primaryBound.hasMethod(methodName)) return true; + for (TypeInfo bound : additionalBounds) { + if (bound.hasMethod(methodName)) return true; + } + return false; + } + + @Override + public boolean hasMethod(String methodName, int paramCount) { + if (primaryBound.hasMethod(methodName, paramCount)) return true; + for (TypeInfo bound : additionalBounds) { + if (bound.hasMethod(methodName, paramCount)) return true; + } + return false; + } + + @Override + public MethodInfo getMethodInfo(String methodName) { + MethodInfo m = primaryBound.getMethodInfo(methodName); + if (m != null) return m; + for (TypeInfo bound : additionalBounds) { + m = bound.getMethodInfo(methodName); + if (m != null) return m; + } + return null; + } + + @Override + public List getAllMethodOverloads(String methodName) { + Set seen = new LinkedHashSet<>(); + seen.addAll(primaryBound.getAllMethodOverloads(methodName)); + for (TypeInfo bound : additionalBounds) { + seen.addAll(bound.getAllMethodOverloads(methodName)); + } + return new ArrayList<>(seen); + } + + @Override + public MethodInfo getBestMethodOverload(String methodName, TypeInfo[] argTypes) { + MethodInfo m = primaryBound.getBestMethodOverload(methodName, argTypes); + if (m != null) return m; + for (TypeInfo bound : additionalBounds) { + m = bound.getBestMethodOverload(methodName, argTypes); + if (m != null) return m; + } + return null; + } + + @Override + public MethodInfo getBestMethodOverload(String methodName, TypeInfo expectedReturnType) { + MethodInfo m = primaryBound.getBestMethodOverload(methodName, expectedReturnType); + if (m != null) return m; + for (TypeInfo bound : additionalBounds) { + m = bound.getBestMethodOverload(methodName, expectedReturnType); + if (m != null) return m; + } + return null; + } + + @Override + public boolean hasField(String fieldName) { + if (primaryBound.hasField(fieldName)) return true; + for (TypeInfo bound : additionalBounds) { + if (bound.hasField(fieldName)) return true; + } + return false; + } + + @Override + public FieldInfo getFieldInfo(String fieldName) { + FieldInfo f = primaryBound.getFieldInfo(fieldName); + if (f != null) return f; + for (TypeInfo bound : additionalBounds) { + f = bound.getFieldInfo(fieldName); + if (f != null) return f; + } + return null; + } + + public TypeInfo getPrimaryBound() { + return primaryBound; + } + + public List getAdditionalBounds() { + return new ArrayList<>(additionalBounds); + } + + @Override + public String getDisplayName() { + StringBuilder sb = new StringBuilder(primaryBound.getDisplayName()); + for (TypeInfo bound : additionalBounds) { + sb.append(" & ").append(bound.getDisplayName()); + } + return sb.toString(); + } + + @Override + public boolean isResolved() { + return true; + } + + @Override + public String toString() { + return "IntersectionTypeInfo{" + getDisplayName() + "}"; + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 2e1fa9aa5..1c5e36967 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -194,12 +194,74 @@ public class TypeInfo { public static TypeInfo typeParameter(String paramName, TypeInfo boundType) { Class javaClass = (boundType != null && boundType.javaClass != null) ? boundType.javaClass : Object.class; Kind kind = (boundType != null) ? boundType.kind : Kind.CLASS; + + if (boundType instanceof IntersectionTypeInfo) { + final IntersectionTypeInfo intersection = (IntersectionTypeInfo) boundType; + TypeInfo ti = new TypeInfo(paramName, paramName, "", kind, javaClass, true, null) { + @Override + public List getAllMethods() { + List result = new ArrayList<>(super.getAllMethods()); + for (TypeInfo bound : intersection.getAdditionalBounds()) + result.addAll(bound.getAllMethods()); + + return result; + } + @Override + public List getAllFields() { + List result = new ArrayList<>(super.getAllFields()); + for (TypeInfo bound : intersection.getAdditionalBounds()) + result.addAll(bound.getAllFields()); + + return result; + } + }; + ti.typeParameterName = paramName; + ti.boundType = boundType; + return ti; + } + TypeInfo ti = new TypeInfo(paramName, paramName, "", kind, javaClass, true, null); ti.typeParameterName = paramName; ti.boundType = boundType; return ti; } + /** + * Create a TypeInfo representing a bounded type parameter from a {@link TypeParamInfo}. + * This is the single point of control for creating type parameter TypeInfos with bound handling. + * + *

If the TypeParamInfo has additional bounds (e.g., {@code T extends Number & Comparable}), + * an {@link IntersectionTypeInfo} is created internally to represent the combined bound. + * This centralizes intersection creation so no caller needs to call {@code IntersectionTypeInfo.of()} directly.

+ * + * @param paramName the type parameter name (e.g., "T") + * @param typeParam the TypeParamInfo containing bound information + * @return a TypeInfo tagged as a type parameter with the effective bound + */ + public static TypeInfo typeParameter(String paramName, TypeParamInfo typeParam) { + if (typeParam == null) { + return typeParameter(paramName); + } + TypeInfo primaryBound = typeParam.getBoundTypeInfo(); + if (primaryBound == null) { + typeParam.resolveBoundType(); + primaryBound = typeParam.getBoundTypeInfo(); + } + + TypeInfo effectiveBound; + if (primaryBound != null && primaryBound.isResolved()) { + List additionalBounds = typeParam.getAdditionalBoundTypes(); + if (additionalBounds != null && !additionalBounds.isEmpty()) { + effectiveBound = IntersectionTypeInfo.of(primaryBound, additionalBounds); + } else { + effectiveBound = primaryBound; + } + } else { + effectiveBound = null; + } + return typeParameter(paramName, effectiveBound); + } + public boolean isTypeParameter() { return typeParameterName != null; } From 07594f574b38c1c185a63889487640af57a798b6 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 04:56:07 +0200 Subject: [PATCH 22/38] Fixed autocomplete showing in comments --- .../gui/util/script/autocomplete/AutocompleteManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java index 1ef9d3034..976688865 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java @@ -165,7 +165,7 @@ public class AutocompleteManager { */ public void onCharTyped(char c, String text, int cursorPosition) { // Check if we should close autocomplete - if (CLOSE_CHARS.indexOf(c) >= 0) { + if (CLOSE_CHARS.indexOf(c) >= 0 || document.isExcludedInclusive(cursorPosition)) { dismiss(); return; } From a3c7398628fd8bc41d8057bf02e3e25f0b041ddc Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 05:52:41 +0200 Subject: [PATCH 23/38] Whole buncha ergonomic hover info tweaks --- .../client/gui/util/GuiScriptTextArea.java | 12 ++++-- .../script/interpreter/hover/HoverState.java | 24 +++++++++++- .../interpreter/hover/TokenHoverInfo.java | 10 ++--- .../interpreter/hover/TokenHoverRenderer.java | 38 ++++++++++++++----- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java index acf13e760..647621117 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java @@ -629,9 +629,15 @@ public class GuiScriptTextArea extends GuiNpcTextField { ((GuiNPCInterface) listener).mouseScroll = wheelDelta; // Intercept wheel scroll for tooltip (highest priority) - if (wheelDelta != 0 && hoverState.isTooltipVisible() && hoverState.isMouseOverTooltip(xMouse, yMouse)) { - hoverState.scrollTooltip(wheelDelta); - wheelDelta = 0; + // Only consume the wheel event when the tooltip actually has content to scroll; + // otherwise let it fall through to the editor so non-scrollable tooltips don't eat input. + if (wheelDelta != 0 && hoverState.isTooltipVisible()) { + if (hoverState.isMouseOverTooltip(xMouse, yMouse)) { + hoverState.scrollTooltip(wheelDelta); + wheelDelta = 0; + } else { + hoverState.clearHover(); + } } // Let autocomplete menu consume scroll first if visible diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java index 2aaf8eed4..af018e5bb 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/HoverState.java @@ -19,7 +19,7 @@ import noppes.npcs.client.gui.util.script.interpreter.token.Token; public class HoverState { /** Minimum hover time (ms) before showing tooltip */ - private static final long HOVER_DELAY_MS = 100; + private static final long HOVER_DELAY_MS = 250; // ==================== STATE ==================== @@ -89,6 +89,11 @@ public class HoverState { /** Whether click-to-pin behaviour is enabled for this hover state. */ private boolean clickToPinEnabled = true; + /** Locked mouse position for tooltip placement (captured once when tooltip becomes visible) */ + private int lockedTooltipMouseX; + private int lockedTooltipMouseY; + private boolean isTooltipPositionLocked; + // ==================== UPDATE ==================== /** @@ -172,6 +177,9 @@ public class HoverState { if (elapsed >= HOVER_DELAY_MS && !tooltipVisible) { tooltipVisible = true; hoverInfo = TokenHoverInfo.fromToken(token); + lockedTooltipMouseX = lastMouseX; + lockedTooltipMouseY = lastMouseY; + isTooltipPositionLocked = true; } } } @@ -223,6 +231,9 @@ public class HoverState { if (elapsed >= HOVER_DELAY_MS && !tooltipVisible) { tooltipVisible = true; hoverInfo = TokenHoverInfo.fromToken(token); + lockedTooltipMouseX = lastMouseX; + lockedTooltipMouseY = lastMouseY; + isTooltipPositionLocked = true; } } } @@ -249,6 +260,7 @@ public class HoverState { targetScrollOffset = 0; tooltipMaxScroll = 0; isDraggingScrollbar = false; + isTooltipPositionLocked = false; } } } @@ -284,6 +296,11 @@ public class HoverState { this.tokenWidth = tokenW; // ensure hoveredToken reflects pinned token this.hoveredToken = token; + if (this.tooltipVisible && !this.isTooltipPositionLocked) { + this.lockedTooltipMouseX = lastMouseX; + this.lockedTooltipMouseY = lastMouseY; + this.isTooltipPositionLocked = true; + } } /** @@ -294,10 +311,15 @@ public class HoverState { this.pinnedHoverInfo = null; this.tooltipVisible = false; this.hoverInfo = null; + this.isTooltipPositionLocked = false; } public boolean isPinned() { return pinnedToken != null; } + public int getLockedMouseX() { return lockedTooltipMouseX; } + public int getLockedMouseY() { return lockedTooltipMouseY; } + public boolean isPositionLocked() { return isTooltipPositionLocked; } + // ==================== POSITION CALCULATION ==================== /** diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java index fb3567223..567f0a8f7 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java @@ -17,7 +17,6 @@ import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; import noppes.npcs.client.gui.util.script.interpreter.token.Token; import noppes.npcs.client.gui.util.script.interpreter.token.TokenErrorMessage; import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; -import noppes.npcs.client.gui.util.script.interpreter.type.IntersectionTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.ScriptTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; @@ -186,7 +185,6 @@ public class TokenHoverInfo { break; case LITERAL: case KEYWORD: - case MODIFIER: case STRING: case COMMENT: if (info.hasErrors()) @@ -443,7 +441,7 @@ public class TokenHoverInfo { if (token.getMethodInfo() != null) { MethodInfo constructor = token.getMethodInfo(); declaration.add(new TextSegment("\n", TokenType.DEFAULT.getHexColor())); - additionalInfo.add("Constructor"); + // additionalInfo.add("Constructor"); buildConstructorDeclaration(constructor, typeInfo); } } @@ -458,7 +456,7 @@ public class TokenHoverInfo { TypeInfo bound = typeInfo.getBoundType(); if (bound != null && bound.getJavaClass() != null && bound.getJavaClass() != Object.class) { - addSegment(" extends ", TokenType.MODIFIER.getHexColor()); + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); addSegment(bound.getSimpleName(), getColorForTypeInfo(bound)); } addSegment(">", TokenType.DEFAULT.getHexColor()); @@ -674,7 +672,7 @@ public class TokenHoverInfo { addInitializationTokens(token, fieldInfo); // Show it's a local variable - additionalInfo.add("Local variable"); + // additionalInfo.add("Local variable"); } public String getPackageName(TypeInfo type) { @@ -723,7 +721,7 @@ public class TokenHoverInfo { addSegment(fieldInfo.getName(), TokenType.PARAMETER.getHexColor()); - additionalInfo.add("Parameter"); + // additionalInfo.add("Parameter"); } private void extractUndefinedInfo(Token token) { diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java index aed5d4391..ec9fae79a 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverRenderer.java @@ -39,7 +39,7 @@ public class TokenHoverRenderer { private static final int SEPARATOR_SPACING = 5; /** Vertical offset from token */ - private static final int VERTICAL_OFFSET = 4; + private static final int VERTICAL_OFFSET = 1; /** Maximum tooltip width as percentage of viewport */ private static final float MAX_WIDTH_RATIO = 0.9f; @@ -137,9 +137,20 @@ public class TokenHoverRenderer { } } - // Position the tooltip — use dragged position if user has panned the panel - int tooltipX = positionOverridden ? hoverState.getOverriddenTooltipX() : tokenX; - int tooltipY = positionOverridden ? hoverState.getOverriddenTooltipY() : tokenY + lineHeight + VERTICAL_OFFSET; + // Position the tooltip — use dragged position if user has panned the panel, + // otherwise use locked mouse position (captured when tooltip first became visible) + int tooltipX; + int tooltipY; + if (positionOverridden) { + tooltipX = hoverState.getOverriddenTooltipX(); + tooltipY = hoverState.getOverriddenTooltipY(); + } else if (hoverState.isPositionLocked()) { + tooltipX = hoverState.getLockedMouseX() + 2; + tooltipY = tokenY + lineHeight + VERTICAL_OFFSET; + } else { + tooltipX = tokenX; + tooltipY = tokenY + lineHeight + VERTICAL_OFFSET; + } // Clamp position — use screen bounds when user has dragged the panel outside the editor viewport int leftBound = useScreenBounds ? 0 : viewportX; @@ -164,7 +175,7 @@ public class TokenHoverRenderer { if (useScreenBounds) { tooltipY = bottomBound - boxHeight; } else { - tooltipY = tokenY - boxHeight - VERTICAL_OFFSET; // try above token + tooltipY = tokenY - boxHeight; } } if (tooltipY < topBound) { @@ -176,13 +187,20 @@ public class TokenHoverRenderer { // Mouse-over detection bounds: // When dragged, use panel rect only — no gap extension (token is unrelated to panel position) - // When default, union the token bottom and the tooltip rect so both directions are covered + // When default and tooltip is BELOW the token, union the token bottom and the tooltip rect + // so the small gap between token and tooltip doesn't break hover detection. + // When tooltip is ABOVE the token, use only the tooltip rect — bridging would cover + // intervening tokens and prevent hover-switching between them. if (hoverState.hasOverriddenPosition()) { hoverState.setTooltipBounds(tooltipX, tooltipY, boxWidth, boxHeight); - } else { - int boundsTopY = Math.min(tokenY + lineHeight, tooltipY); - int boundsBottomY = Math.max(tooltipY + boxHeight, tokenY + lineHeight); + } else if (tooltipY >= tokenY + lineHeight) { + // Tooltip is below the token — bridge the gap + int boundsTopY = tokenY + lineHeight; + int boundsBottomY = tooltipY + boxHeight; hoverState.setTooltipBounds(tooltipX, boundsTopY, boxWidth, boundsBottomY - boundsTopY); + } else { + // Tooltip is above the token — use tooltip rect only + hoverState.setTooltipBounds(tooltipX, tooltipY, boxWidth, boxHeight); } // Render the tooltip @@ -218,7 +236,7 @@ public class TokenHoverRenderer { int boxHeight = visibleContentHeight + PADDING * 2; // Store scroll metadata into HoverState - hoverState.setTooltipMaxScroll(Math.max(0, totalContentHeight - visibleContentHeight + BOTTOM_GAP)); + hoverState.setTooltipMaxScroll(Math.max(0, totalContentHeight - visibleContentHeight + (hasScrollbar? BOTTOM_GAP : 0))); // Draw background Gui.drawRect(x, y, x + boxWidth, y + boxHeight, BG_COLOR); From 728208183208f76af0962d8b46d32000c9408403 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 06:06:00 +0200 Subject: [PATCH 24/38] Fixed x undefined when //comment. x = 10; --- .../npcs/client/gui/util/script/interpreter/ScriptDocument.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index a602fce6a..dfe41103d 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -10211,7 +10211,7 @@ for (ScriptTypeInfo type:scriptTypes.values()) { int i = position - 1; while (i >= 0 && Character.isWhitespace(text.charAt(i))) i--; - return i >= 0 && text.charAt(i) == '.'; + return i >= 0 && text.charAt(i) == '.' && !isExcluded(i); } boolean isInImportOrPackage(int position) { From 0906378894ef52e8dca4c18315b9e6fc8392f575 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 06:21:07 +0200 Subject: [PATCH 25/38] JANINO FIXES --- tools/standalone-JaninoLoader-1.0.2.jar | Bin 1174631 -> 1177125 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/standalone-JaninoLoader-1.0.2.jar b/tools/standalone-JaninoLoader-1.0.2.jar index a41ae97686f4b7ae15a1a2d1bd42d94ff9d86675..a03157587eb067f33a146edd9afaef1cc6697f7c 100644 GIT binary patch delta 265265 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%0AeV|{scgWudu%a-$)FxLstM?4JT9@aCe&< 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Ν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

L)kc?x@gD#h(0!_+MLMh$Vk*_`9)EGkHw8azB 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 OJ>E8k-Z$|2+wgxaG79Vf delta 263164 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�hZc$^(!)eX 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%0D!#Uk*RFy(3|TVN}4tlx;@bfg1& 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 Date: Fri, 13 Mar 2026 06:41:22 +0200 Subject: [PATCH 26/38] editor color scheme improvements --- .../script/interpreter/token/TokenType.java | 14 ++++---- .../colorscheme/script_editor_scheme.json | 33 +++++-------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java index 7b6be3444..200e60f6c 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java @@ -14,11 +14,11 @@ import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; public enum TokenType { // Comments and strings have highest priority - they override everything inside them COMMENT(0xFF777777, 140), - STRING(0xFFCC8855, 130), + STRING(0xFF17C6A3, 130), // JSDoc elements - lower priority but will fill gaps left by fragmented comment marking - JSDOC_TAG(0xFFCC9933, 125,true, true), // @param, @type, @return etc. (gold/orange) - JSDOC_TYPE(0xFF00AAAA, 124), // {TypeName} in JSDoc (aqua like types) + JSDOC_TAG(0xFF8E8070, 125,true, true), // @param, @type, @return etc. (gold/orange) + JSDOC_TYPE(0xFF9A8C7C, 124), // {TypeName} in JSDoc (aqua like types) UNUSED_IMPORT(0xFF666666, 119), // unused import statements (gray) @@ -26,9 +26,9 @@ public enum TokenType { KEYWORD(0xFFFF5555, 100,true, false), // control flow: if, else, for, while, etc. // Type declarations and references - INTERFACE_DECL(0xFF55FFFF, 85), // interface names (aqua) + INTERFACE_DECL(0xFF80F2F6, 85), // interface names (aqua) ENUM_DECL(0xFFFF55FF, 85), // enum names (magenta) - ENUM_CONSTANT(0xFF55FFFF, 84, true, false), // enum constant values (blue, bold+italic) - like IntelliJ + ENUM_CONSTANT(0xFF55FFFF, 84, true, true), // enum constant values (blue, bold+italic) - like IntelliJ CLASS_DECL(0xFF00AAAA, 85), // class names in declarations IMPORTED_CLASS(0xFF00AAAA, 75), // imported class usages GENERIC_TYPE_PARAM(0xFF00FA9A, 76), // generic type parameters like T, E, K, V (light green) @@ -43,10 +43,10 @@ public enum TokenType { PARAMETER(0xFF5555FF, 36), // method parameters (blue) GLOBAL_FIELD(0xFF55FFFF, 35), // class-level fields (aqua) LOCAL_FIELD(0xFFFFFF55, 25), // local variables (yellow) - STATIC_FINAL_FIELD(0xFFFF55FF, 36, false, true), // static final fields (magenta, italic) + STATIC_FINAL_FIELD(0xFFFF55FF, 36, true, true), // static final fields (magenta, italic) // Literals - LITERAL(0xFF777777, 40), // numeric and boolean literals + LITERAL(0xFF79C0FF, 40), // numeric and boolean literals // Default VARIABLE(0xFFFFFFFF, 30), // generic variables diff --git a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json index 8b41acc3f..6a0da80b8 100644 --- a/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json +++ b/src/main/resources/assets/customnpcs/colorscheme/script_editor_scheme.json @@ -16,17 +16,17 @@ "italic": false }, "STRING": { - "color": "#FFCC8855", + "color": "#FF16c57d", "bold": false, "italic": false }, "JSDOC_TAG": { - "color": "#FFCC9933", - "bold": false, + "color": "#FF8E8070", + "bold": true, "italic": false }, "JSDOC_TYPE": { - "color": "#FF00AAAA", + "color": "#FF9A8C7C", "bold": false, "italic": false }, @@ -35,28 +35,13 @@ "bold": false, "italic": false }, - "CLASS_KEYWORD": { - "color": "#FFFF5555", - "bold": false, - "italic": false - }, - "IMPORT_KEYWORD": { - "color": "#FFFFAA00", - "bold": false, - "italic": false - }, "KEYWORD": { "color": "#FFFF5555", "bold": false, "italic": false }, - "MODIFIER": { - "color": "#FFFFAA00", - "bold": false, - "italic": false - }, "INTERFACE_DECL": { - "color": "#FF55FFFF", + "color": "#FF80F2F6", "bold": false, "italic": false }, @@ -68,7 +53,7 @@ "ENUM_CONSTANT": { "color": "#FF55FFFF", "bold": true, - "italic": false + "italic": true }, "CLASS_DECL": { "color": "#FF00AAAA", @@ -121,12 +106,12 @@ "italic": false }, "STATIC_FINAL_FIELD": { - "color": "#FFFF55FF", - "bold": false, + "color": "#FF8DDAF8", + "bold": true, "italic": true }, "LITERAL": { - "color": "#FF777777", + "color": "#FF79C0FF", "bold": false, "italic": false }, From 691a7fb2c78639fad13cd9218c8f4851b2f340f5 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 17:47:29 +0200 Subject: [PATCH 27/38] unified TypeInfo API access to it uses exposed TypeInfo members instead of inner raw Class reflection calls --- .../autocomplete/JSAutocompleteProvider.java | 176 +++++---- .../JavaAutocompleteProvider.java | 168 ++------ .../script/interpreter/ScriptDocument.java | 35 +- .../interpreter/type/ScriptTypeInfo.java | 68 +++- .../script/interpreter/type/TypeInfo.java | 371 ++++++++++++++---- 5 files changed, 508 insertions(+), 310 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java index b342a5384..e69102b59 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java @@ -1,15 +1,16 @@ package noppes.npcs.client.gui.util.script.autocomplete; import noppes.npcs.client.gui.util.script.interpreter.js_parser.*; +import noppes.npcs.client.gui.util.script.interpreter.field.EnumConstantInfo; import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; import noppes.npcs.client.gui.util.script.interpreter.type.synthetic.*; +import noppes.npcs.client.gui.util.script.interpreter.type.ScriptTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; import noppes.npcs.config.ConfigScript; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -37,6 +38,15 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider { /** * Add suggestions for member access (after dot). * Uses ScriptDocument's unified type resolution system. + * + * Fixes applied vs original implementation: + * - Single getMemberAccessResolvePosition() call (was duplicated) + * - Single getMergeRegistryType() call (was duplicated) + * - Shared addedMethods/addedFields sets across ALL sources for cross-source deduplication + * - Unified nested type lookup via getAllNestedTypes() instead of raw reflection + * - Single Object method injection path (registry-based via fromJSMethod) + * - Name-based Object.class guard instead of fragile Class identity comparison + * - Logged SecurityException instead of silently swallowed */ protected void addMemberSuggestions(Context context, List items) { String receiverExpr = context.receiverExpression; @@ -44,113 +54,105 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider { return; } + // Resolve position once — used for both type resolution and static context detection + int resolvePos = getMemberAccessResolvePosition(context); + // Use ScriptDocument's resolveExpressionType - handles both Java and JS - TypeInfo receiverType = document.resolveExpressionType(receiverExpr, getMemberAccessResolvePosition(context)); + TypeInfo receiverType = document.resolveExpressionType(receiverExpr, resolvePos); if (receiverType == null || !receiverType.isResolved()) { return; } - // Check for synthetic types first (e.g., Nashorn Java object, custom types) - SyntheticType syntheticType = - document.getTypeResolver().getSyntheticType(receiverType.getSimpleName()); + // --- JS-SPECIFIC: synthetic type early return --- + SyntheticType syntheticType = document.getTypeResolver().getSyntheticType(receiverType.getSimpleName()); if (syntheticType != null) { addSyntheticTypeSuggestions(syntheticType, items, context.methodsOnly); return; } - boolean isStaticContext = isStaticAccess(receiverExpr, getMemberAccessResolvePosition(context)); + boolean isStaticContext = isStaticAccess(receiverExpr, resolvePos); + // Resolve merge-registry type once — used for both method and field fallback Class javaClass = receiverType.getJavaClass(); - if (javaClass != null) { - Set addedMethods = new HashSet<>(); - for (Method method : javaClass.getMethods()) { - if (!Modifier.isPublic(method.getModifiers())) continue; - if (isStaticContext && !Modifier.isStatic(method.getModifiers())) continue; - String sig = method.getName() + "(" + method.getParameterCount() + ")"; - if (addedMethods.add(sig)) { - items.add(AutocompleteItem.fromMethod(MethodInfo.fromReflection(method, receiverType), context.methodsOnly)); - } + JSTypeInfo mergeRegistryType = (javaClass != null + && receiverType.getSyntheticMethods().isEmpty() + && receiverType.getSyntheticFields().isEmpty()) + ? getMergeRegistryType(javaClass) : null; + + // Shared deduplication sets — prevent the same method/field appearing from multiple sources + Set addedMethods = new HashSet<>(); + Set addedFields = new HashSet<>(); + + // ---- SHARED: unified method enumeration (TypeInfo.getAllMethods covers reflection + synthetics) ---- + for (MethodInfo method : receiverType.getAllMethods()) { + if (isStaticContext && !Modifier.isStatic(method.getModifiers())) + continue; + String sig = method.getName() + "(" + method.getParameterCount() + ")"; + if (addedMethods.add(sig)) + items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); + } + + // --- JS-SPECIFIC: merge registry type fallback for methods --- + if (mergeRegistryType != null) { + addMethodsFromType(mergeRegistryType, receiverType, items, addedMethods, context.methodsOnly, + isStaticContext); + } + + if (!context.methodsOnly) { + // ---- SHARED: unified field enumeration with deduplication ---- + for (FieldInfo field : receiverType.getAllFields()) { + if (isStaticContext && !Modifier.isStatic(field.getModifiers())) + continue; + if (addedFields.add(field.getName())) + items.add(AutocompleteItem.fromField(field)); } - List effectiveSyntheticMethods = receiverType.getSyntheticMethods(); - if (!effectiveSyntheticMethods.isEmpty()) { - for (MethodInfo method : effectiveSyntheticMethods) { - if (isStaticContext && !method.isStatic()) continue; - items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); - } - } else { - JSTypeInfo jsType = getMergeRegistryType(javaClass); - if (jsType != null) { - addMethodsFromType(jsType, receiverType, items, new HashSet<>(), context.methodsOnly, isStaticContext); - } + + // --- JS-SPECIFIC: merge registry type fallback for fields --- + if (mergeRegistryType != null) { + addFieldsFromType(mergeRegistryType, receiverType, items, addedFields, isStaticContext); } - if (!context.methodsOnly) { - for (Field field : javaClass.getFields()) { - if (!Modifier.isPublic(field.getModifiers())) continue; - if (isStaticContext && !Modifier.isStatic(field.getModifiers())) continue; - items.add(AutocompleteItem.fromField(FieldInfo.fromReflection(field, receiverType))); - } - if (!receiverType.getSyntheticFields().isEmpty()) { - for (FieldInfo field : receiverType.getSyntheticFields()) { - if (isStaticContext && !field.isStatic()) continue; - items.add(AutocompleteItem.fromField(field)); - } - } else { - JSTypeInfo jsType = getMergeRegistryType(javaClass); - if (jsType != null) { - addFieldsFromType(jsType, receiverType, items, new HashSet<>(), isStaticContext); - } - } + } + + // ---- SHARED: nested types (inner classes) in static context via getAllNestedTypes() ---- + if (isStaticContext && !context.methodsOnly) { + // ScriptTypeInfo.getAllNestedTypes() returns script inner classes directly; + // TypeInfo.getAllNestedTypes() uses reflection. No duplicate logic needed. + for (TypeInfo nestedType : receiverType.getAllNestedTypes()) { + items.add(AutocompleteItem.fromType(nestedType)); } - if (!isStaticContext && javaClass != Object.class) { - JSTypeInfo objJSType = registry.getType("Object"); - if (objJSType != null) { - for (JSMethodInfo m : objJSType.getMethods().values()) { - if (!m.isStatic()) { + } + + // Enum constants — polymorphic via TypeInfo.getEnumConstants() + if (!context.methodsOnly) { + for (EnumConstantInfo enumConstant : receiverType.getEnumConstants().values()) { + items.add(AutocompleteItem.fromField(enumConstant.getFieldInfo())); + } + } + + // --- JS-SPECIFIC: Object methods from JS registry (single unified path) --- + // Add Object.class JS methods for instance access, unless receiver IS Object itself. + // Uses name comparison instead of Class identity for robustness across classloaders. + if (!isStaticContext && (javaClass == null || !"java.lang.Object".equals(javaClass.getName()))) { + JSTypeInfo objJSType = registry.getType("Object"); + if (objJSType != null) { + for (JSMethodInfo m : objJSType.getMethods().values()) { + if (!m.isStatic()) { + String sig = m.getName() + "(" + m.getParameterCount() + ")"; + if (addedMethods.add(sig)) { items.add(AutocompleteItem.fromJSMethod(m, receiverType, 1, context.methodsOnly)); } } } } - return; } - Set syntheticMethodNames = new HashSet<>(); - for (MethodInfo method : receiverType.getSyntheticMethods()) { - syntheticMethodNames.add(method.getName()); - if (isStaticContext && !method.isStatic()) continue; - items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); - } - for (FieldInfo field : receiverType.getSyntheticFields()) { - if (!context.methodsOnly) { - if (isStaticContext && !field.isStatic()) continue; - if (syntheticMethodNames.contains(field.getName())) continue; - items.add(AutocompleteItem.fromField(field)); - } - } - - JSTypeInfo jsTypeInfo = receiverType.getJSTypeInfo(); - if (jsTypeInfo != null) { - addMethodsFromType(jsTypeInfo, receiverType, items, new HashSet<>(), context.methodsOnly, isStaticContext); - if (!context.methodsOnly && ConfigScript.ShowImplementationFieldsInAutocomplete) { - addFieldsFromType(jsTypeInfo, receiverType, items, new HashSet<>(), isStaticContext); - } - } - - if (!isStaticContext) { - Set addedObjMethods = new HashSet<>(); - for (Method m : Object.class.getMethods()) { - if (!Modifier.isPublic(m.getModifiers()) || Modifier.isStatic(m.getModifiers())) continue; - String sig = m.getName() + "(" + m.getParameterCount() + ")"; - if (addedObjMethods.add(sig)) { - items.add(AutocompleteItem.fromMethod(MethodInfo.fromReflection(m, receiverType), context.methodsOnly)); - } - } - JSTypeInfo objJSType = registry.getType("Object"); - if (objJSType != null) { - for (JSMethodInfo m : objJSType.getMethods().values()) { - if (!m.isStatic()) { - items.add(AutocompleteItem.fromJSMethod(m, receiverType, 1, context.methodsOnly)); - } + // --- JS-SPECIFIC: pure JS type fallback (javaClass == null, not ScriptTypeInfo) --- + if (javaClass == null && !(receiverType instanceof ScriptTypeInfo)) { + JSTypeInfo jsTypeInfo = receiverType.getJSTypeInfo(); + if (jsTypeInfo != null) { + addMethodsFromType(jsTypeInfo, receiverType, items, addedMethods, context.methodsOnly, isStaticContext); + if (!context.methodsOnly && ConfigScript.ShowImplementationFieldsInAutocomplete) { + addFieldsFromType(jsTypeInfo, receiverType, items, addedFields, isStaticContext); } } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java index c268baf27..3aad528c3 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java @@ -10,8 +10,6 @@ import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -100,92 +98,52 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { if (receiverExpr == null || receiverExpr.isEmpty()) { return; } + + // Resolve position once — used for both type resolution and static context detection + int resolvePos = getMemberAccessResolvePosition(context); - // Resolve the type of the receiver expression - TypeInfo receiverType = document.resolveExpressionType(receiverExpr, getMemberAccessResolvePosition(context)); + TypeInfo receiverType = document.resolveExpressionType(receiverExpr, resolvePos); if (receiverType == null || !receiverType.isResolved()) { return; } - // Determine if this is a static context (accessing a class type) - boolean isStaticContext = isStaticAccess(receiverExpr, getMemberAccessResolvePosition(context)); + boolean isStaticContext = isStaticAccess(receiverExpr, resolvePos); - Class clazz = receiverType.getJavaClass(); - if (clazz == null) { - // Try ScriptTypeInfo - if (receiverType instanceof ScriptTypeInfo) { - addScriptTypeMembers((ScriptTypeInfo) receiverType, items, isStaticContext, context.methodsOnly); - } - return; - } - - // Add methods + // Shared deduplication sets across all member sources Set addedMethods = new HashSet<>(); - for (Method method : clazz.getMethods()) { - if (Modifier.isPublic(method.getModifiers())) { - // Filter by static context - if (isStaticContext && !Modifier.isStatic(method.getModifiers())) { - continue; - } - - String sig = method.getName() + "(" + method.getParameterCount() + ")"; - if (!addedMethods.contains(sig)) { - addedMethods.add(sig); - MethodInfo methodInfo = MethodInfo.fromReflection(method, receiverType); - items.add(AutocompleteItem.fromMethod(methodInfo, context.methodsOnly)); - } - } - } + Set addedFields = new HashSet<>(); - for (MethodInfo method : receiverType.getSyntheticMethods()) { - if (isStaticContext && !Modifier.isStatic(method.getModifiers())) - continue; - - items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); + // Unified method enumeration — works for Java types, ScriptTypeInfo, and intersection bounds + for (MethodInfo method : receiverType.getAllMethods()) { + if (isStaticContext && !Modifier.isStatic(method.getModifiers())) continue; + String sig = method.getName() + "(" + method.getParameterCount() + ")"; + if (addedMethods.add(sig)) + items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); } - // Add fields (skip if methodsOnly is true - but the filtering will be done in getSuggestions) if (!context.methodsOnly) { - for (Field field : clazz.getFields()) { - if (Modifier.isPublic(field.getModifiers())) { - // Filter by static context - if (isStaticContext && !Modifier.isStatic(field.getModifiers())) { - continue; - } - - FieldInfo fieldInfo = FieldInfo.fromReflection(field, receiverType); - items.add(AutocompleteItem.fromField(fieldInfo)); - } - } - - for (FieldInfo field : receiverType.getSyntheticFields()) { - if (isStaticContext && !Modifier.isStatic(field.getModifiers())) - continue; - - items.add(AutocompleteItem.fromField(field)); + // Unified field enumeration with deduplication + for (FieldInfo field : receiverType.getAllFields()) { + if (isStaticContext && !Modifier.isStatic(field.getModifiers())) continue; + if (addedFields.add(field.getName())) + items.add(AutocompleteItem.fromField(field)); } } - // Add nested types (inner classes/interfaces) in static context + // Nested types (inner classes) in static context via getAllNestedTypes() if (isStaticContext && !context.methodsOnly) { - try { - for (Class nested : clazz.getDeclaredClasses()) { - if (!Modifier.isPublic(nested.getModifiers())) { - continue; - } - // Convert $ notation to dot notation for resolution - String nestedFullName = nested.getName().replace('$', '.'); - TypeInfo nestedType = TypeResolver.getInstance().resolveFullName(nestedFullName); - if (nestedType != null && nestedType.isResolved()) { - items.add(AutocompleteItem.fromType(nestedType)); - } - } - } catch (SecurityException ignored) { - // Some runtimes may restrict getDeclaredClasses() + for (TypeInfo nestedType : receiverType.getAllNestedTypes()) { + items.add(AutocompleteItem.fromType(nestedType)); + } + } + + // Enum constants — polymorphic via TypeInfo.getEnumConstants() + if (!context.methodsOnly) { + for (EnumConstantInfo enumConstant : receiverType.getEnumConstants().values()) { + items.add(AutocompleteItem.fromField(enumConstant.getFieldInfo())); } } - } /** @@ -218,76 +176,6 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { return Math.max(0, Math.min(context.prefixStart, context.text.length())); } - /** - * Add members from a script-defined type. - */ - protected void addScriptTypeMembers(ScriptTypeInfo scriptType, List items, boolean isStaticContext) { - addScriptTypeMembers(scriptType, items, isStaticContext, false); - } - - /** - * Add members from a script-defined type. - * @param scriptType The script type to get members from - * @param items The list to add items to - * @param isStaticContext Whether we're in a static context - * @param forMethodReference If true, only add methods with no parentheses in insert text - */ - protected void addScriptTypeMembers(ScriptTypeInfo scriptType, List items, boolean isStaticContext, boolean forMethodReference) { - // Add methods (getMethods returns Map>) - for (List overloads : scriptType.getMethods().values()) { - for (MethodInfo method : overloads) { - // Filter by static context - if (isStaticContext && !method.isStatic()) { - continue; - } - items.add(AutocompleteItem.fromMethod(method, forMethodReference)); - } - } - - // Add fields (skip if methodsOnly/forMethodReference is true) - if (!forMethodReference) { - // Add fields (getFields returns Map) - for (FieldInfo field : scriptType.getFields().values()) { - // Filter by static context - if (isStaticContext && !field.isStatic()) { - continue; - } - items.add(AutocompleteItem.fromField(field)); - } - - // Add enum constants (getEnumConstants returns Map) - for (EnumConstantInfo enumConstant : scriptType.getEnumConstants().values()) { - items.add(AutocompleteItem.fromField(enumConstant.getFieldInfo())); - } - - // Add nested types (inner classes/interfaces) in static context - if (isStaticContext) { - for (ScriptTypeInfo inner : scriptType.getInnerClasses()) { - items.add(AutocompleteItem.fromType(inner)); - } - } - } - - // Add parent class members - if (scriptType.hasSuperClass()) { - TypeInfo superType = scriptType.getSuperClass(); - if (superType != null && superType.getJavaClass() != null) { - Class superClazz = superType.getJavaClass(); - Set addedMethods = new HashSet<>(); - for (Method method : superClazz.getMethods()) { - if (Modifier.isPublic(method.getModifiers())) { - String sig = method.getName() + "(" + method.getParameterCount() + ")"; - if (!addedMethods.contains(sig)) { - addedMethods.add(sig); - MethodInfo methodInfo = MethodInfo.fromReflection(method, superType); - items.add(AutocompleteItem.fromMethod(methodInfo, forMethodReference)); - } - } - } - } - } - } - /** * Add suggestions based on current scope (not after a dot). */ diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index dfe41103d..fe8e3ac29 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -4308,6 +4308,37 @@ public class ScriptDocument { return resolveTypeAndTrackUsage(typeName); } + private TypeInfo substituteTypeParams(TypeInfo type, int position) { + if (type == null) + return null; + + if (!type.isResolved() && type.getSimpleName() != null + && !type.getSimpleName().contains(".")) { + TypeInfo sub = resolveType(type.getSimpleName(), position); + return (sub != null && sub.isResolved()) ? sub : type; + } + + if (type.isParameterized()) { + List args = type.getAppliedTypeArgs(); + if (args != null && !args.isEmpty()) { + List substituted = new ArrayList<>(args.size()); + boolean anyChanged = false; + for (TypeInfo arg : args) { + TypeInfo sub = substituteTypeParams(arg, position); + if (sub != arg) + anyChanged = true; + substituted.add(sub); + } + if (anyChanged) { + TypeInfo raw = type.getRawType(); + return raw != null ? raw.parameterize(substituted) : type.parameterize(substituted); + } + } + } + + return type; + } + /** * Position-aware type resolution overload. * Resolves a type name with positional context so that an unqualified inner class name @@ -4330,7 +4361,7 @@ public class ScriptDocument { // If already resolved, no need for positional fallback if (resolved != null && resolved.isResolved()) { - return resolved; + return substituteTypeParams(resolved, position); } if (typeName != null && !typeName.contains(".")) { @@ -9967,7 +9998,7 @@ for (ScriptTypeInfo type:scriptTypes.values()) { TokenType type = isClassTypeInfo ? varInfo.isGlobal() ? TokenType.GLOBAL_FIELD - : TokenType.LOCAL_FIELD : info.getTokenType(); + : TokenType.LOCAL_FIELD : TokenType.METHOD_CALL; marks.add(new ScriptLine.Mark(start, end, type, isClassTypeInfo ? varInfo : ctorCall)); continue; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java index 2c49b036a..5ee8d3783 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java @@ -10,6 +10,7 @@ import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -176,8 +177,6 @@ public class ScriptTypeInfo extends TypeInfo { Set active = PARAMETERIZING.get(); if (!active.add(this)) { - // Re-entrant call on the same raw type — fall back to shallow parameterization - // (no method/field substitution) to break the infinite recursion. return super.parameterize(typeArgs); } @@ -310,7 +309,11 @@ public class ScriptTypeInfo extends TypeInfo { if (enumConstants.containsKey(fieldName)) return true; - + + for (FieldInfo f : getSyntheticFields()) + if (f.getName().equals(fieldName)) + return true; + return false; } @@ -325,6 +328,10 @@ public class ScriptTypeInfo extends TypeInfo { return enumConst.getFieldInfo(); } + for (FieldInfo f : getSyntheticFields()) + if (f.getName().equals(fieldName)) + return f; + return null; } @@ -361,6 +368,7 @@ public class ScriptTypeInfo extends TypeInfo { /** * Get all enum constants. */ + @Override public Map getEnumConstants() { return new HashMap<>(enumConstants); } @@ -380,32 +388,51 @@ public class ScriptTypeInfo extends TypeInfo { @Override public boolean hasMethod(String methodName) { - return methods.containsKey(methodName); + if (methods.containsKey(methodName)) + return true; + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName)) + return true; + return false; } @Override public boolean hasMethod(String methodName, int paramCount) { List overloads = methods.get(methodName); - if (overloads == null) return false; - for (MethodInfo m : overloads) { - if (m.getParameterCount() == paramCount) { - return true; + if (overloads != null) { + for (MethodInfo m : overloads) { + if (m.getParameterCount() == paramCount) { + return true; + } } } + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName) && m.getParameterCount() == paramCount) + return true; return false; } @Override public MethodInfo getMethodInfo(String methodName) { List overloads = methods.get(methodName); - return (overloads != null && !overloads.isEmpty()) ? overloads.get(0) : null; + if (overloads != null && !overloads.isEmpty()) + return overloads.get(0); + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName)) + return m; + return null; } /** * Get all method overloads with the given name. */ + @Override public List getAllMethodOverloads(String methodName) { - return methods.getOrDefault(methodName, new ArrayList<>()); + List result = new ArrayList<>(methods.getOrDefault(methodName, Collections.emptyList())); + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName)) + result.add(m); + return result; } /** @@ -432,7 +459,26 @@ public class ScriptTypeInfo extends TypeInfo { allMethods.addAll(overloads); } return allMethods; - } + } + + @Override + public List getAllMethods() { + List result = getAllMethodsFlat(); + result.addAll(getSyntheticMethods()); + return result; + } + + @Override + public List getAllFields() { + List result = new ArrayList<>(getFields().values()); + result.addAll(getSyntheticFields()); + return result; + } + + @Override + public List getAllNestedTypes() { + return new ArrayList<>(innerClasses); + } // ==================== CONSTRUCTOR MANAGEMENT ==================== diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 1c5e36967..25044707a 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -771,6 +771,149 @@ public class TypeInfo { } } + /** + * Returns all public instance members of this type for autocomplete/resolution. + * Override in subclasses to extend or replace the default Java reflection path. + */ + public List getAllMethods() { + if (javaClass != null) { + // Java reflection path: enumerate public methods + synthetics + List result = new ArrayList<>(); + try { + for (java.lang.reflect.Method m : javaClass.getMethods()) { + try { + result.add(MethodInfo.fromReflection(m, this)); + } catch (Exception e) { + // Skip individual methods that fail (e.g., linkage errors on obscure return types) + } + } + } catch (Exception ignored) {} + result.addAll(getSyntheticMethods()); + return result; + } + + // javaClass == null: check rawType, jsTypeInfo, synthetics in priority order + if (rawType != null && rawType != this) { + List rawMethods = rawType.getAllMethods(); + if (!rawMethods.isEmpty() && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + List substituted = new ArrayList<>(rawMethods.size()); + for (MethodInfo m : rawMethods) { + substituted.add(m.substituteTypeParams(bindings)); + } + return substituted; + } + } + return rawMethods; + } + + // No javaClass, no rawType — collect from jsTypeInfo and synthetics + List result = new ArrayList<>(); + if (jsTypeInfo != null) { + for (JSMethodInfo m : jsTypeInfo.getMethods().values()) { + result.add(MethodInfo.fromJSMethod(m, this)); + } + } + result.addAll(getSyntheticMethods()); + return result; + } + + public List getAllFields() { + if (javaClass != null) { + // Java reflection path: enumerate public fields + synthetics + List result = new ArrayList<>(); + try { + for (java.lang.reflect.Field f : javaClass.getFields()) { + try { + result.add(FieldInfo.fromReflection(f, this)); + } catch (Exception e) { + // Skip individual fields that fail rather than losing ALL fields. + } + } + } catch (Exception ignored) {} + result.addAll(getSyntheticFields()); + return result; + } + + // javaClass == null: check rawType, jsTypeInfo, synthetics in priority order + if (rawType != null && rawType != this) { + List rawFields = rawType.getAllFields(); + if (!rawFields.isEmpty() && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + List substituted = new ArrayList<>(rawFields.size()); + for (FieldInfo f : rawFields) { + substituted.add(f.substituteTypeParams(bindings)); + } + return substituted; + } + } + return rawFields; + } + + // No javaClass, no rawType — collect from jsTypeInfo and synthetics + List result = new ArrayList<>(); + if (jsTypeInfo != null) { + for (JSFieldInfo f : jsTypeInfo.getFields().values()) { + result.add(FieldInfo.fromJSField(f, this)); + } + } + result.addAll(getSyntheticFields()); + return result; + } + + /** + * Returns all public nested types (inner classes/interfaces/enums) of this type. + * Uses reflection to discover nested types from the Java class, filters to public only, + * converts internal '$' separators to '.' for name resolution, and resolves each via TypeResolver. + * + * Override in subclasses (e.g., ScriptTypeInfo) to return script-defined inner classes. + * + * @return List of resolved nested TypeInfo instances (may be empty, never null) + */ + public List getAllNestedTypes() { + if (javaClass != null) { + List result = new ArrayList<>(); + try { + for (Class nested : javaClass.getDeclaredClasses()) { + if (!Modifier.isPublic(nested.getModifiers())) { + continue; + } + // Convert JVM internal '$' separator to '.' for TypeResolver lookup + String nestedFullName = nested.getName().replace('$', '.'); + TypeInfo nestedType = TypeResolver.getInstance().resolveFullName(nestedFullName); + if (nestedType != null && nestedType.isResolved()) { + result.add(nestedType); + } + } + } catch (SecurityException ignored) { + // Some runtimes may restrict getDeclaredClasses() + } + return result; + } + + if (rawType != null && rawType != this) { + return rawType.getAllNestedTypes(); + } + + // No javaClass, no rawType — check jsTypeInfo for inner types + if (jsTypeInfo != null) { + Map innerTypes = jsTypeInfo.getInnerTypes(); + if (!innerTypes.isEmpty()) { + List result = new ArrayList<>(innerTypes.size()); + for (JSTypeInfo inner : innerTypes.values()) { + TypeInfo ti = TypeInfo.fromJSTypeInfo(inner); + if (ti != null) { + result.add(ti); + } + } + return result; + } + } + return Collections.emptyList(); + } + /** * Check if this type has a method with the given name. */ @@ -789,6 +932,8 @@ public class TypeInfo { } catch (Exception e) { // Security or linkage error } + } else if (rawType != null && rawType != this) { + return rawType.hasMethod(methodName); } TypeInfo obj = TypeInfo.object(); @@ -817,6 +962,8 @@ public class TypeInfo { } catch (Exception e) { // Security or linkage error } + } else if (rawType != null && rawType != this) { + return rawType.hasMethod(methodName, paramCount); } TypeInfo obj = TypeInfo.object(); if (obj != this) return obj.hasMethod(methodName); @@ -828,13 +975,15 @@ public class TypeInfo { * Override in ScriptTypeInfo for script-defined types. */ public boolean hasConstructors() { - if (javaClass == null) return false; - try { - return javaClass.getConstructors().length > 0; - } catch (Exception e) { - // Security or linkage error - return false; + if (javaClass != null) { + try { + return javaClass.getConstructors().length > 0; + } catch (Exception e) { + return false; + } } + if (rawType != null && rawType != this) return rawType.hasConstructors(); + return false; } /** @@ -843,16 +992,18 @@ public class TypeInfo { */ public List getConstructors() { List result = new ArrayList<>(); - if (javaClass == null) return result; - - try { - java.lang.reflect.Constructor[] constructors = javaClass.getConstructors(); - for (java.lang.reflect.Constructor ctor : constructors) { - result.add(MethodInfo.fromReflectionConstructor(ctor, this)); + if (javaClass != null) { + try { + java.lang.reflect.Constructor[] constructors = javaClass.getConstructors(); + for (java.lang.reflect.Constructor ctor : constructors) { + result.add(MethodInfo.fromReflectionConstructor(ctor, this)); + } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return result; } + if (rawType != null && rawType != this) return rawType.getConstructors(); return result; } @@ -861,45 +1012,49 @@ public class TypeInfo { * Override in ScriptTypeInfo for script-defined types. */ public MethodInfo findConstructor(int argCount) { - if (javaClass == null) return null; - - try { - Constructor[] constructors = javaClass.getConstructors(); - for (Constructor ctor : constructors) { - if (ctor.getParameterCount() == argCount) { - return MethodInfo.fromReflectionConstructor(ctor, this); + if (javaClass != null) { + try { + Constructor[] constructors = javaClass.getConstructors(); + for (Constructor ctor : constructors) { + if (ctor.getParameterCount() == argCount) { + return MethodInfo.fromReflectionConstructor(ctor, this); + } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; } + if (rawType != null && rawType != this) return rawType.findConstructor(argCount); return null; } public MethodInfo findConstructor(TypeInfo[] argTypes) { - if (javaClass == null) return null; - - try { - Constructor[] constructors = javaClass.getConstructors(); - for (Constructor ctor : constructors) { - if (ctor.getParameterCount() == argTypes.length) { - Class[] paramTypes = ctor.getParameterTypes(); - boolean match = true; - for (int i = 0; i < argTypes.length; i++) { - TypeInfo paramTypeInfo = TypeInfo.fromClass(paramTypes[i]); - if (!TypeChecker.isTypeCompatible(paramTypeInfo, argTypes[i])) { - match = false; - break; + if (javaClass != null) { + try { + Constructor[] constructors = javaClass.getConstructors(); + for (Constructor ctor : constructors) { + if (ctor.getParameterCount() == argTypes.length) { + Class[] paramTypes = ctor.getParameterTypes(); + boolean match = true; + for (int i = 0; i < argTypes.length; i++) { + TypeInfo paramTypeInfo = TypeInfo.fromClass(paramTypes[i]); + if (!TypeChecker.isTypeCompatible(paramTypeInfo, argTypes[i])) { + match = false; + break; + } + } + if (match) { + return MethodInfo.fromReflectionConstructor(ctor, this); } } - if (match) { - return MethodInfo.fromReflectionConstructor(ctor, this); - } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; } + if (rawType != null && rawType != this) return rawType.findConstructor(argTypes); return null; } @@ -913,30 +1068,63 @@ public class TypeInfo { return jsTypeInfo.hasField(fieldName); } - if (javaClass == null) return false; - try { - for (java.lang.reflect.Field f : javaClass.getFields()) { - if (f.getName().equals(fieldName)) { - return true; + if (javaClass != null) { + try { + for (java.lang.reflect.Field f : javaClass.getFields()) { + if (f.getName().equals(fieldName)) { + return true; + } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return false; } + if (rawType != null && rawType != this) return rawType.hasField(fieldName); return false; } - public boolean hasEnumConstant(String constantName) { - if (javaClass == null || !javaClass.isEnum()) return false; + /** + * Returns all enum constants for this type as a name-to-EnumConstantInfo map. + * For Java enum types, builds the map via reflection. For script-defined enums, + * ScriptTypeInfo overrides this to return its stored constants directly. + * + * @return Map of constant name to EnumConstantInfo (empty if not an enum or no constants) + */ + public Map getEnumConstants() { + if (javaClass == null || !javaClass.isEnum()) { + if (rawType != null && rawType != this) { + return rawType.getEnumConstants(); + } + return Collections.emptyMap(); + } + Map result = new LinkedHashMap<>(); try { Object[] constants = javaClass.getEnumConstants(); for (Object constant : constants) { - if (constant.toString().equals(constantName)) - return true; + String name = constant.toString(); + result.put(name, EnumConstantInfo.fromReflection(name, this, null)); } } catch (Exception e) { - // Security or linkage error + // Security or linkage error — return whatever we have so far } + return result; + } + + public boolean hasEnumConstant(String constantName) { + if (javaClass != null && javaClass.isEnum()) { + try { + Object[] constants = javaClass.getEnumConstants(); + for (Object constant : constants) { + if (constant.toString().equals(constantName)) + return true; + } + } catch (Exception e) { + // Security or linkage error + } + return false; + } + if (rawType != null && rawType != this) return rawType.hasEnumConstant(constantName); return false; } @@ -944,16 +1132,19 @@ public class TypeInfo { * Get an enum constant by name. */ public EnumConstantInfo getEnumConstant(String constantName) { - if (javaClass == null || !javaClass.isEnum()) return null; - try { - Object[] constants = javaClass.getEnumConstants(); - for (Object constant : constants) { - if (constant.toString().equals(constantName)) - return EnumConstantInfo.fromReflection(constantName, this, null); + if (javaClass != null && javaClass.isEnum()) { + try { + Object[] constants = javaClass.getEnumConstants(); + for (Object constant : constants) { + if (constant.toString().equals(constantName)) + return EnumConstantInfo.fromReflection(constantName, this, null); + } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; } + if (rawType != null && rawType != this) return rawType.getEnumConstant(constantName); return null; } @@ -976,6 +1167,13 @@ public class TypeInfo { } catch (Exception e) { // Security or linkage error } + } else if (rawType != null && rawType != this) { + MethodInfo rawMethod = rawType.getMethodInfo(methodName); + if (rawMethod != null && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) return rawMethod.substituteTypeParams(bindings); + } + return rawMethod; } TypeInfo obj = TypeInfo.object(); if (obj != this) return obj.getMethodInfo(methodName); @@ -1012,6 +1210,18 @@ public class TypeInfo { // Security or linkage error } if (!overloads.isEmpty()) return overloads; + } else if (rawType != null && rawType != this) { + java.util.List rawOverloads = rawType.getAllMethodOverloads(methodName); + if (!rawOverloads.isEmpty() && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + for (MethodInfo m : rawOverloads) { + overloads.add(m.substituteTypeParams(bindings)); + } + return overloads; + } + } + return rawOverloads; } TypeInfo obj = TypeInfo.object(); if (obj != this) return obj.getAllMethodOverloads(methodName); @@ -1078,16 +1288,25 @@ public class TypeInfo { return null; } - if (javaClass == null) return null; - try { - for (java.lang.reflect.Field f : javaClass.getFields()) { - if (f.getName().equals(fieldName)) { - // Create a synthetic FieldInfo from reflection - return FieldInfo.fromReflection(f, this); + if (javaClass != null) { + try { + for (java.lang.reflect.Field f : javaClass.getFields()) { + if (f.getName().equals(fieldName)) { + return FieldInfo.fromReflection(f, this); + } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; + } + if (rawType != null && rawType != this) { + FieldInfo rawField = rawType.getFieldInfo(fieldName); + if (rawField != null && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) return rawField.substituteTypeParams(bindings); + } + return rawField; } return null; } @@ -1206,7 +1425,19 @@ public class TypeInfo { return null; } - // Not a functional interface + // Not a functional interface — try rawType for parameterized script types + if (rawType != null && rawType != this) { + MethodInfo rawSAM = rawType.getSingleAbstractMethod(); + if (rawSAM != null && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + cachedSAM = rawSAM.substituteTypeParams(bindings); + return cachedSAM; + } + } + cachedSAM = rawSAM; + return cachedSAM; + } cachedSAM = null; return null; From 53446e06c6e116369115978ebe2ee4d8c7c6eaef Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 17:47:29 +0200 Subject: [PATCH 28/38] unified TypeInfo API access to it uses exposed TypeInfo members instead of inner raw Class reflection calls --- .../autocomplete/JSAutocompleteProvider.java | 176 +++++---- .../JavaAutocompleteProvider.java | 168 ++------ .../interpreter/type/ScriptTypeInfo.java | 68 +++- .../script/interpreter/type/TypeInfo.java | 371 ++++++++++++++---- 4 files changed, 475 insertions(+), 308 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java index b342a5384..e69102b59 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java @@ -1,15 +1,16 @@ package noppes.npcs.client.gui.util.script.autocomplete; import noppes.npcs.client.gui.util.script.interpreter.js_parser.*; +import noppes.npcs.client.gui.util.script.interpreter.field.EnumConstantInfo; import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; import noppes.npcs.client.gui.util.script.interpreter.type.synthetic.*; +import noppes.npcs.client.gui.util.script.interpreter.type.ScriptTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; import noppes.npcs.config.ConfigScript; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -37,6 +38,15 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider { /** * Add suggestions for member access (after dot). * Uses ScriptDocument's unified type resolution system. + * + * Fixes applied vs original implementation: + * - Single getMemberAccessResolvePosition() call (was duplicated) + * - Single getMergeRegistryType() call (was duplicated) + * - Shared addedMethods/addedFields sets across ALL sources for cross-source deduplication + * - Unified nested type lookup via getAllNestedTypes() instead of raw reflection + * - Single Object method injection path (registry-based via fromJSMethod) + * - Name-based Object.class guard instead of fragile Class identity comparison + * - Logged SecurityException instead of silently swallowed */ protected void addMemberSuggestions(Context context, List items) { String receiverExpr = context.receiverExpression; @@ -44,113 +54,105 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider { return; } + // Resolve position once — used for both type resolution and static context detection + int resolvePos = getMemberAccessResolvePosition(context); + // Use ScriptDocument's resolveExpressionType - handles both Java and JS - TypeInfo receiverType = document.resolveExpressionType(receiverExpr, getMemberAccessResolvePosition(context)); + TypeInfo receiverType = document.resolveExpressionType(receiverExpr, resolvePos); if (receiverType == null || !receiverType.isResolved()) { return; } - // Check for synthetic types first (e.g., Nashorn Java object, custom types) - SyntheticType syntheticType = - document.getTypeResolver().getSyntheticType(receiverType.getSimpleName()); + // --- JS-SPECIFIC: synthetic type early return --- + SyntheticType syntheticType = document.getTypeResolver().getSyntheticType(receiverType.getSimpleName()); if (syntheticType != null) { addSyntheticTypeSuggestions(syntheticType, items, context.methodsOnly); return; } - boolean isStaticContext = isStaticAccess(receiverExpr, getMemberAccessResolvePosition(context)); + boolean isStaticContext = isStaticAccess(receiverExpr, resolvePos); + // Resolve merge-registry type once — used for both method and field fallback Class javaClass = receiverType.getJavaClass(); - if (javaClass != null) { - Set addedMethods = new HashSet<>(); - for (Method method : javaClass.getMethods()) { - if (!Modifier.isPublic(method.getModifiers())) continue; - if (isStaticContext && !Modifier.isStatic(method.getModifiers())) continue; - String sig = method.getName() + "(" + method.getParameterCount() + ")"; - if (addedMethods.add(sig)) { - items.add(AutocompleteItem.fromMethod(MethodInfo.fromReflection(method, receiverType), context.methodsOnly)); - } + JSTypeInfo mergeRegistryType = (javaClass != null + && receiverType.getSyntheticMethods().isEmpty() + && receiverType.getSyntheticFields().isEmpty()) + ? getMergeRegistryType(javaClass) : null; + + // Shared deduplication sets — prevent the same method/field appearing from multiple sources + Set addedMethods = new HashSet<>(); + Set addedFields = new HashSet<>(); + + // ---- SHARED: unified method enumeration (TypeInfo.getAllMethods covers reflection + synthetics) ---- + for (MethodInfo method : receiverType.getAllMethods()) { + if (isStaticContext && !Modifier.isStatic(method.getModifiers())) + continue; + String sig = method.getName() + "(" + method.getParameterCount() + ")"; + if (addedMethods.add(sig)) + items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); + } + + // --- JS-SPECIFIC: merge registry type fallback for methods --- + if (mergeRegistryType != null) { + addMethodsFromType(mergeRegistryType, receiverType, items, addedMethods, context.methodsOnly, + isStaticContext); + } + + if (!context.methodsOnly) { + // ---- SHARED: unified field enumeration with deduplication ---- + for (FieldInfo field : receiverType.getAllFields()) { + if (isStaticContext && !Modifier.isStatic(field.getModifiers())) + continue; + if (addedFields.add(field.getName())) + items.add(AutocompleteItem.fromField(field)); } - List effectiveSyntheticMethods = receiverType.getSyntheticMethods(); - if (!effectiveSyntheticMethods.isEmpty()) { - for (MethodInfo method : effectiveSyntheticMethods) { - if (isStaticContext && !method.isStatic()) continue; - items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); - } - } else { - JSTypeInfo jsType = getMergeRegistryType(javaClass); - if (jsType != null) { - addMethodsFromType(jsType, receiverType, items, new HashSet<>(), context.methodsOnly, isStaticContext); - } + + // --- JS-SPECIFIC: merge registry type fallback for fields --- + if (mergeRegistryType != null) { + addFieldsFromType(mergeRegistryType, receiverType, items, addedFields, isStaticContext); } - if (!context.methodsOnly) { - for (Field field : javaClass.getFields()) { - if (!Modifier.isPublic(field.getModifiers())) continue; - if (isStaticContext && !Modifier.isStatic(field.getModifiers())) continue; - items.add(AutocompleteItem.fromField(FieldInfo.fromReflection(field, receiverType))); - } - if (!receiverType.getSyntheticFields().isEmpty()) { - for (FieldInfo field : receiverType.getSyntheticFields()) { - if (isStaticContext && !field.isStatic()) continue; - items.add(AutocompleteItem.fromField(field)); - } - } else { - JSTypeInfo jsType = getMergeRegistryType(javaClass); - if (jsType != null) { - addFieldsFromType(jsType, receiverType, items, new HashSet<>(), isStaticContext); - } - } + } + + // ---- SHARED: nested types (inner classes) in static context via getAllNestedTypes() ---- + if (isStaticContext && !context.methodsOnly) { + // ScriptTypeInfo.getAllNestedTypes() returns script inner classes directly; + // TypeInfo.getAllNestedTypes() uses reflection. No duplicate logic needed. + for (TypeInfo nestedType : receiverType.getAllNestedTypes()) { + items.add(AutocompleteItem.fromType(nestedType)); } - if (!isStaticContext && javaClass != Object.class) { - JSTypeInfo objJSType = registry.getType("Object"); - if (objJSType != null) { - for (JSMethodInfo m : objJSType.getMethods().values()) { - if (!m.isStatic()) { + } + + // Enum constants — polymorphic via TypeInfo.getEnumConstants() + if (!context.methodsOnly) { + for (EnumConstantInfo enumConstant : receiverType.getEnumConstants().values()) { + items.add(AutocompleteItem.fromField(enumConstant.getFieldInfo())); + } + } + + // --- JS-SPECIFIC: Object methods from JS registry (single unified path) --- + // Add Object.class JS methods for instance access, unless receiver IS Object itself. + // Uses name comparison instead of Class identity for robustness across classloaders. + if (!isStaticContext && (javaClass == null || !"java.lang.Object".equals(javaClass.getName()))) { + JSTypeInfo objJSType = registry.getType("Object"); + if (objJSType != null) { + for (JSMethodInfo m : objJSType.getMethods().values()) { + if (!m.isStatic()) { + String sig = m.getName() + "(" + m.getParameterCount() + ")"; + if (addedMethods.add(sig)) { items.add(AutocompleteItem.fromJSMethod(m, receiverType, 1, context.methodsOnly)); } } } } - return; } - Set syntheticMethodNames = new HashSet<>(); - for (MethodInfo method : receiverType.getSyntheticMethods()) { - syntheticMethodNames.add(method.getName()); - if (isStaticContext && !method.isStatic()) continue; - items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); - } - for (FieldInfo field : receiverType.getSyntheticFields()) { - if (!context.methodsOnly) { - if (isStaticContext && !field.isStatic()) continue; - if (syntheticMethodNames.contains(field.getName())) continue; - items.add(AutocompleteItem.fromField(field)); - } - } - - JSTypeInfo jsTypeInfo = receiverType.getJSTypeInfo(); - if (jsTypeInfo != null) { - addMethodsFromType(jsTypeInfo, receiverType, items, new HashSet<>(), context.methodsOnly, isStaticContext); - if (!context.methodsOnly && ConfigScript.ShowImplementationFieldsInAutocomplete) { - addFieldsFromType(jsTypeInfo, receiverType, items, new HashSet<>(), isStaticContext); - } - } - - if (!isStaticContext) { - Set addedObjMethods = new HashSet<>(); - for (Method m : Object.class.getMethods()) { - if (!Modifier.isPublic(m.getModifiers()) || Modifier.isStatic(m.getModifiers())) continue; - String sig = m.getName() + "(" + m.getParameterCount() + ")"; - if (addedObjMethods.add(sig)) { - items.add(AutocompleteItem.fromMethod(MethodInfo.fromReflection(m, receiverType), context.methodsOnly)); - } - } - JSTypeInfo objJSType = registry.getType("Object"); - if (objJSType != null) { - for (JSMethodInfo m : objJSType.getMethods().values()) { - if (!m.isStatic()) { - items.add(AutocompleteItem.fromJSMethod(m, receiverType, 1, context.methodsOnly)); - } + // --- JS-SPECIFIC: pure JS type fallback (javaClass == null, not ScriptTypeInfo) --- + if (javaClass == null && !(receiverType instanceof ScriptTypeInfo)) { + JSTypeInfo jsTypeInfo = receiverType.getJSTypeInfo(); + if (jsTypeInfo != null) { + addMethodsFromType(jsTypeInfo, receiverType, items, addedMethods, context.methodsOnly, isStaticContext); + if (!context.methodsOnly && ConfigScript.ShowImplementationFieldsInAutocomplete) { + addFieldsFromType(jsTypeInfo, receiverType, items, addedFields, isStaticContext); } } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java index c268baf27..3aad528c3 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java @@ -10,8 +10,6 @@ import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -100,92 +98,52 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { if (receiverExpr == null || receiverExpr.isEmpty()) { return; } + + // Resolve position once — used for both type resolution and static context detection + int resolvePos = getMemberAccessResolvePosition(context); - // Resolve the type of the receiver expression - TypeInfo receiverType = document.resolveExpressionType(receiverExpr, getMemberAccessResolvePosition(context)); + TypeInfo receiverType = document.resolveExpressionType(receiverExpr, resolvePos); if (receiverType == null || !receiverType.isResolved()) { return; } - // Determine if this is a static context (accessing a class type) - boolean isStaticContext = isStaticAccess(receiverExpr, getMemberAccessResolvePosition(context)); + boolean isStaticContext = isStaticAccess(receiverExpr, resolvePos); - Class clazz = receiverType.getJavaClass(); - if (clazz == null) { - // Try ScriptTypeInfo - if (receiverType instanceof ScriptTypeInfo) { - addScriptTypeMembers((ScriptTypeInfo) receiverType, items, isStaticContext, context.methodsOnly); - } - return; - } - - // Add methods + // Shared deduplication sets across all member sources Set addedMethods = new HashSet<>(); - for (Method method : clazz.getMethods()) { - if (Modifier.isPublic(method.getModifiers())) { - // Filter by static context - if (isStaticContext && !Modifier.isStatic(method.getModifiers())) { - continue; - } - - String sig = method.getName() + "(" + method.getParameterCount() + ")"; - if (!addedMethods.contains(sig)) { - addedMethods.add(sig); - MethodInfo methodInfo = MethodInfo.fromReflection(method, receiverType); - items.add(AutocompleteItem.fromMethod(methodInfo, context.methodsOnly)); - } - } - } + Set addedFields = new HashSet<>(); - for (MethodInfo method : receiverType.getSyntheticMethods()) { - if (isStaticContext && !Modifier.isStatic(method.getModifiers())) - continue; - - items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); + // Unified method enumeration — works for Java types, ScriptTypeInfo, and intersection bounds + for (MethodInfo method : receiverType.getAllMethods()) { + if (isStaticContext && !Modifier.isStatic(method.getModifiers())) continue; + String sig = method.getName() + "(" + method.getParameterCount() + ")"; + if (addedMethods.add(sig)) + items.add(AutocompleteItem.fromMethod(method, context.methodsOnly)); } - // Add fields (skip if methodsOnly is true - but the filtering will be done in getSuggestions) if (!context.methodsOnly) { - for (Field field : clazz.getFields()) { - if (Modifier.isPublic(field.getModifiers())) { - // Filter by static context - if (isStaticContext && !Modifier.isStatic(field.getModifiers())) { - continue; - } - - FieldInfo fieldInfo = FieldInfo.fromReflection(field, receiverType); - items.add(AutocompleteItem.fromField(fieldInfo)); - } - } - - for (FieldInfo field : receiverType.getSyntheticFields()) { - if (isStaticContext && !Modifier.isStatic(field.getModifiers())) - continue; - - items.add(AutocompleteItem.fromField(field)); + // Unified field enumeration with deduplication + for (FieldInfo field : receiverType.getAllFields()) { + if (isStaticContext && !Modifier.isStatic(field.getModifiers())) continue; + if (addedFields.add(field.getName())) + items.add(AutocompleteItem.fromField(field)); } } - // Add nested types (inner classes/interfaces) in static context + // Nested types (inner classes) in static context via getAllNestedTypes() if (isStaticContext && !context.methodsOnly) { - try { - for (Class nested : clazz.getDeclaredClasses()) { - if (!Modifier.isPublic(nested.getModifiers())) { - continue; - } - // Convert $ notation to dot notation for resolution - String nestedFullName = nested.getName().replace('$', '.'); - TypeInfo nestedType = TypeResolver.getInstance().resolveFullName(nestedFullName); - if (nestedType != null && nestedType.isResolved()) { - items.add(AutocompleteItem.fromType(nestedType)); - } - } - } catch (SecurityException ignored) { - // Some runtimes may restrict getDeclaredClasses() + for (TypeInfo nestedType : receiverType.getAllNestedTypes()) { + items.add(AutocompleteItem.fromType(nestedType)); + } + } + + // Enum constants — polymorphic via TypeInfo.getEnumConstants() + if (!context.methodsOnly) { + for (EnumConstantInfo enumConstant : receiverType.getEnumConstants().values()) { + items.add(AutocompleteItem.fromField(enumConstant.getFieldInfo())); } } - } /** @@ -218,76 +176,6 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { return Math.max(0, Math.min(context.prefixStart, context.text.length())); } - /** - * Add members from a script-defined type. - */ - protected void addScriptTypeMembers(ScriptTypeInfo scriptType, List items, boolean isStaticContext) { - addScriptTypeMembers(scriptType, items, isStaticContext, false); - } - - /** - * Add members from a script-defined type. - * @param scriptType The script type to get members from - * @param items The list to add items to - * @param isStaticContext Whether we're in a static context - * @param forMethodReference If true, only add methods with no parentheses in insert text - */ - protected void addScriptTypeMembers(ScriptTypeInfo scriptType, List items, boolean isStaticContext, boolean forMethodReference) { - // Add methods (getMethods returns Map>) - for (List overloads : scriptType.getMethods().values()) { - for (MethodInfo method : overloads) { - // Filter by static context - if (isStaticContext && !method.isStatic()) { - continue; - } - items.add(AutocompleteItem.fromMethod(method, forMethodReference)); - } - } - - // Add fields (skip if methodsOnly/forMethodReference is true) - if (!forMethodReference) { - // Add fields (getFields returns Map) - for (FieldInfo field : scriptType.getFields().values()) { - // Filter by static context - if (isStaticContext && !field.isStatic()) { - continue; - } - items.add(AutocompleteItem.fromField(field)); - } - - // Add enum constants (getEnumConstants returns Map) - for (EnumConstantInfo enumConstant : scriptType.getEnumConstants().values()) { - items.add(AutocompleteItem.fromField(enumConstant.getFieldInfo())); - } - - // Add nested types (inner classes/interfaces) in static context - if (isStaticContext) { - for (ScriptTypeInfo inner : scriptType.getInnerClasses()) { - items.add(AutocompleteItem.fromType(inner)); - } - } - } - - // Add parent class members - if (scriptType.hasSuperClass()) { - TypeInfo superType = scriptType.getSuperClass(); - if (superType != null && superType.getJavaClass() != null) { - Class superClazz = superType.getJavaClass(); - Set addedMethods = new HashSet<>(); - for (Method method : superClazz.getMethods()) { - if (Modifier.isPublic(method.getModifiers())) { - String sig = method.getName() + "(" + method.getParameterCount() + ")"; - if (!addedMethods.contains(sig)) { - addedMethods.add(sig); - MethodInfo methodInfo = MethodInfo.fromReflection(method, superType); - items.add(AutocompleteItem.fromMethod(methodInfo, forMethodReference)); - } - } - } - } - } - } - /** * Add suggestions based on current scope (not after a dot). */ diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java index 2c49b036a..5ee8d3783 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java @@ -10,6 +10,7 @@ import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -176,8 +177,6 @@ public class ScriptTypeInfo extends TypeInfo { Set active = PARAMETERIZING.get(); if (!active.add(this)) { - // Re-entrant call on the same raw type — fall back to shallow parameterization - // (no method/field substitution) to break the infinite recursion. return super.parameterize(typeArgs); } @@ -310,7 +309,11 @@ public class ScriptTypeInfo extends TypeInfo { if (enumConstants.containsKey(fieldName)) return true; - + + for (FieldInfo f : getSyntheticFields()) + if (f.getName().equals(fieldName)) + return true; + return false; } @@ -325,6 +328,10 @@ public class ScriptTypeInfo extends TypeInfo { return enumConst.getFieldInfo(); } + for (FieldInfo f : getSyntheticFields()) + if (f.getName().equals(fieldName)) + return f; + return null; } @@ -361,6 +368,7 @@ public class ScriptTypeInfo extends TypeInfo { /** * Get all enum constants. */ + @Override public Map getEnumConstants() { return new HashMap<>(enumConstants); } @@ -380,32 +388,51 @@ public class ScriptTypeInfo extends TypeInfo { @Override public boolean hasMethod(String methodName) { - return methods.containsKey(methodName); + if (methods.containsKey(methodName)) + return true; + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName)) + return true; + return false; } @Override public boolean hasMethod(String methodName, int paramCount) { List overloads = methods.get(methodName); - if (overloads == null) return false; - for (MethodInfo m : overloads) { - if (m.getParameterCount() == paramCount) { - return true; + if (overloads != null) { + for (MethodInfo m : overloads) { + if (m.getParameterCount() == paramCount) { + return true; + } } } + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName) && m.getParameterCount() == paramCount) + return true; return false; } @Override public MethodInfo getMethodInfo(String methodName) { List overloads = methods.get(methodName); - return (overloads != null && !overloads.isEmpty()) ? overloads.get(0) : null; + if (overloads != null && !overloads.isEmpty()) + return overloads.get(0); + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName)) + return m; + return null; } /** * Get all method overloads with the given name. */ + @Override public List getAllMethodOverloads(String methodName) { - return methods.getOrDefault(methodName, new ArrayList<>()); + List result = new ArrayList<>(methods.getOrDefault(methodName, Collections.emptyList())); + for (MethodInfo m : getSyntheticMethods()) + if (m.getName().equals(methodName)) + result.add(m); + return result; } /** @@ -432,7 +459,26 @@ public class ScriptTypeInfo extends TypeInfo { allMethods.addAll(overloads); } return allMethods; - } + } + + @Override + public List getAllMethods() { + List result = getAllMethodsFlat(); + result.addAll(getSyntheticMethods()); + return result; + } + + @Override + public List getAllFields() { + List result = new ArrayList<>(getFields().values()); + result.addAll(getSyntheticFields()); + return result; + } + + @Override + public List getAllNestedTypes() { + return new ArrayList<>(innerClasses); + } // ==================== CONSTRUCTOR MANAGEMENT ==================== diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 1c5e36967..25044707a 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -771,6 +771,149 @@ public class TypeInfo { } } + /** + * Returns all public instance members of this type for autocomplete/resolution. + * Override in subclasses to extend or replace the default Java reflection path. + */ + public List getAllMethods() { + if (javaClass != null) { + // Java reflection path: enumerate public methods + synthetics + List result = new ArrayList<>(); + try { + for (java.lang.reflect.Method m : javaClass.getMethods()) { + try { + result.add(MethodInfo.fromReflection(m, this)); + } catch (Exception e) { + // Skip individual methods that fail (e.g., linkage errors on obscure return types) + } + } + } catch (Exception ignored) {} + result.addAll(getSyntheticMethods()); + return result; + } + + // javaClass == null: check rawType, jsTypeInfo, synthetics in priority order + if (rawType != null && rawType != this) { + List rawMethods = rawType.getAllMethods(); + if (!rawMethods.isEmpty() && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + List substituted = new ArrayList<>(rawMethods.size()); + for (MethodInfo m : rawMethods) { + substituted.add(m.substituteTypeParams(bindings)); + } + return substituted; + } + } + return rawMethods; + } + + // No javaClass, no rawType — collect from jsTypeInfo and synthetics + List result = new ArrayList<>(); + if (jsTypeInfo != null) { + for (JSMethodInfo m : jsTypeInfo.getMethods().values()) { + result.add(MethodInfo.fromJSMethod(m, this)); + } + } + result.addAll(getSyntheticMethods()); + return result; + } + + public List getAllFields() { + if (javaClass != null) { + // Java reflection path: enumerate public fields + synthetics + List result = new ArrayList<>(); + try { + for (java.lang.reflect.Field f : javaClass.getFields()) { + try { + result.add(FieldInfo.fromReflection(f, this)); + } catch (Exception e) { + // Skip individual fields that fail rather than losing ALL fields. + } + } + } catch (Exception ignored) {} + result.addAll(getSyntheticFields()); + return result; + } + + // javaClass == null: check rawType, jsTypeInfo, synthetics in priority order + if (rawType != null && rawType != this) { + List rawFields = rawType.getAllFields(); + if (!rawFields.isEmpty() && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + List substituted = new ArrayList<>(rawFields.size()); + for (FieldInfo f : rawFields) { + substituted.add(f.substituteTypeParams(bindings)); + } + return substituted; + } + } + return rawFields; + } + + // No javaClass, no rawType — collect from jsTypeInfo and synthetics + List result = new ArrayList<>(); + if (jsTypeInfo != null) { + for (JSFieldInfo f : jsTypeInfo.getFields().values()) { + result.add(FieldInfo.fromJSField(f, this)); + } + } + result.addAll(getSyntheticFields()); + return result; + } + + /** + * Returns all public nested types (inner classes/interfaces/enums) of this type. + * Uses reflection to discover nested types from the Java class, filters to public only, + * converts internal '$' separators to '.' for name resolution, and resolves each via TypeResolver. + * + * Override in subclasses (e.g., ScriptTypeInfo) to return script-defined inner classes. + * + * @return List of resolved nested TypeInfo instances (may be empty, never null) + */ + public List getAllNestedTypes() { + if (javaClass != null) { + List result = new ArrayList<>(); + try { + for (Class nested : javaClass.getDeclaredClasses()) { + if (!Modifier.isPublic(nested.getModifiers())) { + continue; + } + // Convert JVM internal '$' separator to '.' for TypeResolver lookup + String nestedFullName = nested.getName().replace('$', '.'); + TypeInfo nestedType = TypeResolver.getInstance().resolveFullName(nestedFullName); + if (nestedType != null && nestedType.isResolved()) { + result.add(nestedType); + } + } + } catch (SecurityException ignored) { + // Some runtimes may restrict getDeclaredClasses() + } + return result; + } + + if (rawType != null && rawType != this) { + return rawType.getAllNestedTypes(); + } + + // No javaClass, no rawType — check jsTypeInfo for inner types + if (jsTypeInfo != null) { + Map innerTypes = jsTypeInfo.getInnerTypes(); + if (!innerTypes.isEmpty()) { + List result = new ArrayList<>(innerTypes.size()); + for (JSTypeInfo inner : innerTypes.values()) { + TypeInfo ti = TypeInfo.fromJSTypeInfo(inner); + if (ti != null) { + result.add(ti); + } + } + return result; + } + } + return Collections.emptyList(); + } + /** * Check if this type has a method with the given name. */ @@ -789,6 +932,8 @@ public class TypeInfo { } catch (Exception e) { // Security or linkage error } + } else if (rawType != null && rawType != this) { + return rawType.hasMethod(methodName); } TypeInfo obj = TypeInfo.object(); @@ -817,6 +962,8 @@ public class TypeInfo { } catch (Exception e) { // Security or linkage error } + } else if (rawType != null && rawType != this) { + return rawType.hasMethod(methodName, paramCount); } TypeInfo obj = TypeInfo.object(); if (obj != this) return obj.hasMethod(methodName); @@ -828,13 +975,15 @@ public class TypeInfo { * Override in ScriptTypeInfo for script-defined types. */ public boolean hasConstructors() { - if (javaClass == null) return false; - try { - return javaClass.getConstructors().length > 0; - } catch (Exception e) { - // Security or linkage error - return false; + if (javaClass != null) { + try { + return javaClass.getConstructors().length > 0; + } catch (Exception e) { + return false; + } } + if (rawType != null && rawType != this) return rawType.hasConstructors(); + return false; } /** @@ -843,16 +992,18 @@ public class TypeInfo { */ public List getConstructors() { List result = new ArrayList<>(); - if (javaClass == null) return result; - - try { - java.lang.reflect.Constructor[] constructors = javaClass.getConstructors(); - for (java.lang.reflect.Constructor ctor : constructors) { - result.add(MethodInfo.fromReflectionConstructor(ctor, this)); + if (javaClass != null) { + try { + java.lang.reflect.Constructor[] constructors = javaClass.getConstructors(); + for (java.lang.reflect.Constructor ctor : constructors) { + result.add(MethodInfo.fromReflectionConstructor(ctor, this)); + } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return result; } + if (rawType != null && rawType != this) return rawType.getConstructors(); return result; } @@ -861,45 +1012,49 @@ public class TypeInfo { * Override in ScriptTypeInfo for script-defined types. */ public MethodInfo findConstructor(int argCount) { - if (javaClass == null) return null; - - try { - Constructor[] constructors = javaClass.getConstructors(); - for (Constructor ctor : constructors) { - if (ctor.getParameterCount() == argCount) { - return MethodInfo.fromReflectionConstructor(ctor, this); + if (javaClass != null) { + try { + Constructor[] constructors = javaClass.getConstructors(); + for (Constructor ctor : constructors) { + if (ctor.getParameterCount() == argCount) { + return MethodInfo.fromReflectionConstructor(ctor, this); + } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; } + if (rawType != null && rawType != this) return rawType.findConstructor(argCount); return null; } public MethodInfo findConstructor(TypeInfo[] argTypes) { - if (javaClass == null) return null; - - try { - Constructor[] constructors = javaClass.getConstructors(); - for (Constructor ctor : constructors) { - if (ctor.getParameterCount() == argTypes.length) { - Class[] paramTypes = ctor.getParameterTypes(); - boolean match = true; - for (int i = 0; i < argTypes.length; i++) { - TypeInfo paramTypeInfo = TypeInfo.fromClass(paramTypes[i]); - if (!TypeChecker.isTypeCompatible(paramTypeInfo, argTypes[i])) { - match = false; - break; + if (javaClass != null) { + try { + Constructor[] constructors = javaClass.getConstructors(); + for (Constructor ctor : constructors) { + if (ctor.getParameterCount() == argTypes.length) { + Class[] paramTypes = ctor.getParameterTypes(); + boolean match = true; + for (int i = 0; i < argTypes.length; i++) { + TypeInfo paramTypeInfo = TypeInfo.fromClass(paramTypes[i]); + if (!TypeChecker.isTypeCompatible(paramTypeInfo, argTypes[i])) { + match = false; + break; + } + } + if (match) { + return MethodInfo.fromReflectionConstructor(ctor, this); } } - if (match) { - return MethodInfo.fromReflectionConstructor(ctor, this); - } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; } + if (rawType != null && rawType != this) return rawType.findConstructor(argTypes); return null; } @@ -913,30 +1068,63 @@ public class TypeInfo { return jsTypeInfo.hasField(fieldName); } - if (javaClass == null) return false; - try { - for (java.lang.reflect.Field f : javaClass.getFields()) { - if (f.getName().equals(fieldName)) { - return true; + if (javaClass != null) { + try { + for (java.lang.reflect.Field f : javaClass.getFields()) { + if (f.getName().equals(fieldName)) { + return true; + } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return false; } + if (rawType != null && rawType != this) return rawType.hasField(fieldName); return false; } - public boolean hasEnumConstant(String constantName) { - if (javaClass == null || !javaClass.isEnum()) return false; + /** + * Returns all enum constants for this type as a name-to-EnumConstantInfo map. + * For Java enum types, builds the map via reflection. For script-defined enums, + * ScriptTypeInfo overrides this to return its stored constants directly. + * + * @return Map of constant name to EnumConstantInfo (empty if not an enum or no constants) + */ + public Map getEnumConstants() { + if (javaClass == null || !javaClass.isEnum()) { + if (rawType != null && rawType != this) { + return rawType.getEnumConstants(); + } + return Collections.emptyMap(); + } + Map result = new LinkedHashMap<>(); try { Object[] constants = javaClass.getEnumConstants(); for (Object constant : constants) { - if (constant.toString().equals(constantName)) - return true; + String name = constant.toString(); + result.put(name, EnumConstantInfo.fromReflection(name, this, null)); } } catch (Exception e) { - // Security or linkage error + // Security or linkage error — return whatever we have so far } + return result; + } + + public boolean hasEnumConstant(String constantName) { + if (javaClass != null && javaClass.isEnum()) { + try { + Object[] constants = javaClass.getEnumConstants(); + for (Object constant : constants) { + if (constant.toString().equals(constantName)) + return true; + } + } catch (Exception e) { + // Security or linkage error + } + return false; + } + if (rawType != null && rawType != this) return rawType.hasEnumConstant(constantName); return false; } @@ -944,16 +1132,19 @@ public class TypeInfo { * Get an enum constant by name. */ public EnumConstantInfo getEnumConstant(String constantName) { - if (javaClass == null || !javaClass.isEnum()) return null; - try { - Object[] constants = javaClass.getEnumConstants(); - for (Object constant : constants) { - if (constant.toString().equals(constantName)) - return EnumConstantInfo.fromReflection(constantName, this, null); + if (javaClass != null && javaClass.isEnum()) { + try { + Object[] constants = javaClass.getEnumConstants(); + for (Object constant : constants) { + if (constant.toString().equals(constantName)) + return EnumConstantInfo.fromReflection(constantName, this, null); + } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; } + if (rawType != null && rawType != this) return rawType.getEnumConstant(constantName); return null; } @@ -976,6 +1167,13 @@ public class TypeInfo { } catch (Exception e) { // Security or linkage error } + } else if (rawType != null && rawType != this) { + MethodInfo rawMethod = rawType.getMethodInfo(methodName); + if (rawMethod != null && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) return rawMethod.substituteTypeParams(bindings); + } + return rawMethod; } TypeInfo obj = TypeInfo.object(); if (obj != this) return obj.getMethodInfo(methodName); @@ -1012,6 +1210,18 @@ public class TypeInfo { // Security or linkage error } if (!overloads.isEmpty()) return overloads; + } else if (rawType != null && rawType != this) { + java.util.List rawOverloads = rawType.getAllMethodOverloads(methodName); + if (!rawOverloads.isEmpty() && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + for (MethodInfo m : rawOverloads) { + overloads.add(m.substituteTypeParams(bindings)); + } + return overloads; + } + } + return rawOverloads; } TypeInfo obj = TypeInfo.object(); if (obj != this) return obj.getAllMethodOverloads(methodName); @@ -1078,16 +1288,25 @@ public class TypeInfo { return null; } - if (javaClass == null) return null; - try { - for (java.lang.reflect.Field f : javaClass.getFields()) { - if (f.getName().equals(fieldName)) { - // Create a synthetic FieldInfo from reflection - return FieldInfo.fromReflection(f, this); + if (javaClass != null) { + try { + for (java.lang.reflect.Field f : javaClass.getFields()) { + if (f.getName().equals(fieldName)) { + return FieldInfo.fromReflection(f, this); + } } + } catch (Exception e) { + // Security or linkage error } - } catch (Exception e) { - // Security or linkage error + return null; + } + if (rawType != null && rawType != this) { + FieldInfo rawField = rawType.getFieldInfo(fieldName); + if (rawField != null && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) return rawField.substituteTypeParams(bindings); + } + return rawField; } return null; } @@ -1206,7 +1425,19 @@ public class TypeInfo { return null; } - // Not a functional interface + // Not a functional interface — try rawType for parameterized script types + if (rawType != null && rawType != this) { + MethodInfo rawSAM = rawType.getSingleAbstractMethod(); + if (rawSAM != null && isParameterized()) { + Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); + if (!bindings.isEmpty()) { + cachedSAM = rawSAM.substituteTypeParams(bindings); + return cachedSAM; + } + } + cachedSAM = rawSAM; + return cachedSAM; + } cachedSAM = null; return null; From f66d2f019396066dd3e0bfcf8894c4485a86f465 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 18:29:06 +0200 Subject: [PATCH 29/38] GenericContext overhaul, removed redundant TypeSubstitutor --- .../script/interpreter/ScriptDocument.java | 50 +++++- .../script/interpreter/field/FieldInfo.java | 43 +++++- .../script/interpreter/method/MethodInfo.java | 47 ++++-- .../interpreter/type/GenericContext.java | 14 +- .../interpreter/type/ScriptTypeInfo.java | 27 +--- .../script/interpreter/type/TypeInfo.java | 50 +++--- .../interpreter/type/TypeSubstitutor.java | 146 ------------------ 7 files changed, 155 insertions(+), 222 deletions(-) delete mode 100644 src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeSubstitutor.java diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index dfe41103d..99590522f 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -4308,6 +4308,54 @@ public class ScriptDocument { return resolveTypeAndTrackUsage(typeName); } + /** + * Recursively resolve any unresolved type names inside a TypeInfo using position-aware resolution. + * + * This handles a different concern than {@link GenericContext#substitute(TypeInfo)} — + * it does not replace type variables with concrete bindings. Instead, it re-resolves + * unresolved simple names (e.g., inner class names like "Node" or script-declared type + * parameters like "T") that appear as type arguments in parameterized types. + * + * For example, if a type resolves to {@code List} but "Node" is still unresolved, + * this will attempt to resolve "Node" using the position-aware + * {@link #resolveType(String, int)} which can find inner classes and type parameters + * visible at the given position. + * + * @param type the type whose unresolved components should be re-resolved + * @param position the script text offset for scope-aware resolution + * @return the type with all resolvable components resolved, or the original if nothing changed + */ + private TypeInfo substituteTypeParams(TypeInfo type, int position) { + if (type == null) + return null; + + if (!type.isResolved() && type.getSimpleName() != null + && !type.getSimpleName().contains(".")) { + TypeInfo sub = resolveType(type.getSimpleName(), position); + return (sub != null && sub.isResolved()) ? sub : type; + } + + if (type.isParameterized()) { + List args = type.getAppliedTypeArgs(); + if (args != null && !args.isEmpty()) { + List substituted = new ArrayList<>(args.size()); + boolean anyChanged = false; + for (TypeInfo arg : args) { + TypeInfo sub = substituteTypeParams(arg, position); + if (sub != arg) + anyChanged = true; + substituted.add(sub); + } + if (anyChanged) { + TypeInfo raw = type.getRawType(); + return raw != null ? raw.parameterize(substituted) : type.parameterize(substituted); + } + } + } + + return type; + } + /** * Position-aware type resolution overload. * Resolves a type name with positional context so that an unqualified inner class name @@ -4330,7 +4378,7 @@ public class ScriptDocument { // If already resolved, no need for positional fallback if (resolved != null && resolved.isResolved()) { - return resolved; + return substituteTypeParams(resolved, position); } if (typeName != null && !typeName.contains(".")) { diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java index 466f1d8c4..78f342db5 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/field/FieldInfo.java @@ -9,7 +9,7 @@ import noppes.npcs.client.gui.util.script.interpreter.jsdoc.JSDocInfo; import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; import noppes.npcs.client.gui.util.script.interpreter.type.GenericContext; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; -import noppes.npcs.client.gui.util.script.interpreter.type.TypeSubstitutor; + import noppes.npcs.client.gui.util.script.interpreter.method.MethodCallInfo; import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo; @@ -18,7 +18,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; /** * Metadata for a field (variable) declaration or reference. @@ -165,12 +164,8 @@ public final class FieldInfo { } // If the receiver is parameterized, substitute class type variables in the field type - if (GenericContext.hasGenerics(containingType)) { - Map receiverBindings = TypeSubstitutor.createBindingsFromReceiver(containingType); - if (!receiverBindings.isEmpty()) { - type = TypeSubstitutor.substitute(type, receiverBindings); - } - } + if (GenericContext.hasGenerics(containingType)) + type = GenericContext.forReceiver(containingType).substitute(type); // Check if this is an enum constant if (field.isEnumConstant()) { @@ -531,6 +526,38 @@ public final class FieldInfo { public String getDocumentation() { return documentation; } public JSDocInfo getJSDocInfo() { return jsDocInfo; } public void setJSDocInfo(JSDocInfo jsDocInfo) { this.jsDocInfo = jsDocInfo; } + + /** + * Create a copy of this field with its declared type substituted using the given context. + * Returns {@code this} unchanged if the context is null, the declared type is null, + * or substitution produces the same type (identity check). + * + * Used when a generic type is parameterized (e.g., {@code Box}) and its raw fields + * (declared with type variables like T) need to reflect the concrete type arguments. + * + * Example: for {@code class Box { T value; }}, calling this on the raw field {@code value: T} + * with a context binding {@code T → String} produces {@code value: String}. + * + * @param context the generic context containing type variable bindings; if null, returns {@code this} unchanged + * @return a new FieldInfo with the substituted declared type, or {@code this} if no substitution occurred + */ + public FieldInfo substituteTypeParams(GenericContext context) { + if (context == null || declaredType == null) { + return this; + } + TypeInfo subType = context.substitute(declaredType); + if (subType == declaredType) { + return this; + } + FieldInfo result = new FieldInfo(name, scope, subType, declarationOffset, resolved, + containingMethod, documentation, initStart, initEnd, modifiers, reflectionField); + result.jsDocInfo = this.jsDocInfo; + result.scopeInfo = this.scopeInfo; + result.isVarArg = this.isVarArg; + result.inferredType = this.inferredType; + return result; + } + public int getInitStart() { return initStart; } public int getInitEnd() { return initEnd; } public boolean hasInitializer() { return initStart >= 0 && initEnd > initStart; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java index ccfc347c5..12ba570d3 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java @@ -11,7 +11,7 @@ import noppes.npcs.client.gui.util.script.interpreter.token.TokenType; import noppes.npcs.client.gui.util.script.interpreter.type.GenericContext; import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; -import noppes.npcs.client.gui.util.script.interpreter.type.TypeSubstitutor; + import noppes.npcs.client.gui.util.script.interpreter.type.GenericParameterAdapter; import java.lang.reflect.Constructor; @@ -173,13 +173,12 @@ public final class MethodInfo { } // If the receiver is parameterized (e.g., List), substitute class type variables (E -> String) - Map receiverBindings = null; + GenericContext receiverCtx = null; if (GenericContext.hasGenerics(containingType)) { - receiverBindings = TypeSubstitutor.createBindingsFromReceiver(containingType); - if (!receiverBindings.isEmpty()) { - returnType = TypeSubstitutor.substitute(returnType, receiverBindings); - } + receiverCtx = GenericContext.forReceiver(containingType); + returnType = receiverCtx.substitute(returnType); } + List params = new ArrayList<>(); // Use getGenericParameterTypes() to preserve generic information java.lang.reflect.Type[] genericParamTypes = method.getGenericParameterTypes(); @@ -190,9 +189,8 @@ public final class MethodInfo { paramType = TypeInfo.fromClass(method.getParameterTypes()[i]); } - if (receiverBindings != null && !receiverBindings.isEmpty()) { - paramType = TypeSubstitutor.substitute(paramType, receiverBindings); - } + if (receiverCtx != null) + paramType = receiverCtx.substitute(paramType); // Adapt Object params to receiver generic type args (e.g., Map.get(Object) -> Map.get(K)) TypeInfo adapted = GenericParameterAdapter.adaptParameterType(method, containingType, i, paramType); @@ -377,6 +375,37 @@ public final class MethodInfo { */ public boolean hasInheritanceMarker() { return isOverride() || isImplements(); } + /** + * Create a copy of this method with all type variables substituted using the given context. + * Applies substitution to both the return type and every parameter type recursively. + * + * Used when a generic type is parameterized (e.g., {@code Box}) and its raw methods + * (declared with type variables like T) need to reflect the concrete type arguments. + * + * Example: for {@code class Box { T get(); }}, calling this on the raw {@code get() → T} + * with a context binding {@code T → String} produces {@code get() → String}. + * + * @param context the generic context containing type variable bindings; if null, returns {@code this} unchanged + * @return a new MethodInfo with substituted types, or {@code this} if context is null + */ + public MethodInfo substituteTypeParams(GenericContext context) { + if (context == null) { + return this; + } + TypeInfo subReturnType = context.substitute(returnType); + List subParams = new ArrayList<>(parameters.size()); + for (FieldInfo param : parameters) { + subParams.add(param.substituteTypeParams(context)); + } + MethodInfo result = new MethodInfo(name, subReturnType, containingType, subParams, + fullDeclarationOffset, typeOffset, nameOffset, bodyStart, bodyEnd, + resolved, isDeclaration, modifiers, documentation, javaMethod); + result.jsDocInfo = this.jsDocInfo; + result.overridesFrom = this.overridesFrom; + result.implementsFrom = this.implementsFrom; + return result; + } + /** * Check if a position is inside this method's body. */ diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java index 394000384..455e8c6b3 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/GenericContext.java @@ -8,12 +8,16 @@ import java.util.List; import java.util.Map; /** - * A context for resolving and substituting declared type parameters (T, E, K, V...) - * based on a receiver type. + * Single source of truth for generic type variable substitution. * - * Policy: - * - Prefer applied type arguments when present (e.g. List binds E -> String). - * - Fall back to declared bounds when no applied argument exists (e.g. T extends Entity -> Entity). + * Resolves type parameters (T, E, K, V...) to concrete types using: + * 1. Applied type arguments (e.g., List<String> binds E → String) — priority + * 2. Declared bounds fallback (e.g., <T extends Entity> binds T → Entity) — fallback + * + * Usage patterns: + * - {@link #forReceiver(TypeInfo)} — build context from a parameterized receiver type + * - {@link #fromBindings(List, List)} — build context from explicit params/args (anti-recursion safe) + * - {@link #substitute(TypeInfo)} — instance method with two-tier resolution */ public final class GenericContext { diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java index 5ee8d3783..b40c17bf9 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/ScriptTypeInfo.java @@ -153,24 +153,6 @@ public class ScriptTypeInfo extends TypeInfo { return super.getTypeParam(name); } - private static MethodInfo substituteMethod(MethodInfo m, GenericContext ctx) { - TypeInfo retType = m.getReturnType(); - TypeInfo subRet = ctx.substitute(retType); - List params = new ArrayList<>(m.getParameters()); - boolean changed = subRet != retType; - for (int i = 0; i < params.size(); i++) { - FieldInfo p = params.get(i); - TypeInfo subP = ctx.substitute(p.getTypeInfo()); - if (subP != p.getTypeInfo()) { - params.set(i, FieldInfo.reflectionParam(p.getName(), subP)); - changed = true; - } - } - return changed ? MethodInfo.external(m.getName(), subRet, m.getContainingType(), - params, m.getModifiers(), m.getDocumentation()) : m; - } - - @Override public TypeInfo parameterize(List typeArgs) { if (typeArgs == null || typeArgs.isEmpty()) return this; @@ -198,17 +180,14 @@ public class ScriptTypeInfo extends TypeInfo { // Parameterize methods, constructors, and fields with the generic context of this type. for (Map.Entry> entry : this.methods.entrySet()) { List substituted = new ArrayList<>(); - for (MethodInfo m : entry.getValue()) substituted.add(substituteMethod(m, ctx)); + for (MethodInfo m : entry.getValue()) substituted.add(m.substituteTypeParams(ctx)); result.methods.put(entry.getKey(), substituted); } for (MethodInfo ctor : this.constructors) { - result.constructors.add(substituteMethod(ctor, ctx)); + result.constructors.add(ctor.substituteTypeParams(ctx)); } for (Map.Entry entry : this.fields.entrySet()) { - FieldInfo f = entry.getValue(); - TypeInfo subType = ctx.substitute(f.getTypeInfo()); - result.fields.put(entry.getKey(), subType != f.getTypeInfo() - ? FieldInfo.external(f.getName(), subType, null, f.getModifiers()) : f); + result.fields.put(entry.getKey(), entry.getValue().substituteTypeParams(ctx)); } return result; } finally { diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 25044707a..6a8d2b855 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -796,14 +796,12 @@ public class TypeInfo { if (rawType != null && rawType != this) { List rawMethods = rawType.getAllMethods(); if (!rawMethods.isEmpty() && isParameterized()) { - Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); - if (!bindings.isEmpty()) { - List substituted = new ArrayList<>(rawMethods.size()); - for (MethodInfo m : rawMethods) { - substituted.add(m.substituteTypeParams(bindings)); - } - return substituted; + GenericContext ctx = GenericContext.forReceiver(this); + List substituted = new ArrayList<>(rawMethods.size()); + for (MethodInfo m : rawMethods) { + substituted.add(m.substituteTypeParams(ctx)); } + return substituted; } return rawMethods; } @@ -840,14 +838,12 @@ public class TypeInfo { if (rawType != null && rawType != this) { List rawFields = rawType.getAllFields(); if (!rawFields.isEmpty() && isParameterized()) { - Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); - if (!bindings.isEmpty()) { - List substituted = new ArrayList<>(rawFields.size()); - for (FieldInfo f : rawFields) { - substituted.add(f.substituteTypeParams(bindings)); - } - return substituted; + GenericContext ctx = GenericContext.forReceiver(this); + List substituted = new ArrayList<>(rawFields.size()); + for (FieldInfo f : rawFields) { + substituted.add(f.substituteTypeParams(ctx)); } + return substituted; } return rawFields; } @@ -1170,8 +1166,8 @@ public class TypeInfo { } else if (rawType != null && rawType != this) { MethodInfo rawMethod = rawType.getMethodInfo(methodName); if (rawMethod != null && isParameterized()) { - Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); - if (!bindings.isEmpty()) return rawMethod.substituteTypeParams(bindings); + GenericContext ctx = GenericContext.forReceiver(this); + return rawMethod.substituteTypeParams(ctx); } return rawMethod; } @@ -1213,13 +1209,11 @@ public class TypeInfo { } else if (rawType != null && rawType != this) { java.util.List rawOverloads = rawType.getAllMethodOverloads(methodName); if (!rawOverloads.isEmpty() && isParameterized()) { - Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); - if (!bindings.isEmpty()) { - for (MethodInfo m : rawOverloads) { - overloads.add(m.substituteTypeParams(bindings)); - } - return overloads; + GenericContext ctx = GenericContext.forReceiver(this); + for (MethodInfo m : rawOverloads) { + overloads.add(m.substituteTypeParams(ctx)); } + return overloads; } return rawOverloads; } @@ -1303,8 +1297,8 @@ public class TypeInfo { if (rawType != null && rawType != this) { FieldInfo rawField = rawType.getFieldInfo(fieldName); if (rawField != null && isParameterized()) { - Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); - if (!bindings.isEmpty()) return rawField.substituteTypeParams(bindings); + GenericContext ctx = GenericContext.forReceiver(this); + return rawField.substituteTypeParams(ctx); } return rawField; } @@ -1429,11 +1423,9 @@ public class TypeInfo { if (rawType != null && rawType != this) { MethodInfo rawSAM = rawType.getSingleAbstractMethod(); if (rawSAM != null && isParameterized()) { - Map bindings = TypeSubstitutor.createBindingsFromReceiver(this); - if (!bindings.isEmpty()) { - cachedSAM = rawSAM.substituteTypeParams(bindings); - return cachedSAM; - } + GenericContext ctx = GenericContext.forReceiver(this); + cachedSAM = rawSAM.substituteTypeParams(ctx); + return cachedSAM; } cachedSAM = rawSAM; return cachedSAM; diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeSubstitutor.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeSubstitutor.java deleted file mode 100644 index 2554867d0..000000000 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeSubstitutor.java +++ /dev/null @@ -1,146 +0,0 @@ -package noppes.npcs.client.gui.util.script.interpreter.type; - -import noppes.npcs.client.gui.util.script.interpreter.js_parser.TypeParamInfo; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Utility for substituting type variables (like T, E, K, V) with concrete types. - * - * Used when resolving members on parameterized types: - * - List.get(int) returns String (not T/Object) - * - Map.get(Object) returns Integer (not V) - * - * Handles nested generics: - * - List>.get(0) returns Map - */ -public class TypeSubstitutor { - - /** - * Create a binding map from declared type parameters to applied type arguments. - * - * Example: For List where List is declared as interface List: - * - declaredParams = [TypeParamInfo("E", ...)] - * - appliedArgs = [TypeInfo(String)] - * - Result: {"E" -> TypeInfo(String)} - * - * @param declaredParams The declared type parameters (from the generic type definition) - * @param appliedArgs The applied type arguments (from the parameterized usage) - * @return A map from type parameter names to their concrete TypeInfo values - */ - public static Map createBindings(List declaredParams, List appliedArgs) { - Map bindings = new HashMap<>(); - - if (declaredParams == null || appliedArgs == null) { - return bindings; - } - - int count = Math.min(declaredParams.size(), appliedArgs.size()); - for (int i = 0; i < count; i++) { - String paramName = declaredParams.get(i).getName(); - TypeInfo argType = appliedArgs.get(i); - if (paramName != null && argType != null) { - bindings.put(paramName, argType); - } - } - - return bindings; - } - - /** - * Create bindings from a parameterized receiver type. - * - * @param receiverType The parameterized type (e.g., List) - * @return Bindings from the type's declared params to its applied args - */ - public static Map createBindingsFromReceiver(TypeInfo receiverType) { - if (receiverType == null) { - return new HashMap<>(); - } - - // Get the raw type to access declared type parameters - TypeInfo rawType = receiverType.getRawType(); - List declaredParams = null; - - // Get declared params from JSTypeInfo or reflection - if (rawType.isJSType() && rawType.getJSTypeInfo() != null) { - declaredParams = rawType.getJSTypeInfo().getTypeParams(); - } else { - declaredParams = rawType.getTypeParams(); - } - - // Get applied args from the parameterized type - List appliedArgs = receiverType.getAppliedTypeArgs(); - - return createBindings(declaredParams, appliedArgs); - } - - /** - * Substitute type variables in a type using the given bindings. - * - * @param type The type to substitute (may contain type variables like T, E) - * @param bindings The map from type variable names to concrete types - * @return The substituted type - */ - public static TypeInfo substitute(TypeInfo type, Map bindings) { - if (type == null || bindings == null || bindings.isEmpty()) { - return type; - } - - String typeName = type.getSimpleName(); - - // Check if this type is itself a type variable. - // Two cases: - // 1. Unresolved TypeInfo (Java reflection path: TypeInfo.fromGenericType creates these for T, E, K, V) - // 2. TypeInfo.typeParameter() (script-defined path: resolved but tagged as a type parameter) - // For tagged type parameters, use getTypeParameterName() as the lookup key. - if (!type.isResolved() || type.isTypeParameter()) { - String lookupKey = type.isTypeParameter() ? type.getTypeParameterName() : typeName; - TypeInfo substitution = bindings.get(lookupKey); - if (substitution != null) { - return substitution; - } - } - - // If the type has applied type arguments, substitute within them recursively - if (type.isParameterized()) { - List originalArgs = type.getAppliedTypeArgs(); - List substitutedArgs = new ArrayList<>(); - boolean changed = false; - - for (TypeInfo arg : originalArgs) { - TypeInfo substitutedArg = substitute(arg, bindings); - substitutedArgs.add(substitutedArg); - if (substitutedArg != arg) { - changed = true; - } - } - - if (changed) { - // Create a new parameterized type with substituted args - return type.getRawType().parameterize(substitutedArgs); - } - } - - // Handle array types - substitute the element type - if (type.getSimpleName().endsWith("[]")) { - TypeStringNormalizer.ArraySplit split = TypeStringNormalizer.splitArraySuffixes(typeName); - String elementTypeName = split.base; - int dims = split.dimensions; - TypeInfo elementSubstitution = elementTypeName != null ? bindings.get(elementTypeName) : null; - if (elementSubstitution != null) { - TypeInfo result = elementSubstitution; - for (int i = 0; i < dims; i++) { - result = TypeInfo.arrayOf(result); - } - return result; - } - } - - return type; - } - -} From 82128ce318c00746f344651a59299d73e92d5fbf Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 18:33:03 +0200 Subject: [PATCH 30/38] Proper Hover Info data for generic classes with type params --- .../interpreter/hover/TokenHoverInfo.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java index 567f0a8f7..9bfb9ff3d 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java @@ -582,7 +582,7 @@ public class TokenHoverInfo { // // Show modifiers from source if we have a declaration position // String modifiers = extractModifiersAtPosition(fieldInfo.getDeclarationOffset()); // if (modifiers != null && !modifiers.isEmpty()) { -// addSegment(modifiers + " ", TokenType.MODIFIER.getHexColor()); +// addSegment(modifiers + " ", TokenType.KEYWORD.getHexColor()); // } // } @@ -802,6 +802,64 @@ public class TokenHoverInfo { } else { addSegment(param.getBoundTypeName(), TokenType.IMPORTED_CLASS.getHexColor()); } + + List additionalBoundTypes = param.getAdditionalBoundTypes(); + List additionalBoundNames = param.getAdditionalBoundNames(); + for (int j = 0; j < additionalBoundNames.size(); j++) { + addSegment(" & ", TokenType.DEFAULT.getHexColor()); + TypeInfo additionalBoundType = j < additionalBoundTypes.size() ? additionalBoundTypes.get(j) : null; + if (additionalBoundType != null && additionalBoundType.isResolved()) { + addTypeSegments(additionalBoundType); + if (!additionalBoundType.isParameterized()) { + addBoundTypeParamSegments(additionalBoundType); + } + } else { + addSegment(additionalBoundNames.get(j), TokenType.IMPORTED_CLASS.getHexColor()); + } + } + } + } + + addSegment(">", TokenType.DEFAULT.getHexColor()); + } + + private void addBoundTypeParamSegments(TypeInfo boundType) { + List params = boundType.getTypeParams(); + if (params == null || params.isEmpty()) return; + + addSegment("<", TokenType.DEFAULT.getHexColor()); + for (int i = 0; i < params.size(); i++) { + if (i > 0) + addSegment(", ", TokenType.DEFAULT.getHexColor()); + TypeParamInfo tp = params.get(i); + addSegment(tp.getName(), TokenType.GENERIC_TYPE_PARAM.getHexColor()); + + if (tp.getBoundTypeName() != null && !"Object".equals(tp.getBoundTypeName())) { + addSegment(" extends ", TokenType.KEYWORD.getHexColor()); + TypeInfo innerBound = tp.getBoundTypeInfo(); + if (innerBound != null && innerBound.isResolved()) { + addTypeSegments(innerBound); + if (!innerBound.isParameterized()) { + addBoundTypeParamSegments(innerBound); + } + } else { + addSegment(tp.getBoundTypeName(), TokenType.IMPORTED_CLASS.getHexColor()); + } + + List innerAdditional = tp.getAdditionalBoundTypes(); + List innerAdditionalNames = tp.getAdditionalBoundNames(); + for (int j = 0; j < innerAdditionalNames.size(); j++) { + addSegment(" & ", TokenType.DEFAULT.getHexColor()); + TypeInfo innerAddBound = j < innerAdditional.size() ? innerAdditional.get(j) : null; + if (innerAddBound != null && innerAddBound.isResolved()) { + addTypeSegments(innerAddBound); + if (!innerAddBound.isParameterized()) { + addBoundTypeParamSegments(innerAddBound); + } + } else { + addSegment(innerAdditionalNames.get(j), TokenType.IMPORTED_CLASS.getHexColor()); + } + } addSegment(" extends ", TokenType.KEYWORD.getHexColor()); } } From 85d4bb2628df19982b75510f41daf75f0f6f95d2 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 18:33:27 +0200 Subject: [PATCH 31/38] man get this old washed shit outta my face --- .../npcs/client/gui/util/script/JavaTextContainer.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java b/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java index b54b1cf1d..87d330726 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java @@ -575,7 +575,7 @@ public class JavaTextContainer extends TextContainer { for (ImportEntry ie : importEntries) { // Highlight the 'import' keyword - marks.add(new Mark(ie.importKwStart, ie.importKwEnd, TokenType.IMPORT_KEYWORD)); + marks.add(new Mark(ie.importKwStart, ie.importKwEnd, TokenType.KEYWORD)); String fullPath = ie.fullPath; int pathStart = ie.pathStart; @@ -836,7 +836,7 @@ public class JavaTextContainer extends TextContainer { Matcher m = CLASS_DECL.matcher(text); List excluded = MethodBlock.getExcludedRanges(text); while (m.find()) { - marks.add(new Mark(m.start(1), m.end(1), TokenType.CLASS_KEYWORD)); + marks.add(new Mark(m.start(1), m.end(1), TokenType.KEYWORD)); int nameStart = m.start(2); int nameEnd = m.end(2); @@ -868,7 +868,7 @@ public class JavaTextContainer extends TextContainer { // Highlight general keywords collectPatternMatches(marks, KEYWORD, TokenType.KEYWORD); - collectPatternMatches(marks, MODIFIER, TokenType.MODIFIER); + collectPatternMatches(marks, MODIFIER, TokenType.KEYWORD); collectTypeDeclarations(marks); collectPatternMatches(marks, NEW_TYPE, TokenType.NEW_TYPE, 1); @@ -1211,10 +1211,7 @@ public class JavaTextContainer extends TextContainer { public enum TokenType { COMMENT('7', 130), STRING('5', 120), - CLASS_KEYWORD('c', 115), - IMPORT_KEYWORD('6', 110), KEYWORD('c', 100), - MODIFIER('6', 90), NEW_TYPE('d', 80), IMPORTED_CLASS('3', 75), //imported classes used in code INTERFACE_DECL('b', 85), From b6e3ee8404a291c5e7c11fdf3d0a11fe7968b06d Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 18:34:09 +0200 Subject: [PATCH 32/38] Umm one is enough --- src/main/java/noppes/npcs/client/ClientProxy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/noppes/npcs/client/ClientProxy.java b/src/main/java/noppes/npcs/client/ClientProxy.java index 71a5b7967..ce49e6eee 100644 --- a/src/main/java/noppes/npcs/client/ClientProxy.java +++ b/src/main/java/noppes/npcs/client/ClientProxy.java @@ -961,7 +961,7 @@ public class ClientProxy extends CommonProxy { public void drawString(String text, int x, int y, int color) { if (useCustomFont) { - textFont.renderString(text, x, y, color, true); + // textFont.renderString(text, x, y, color, true); textFont.renderString(text, x, y, color, false); } else { Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(text, x, y, color); From ce8c9b3b94df45c1029c23c26061ef46229d09d2 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 19:40:06 +0200 Subject: [PATCH 33/38] oh shit --- .../script/interpreter/ScriptDocument.java | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index 2badb6856..f7089bedd 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -4308,37 +4308,6 @@ public class ScriptDocument { return resolveTypeAndTrackUsage(typeName); } - private TypeInfo substituteTypeParams(TypeInfo type, int position) { - if (type == null) - return null; - - if (!type.isResolved() && type.getSimpleName() != null - && !type.getSimpleName().contains(".")) { - TypeInfo sub = resolveType(type.getSimpleName(), position); - return (sub != null && sub.isResolved()) ? sub : type; - } - - if (type.isParameterized()) { - List args = type.getAppliedTypeArgs(); - if (args != null && !args.isEmpty()) { - List substituted = new ArrayList<>(args.size()); - boolean anyChanged = false; - for (TypeInfo arg : args) { - TypeInfo sub = substituteTypeParams(arg, position); - if (sub != arg) - anyChanged = true; - substituted.add(sub); - } - if (anyChanged) { - TypeInfo raw = type.getRawType(); - return raw != null ? raw.parameterize(substituted) : type.parameterize(substituted); - } - } - } - - return type; - } - /** * Recursively resolve any unresolved type names inside a TypeInfo using position-aware resolution. * From c0a022c5b5dd68922fb5ff296cf3b0fa8396626a Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 19:49:30 +0200 Subject: [PATCH 34/38] Tightened excluded range checks in receiver chain resolution (fixes stupid . in comments fkin up next line bug) --- .../autocomplete/AutocompleteManager.java | 36 ++++++++++++++++--- .../script/interpreter/FieldChainMarker.java | 8 ++--- .../script/interpreter/ScriptDocument.java | 30 +++++++++++----- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java index 976688865..729a8dd74 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteManager.java @@ -389,6 +389,17 @@ public class AutocompleteManager { // Walk left across a dotted receiver chain while (pos >= 0) { + // Skip excluded regions (comments/strings) to avoid reading dots from inside them + if (document != null && document.isExcluded(pos)) { + int jumped = jumpBeforeExcluded(pos); + if (jumped == pos) { + pos--; + } else { + pos = jumped; + } + continue; + } + char c = text.charAt(pos); if (Character.isWhitespace(c)) { @@ -414,10 +425,24 @@ public class AutocompleteManager { // Consume identifier while (pos >= 0 && Character.isJavaIdentifierPart(text.charAt(pos))) pos--; - // If preceded by a dot, keep going + // If preceded by a dot, keep going (skip excluded ranges when looking for the dot) int checkPos = pos; - while (checkPos >= 0 && Character.isWhitespace(text.charAt(checkPos))) { - checkPos--; + while (checkPos >= 0) { + char ch = text.charAt(checkPos); + if (Character.isWhitespace(ch)) { + checkPos--; + continue; + } + if (document != null && document.isExcluded(checkPos)) { + int jumped = jumpBeforeExcluded(checkPos); + if (jumped == checkPos) { + checkPos--; + } else { + checkPos = jumped; + } + continue; + } + break; } if (checkPos >= 0 && text.charAt(checkPos) == '.') { pos = checkPos - 1; @@ -1044,13 +1069,16 @@ public class AutocompleteManager { // Check if we found a dot if (pos >= 0 && text.charAt(pos) == '.') { + if (document != null && document.isExcluded(pos)) return -1; return pos; } else { while (pos >= 0 && Character.isJavaIdentifierPart(text.charAt(pos))) pos--; - if (pos >= 0 && text.charAt(pos) == '.') + if (pos >= 0 && text.charAt(pos) == '.') { + if (document != null && document.isExcluded(pos)) return -1; return pos; + } } return -1; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java index 2eeff85c0..5659c7f56 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java @@ -151,11 +151,11 @@ public class FieldChainMarker { int pos = m.end(2); while (pos < text.length()) { pos = document.skipWhitespace(pos); - if (pos >= text.length() || text.charAt(pos) != '.') break; + if (pos >= text.length() || document.isExcluded(pos) || text.charAt(pos) != '.') break; pos++; // Skip dot pos = document.skipWhitespace(pos); - if (pos >= text.length() || !Character.isJavaIdentifierStart(text.charAt(pos))) break; + if (pos >= text.length() || document.isExcluded(pos) || !Character.isJavaIdentifierStart(text.charAt(pos))) break; // Read identifier int identStart = pos; @@ -452,11 +452,11 @@ public class FieldChainMarker { int pos = identEnd; while (pos < text.length()) { pos = document.skipWhitespace(pos); - if (pos >= text.length() || text.charAt(pos) != '.') break; + if (pos >= text.length() || document.isExcluded(pos) || text.charAt(pos) != '.') break; pos++; // Skip dot pos = document.skipWhitespace(pos); - if (pos >= text.length() || !Character.isJavaIdentifierStart(text.charAt(pos))) break; + if (pos >= text.length() || document.isExcluded(pos) || !Character.isJavaIdentifierStart(text.charAt(pos))) break; // Read identifier int nStart = pos; diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index f7089bedd..e9d6d7cf2 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -6467,7 +6467,7 @@ public class ScriptDocument { while (pos >= 0 && Character.isWhitespace(text.charAt(pos))) pos--; - if (pos < 0 || text.charAt(pos) != '.') + if (pos < 0 || isExcluded(pos) || text.charAt(pos) != '.') return false; // Skip the dot and any whitespace @@ -6475,7 +6475,7 @@ public class ScriptDocument { while (pos >= 0 && Character.isWhitespace(text.charAt(pos))) pos--; - if (pos < 0) + if (pos < 0 || isExcluded(pos)) return false; // Check what's before the dot - could be: @@ -6506,7 +6506,7 @@ public class ScriptDocument { pos--; // If preceded by a dot, this is part of a chain - treat as instance for now - if (pos >= 0 && text.charAt(pos) == '.') { + if (pos >= 0 && !isExcluded(pos) && text.charAt(pos) == '.') { return false; } @@ -7199,7 +7199,8 @@ public class ScriptDocument { while (scanPos >= 0 && Character.isWhitespace(text.charAt(scanPos))) scanPos--; - if (scanPos < 0 || text.charAt(scanPos) != '.') { + // Guard: dot inside a comment/string must not be treated as a receiver chain separator + if (scanPos < 0 || isExcluded(scanPos) || text.charAt(scanPos) != '.') { return null; // No receiver } @@ -8130,11 +8131,24 @@ public class ScriptDocument { if (Character.isJavaIdentifierPart(c)) { while (pos >= 0 && Character.isJavaIdentifierPart(text.charAt(pos))) pos--; - // Skip whitespace to check for chained identifier (preceded by a dot) + // Skip whitespace AND excluded ranges to check for chained identifier (preceded by a dot). + // Without skipping excluded ranges, a dot inside a comment (e.g. "//event.\n player") + // would be mistaken for a chain continuation dot. int checkPos = pos; - while (checkPos >= 0 && Character.isWhitespace(text.charAt(checkPos))) checkPos--; - // If it's part of a chained identifier (preceded by a dot), continue - if (checkPos >= 0 && text.charAt(checkPos) == '.') { pos = checkPos - 1; continue; } + while (checkPos >= 0) { + if (isExcluded(checkPos)) { + for (int[] range : excludedRanges) { + if (checkPos >= range[0] && checkPos < range[1]) { + checkPos = range[0] - 1; + break; + } + } + continue; + } + if (Character.isWhitespace(text.charAt(checkPos))) { checkPos--; continue; } + break; + } + if (checkPos >= 0 && !isExcluded(checkPos) && text.charAt(checkPos) == '.') { pos = checkPos - 1; continue; } break; } From f25b9164d06c5f81a6035892b477694bbb14544b Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 20:01:10 +0200 Subject: [PATCH 35/38] Added parameter autocomplete coloring --- .../script/autocomplete/AutocompleteItem.java | 17 ++++++++++------- .../script/autocomplete/AutocompleteMenu.java | 2 ++ .../script/interpreter/token/TokenType.java | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java index a8adf2031..cac2c2c11 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java @@ -22,12 +22,13 @@ public class AutocompleteItem implements Comparable { public enum Kind { ENUM_CONSTANT(-1), // Enum constant value (highest priority for enums) METHOD(0), // Method or function - FIELD(1), // Field or property - VARIABLE(2), // Local variable or parameter - CLASS(3), // Class or interface type - ENUM(4), // Enum type - KEYWORD(6), // Language keyword - SNIPPET(7); // Code snippet + FIELD(10), // Field or property + PARAMETER(19), // Local variable or parameter + VARIABLE(20), // Local variable or parameter + CLASS(30), // Class or interface type + ENUM(40), // Enum type + KEYWORD(60), // Language keyword + SNIPPET(70); // Code snippet private final int priority; @@ -158,7 +159,7 @@ public class AutocompleteItem implements Comparable { Kind kind; switch (field.getScope()) { case PARAMETER: - kind = Kind.VARIABLE; + kind = Kind.PARAMETER; break; case LOCAL: kind = Kind.VARIABLE; @@ -694,6 +695,7 @@ public class AutocompleteItem implements Comparable { case METHOD: return "m"; case FIELD: return "f"; case VARIABLE: return "v"; + case PARAMETER: return "p"; case CLASS: return "C"; case ENUM: return "E"; case ENUM_CONSTANT: return "e"; @@ -711,6 +713,7 @@ public class AutocompleteItem implements Comparable { case METHOD: return 0xFFB877DB; // Purple for methods case FIELD: return 0xFF79C0FF; // Blue for fields case VARIABLE: return 0xFF7EE787; // Green for variables + case PARAMETER: return 0XFFFF00FF; // Green for variables case CLASS: return 0xFFFFA657; // Orange for classes case ENUM: return 0xFFFFD866; // Yellow for enums case ENUM_CONSTANT: return 0xFFFFD866; diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java index 5912b5980..4e060303a 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java @@ -482,6 +482,8 @@ public class AutocompleteMenu extends Gui { return TokenType.getColor(item.getTypeInfo()); case VARIABLE: return TokenType.LOCAL_FIELD.getHexColor(); + case PARAMETER: + return TokenType.PARAMETER.getHexColor(); case KEYWORD: return TokenType.KEYWORD.getHexColor(); default: diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java index 200e60f6c..bf38a1f66 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java @@ -1,5 +1,6 @@ package noppes.npcs.client.gui.util.script.interpreter.token; +import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; /** @@ -110,7 +111,7 @@ public enum TokenType { public static int getColor(TypeInfo typeInfo) { return getByType(typeInfo).getHexColor(); } - + /** * Convert this token type to a Minecraft color code character. * Used for backward compatibility with the existing rendering system. From 81b3d1c2d3f91ba92886cb292aeb3d86ae86ffc9 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 20:47:54 +0200 Subject: [PATCH 36/38] Fixed autocomplete item package color for interfaces/enums --- .../client/gui/util/script/autocomplete/AutocompleteMenu.java | 3 +++ .../client/gui/util/script/interpreter/token/TokenType.java | 3 +++ .../npcs/client/gui/util/script/interpreter/type/TypeInfo.java | 1 + 3 files changed, 7 insertions(+) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java index 4e060303a..4fc78de21 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteMenu.java @@ -639,6 +639,9 @@ public class AutocompleteMenu extends Gui { private void drawTypeLabel(AutocompleteItem item, String typeLabel, int x, int y, int typeColor, TypeInfo typeInfo) { if (typeInfo == null || item.getKind() == AutocompleteItem.Kind.CLASS) { //draw package on right + // draw default package color instead of interface/enum colors + if (typeInfo != null && !typeInfo.isClass()) + typeColor = TokenType.getPackageColor(); drawSimpleTypeWithArraySuffix(typeLabel, x, y, typeColor); return; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java index bf38a1f66..e5bd1f244 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/token/TokenType.java @@ -112,6 +112,9 @@ public enum TokenType { return getByType(typeInfo).getHexColor(); } + public static int getPackageColor(){ + return IMPORTED_CLASS.getHexColor(); + } /** * Convert this token type to a Minecraft color code character. * Used for backward compatibility with the existing rendering system. diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 6a8d2b855..dcac25c99 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -604,6 +604,7 @@ public class TypeInfo { public boolean isInnerClass() { return enclosingType != null; } public boolean isInterface() {return kind == Kind.INTERFACE;} public boolean isEnum() {return kind == Kind.ENUM;} + public boolean isClass() {return kind == Kind.CLASS;} public boolean isPrimitive() {return this.isPrimitive || javaClass != null && javaClass.isPrimitive();} private TypeInfo setPrimitive(boolean value) { this.isPrimitive = value; return this;} From 956410c345be820b789d629e6017488983249777 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Fri, 13 Mar 2026 23:00:06 +0200 Subject: [PATCH 37/38] feat: implement IntelliJ-style weigher chain for autocomplete ranking - Add 8 independent weigher classes (MatchQuality, MemberKind, ContextFit, UsageFrequency, ImportStatus, Deprecated, InheritanceDepth, Alphabetical) - Replace fragile penalty-based scoring with composable weigher chain architecture - Expand MemberKind to 11 tiers: enum_const > local > instance_field > instance_method > type_class > type_enum > type_interface > static_field > static_method > keyword > snippet - Reorder weighers for optimal UX: imported always ranks above unimported regardless of usage - Fix unimported class penalty bug (was being overwritten by calculateMatchScore) - Implement DeprecatedWeigher (deprecated flag now scored) - Mark addScoreBoost() @Deprecated in favor of weigher chain - Add getInheritanceDepth() getter to AutocompleteItem - Update JSAutocompleteProvider to use 8-weigher chain with InheritanceDepthWeigher - Comprehensive test coverage: 127+ test methods across weigher unit tests and integration tests - Matches IntelliJ IDEA's weigher chain pattern (battle-tested production architecture) --- .../script/autocomplete/AutocompleteItem.java | 15 +- .../autocomplete/CompletionWeigherChains.java | 33 +++++ .../autocomplete/JSAutocompleteProvider.java | 7 +- .../JavaAutocompleteProvider.java | 134 +++--------------- .../script/autocomplete/UsageTracker.java | 2 +- .../weighter/AlphabeticalWeigher.java | 15 ++ .../weighter/CompletionWeigher.java | 40 ++++++ .../weighter/ContextFitWeigher.java | 38 +++++ .../weighter/DeprecatedWeigher.java | 15 ++ .../weighter/ImportStatusWeigher.java | 27 ++++ .../weighter/InheritanceDepthWeigher.java | 26 ++++ .../weighter/MatchQualityWeigher.java | 22 +++ .../weighter/MemberKindWeigher.java | 56 ++++++++ .../autocomplete/weighter/ScoringContext.java | 27 ++++ .../weighter/UsageFrequencyWeigher.java | 25 ++++ .../autocomplete/weighter/WeigherChain.java | 81 +++++++++++ 16 files changed, 443 insertions(+), 120 deletions(-) create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/CompletionWeigherChains.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/AlphabeticalWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/CompletionWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ContextFitWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/DeprecatedWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ImportStatusWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/InheritanceDepthWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MatchQualityWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MemberKindWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ScoringContext.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/UsageFrequencyWeigher.java create mode 100644 src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/WeigherChain.java diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java index cac2c2c11..6d2f5ff42 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/AutocompleteItem.java @@ -1,5 +1,7 @@ package noppes.npcs.client.gui.util.script.autocomplete; +import noppes.npcs.client.gui.util.script.autocomplete.weighter.CompletionWeigher; +import noppes.npcs.client.gui.util.script.autocomplete.weighter.WeigherChain; import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSFieldInfo; import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSMethodInfo; @@ -142,7 +144,7 @@ public class AutocompleteItem implements Comparable { signature, method.getDocumentation(), method, - false, // TODO: Check for @Deprecated annotation + method.getJavaMethod() != null && method.getJavaMethod().isAnnotationPresent(Deprecated.class), false, // Methods don't require imports null, -1 // Java methods don't use inheritance depth sorting @@ -578,8 +580,12 @@ public class AutocompleteItem implements Comparable { } /** - * Add a boost to the match score (e.g., from usage tracking). + * @deprecated Use {@link WeigherChain} instead. This method is no longer + * called by the autocomplete system. Score boosts are now handled by + * individual {@link CompletionWeigher} implementations that return + * independent comparable values per scoring dimension. */ + @Deprecated public void addScoreBoost(int boost) { this.matchScore += boost; } @@ -600,6 +606,7 @@ public class AutocompleteItem implements Comparable { public String getImportPath() { return importPath; } public int getMatchScore() { return matchScore; } public int[] getMatchIndices() { return matchIndices; } + public int getInheritanceDepth() { return inheritanceDepth; } public int getColor() { return color; }; public AutocompleteItem setColor(int col){ this.color = col;return this; } /** @@ -723,6 +730,10 @@ public class AutocompleteItem implements Comparable { } } + /** + * Note: No longer used for autocomplete sorting (weigher chain used instead). + * Kept for backward compatibility and collections sorting. + */ @Override public int compareTo(AutocompleteItem other) { // First by match score (descending) - this includes all penalties and boosts diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/CompletionWeigherChains.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/CompletionWeigherChains.java new file mode 100644 index 000000000..010e2dea1 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/CompletionWeigherChains.java @@ -0,0 +1,33 @@ +package noppes.npcs.client.gui.util.script.autocomplete; + +import noppes.npcs.client.gui.util.script.autocomplete.weighter.*; + +import java.util.Arrays; + +public class CompletionWeigherChains { + + public static WeigherChain javaChain() { + return new WeigherChain(Arrays.asList( + new MatchQualityWeigher(), + new MemberKindWeigher(), + new ContextFitWeigher(), + new ImportStatusWeigher(), + new UsageFrequencyWeigher(), + new DeprecatedWeigher(), + new AlphabeticalWeigher() + )); + } + + public static WeigherChain jsChain() { + return new WeigherChain(Arrays.asList( + new MatchQualityWeigher(), + new MemberKindWeigher(), + new ContextFitWeigher(), + new ImportStatusWeigher(), + new UsageFrequencyWeigher(), + new InheritanceDepthWeigher(), + new DeprecatedWeigher(), + new AlphabeticalWeigher() + )); + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java index e69102b59..d6a49846e 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JSAutocompleteProvider.java @@ -1,5 +1,6 @@ package noppes.npcs.client.gui.util.script.autocomplete; +import noppes.npcs.client.gui.util.script.autocomplete.weighter.WeigherChain; import noppes.npcs.client.gui.util.script.interpreter.js_parser.*; import noppes.npcs.client.gui.util.script.interpreter.field.EnumConstantInfo; import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; @@ -8,7 +9,6 @@ import noppes.npcs.client.gui.util.script.interpreter.type.synthetic.*; import noppes.npcs.client.gui.util.script.interpreter.type.ScriptTypeInfo; import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker; import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; -import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver; import noppes.npcs.config.ConfigScript; import java.lang.reflect.Modifier; @@ -350,6 +350,11 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider { return UsageTracker.getJSInstance(); } + @Override + protected WeigherChain getWeigherChain() { + return CompletionWeigherChains.jsChain(); + } + public String[] getKeywords() { return TypeChecker.getJavaScriptKeywords(); } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java index 3aad528c3..acb9cee3f 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/JavaAutocompleteProvider.java @@ -1,5 +1,7 @@ package noppes.npcs.client.gui.util.script.autocomplete; +import noppes.npcs.client.gui.util.script.autocomplete.weighter.ScoringContext; +import noppes.npcs.client.gui.util.script.autocomplete.weighter.WeigherChain; import noppes.npcs.client.gui.util.script.interpreter.ScriptDocument; import noppes.npcs.client.gui.util.script.interpreter.field.EnumConstantInfo; import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo; @@ -81,12 +83,9 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { } } - // Filter and score by prefix, then apply usage boosts and static penalties + // Filter by prefix, then sort using weigher chain filterAndScore(items, context.prefix, context.isMemberAccess, isStaticContext, ownerFullName); - // Sort by score - Collections.sort(items); - return items; } @@ -315,8 +314,6 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { if (existingSimpleNames.contains(type.getSimpleName())) { continue; } - - // Create an item that requires import AutocompleteItem item = new AutocompleteItem.Builder() .name(type.getSimpleName()) .insertText(type.getSimpleName()) @@ -371,126 +368,31 @@ public class JavaAutocompleteProvider implements AutocompleteProvider { return UsageTracker.getJavaInstance(); } - /** - * Filter items by prefix, calculate match scores, apply usage boosts, and penalize static members in instance contexts. - */ - protected void filterAndScore(List items, String prefix, + protected WeigherChain getWeigherChain() { + return CompletionWeigherChains.javaChain(); + } + + protected void filterAndScore(List items, String prefix, boolean isMemberAccess, boolean isStaticContext, String ownerFullName) { - UsageTracker tracker = getUsageTracker(); - - if (prefix == null || prefix.isEmpty()) { - // No filtering needed, all items get a base score + usage boost - for (AutocompleteItem item : items) { - item.calculateMatchScore("", false); - applyUsageBoost(item, tracker, ownerFullName); - applyStaticPenalty(item, isMemberAccess, isStaticContext); - applyObjectMethodPenalty(item); - applyKeywordPenalty(item, prefix); - } - return; - } - - // For non-member access (first word), require strict prefix matching - // For member access (after dot), allow fuzzy/contains matching boolean requirePrefix = !isMemberAccess; - - // Filter, score, apply usage boosts, and apply penalties + Iterator iter = items.iterator(); while (iter.hasNext()) { AutocompleteItem item = iter.next(); - int score = item.calculateMatchScore(prefix, requirePrefix); + int score = item.calculateMatchScore( + prefix != null ? prefix : "", requirePrefix); if (score < 0) { iter.remove(); - } else { - applyUsageBoost(item, tracker, ownerFullName); - applyStaticPenalty(item, isMemberAccess, isStaticContext); - applyObjectMethodPenalty(item); - applyKeywordPenalty(item, prefix); } } - } - - /** - * Apply usage-based score boost to an item. - */ - protected void applyUsageBoost(AutocompleteItem item, UsageTracker tracker, String ownerFullName) { - int usageCount = tracker.getUsageCount(item, ownerFullName); - int boost = UsageTracker.calculateUsageBoost(usageCount); - item.addScoreBoost(boost); - } - - /** - * Apply penalty to static members when accessed in a non-static (instance) context. - * This matches IntelliJ's behavior where static members are deprioritized when - * accessing through an instance (e.g., Minecraft.getMinecraft().getMinecraft()). - * However, if the item is a very strong match (exact prefix), don't penalize as much. - */ - protected void applyStaticPenalty(AutocompleteItem item, boolean isMemberAccess, boolean isStaticContext) { - // Only apply penalty in member access contexts (after dot) - if (!isMemberAccess) { - return; - } - - // Only penalize when we're in an instance context (not static) - if (isStaticContext) { - return; - } - - boolean isStatic = item.isStatic(); - - // Apply penalty to static members in instance context - if (isStatic) { - int matchScore = item.getMatchScore(); - // Strong prefix matches (score >= 800) get a lighter penalty - // Weaker matches get pushed down more aggressively - if (matchScore >= 800) { - // Light penalty for exact prefix matches - just deprioritize slightly - item.addScoreBoost(-200); - } else { - // Heavy penalty for fuzzy/substring matches - push to bottom - item.addScoreBoost(-matchScore); - } - } - } - - /** - * Apply penalty to inherited Object methods to push them to bottom. - * Strong matches get lighter penalty, weak matches get pushed all the way down. - */ - protected void applyObjectMethodPenalty(AutocompleteItem item) { - if (!item.isInheritedObjectMethod()) { - return; - } - - int matchScore = item.getMatchScore(); - // Strong prefix matches (score >= 900) get a moderate penalty - // Everything else gets pushed to the very bottom - if (matchScore >= 900) { - // Strong match - moderate penalty to keep it visible but below normal methods - item.addScoreBoost(-500); - } else { - // Weak match - heavy penalty to push to bottom - item.addScoreBoost(-10000); - } - } - /** - * Push keywords below non-keywords unless user typed a longer prefix. - */ - protected void applyKeywordPenalty(AutocompleteItem item, String prefix) { - if (item.getKind() != AutocompleteItem.Kind.KEYWORD) { - return; - } + ScoringContext context = new ScoringContext( + prefix, isMemberAccess, isStaticContext, + ownerFullName, getUsageTracker(), requirePrefix + ); - if (prefix == null || prefix.length() < 2) { - item.addScoreBoost(-10000); - } - } - - /** - * Builder class for AutocompleteItem to handle cases without source data. - */ - private static class AutocompleteItemBuilder { - // This would be needed if AutocompleteItem had a builder pattern + WeigherChain weigherChain = getWeigherChain(); + Comparator comparator = weigherChain.buildComparator(context); + items.sort(comparator); } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/UsageTracker.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/UsageTracker.java index 6d23e0c2f..ee95f2fdf 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/UsageTracker.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/UsageTracker.java @@ -122,7 +122,7 @@ public class UsageTracker { // ==================== INSTANCE METHODS ==================== - private UsageTracker(String filename) { + UsageTracker(String filename) { File dir = getDir(); this.file = new File(dir, filename); } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/AlphabeticalWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/AlphabeticalWeigher.java new file mode 100644 index 000000000..93252dc69 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/AlphabeticalWeigher.java @@ -0,0 +1,15 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +public class AlphabeticalWeigher extends CompletionWeigher { + + public AlphabeticalWeigher() { + super("alphabetical"); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + return item.getName().toLowerCase(); + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/CompletionWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/CompletionWeigher.java new file mode 100644 index 000000000..0505da0d1 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/CompletionWeigher.java @@ -0,0 +1,40 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +/** + * A single scoring dimension for autocomplete ranking. + * + * Weighers are evaluated in chain order. For each pair of items being compared, + * the first weigher to return non-equal values determines the ordering. + * + * Contract: + * - weigh() MUST be a pure function (no side effects, no mutations) + * - weigh() MUST return consistent results for the same item+context + * - weigh() MAY return null to abstain (treated as equal for this weigher) + * - Lower Comparable values = higher priority (shown first) unless negated + * + * Modeled after IntelliJ's LookupElementWeigher (Apache 2.0). + */ +public abstract class CompletionWeigher { + + private final String id; + private final boolean negated; + + protected CompletionWeigher(String id, boolean negated) { + this.id = id; + this.negated = negated; + } + + protected CompletionWeigher(String id) { + this(id, false); + } + + public abstract Comparable weigh(AutocompleteItem item, ScoringContext context); + + public String getId() { return id; } + public boolean isNegated() { return negated; } + + @Override + public String toString() { return id; } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ContextFitWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ContextFitWeigher.java new file mode 100644 index 000000000..f2e1db62d --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ContextFitWeigher.java @@ -0,0 +1,38 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +/** + * How well does this item fit the current access context? + * + * Combines what were previously applyStaticPenalty() and applyObjectMethodPenalty(). + * Uses ordered enum categories, eliminating all magic threshold numbers. + */ +public class ContextFitWeigher extends CompletionWeigher { + + public enum ContextFit { + /** Item naturally belongs in this context. */ + NATURAL, + /** Static member accessed through an instance — legal but bad style. */ + WRONG_STATIC_CONTEXT, + /** Inherited Object method (wait, notify, hashCode, getClass, etc.) */ + OBJECT_METHOD + } + + public ContextFitWeigher() { + super("contextFit"); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + if (item.isInheritedObjectMethod()) { + return ContextFit.OBJECT_METHOD; + } + + if (context.isMemberAccess && !context.isStaticContext && item.isStatic()) { + return ContextFit.WRONG_STATIC_CONTEXT; + } + + return ContextFit.NATURAL; + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/DeprecatedWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/DeprecatedWeigher.java new file mode 100644 index 000000000..c8044226f --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/DeprecatedWeigher.java @@ -0,0 +1,15 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +public class DeprecatedWeigher extends CompletionWeigher { + + public DeprecatedWeigher() { + super("deprecated"); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + return item.isDeprecated(); + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ImportStatusWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ImportStatusWeigher.java new file mode 100644 index 000000000..7008e6e4b --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ImportStatusWeigher.java @@ -0,0 +1,27 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +/** + * Demote unimported classes below imported ones. + * + * Fixes the bug where the unimported class penalty (-500) was applied at + * creation time and overwritten by calculateMatchScore(). In the chain model, + * import status is a separate dimension that can never be overwritten. + */ +public class ImportStatusWeigher extends CompletionWeigher { + + public enum ImportStatus { + IMPORTED, + UNIMPORTED + } + + public ImportStatusWeigher() { + super("importStatus"); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + return item.requiresImport() ? ImportStatus.UNIMPORTED : ImportStatus.IMPORTED; + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/InheritanceDepthWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/InheritanceDepthWeigher.java new file mode 100644 index 000000000..4c8ba8e58 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/InheritanceDepthWeigher.java @@ -0,0 +1,26 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +/** + * Prefer members defined closer in the inheritance tree. + * Child class members rank above parent class members. + * + * Only meaningful for JS/.d.ts types where inheritance depth is tracked. + * For items without inheritance tracking (depth < 0), this weigher abstains. + */ +public class InheritanceDepthWeigher extends CompletionWeigher { + + public InheritanceDepthWeigher() { + super("inheritanceDepth"); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + int depth = item.getInheritanceDepth(); + if (depth < 0) { + return null; + } + return depth; + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MatchQualityWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MatchQualityWeigher.java new file mode 100644 index 000000000..a8f638729 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MatchQualityWeigher.java @@ -0,0 +1,22 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +/** + * Text match quality against the user's prefix. + * PRIMARY sort dimension — how well the item name matches what was typed. + * + * Returns the existing calculateMatchScore() result, negated so that + * higher scores = higher priority. + */ +public class MatchQualityWeigher extends CompletionWeigher { + + public MatchQualityWeigher() { + super("matchQuality", true); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + return item.getMatchScore(); + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MemberKindWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MemberKindWeigher.java new file mode 100644 index 000000000..af2693751 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/MemberKindWeigher.java @@ -0,0 +1,56 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; +import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo; + +public class MemberKindWeigher extends CompletionWeigher { + + public enum MemberKind { + ENUM_CONSTANT, + LOCAL_VARIABLE, + INSTANCE_FIELD, + INSTANCE_METHOD, + TYPE_CLASS, + TYPE_ENUM, + TYPE_INTERFACE, + STATIC_FIELD, + STATIC_METHOD, + KEYWORD, + SNIPPET + } + + public MemberKindWeigher() { + super("memberKind"); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + switch (item.getKind()) { + case ENUM_CONSTANT: return MemberKind.ENUM_CONSTANT; + case PARAMETER: return MemberKind.LOCAL_VARIABLE; + case VARIABLE: return MemberKind.LOCAL_VARIABLE; + case METHOD: + return item.isStatic() ? MemberKind.STATIC_METHOD : MemberKind.INSTANCE_METHOD; + case FIELD: + return item.isStatic() ? MemberKind.STATIC_FIELD : MemberKind.INSTANCE_FIELD; + case CLASS: return resolveTypeTier(item); + case ENUM: return MemberKind.TYPE_ENUM; + case KEYWORD: return MemberKind.KEYWORD; + case SNIPPET: return MemberKind.SNIPPET; + default: return MemberKind.INSTANCE_FIELD; + } + } + + private MemberKind resolveTypeTier(AutocompleteItem item) { + Object source = item.getSourceData(); + if (source instanceof TypeInfo) { + TypeInfo typeInfo = (TypeInfo) source; + switch (typeInfo.getKind()) { + case INTERFACE: return MemberKind.TYPE_INTERFACE; + case ENUM: return MemberKind.TYPE_ENUM; + default: return MemberKind.TYPE_CLASS; + } + } + return MemberKind.TYPE_CLASS; + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ScoringContext.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ScoringContext.java new file mode 100644 index 000000000..6ee5501f5 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/ScoringContext.java @@ -0,0 +1,27 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.UsageTracker; + +/** + * Immutable context for a single scoring pass. + * Created once when suggestions are requested, shared by all weighers. + */ +public class ScoringContext { + + public final String prefix; + public final boolean isMemberAccess; + public final boolean isStaticContext; + public final String ownerFullName; + public final UsageTracker usageTracker; + public final boolean requirePrefix; + + public ScoringContext(String prefix, boolean isMemberAccess, boolean isStaticContext, + String ownerFullName, UsageTracker usageTracker, boolean requirePrefix) { + this.prefix = prefix; + this.isMemberAccess = isMemberAccess; + this.isStaticContext = isStaticContext; + this.ownerFullName = ownerFullName; + this.usageTracker = usageTracker; + this.requirePrefix = requirePrefix; + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/UsageFrequencyWeigher.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/UsageFrequencyWeigher.java new file mode 100644 index 000000000..fbb0a2308 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/UsageFrequencyWeigher.java @@ -0,0 +1,25 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; +import noppes.npcs.client.gui.util.script.autocomplete.UsageTracker; + +/** + * Boost items the user has selected before. + * Uses logarithmic scaling with a cap via UsageTracker.calculateUsageBoost(). + * Negated: higher usage count = higher priority. + */ +public class UsageFrequencyWeigher extends CompletionWeigher { + + public UsageFrequencyWeigher() { + super("usageFrequency", true); + } + + @Override + public Comparable weigh(AutocompleteItem item, ScoringContext context) { + if (context.usageTracker == null) { + return 0; + } + int usageCount = context.usageTracker.getUsageCount(item, context.ownerFullName); + return UsageTracker.calculateUsageBoost(usageCount); + } +} diff --git a/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/WeigherChain.java b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/WeigherChain.java new file mode 100644 index 000000000..3d2a6e878 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/script/autocomplete/weighter/WeigherChain.java @@ -0,0 +1,81 @@ +package noppes.npcs.client.gui.util.script.autocomplete.weighter; + +import noppes.npcs.client.gui.util.script.autocomplete.AutocompleteItem; + +import java.util.*; + +/** + * An ordered list of weighers that produces a Comparator for sorting autocomplete items. + * + * Items are compared dimension-by-dimension through the chain. + * The first weigher to produce a non-equal comparison determines the ordering. + * If all weighers return equal, items are considered equivalent (stable sort preserves + * insertion order). + * + * Simplified from IntelliJ's CompletionSorterImpl — uses Comparator instead of a + * classifier tree since we sort all items in a single batch. + */ +public class WeigherChain { + + private final List weighers; + + public WeigherChain(List weighers) { + this.weighers = Collections.unmodifiableList(new ArrayList<>(weighers)); + } + + /** + * Build a Comparator that evaluates items through the weigher chain. + * + * Weigher results are cached per item via IdentityHashMap to avoid + * recomputing weights during O(N log N) comparisons. + */ + public Comparator buildComparator(ScoringContext context) { + final Map[]> cache = new IdentityHashMap<>(); + final int chainLength = weighers.size(); + + return (a, b) -> { + Comparable[] weightsA = cache.computeIfAbsent(a, k -> computeWeights(k, context)); + Comparable[] weightsB = cache.computeIfAbsent(b, k -> computeWeights(k, context)); + + for (int i = 0; i < chainLength; i++) { + Comparable wA = weightsA[i]; + Comparable wB = weightsB[i]; + + if (wA == null && wB == null) continue; + if (wA == null) return 1; + if (wB == null) return -1; + + @SuppressWarnings("unchecked") + int cmp = ((Comparable) wA).compareTo(wB); + + if (cmp != 0) { + return weighers.get(i).isNegated() ? -cmp : cmp; + } + } + return 0; + }; + } + + private Comparable[] computeWeights(AutocompleteItem item, ScoringContext context) { + Comparable[] weights = new Comparable[weighers.size()]; + for (int i = 0; i < weighers.size(); i++) { + weights[i] = weighers.get(i).weigh(item, context); + } + return weights; + } + + /** + * Get all weigher results for an item (for debugging/testing). + */ + public Map> debugWeights(AutocompleteItem item, ScoringContext context) { + Map> result = new LinkedHashMap<>(); + for (CompletionWeigher weigher : weighers) { + result.put(weigher.getId(), weigher.weigh(item, context)); + } + return result; + } + + public List getWeighers() { + return weighers; + } +} From 16f00225054b265b57db0933aa2952993ccb935e Mon Sep 17 00:00:00 2001 From: Kam Date: Fri, 13 Mar 2026 17:20:12 -0400 Subject: [PATCH 38/38] 1.11.1 --- build.gradle | 2 +- src/main/java/noppes/npcs/CustomNpcs.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a76186d6d..3dfbb49ae 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id "dts.typescript-generator" } -version = "1.11" +version = "1.11.1" group= "kamkeel.customnpc-plus" archivesBaseName = "CustomNPC-Plus" diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index 810354152..d72bdf23f 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -125,7 +125,7 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11") +@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11.1") public class CustomNpcs { @SidedProxy(clientSide = "noppes.npcs.client.ClientProxy", serverSide = "noppes.npcs.CommonProxy")