Cache Handle for O(1) lookups

This commit is contained in:
Kam committed 2026-01-22 19:03:28 -05:00
1 parent ee593c62c0
commit 923c84e3fe
4 files changed
+285 -640

No files matched your search

@@ -6,11 +6,7 @@ import noppes.npcs.constants.EnumScriptType;
import noppes.npcs.constants.ScriptContext;
import noppes.npcs.controllers.data.RecipeScript;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Controller for managing script hooks.
@@ -30,16 +26,10 @@ public class ScriptHookController implements IScriptHookHandler {
public static ScriptHookController Instance;
// Built-in hooks per context (legacy string list)
private final Map<String, List<String>> builtInHooks = new HashMap<>();
// Addon-registered hooks per context (legacy string list)
private final Map<String, List<String>> addonHooks = new HashMap<>();
// Rich hook definitions per context (NEW)
// Hook definitions per context - single source of truth
private final Map<String, Map<String, HookDefinition>> hookDefinitions = new HashMap<>();
// Revision counter for cache invalidation (NEW)
// Revision counter for cache invalidation
private int hookRevision = 0;
public ScriptHookController() {
@@ -48,48 +38,40 @@ public class ScriptHookController implements IScriptHookHandler {
}
private void initializeBuiltInHooks() {
// Initialize empty lists for all contexts from ScriptContext
// Initialize empty maps for all contexts from ScriptContext
for (ScriptContext context : ScriptContext.values()) {
if (!context.hookContext.isEmpty()) {
builtInHooks.put(context.hookContext, new ArrayList<>());
addonHooks.put(context.hookContext, new ArrayList<>());
hookDefinitions.put(context.hookContext, new HashMap<>());
hookDefinitions.put(context.hookContext, new LinkedHashMap<>());
}
}
// NPC hooks with full definitions
// NPC hooks
initializeNpcHooks();
// Player hooks with full definitions
// Player hooks
initializePlayerHooks();
// Block hooks with full definitions
// Block hooks
initializeBlockHooks();
// Item hooks with full definitions
// Item hooks
initializeItemHooks();
// Linked item hooks with full definitions
// Linked item hooks
initializeLinkedItemHooks();
// Recipe hooks
registerBuiltIn(ScriptContext.RECIPE,
RecipeScript.ScriptType.PRE.function,
RecipeScript.ScriptType.POST.function
);
registerHookDef(ScriptContext.RECIPE, RecipeScript.ScriptType.PRE.function, null, null);
registerHookDef(ScriptContext.RECIPE, RecipeScript.ScriptType.POST.function, null, null);
// Effect hooks
registerBuiltIn(ScriptContext.EFFECT,
EnumScriptType.ON_EFFECT_ADD.function,
EnumScriptType.ON_EFFECT_TICK.function,
EnumScriptType.ON_EFFECT_REMOVE.function
);
registerHookDef(ScriptContext.EFFECT, EnumScriptType.ON_EFFECT_ADD.function, null, null);
registerHookDef(ScriptContext.EFFECT, EnumScriptType.ON_EFFECT_TICK.function, null, null);
registerHookDef(ScriptContext.EFFECT, EnumScriptType.ON_EFFECT_REMOVE.function, null, null);
// Forge hooks - init + CNPC-specific hooks, the rest are dynamically discovered from Forge event classes
registerBuiltIn(ScriptContext.FORGE,
EnumScriptType.INIT.function,
EnumScriptType.CNPC_NATURAL_SPAWN.function
);
// Forge hooks
registerHookDef(ScriptContext.FORGE, EnumScriptType.INIT.function, null, null);
registerHookDef(ScriptContext.FORGE, EnumScriptType.CNPC_NATURAL_SPAWN.function, null, null);
}
private void initializeNpcHooks() {
@@ -99,60 +81,37 @@ public class ScriptHookController implements IScriptHookHandler {
String abilityImport = "noppes.npcs.api.event.IAbilityEvent";
// Core lifecycle
registerBuiltInDefinition(ctx, EnumScriptType.INIT.function,
"noppes.npcs.api.event.INpcEvent$InitEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.TICK.function,
"noppes.npcs.api.event.INpcEvent$UpdateEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.TIMER.function,
"noppes.npcs.api.event.INpcEvent$TimerEvent", npcImport);
registerHookDef(ctx, EnumScriptType.INIT.function, "noppes.npcs.api.event.INpcEvent$InitEvent", npcImport);
registerHookDef(ctx, EnumScriptType.TICK.function, "noppes.npcs.api.event.INpcEvent$UpdateEvent", npcImport);
registerHookDef(ctx, EnumScriptType.TIMER.function, "noppes.npcs.api.event.INpcEvent$TimerEvent", npcImport);
// Interaction
registerBuiltInDefinition(ctx, EnumScriptType.INTERACT.function,
"noppes.npcs.api.event.INpcEvent$InteractEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.DIALOG.function,
"noppes.npcs.api.event.INpcEvent$DialogEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.DIALOG_CLOSE.function,
"noppes.npcs.api.event.INpcEvent$DialogClosedEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.COLLIDE.function,
"noppes.npcs.api.event.INpcEvent$CollideEvent", npcImport);
registerHookDef(ctx, EnumScriptType.INTERACT.function, "noppes.npcs.api.event.INpcEvent$InteractEvent", npcImport);
registerHookDef(ctx, EnumScriptType.DIALOG.function, "noppes.npcs.api.event.INpcEvent$DialogEvent", npcImport);
registerHookDef(ctx, EnumScriptType.DIALOG_CLOSE.function, "noppes.npcs.api.event.INpcEvent$DialogClosedEvent", npcImport);
registerHookDef(ctx, EnumScriptType.COLLIDE.function, "noppes.npcs.api.event.INpcEvent$CollideEvent", npcImport);
// Combat
registerBuiltInDefinition(ctx, EnumScriptType.DAMAGED.function,
"noppes.npcs.api.event.INpcEvent$DamagedEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.KILLED.function,
"noppes.npcs.api.event.INpcEvent$DiedEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.KILLS.function,
"noppes.npcs.api.event.INpcEvent$KilledEntityEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.ATTACK_MELEE.function,
"noppes.npcs.api.event.INpcEvent$MeleeAttackEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.ATTACK_SWING.function,
"noppes.npcs.api.event.INpcEvent$SwingEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.RANGED_LAUNCHED.function,
"noppes.npcs.api.event.INpcEvent$RangedLaunchedEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.TARGET.function,
"noppes.npcs.api.event.INpcEvent$TargetEvent", npcImport);
registerBuiltInDefinition(ctx, EnumScriptType.TARGET_LOST.function,
"noppes.npcs.api.event.INpcEvent$TargetLostEvent", npcImport);
registerHookDef(ctx, EnumScriptType.DAMAGED.function, "noppes.npcs.api.event.INpcEvent$DamagedEvent", npcImport);
registerHookDef(ctx, EnumScriptType.KILLED.function, "noppes.npcs.api.event.INpcEvent$DiedEvent", npcImport);
registerHookDef(ctx, EnumScriptType.KILLS.function, "noppes.npcs.api.event.INpcEvent$KilledEntityEvent", npcImport);
registerHookDef(ctx, EnumScriptType.ATTACK_MELEE.function, "noppes.npcs.api.event.INpcEvent$MeleeAttackEvent", npcImport);
registerHookDef(ctx, EnumScriptType.ATTACK_SWING.function, "noppes.npcs.api.event.INpcEvent$SwingEvent", npcImport);
registerHookDef(ctx, EnumScriptType.RANGED_LAUNCHED.function, "noppes.npcs.api.event.INpcEvent$RangedLaunchedEvent", npcImport);
registerHookDef(ctx, EnumScriptType.TARGET.function, "noppes.npcs.api.event.INpcEvent$TargetEvent", npcImport);
registerHookDef(ctx, EnumScriptType.TARGET_LOST.function, "noppes.npcs.api.event.INpcEvent$TargetLostEvent", npcImport);
// Projectile events
registerBuiltInDefinition(ctx, EnumScriptType.PROJECTILE_TICK.function,
"noppes.npcs.api.event.IProjectileEvent$UpdateEvent", projImport);
registerBuiltInDefinition(ctx, EnumScriptType.PROJECTILE_IMPACT.function,
"noppes.npcs.api.event.IProjectileEvent$ImpactEvent", projImport);
registerHookDef(ctx, EnumScriptType.PROJECTILE_TICK.function, "noppes.npcs.api.event.IProjectileEvent$UpdateEvent", projImport);
registerHookDef(ctx, EnumScriptType.PROJECTILE_IMPACT.function, "noppes.npcs.api.event.IProjectileEvent$ImpactEvent", projImport);
// Ability events
registerBuiltInDefinition(ctx, EnumScriptType.ABILITY_START.function,
"noppes.npcs.api.event.IAbilityEvent$StartEvent", abilityImport);
registerBuiltInDefinition(ctx, EnumScriptType.ABILITY_EXECUTE.function,
"noppes.npcs.api.event.IAbilityEvent$ExecuteEvent", abilityImport);
registerBuiltInDefinition(ctx, EnumScriptType.ABILITY_HIT.function,
"noppes.npcs.api.event.IAbilityEvent$HitEvent", abilityImport);
registerBuiltInDefinition(ctx, EnumScriptType.ABILITY_TICK.function,
"noppes.npcs.api.event.IAbilityEvent$TickEvent", abilityImport);
registerBuiltInDefinition(ctx, EnumScriptType.ABILITY_INTERRUPT.function,
"noppes.npcs.api.event.IAbilityEvent$InterruptEvent", abilityImport);
registerBuiltInDefinition(ctx, EnumScriptType.ABILITY_COMPLETE.function,
"noppes.npcs.api.event.IAbilityEvent$CompleteEvent", abilityImport);
registerHookDef(ctx, EnumScriptType.ABILITY_START.function, "noppes.npcs.api.event.IAbilityEvent$StartEvent", abilityImport);
registerHookDef(ctx, EnumScriptType.ABILITY_EXECUTE.function, "noppes.npcs.api.event.IAbilityEvent$ExecuteEvent", abilityImport);
registerHookDef(ctx, EnumScriptType.ABILITY_HIT.function, "noppes.npcs.api.event.IAbilityEvent$HitEvent", abilityImport);
registerHookDef(ctx, EnumScriptType.ABILITY_TICK.function, "noppes.npcs.api.event.IAbilityEvent$TickEvent", abilityImport);
registerHookDef(ctx, EnumScriptType.ABILITY_INTERRUPT.function, "noppes.npcs.api.event.IAbilityEvent$InterruptEvent", abilityImport);
registerHookDef(ctx, EnumScriptType.ABILITY_COMPLETE.function, "noppes.npcs.api.event.IAbilityEvent$CompleteEvent", abilityImport);
}
private void initializePlayerHooks() {
@@ -166,238 +125,143 @@ public class ScriptHookController implements IScriptHookHandler {
String animImport = "noppes.npcs.api.event.IAnimationEvent";
// Core lifecycle
registerBuiltInDefinition(ctx, EnumScriptType.INIT.function,
"noppes.npcs.api.event.IPlayerEvent$InitEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.TICK.function,
"noppes.npcs.api.event.IPlayerEvent$UpdateEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.TIMER.function,
"noppes.npcs.api.event.IPlayerEvent$TimerEvent", playerImport);
registerHookDef(ctx, EnumScriptType.INIT.function, "noppes.npcs.api.event.IPlayerEvent$InitEvent", playerImport);
registerHookDef(ctx, EnumScriptType.TICK.function, "noppes.npcs.api.event.IPlayerEvent$UpdateEvent", playerImport);
registerHookDef(ctx, EnumScriptType.TIMER.function, "noppes.npcs.api.event.IPlayerEvent$TimerEvent", playerImport);
// Combat
registerBuiltInDefinition(ctx, EnumScriptType.ATTACK.function,
"noppes.npcs.api.event.IPlayerEvent$AttackEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.ATTACKED.function,
"noppes.npcs.api.event.IPlayerEvent$AttackedEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.DAMAGED.function,
"noppes.npcs.api.event.IPlayerEvent$DamagedEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.DAMAGED_ENTITY.function,
"noppes.npcs.api.event.IPlayerEvent$DamagedEntityEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.KILLS.function,
"noppes.npcs.api.event.IPlayerEvent$KilledEntityEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.KILLED.function,
"noppes.npcs.api.event.IPlayerEvent$DiedEvent", playerImport);
registerHookDef(ctx, EnumScriptType.ATTACK.function, "noppes.npcs.api.event.IPlayerEvent$AttackEvent", playerImport);
registerHookDef(ctx, EnumScriptType.ATTACKED.function, "noppes.npcs.api.event.IPlayerEvent$AttackedEvent", playerImport);
registerHookDef(ctx, EnumScriptType.DAMAGED.function, "noppes.npcs.api.event.IPlayerEvent$DamagedEvent", playerImport);
registerHookDef(ctx, EnumScriptType.DAMAGED_ENTITY.function, "noppes.npcs.api.event.IPlayerEvent$DamagedEntityEvent", playerImport);
registerHookDef(ctx, EnumScriptType.KILLS.function, "noppes.npcs.api.event.IPlayerEvent$KilledEntityEvent", playerImport);
registerHookDef(ctx, EnumScriptType.KILLED.function, "noppes.npcs.api.event.IPlayerEvent$DiedEvent", playerImport);
// Interaction
registerBuiltInDefinition(ctx, EnumScriptType.INTERACT.function,
"noppes.npcs.api.event.IPlayerEvent$InteractEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.RIGHT_CLICK.function,
"noppes.npcs.api.event.IPlayerEvent$RightClickEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.BREAK_BLOCK.function,
"noppes.npcs.api.event.IPlayerEvent$BreakEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.CHAT.function,
"noppes.npcs.api.event.IPlayerEvent$ChatEvent", playerImport);
registerHookDef(ctx, EnumScriptType.INTERACT.function, "noppes.npcs.api.event.IPlayerEvent$InteractEvent", playerImport);
registerHookDef(ctx, EnumScriptType.RIGHT_CLICK.function, "noppes.npcs.api.event.IPlayerEvent$RightClickEvent", playerImport);
registerHookDef(ctx, EnumScriptType.BREAK_BLOCK.function, "noppes.npcs.api.event.IPlayerEvent$BreakEvent", playerImport);
registerHookDef(ctx, EnumScriptType.CHAT.function, "noppes.npcs.api.event.IPlayerEvent$ChatEvent", playerImport);
// Connection
registerBuiltInDefinition(ctx, EnumScriptType.LOGIN.function,
"noppes.npcs.api.event.IPlayerEvent$LoginEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.LOGOUT.function,
"noppes.npcs.api.event.IPlayerEvent$LogoutEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.RESPAWN.function,
"noppes.npcs.api.event.IPlayerEvent$RespawnEvent", playerImport);
registerHookDef(ctx, EnumScriptType.LOGIN.function, "noppes.npcs.api.event.IPlayerEvent$LoginEvent", playerImport);
registerHookDef(ctx, EnumScriptType.LOGOUT.function, "noppes.npcs.api.event.IPlayerEvent$LogoutEvent", playerImport);
registerHookDef(ctx, EnumScriptType.RESPAWN.function, "noppes.npcs.api.event.IPlayerEvent$RespawnEvent", playerImport);
// Input
registerBuiltInDefinition(ctx, EnumScriptType.KEY_PRESSED.function,
"noppes.npcs.api.event.IPlayerEvent$KeyPressedEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.MOUSE_CLICKED.function,
"noppes.npcs.api.event.IPlayerEvent$MouseClickedEvent", playerImport);
registerHookDef(ctx, EnumScriptType.KEY_PRESSED.function, "noppes.npcs.api.event.IPlayerEvent$KeyPressedEvent", playerImport);
registerHookDef(ctx, EnumScriptType.MOUSE_CLICKED.function, "noppes.npcs.api.event.IPlayerEvent$MouseClickedEvent", playerImport);
// Items
registerBuiltInDefinition(ctx, EnumScriptType.PICKUP.function,
"noppes.npcs.api.event.IPlayerEvent$PickUpEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.TOSS.function,
"noppes.npcs.api.event.IPlayerEvent$TossEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.DROP.function,
"noppes.npcs.api.event.IPlayerEvent$DropEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.PICKUP_XP.function,
"noppes.npcs.api.event.IPlayerEvent$PickupXPEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.START_USING_ITEM.function,
"noppes.npcs.api.event.IPlayerEvent$StartUsingItem", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.USING_ITEM.function,
"noppes.npcs.api.event.IPlayerEvent$UsingItem", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.STOP_USING_ITEM.function,
"noppes.npcs.api.event.IPlayerEvent$StopUsingItem", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.FINISH_USING_ITEM.function,
"noppes.npcs.api.event.IPlayerEvent$FinishUsingItem", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.CONTAINER_OPEN.function,
"noppes.npcs.api.event.IPlayerEvent$ContainerOpen", playerImport);
registerHookDef(ctx, EnumScriptType.PICKUP.function, "noppes.npcs.api.event.IPlayerEvent$PickUpEvent", playerImport);
registerHookDef(ctx, EnumScriptType.TOSS.function, "noppes.npcs.api.event.IPlayerEvent$TossEvent", playerImport);
registerHookDef(ctx, EnumScriptType.DROP.function, "noppes.npcs.api.event.IPlayerEvent$DropEvent", playerImport);
registerHookDef(ctx, EnumScriptType.PICKUP_XP.function, "noppes.npcs.api.event.IPlayerEvent$PickupXPEvent", playerImport);
registerHookDef(ctx, EnumScriptType.START_USING_ITEM.function, "noppes.npcs.api.event.IPlayerEvent$StartUsingItem", playerImport);
registerHookDef(ctx, EnumScriptType.USING_ITEM.function, "noppes.npcs.api.event.IPlayerEvent$UsingItem", playerImport);
registerHookDef(ctx, EnumScriptType.STOP_USING_ITEM.function, "noppes.npcs.api.event.IPlayerEvent$StopUsingItem", playerImport);
registerHookDef(ctx, EnumScriptType.FINISH_USING_ITEM.function, "noppes.npcs.api.event.IPlayerEvent$FinishUsingItem", playerImport);
registerHookDef(ctx, EnumScriptType.CONTAINER_OPEN.function, "noppes.npcs.api.event.IPlayerEvent$ContainerOpen", playerImport);
// Movement
registerBuiltInDefinition(ctx, EnumScriptType.JUMP.function,
"noppes.npcs.api.event.IPlayerEvent$JumpEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.FALL.function,
"noppes.npcs.api.event.IPlayerEvent$FallEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.CHANGED_DIM.function,
"noppes.npcs.api.event.IPlayerEvent$ChangedDimension", playerImport);
registerHookDef(ctx, EnumScriptType.JUMP.function, "noppes.npcs.api.event.IPlayerEvent$JumpEvent", playerImport);
registerHookDef(ctx, EnumScriptType.FALL.function, "noppes.npcs.api.event.IPlayerEvent$FallEvent", playerImport);
registerHookDef(ctx, EnumScriptType.CHANGED_DIM.function, "noppes.npcs.api.event.IPlayerEvent$ChangedDimension", playerImport);
// World
registerBuiltInDefinition(ctx, EnumScriptType.RANGED_CHARGE.function,
"noppes.npcs.api.event.IPlayerEvent$RangedChargeEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.RANGED_LAUNCHED.function,
"noppes.npcs.api.event.IPlayerEvent$RangedLaunchedEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.USE_HOE.function,
"noppes.npcs.api.event.IPlayerEvent$UseHoeEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.BONEMEAL.function,
"noppes.npcs.api.event.IPlayerEvent$BonemealEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.FILL_BUCKET.function,
"noppes.npcs.api.event.IPlayerEvent$FillBucketEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.WAKE_UP.function,
"noppes.npcs.api.event.IPlayerEvent$WakeUpEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.SLEEP.function,
"noppes.npcs.api.event.IPlayerEvent$SleepEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.PLAYSOUND.function,
"noppes.npcs.api.event.IPlayerEvent$SoundEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.LIGHTNING.function,
"noppes.npcs.api.event.IPlayerEvent$LightningEvent", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.SCRIPT_COMMAND.function,
"noppes.npcs.api.event.ICustomNPCsEvent$ScriptedCommandEvent", "noppes.npcs.api.event.ICustomNPCsEvent");
registerHookDef(ctx, EnumScriptType.RANGED_CHARGE.function, "noppes.npcs.api.event.IPlayerEvent$RangedChargeEvent", playerImport);
registerHookDef(ctx, EnumScriptType.RANGED_LAUNCHED.function, "noppes.npcs.api.event.IPlayerEvent$RangedLaunchedEvent", playerImport);
registerHookDef(ctx, EnumScriptType.USE_HOE.function, "noppes.npcs.api.event.IPlayerEvent$UseHoeEvent", playerImport);
registerHookDef(ctx, EnumScriptType.BONEMEAL.function, "noppes.npcs.api.event.IPlayerEvent$BonemealEvent", playerImport);
registerHookDef(ctx, EnumScriptType.FILL_BUCKET.function, "noppes.npcs.api.event.IPlayerEvent$FillBucketEvent", playerImport);
registerHookDef(ctx, EnumScriptType.WAKE_UP.function, "noppes.npcs.api.event.IPlayerEvent$WakeUpEvent", playerImport);
registerHookDef(ctx, EnumScriptType.SLEEP.function, "noppes.npcs.api.event.IPlayerEvent$SleepEvent", playerImport);
registerHookDef(ctx, EnumScriptType.PLAYSOUND.function, "noppes.npcs.api.event.IPlayerEvent$SoundEvent", playerImport);
registerHookDef(ctx, EnumScriptType.LIGHTNING.function, "noppes.npcs.api.event.IPlayerEvent$LightningEvent", playerImport);
registerHookDef(ctx, EnumScriptType.SCRIPT_COMMAND.function, "noppes.npcs.api.event.ICustomNPCsEvent$ScriptedCommandEvent", "noppes.npcs.api.event.ICustomNPCsEvent");
// Quest events
registerBuiltInDefinition(ctx, EnumScriptType.QUEST_START.function,
"noppes.npcs.api.event.IQuestEvent$QuestStartEvent", questImport);
registerBuiltInDefinition(ctx, EnumScriptType.QUEST_COMPLETED.function,
"noppes.npcs.api.event.IQuestEvent$QuestCompletedEvent", questImport);
registerBuiltInDefinition(ctx, EnumScriptType.QUEST_TURNIN.function,
"noppes.npcs.api.event.IQuestEvent$QuestTurnedInEvent", questImport);
registerHookDef(ctx, EnumScriptType.QUEST_START.function, "noppes.npcs.api.event.IQuestEvent$QuestStartEvent", questImport);
registerHookDef(ctx, EnumScriptType.QUEST_COMPLETED.function, "noppes.npcs.api.event.IQuestEvent$QuestCompletedEvent", questImport);
registerHookDef(ctx, EnumScriptType.QUEST_TURNIN.function, "noppes.npcs.api.event.IQuestEvent$QuestTurnedInEvent", questImport);
// Dialog events
registerBuiltInDefinition(ctx, EnumScriptType.DIALOG_OPEN.function,
"noppes.npcs.api.event.IDialogEvent$DialogOpen", dialogImport);
registerBuiltInDefinition(ctx, EnumScriptType.DIALOG_OPTION.function,
"noppes.npcs.api.event.IDialogEvent$DialogOption", dialogImport);
registerBuiltInDefinition(ctx, EnumScriptType.DIALOG_CLOSE.function,
"noppes.npcs.api.event.IDialogEvent$DialogClosed", dialogImport);
registerHookDef(ctx, EnumScriptType.DIALOG_OPEN.function, "noppes.npcs.api.event.IDialogEvent$DialogOpen", dialogImport);
registerHookDef(ctx, EnumScriptType.DIALOG_OPTION.function, "noppes.npcs.api.event.IDialogEvent$DialogOption", dialogImport);
registerHookDef(ctx, EnumScriptType.DIALOG_CLOSE.function, "noppes.npcs.api.event.IDialogEvent$DialogClosed", dialogImport);
// Faction events
registerBuiltInDefinition(ctx, EnumScriptType.FACTION_POINTS.function,
"noppes.npcs.api.event.IFactionEvent$FactionPoints", factionImport);
registerHookDef(ctx, EnumScriptType.FACTION_POINTS.function, "noppes.npcs.api.event.IFactionEvent$FactionPoints", factionImport);
// Custom GUI events
registerBuiltInDefinition(ctx, EnumScriptType.CUSTOM_GUI_CLOSED.function,
"noppes.npcs.api.event.ICustomGuiEvent$CloseEvent", guiImport);
registerBuiltInDefinition(ctx, EnumScriptType.CUSTOM_GUI_BUTTON.function,
"noppes.npcs.api.event.ICustomGuiEvent$ButtonEvent", guiImport);
registerBuiltInDefinition(ctx, EnumScriptType.CUSTOM_GUI_SLOT.function,
"noppes.npcs.api.event.ICustomGuiEvent$SlotEvent", guiImport);
registerBuiltInDefinition(ctx, EnumScriptType.CUSTOM_GUI_SLOT_CLICKED.function,
"noppes.npcs.api.event.ICustomGuiEvent$SlotClickEvent", guiImport);
registerBuiltInDefinition(ctx, EnumScriptType.CUSTOM_GUI_SCROLL.function,
"noppes.npcs.api.event.ICustomGuiEvent$ScrollEvent", guiImport);
registerBuiltInDefinition(ctx, EnumScriptType.CUSTOM_GUI_TEXTFIELD.function,
"noppes.npcs.api.event.ICustomGuiEvent$UnfocusedEvent", guiImport);
registerHookDef(ctx, EnumScriptType.CUSTOM_GUI_CLOSED.function, "noppes.npcs.api.event.ICustomGuiEvent$CloseEvent", guiImport);
registerHookDef(ctx, EnumScriptType.CUSTOM_GUI_BUTTON.function, "noppes.npcs.api.event.ICustomGuiEvent$ButtonEvent", guiImport);
registerHookDef(ctx, EnumScriptType.CUSTOM_GUI_SLOT.function, "noppes.npcs.api.event.ICustomGuiEvent$SlotEvent", guiImport);
registerHookDef(ctx, EnumScriptType.CUSTOM_GUI_SLOT_CLICKED.function, "noppes.npcs.api.event.ICustomGuiEvent$SlotClickEvent", guiImport);
registerHookDef(ctx, EnumScriptType.CUSTOM_GUI_SCROLL.function, "noppes.npcs.api.event.ICustomGuiEvent$ScrollEvent", guiImport);
registerHookDef(ctx, EnumScriptType.CUSTOM_GUI_TEXTFIELD.function, "noppes.npcs.api.event.ICustomGuiEvent$UnfocusedEvent", guiImport);
// Party events
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_QUEST_COMPLETED.function,
"noppes.npcs.api.event.IPartyEvent$PartyQuestCompletedEvent", partyImport);
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_QUEST_SET.function,
"noppes.npcs.api.event.IPartyEvent$PartyQuestSetEvent", partyImport);
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_QUEST_TURNED_IN.function,
"noppes.npcs.api.event.IPartyEvent$PartyQuestTurnedInEvent", partyImport);
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_INVITE.function,
"noppes.npcs.api.event.IPartyEvent$PartyInviteEvent", partyImport);
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_KICK.function,
"noppes.npcs.api.event.IPartyEvent$PartyKickEvent", partyImport);
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_LEAVE.function,
"noppes.npcs.api.event.IPartyEvent$PartyLeaveEvent", partyImport);
registerBuiltInDefinition(ctx, EnumScriptType.PARTY_DISBAND.function,
"noppes.npcs.api.event.IPartyEvent$PartyDisbandEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_QUEST_COMPLETED.function, "noppes.npcs.api.event.IPartyEvent$PartyQuestCompletedEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_QUEST_SET.function, "noppes.npcs.api.event.IPartyEvent$PartyQuestSetEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_QUEST_TURNED_IN.function, "noppes.npcs.api.event.IPartyEvent$PartyQuestTurnedInEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_INVITE.function, "noppes.npcs.api.event.IPartyEvent$PartyInviteEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_KICK.function, "noppes.npcs.api.event.IPartyEvent$PartyKickEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_LEAVE.function, "noppes.npcs.api.event.IPartyEvent$PartyLeaveEvent", partyImport);
registerHookDef(ctx, EnumScriptType.PARTY_DISBAND.function, "noppes.npcs.api.event.IPartyEvent$PartyDisbandEvent", partyImport);
// Animation events
registerBuiltInDefinition(ctx, EnumScriptType.ANIMATION_START.function,
"noppes.npcs.api.event.IAnimationEvent$Started", animImport);
registerBuiltInDefinition(ctx, EnumScriptType.ANIMATION_END.function,
"noppes.npcs.api.event.IAnimationEvent$Ended", animImport);
registerBuiltInDefinition(ctx, EnumScriptType.ANIMATION_FRAME_ENTER.function,
"noppes.npcs.api.event.IAnimationEvent$IFrameEvent$Entered", animImport);
registerBuiltInDefinition(ctx, EnumScriptType.ANIMATION_FRAME_EXIT.function,
"noppes.npcs.api.event.IAnimationEvent$IFrameEvent$Exited", animImport);
registerHookDef(ctx, EnumScriptType.ANIMATION_START.function, "noppes.npcs.api.event.IAnimationEvent$Started", animImport);
registerHookDef(ctx, EnumScriptType.ANIMATION_END.function, "noppes.npcs.api.event.IAnimationEvent$Ended", animImport);
registerHookDef(ctx, EnumScriptType.ANIMATION_FRAME_ENTER.function, "noppes.npcs.api.event.IAnimationEvent$IFrameEvent$Entered", animImport);
registerHookDef(ctx, EnumScriptType.ANIMATION_FRAME_EXIT.function, "noppes.npcs.api.event.IAnimationEvent$IFrameEvent$Exited", animImport);
// Profile events
registerBuiltInDefinition(ctx, EnumScriptType.PROFILE_CHANGE.function,
"noppes.npcs.api.event.IPlayerEvent$ProfileEvent$Changed", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.PROFILE_REMOVE.function,
"noppes.npcs.api.event.IPlayerEvent$ProfileEvent$Removed", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.PROFILE_CREATE.function,
"noppes.npcs.api.event.IPlayerEvent$ProfileEvent$Create", playerImport);
registerHookDef(ctx, EnumScriptType.PROFILE_CHANGE.function, "noppes.npcs.api.event.IPlayerEvent$ProfileEvent$Changed", playerImport);
registerHookDef(ctx, EnumScriptType.PROFILE_REMOVE.function, "noppes.npcs.api.event.IPlayerEvent$ProfileEvent$Removed", playerImport);
registerHookDef(ctx, EnumScriptType.PROFILE_CREATE.function, "noppes.npcs.api.event.IPlayerEvent$ProfileEvent$Create", playerImport);
// Effect events (for player context)
registerBuiltInDefinition(ctx, EnumScriptType.ON_EFFECT_ADD.function,
"noppes.npcs.api.event.IPlayerEvent$EffectEvent$Added", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.ON_EFFECT_TICK.function,
"noppes.npcs.api.event.IPlayerEvent$EffectEvent$Ticked", playerImport);
registerBuiltInDefinition(ctx, EnumScriptType.ON_EFFECT_REMOVE.function,
"noppes.npcs.api.event.IPlayerEvent$EffectEvent$Removed", playerImport);
registerHookDef(ctx, EnumScriptType.ON_EFFECT_ADD.function, "noppes.npcs.api.event.IPlayerEvent$EffectEvent$Added", playerImport);
registerHookDef(ctx, EnumScriptType.ON_EFFECT_TICK.function, "noppes.npcs.api.event.IPlayerEvent$EffectEvent$Ticked", playerImport);
registerHookDef(ctx, EnumScriptType.ON_EFFECT_REMOVE.function, "noppes.npcs.api.event.IPlayerEvent$EffectEvent$Removed", playerImport);
}
private void initializeBlockHooks() {
String ctx = ScriptContext.BLOCK.hookContext;
String blockImport = "noppes.npcs.api.event.IBlockEvent";
registerBuiltInDefinition(ctx, EnumScriptType.INIT.function,
"noppes.npcs.api.event.IBlockEvent$InitEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.TICK.function,
"noppes.npcs.api.event.IBlockEvent$UpdateEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.INTERACT.function,
"noppes.npcs.api.event.IBlockEvent$InteractEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.FALLEN_UPON.function,
"noppes.npcs.api.event.IBlockEvent$EntityFallenUponEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.REDSTONE.function,
"noppes.npcs.api.event.IBlockEvent$RedstoneEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.BROKEN.function,
"noppes.npcs.api.event.IBlockEvent$BreakEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.EXPLODED.function,
"noppes.npcs.api.event.IBlockEvent$ExplodedEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.RAIN_FILLED.function,
"noppes.npcs.api.event.IBlockEvent$RainFillEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.NEIGHBOR_CHANGED.function,
"noppes.npcs.api.event.IBlockEvent$NeighborChangedEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.CLICKED.function,
"noppes.npcs.api.event.IBlockEvent$ClickedEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.HARVESTED.function,
"noppes.npcs.api.event.IBlockEvent$HarvestedEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.COLLIDE.function,
"noppes.npcs.api.event.IBlockEvent$CollidedEvent", blockImport);
registerBuiltInDefinition(ctx, EnumScriptType.TIMER.function,
"noppes.npcs.api.event.IBlockEvent$TimerEvent", blockImport);
registerHookDef(ctx, EnumScriptType.INIT.function, "noppes.npcs.api.event.IBlockEvent$InitEvent", blockImport);
registerHookDef(ctx, EnumScriptType.TICK.function, "noppes.npcs.api.event.IBlockEvent$UpdateEvent", blockImport);
registerHookDef(ctx, EnumScriptType.INTERACT.function, "noppes.npcs.api.event.IBlockEvent$InteractEvent", blockImport);
registerHookDef(ctx, EnumScriptType.FALLEN_UPON.function, "noppes.npcs.api.event.IBlockEvent$EntityFallenUponEvent", blockImport);
registerHookDef(ctx, EnumScriptType.REDSTONE.function, "noppes.npcs.api.event.IBlockEvent$RedstoneEvent", blockImport);
registerHookDef(ctx, EnumScriptType.BROKEN.function, "noppes.npcs.api.event.IBlockEvent$BreakEvent", blockImport);
registerHookDef(ctx, EnumScriptType.EXPLODED.function, "noppes.npcs.api.event.IBlockEvent$ExplodedEvent", blockImport);
registerHookDef(ctx, EnumScriptType.RAIN_FILLED.function, "noppes.npcs.api.event.IBlockEvent$RainFillEvent", blockImport);
registerHookDef(ctx, EnumScriptType.NEIGHBOR_CHANGED.function, "noppes.npcs.api.event.IBlockEvent$NeighborChangedEvent", blockImport);
registerHookDef(ctx, EnumScriptType.CLICKED.function, "noppes.npcs.api.event.IBlockEvent$ClickedEvent", blockImport);
registerHookDef(ctx, EnumScriptType.HARVESTED.function, "noppes.npcs.api.event.IBlockEvent$HarvestedEvent", blockImport);
registerHookDef(ctx, EnumScriptType.COLLIDE.function, "noppes.npcs.api.event.IBlockEvent$CollidedEvent", blockImport);
registerHookDef(ctx, EnumScriptType.TIMER.function, "noppes.npcs.api.event.IBlockEvent$TimerEvent", blockImport);
}
private void initializeItemHooks() {
String ctx = ScriptContext.ITEM.hookContext;
String itemImport = "noppes.npcs.api.event.IItemEvent";
registerBuiltInDefinition(ctx, EnumScriptType.INIT.function,
"noppes.npcs.api.event.IItemEvent$InitEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.TICK.function,
"noppes.npcs.api.event.IItemEvent$UpdateEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.TOSSED.function,
"noppes.npcs.api.event.IItemEvent$TossedEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.PICKEDUP.function,
"noppes.npcs.api.event.IItemEvent$PickedUpEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.SPAWN.function,
"noppes.npcs.api.event.IItemEvent$SpawnEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.INTERACT.function,
"noppes.npcs.api.event.IItemEvent$InteractEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.RIGHT_CLICK.function,
"noppes.npcs.api.event.IItemEvent$RightClickEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.ATTACK.function,
"noppes.npcs.api.event.IItemEvent$AttackEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.START_USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$StartUsingItem", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$UsingItem", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.STOP_USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$StopUsingItem", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.FINISH_USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$FinishUsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.INIT.function, "noppes.npcs.api.event.IItemEvent$InitEvent", itemImport);
registerHookDef(ctx, EnumScriptType.TICK.function, "noppes.npcs.api.event.IItemEvent$UpdateEvent", itemImport);
registerHookDef(ctx, EnumScriptType.TOSSED.function, "noppes.npcs.api.event.IItemEvent$TossedEvent", itemImport);
registerHookDef(ctx, EnumScriptType.PICKEDUP.function, "noppes.npcs.api.event.IItemEvent$PickedUpEvent", itemImport);
registerHookDef(ctx, EnumScriptType.SPAWN.function, "noppes.npcs.api.event.IItemEvent$SpawnEvent", itemImport);
registerHookDef(ctx, EnumScriptType.INTERACT.function, "noppes.npcs.api.event.IItemEvent$InteractEvent", itemImport);
registerHookDef(ctx, EnumScriptType.RIGHT_CLICK.function, "noppes.npcs.api.event.IItemEvent$RightClickEvent", itemImport);
registerHookDef(ctx, EnumScriptType.ATTACK.function, "noppes.npcs.api.event.IItemEvent$AttackEvent", itemImport);
registerHookDef(ctx, EnumScriptType.START_USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$StartUsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$UsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.STOP_USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$StopUsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.FINISH_USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$FinishUsingItem", itemImport);
}
private void initializeLinkedItemHooks() {
@@ -406,95 +270,64 @@ public class ScriptHookController implements IScriptHookHandler {
String linkedImport = "noppes.npcs.api.event.ILinkedItemEvent";
// Linked item specific hooks
registerBuiltInDefinition(ctx, EnumScriptType.LINKED_ITEM_BUILD.function,
"noppes.npcs.api.event.ILinkedItemEvent$BuildEvent", linkedImport);
registerBuiltInDefinition(ctx, EnumScriptType.LINKED_ITEM_VERSION.function,
"noppes.npcs.api.event.ILinkedItemEvent$VersionChangeEvent", linkedImport);
registerHookDef(ctx, EnumScriptType.LINKED_ITEM_BUILD.function, "noppes.npcs.api.event.ILinkedItemEvent$BuildEvent", linkedImport);
registerHookDef(ctx, EnumScriptType.LINKED_ITEM_VERSION.function, "noppes.npcs.api.event.ILinkedItemEvent$VersionChangeEvent", linkedImport);
// Standard item hooks
registerBuiltInDefinition(ctx, EnumScriptType.INIT.function,
"noppes.npcs.api.event.IItemEvent$InitEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.TICK.function,
"noppes.npcs.api.event.IItemEvent$UpdateEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.TOSSED.function,
"noppes.npcs.api.event.IItemEvent$TossedEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.PICKEDUP.function,
"noppes.npcs.api.event.IItemEvent$PickedUpEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.SPAWN.function,
"noppes.npcs.api.event.IItemEvent$SpawnEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.INTERACT.function,
"noppes.npcs.api.event.IItemEvent$InteractEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.RIGHT_CLICK.function,
"noppes.npcs.api.event.IItemEvent$RightClickEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.ATTACK.function,
"noppes.npcs.api.event.IItemEvent$AttackEvent", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.START_USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$StartUsingItem", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$UsingItem", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.STOP_USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$StopUsingItem", itemImport);
registerBuiltInDefinition(ctx, EnumScriptType.FINISH_USING_ITEM.function,
"noppes.npcs.api.event.IItemEvent$FinishUsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.INIT.function, "noppes.npcs.api.event.IItemEvent$InitEvent", itemImport);
registerHookDef(ctx, EnumScriptType.TICK.function, "noppes.npcs.api.event.IItemEvent$UpdateEvent", itemImport);
registerHookDef(ctx, EnumScriptType.TOSSED.function, "noppes.npcs.api.event.IItemEvent$TossedEvent", itemImport);
registerHookDef(ctx, EnumScriptType.PICKEDUP.function, "noppes.npcs.api.event.IItemEvent$PickedUpEvent", itemImport);
registerHookDef(ctx, EnumScriptType.SPAWN.function, "noppes.npcs.api.event.IItemEvent$SpawnEvent", itemImport);
registerHookDef(ctx, EnumScriptType.INTERACT.function, "noppes.npcs.api.event.IItemEvent$InteractEvent", itemImport);
registerHookDef(ctx, EnumScriptType.RIGHT_CLICK.function, "noppes.npcs.api.event.IItemEvent$RightClickEvent", itemImport);
registerHookDef(ctx, EnumScriptType.ATTACK.function, "noppes.npcs.api.event.IItemEvent$AttackEvent", itemImport);
registerHookDef(ctx, EnumScriptType.START_USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$StartUsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$UsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.STOP_USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$StopUsingItem", itemImport);
registerHookDef(ctx, EnumScriptType.FINISH_USING_ITEM.function, "noppes.npcs.api.event.IItemEvent$FinishUsingItem", itemImport);
}
/**
* Register a built-in hook with full definition metadata.
* Internal helper to register a hook definition.
*/
private void registerBuiltInDefinition(String context, String hookName, String eventClassName, String... imports) {
HookDefinition def = HookDefinition.builder(hookName)
.eventClass(eventClassName)
.requiredImports(imports)
.build();
private void registerHookDef(String context, String hookName, String eventClassName, String... imports) {
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
if (contextDefs == null) {
contextDefs = new HashMap<>();
contextDefs = new LinkedHashMap<>();
hookDefinitions.put(context, contextDefs);
}
contextDefs.put(hookName, def);
// Also register in legacy string list
registerBuiltIn(context, hookName);
}
/**
* Register built-in hooks for a ScriptContext.
*/
private void registerBuiltIn(ScriptContext context, String... hooks) {
registerBuiltIn(context.hookContext, hooks);
}
private void registerBuiltIn(String context, String... hooks) {
List<String> list = builtInHooks.get(context);
if (list != null) {
for (String hook : hooks) {
if (!list.contains(hook)) {
list.add(hook);
}
}
HookDefinition.Builder builder = HookDefinition.builder(hookName);
if (eventClassName != null) {
builder.eventClass(eventClassName);
}
if (imports != null && imports.length > 0 && imports[0] != null) {
builder.requiredImports(imports);
}
contextDefs.put(hookName, builder.build());
}
// ==================== RICH HOOK REGISTRATION (NEW API) ====================
private void registerHookDef(ScriptContext context, String hookName, String eventClassName, String... imports) {
registerHookDef(context.hookContext, hookName, eventClassName, imports);
}
// ==================== PUBLIC API ====================
@Override
public void registerHookDefinition(String context, IHookDefinition definition) {
if (context == null || definition == null || definition.hookName() == null) {
if (context == null || definition == null || definition.hookName() == null)
return;
}
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
if (contextDefs == null) {
contextDefs = new HashMap<>();
contextDefs = new LinkedHashMap<>();
hookDefinitions.put(context, contextDefs);
}
// Store as HookDefinition (implementation)
if (definition instanceof HookDefinition) {
contextDefs.put(definition.hookName(), (HookDefinition) definition);
} else {
// Convert foreign IHookDefinition to HookDefinition
HookDefinition def = HookDefinition.builder(definition.hookName())
.eventClass(definition.eventClassName())
.paramNames(definition.paramNames())
@@ -504,18 +337,13 @@ public class ScriptHookController implements IScriptHookHandler {
contextDefs.put(definition.hookName(), def);
}
// Also add to legacy addon hooks list for backward compatibility
registerHook(context, definition.hookName());
// Increment revision for cache invalidation
hookRevision++;
}
@Override
public IHookDefinition getHookDefinition(String context, String hookName) {
if (context == null || hookName == null) {
if (context == null || hookName == null)
return null;
}
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
return contextDefs != null ? contextDefs.get(hookName) : null;
@@ -523,14 +351,12 @@ public class ScriptHookController implements IScriptHookHandler {
@Override
public List<IHookDefinition> getAllHookDefinitions(String context) {
if (context == null) {
if (context == null)
return Collections.emptyList();
}
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
if (contextDefs == null || contextDefs.isEmpty()) {
if (contextDefs == null || contextDefs.isEmpty())
return Collections.emptyList();
}
return new ArrayList<>(contextDefs.values());
}
@@ -542,60 +368,44 @@ public class ScriptHookController implements IScriptHookHandler {
// ==================== CONVENIENCE METHODS ====================
/**
* Convenience method to register a hook using ScriptContext.
* @param context The script context
* @param functionName The hook function name
*/
public void registerHook(ScriptContext context, String functionName) {
registerHook(context.hookContext, functionName);
}
/**
* Convenience method to register multiple hooks using ScriptContext.
* @param context The script context
* @param functionNames The hook function names
*/
public void registerHooks(ScriptContext context, String... functionNames) {
for (String fn : functionNames) {
registerHook(context.hookContext, fn);
}
}
/**
* Convenience method to register a hook definition using ScriptContext.
* @param context The script context
* @param definition The hook definition
*/
public void registerHookDefinition(ScriptContext context, IHookDefinition definition) {
registerHookDefinition(context.hookContext, definition);
}
// ==================== LEGACY HOOK REGISTRATION ====================
// ==================== LEGACY API (IScriptHookHandler) ====================
@Override
public void registerHook(String context, String functionName) {
if (context == null || functionName == null || functionName.isEmpty()) {
if (context == null || functionName == null || functionName.isEmpty())
return;
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
if (contextDefs == null) {
contextDefs = new LinkedHashMap<>();
hookDefinitions.put(context, contextDefs);
}
List<String> hooks = addonHooks.get(context);
if (hooks == null) {
// Custom context - create it
hooks = new ArrayList<>();
addonHooks.put(context, hooks);
}
if (!hooks.contains(functionName) && !isBuiltInHook(context, functionName)) {
hooks.add(functionName);
// Only add if not already present
if (!contextDefs.containsKey(functionName)) {
contextDefs.put(functionName, HookDefinition.builder(functionName).build());
hookRevision++;
}
}
@Override
public void registerHooks(String functionName, String... contexts) {
if (functionName == null || functionName.isEmpty() || contexts == null) {
if (functionName == null || functionName.isEmpty() || contexts == null)
return;
}
for (String context : contexts) {
registerHook(context, functionName);
@@ -604,85 +414,57 @@ public class ScriptHookController implements IScriptHookHandler {
@Override
public void unregisterHook(String context, String functionName) {
if (context == null || functionName == null) {
if (context == null || functionName == null)
return;
}
List<String> hooks = addonHooks.get(context);
if (hooks != null) {
hooks.remove(functionName);
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
if (contextDefs != null && contextDefs.remove(functionName) != null) {
hookRevision++;
}
}
@Override
public void unregisterHookFromAll(String functionName) {
if (functionName == null) {
if (functionName == null)
return;
}
for (List<String> hooks : addonHooks.values()) {
hooks.remove(functionName);
for (Map<String, HookDefinition> contextDefs : hookDefinitions.values()) {
if (contextDefs.remove(functionName) != null) {
hookRevision++;
}
}
}
@Override
public List<String> getAddonHooks(String context) {
List<String> hooks = addonHooks.get(context);
return hooks != null ? Collections.unmodifiableList(hooks) : Collections.emptyList();
// With unified storage, we can't distinguish addon vs built-in
// Return empty for backwards compatibility
return Collections.emptyList();
}
@Override
public List<String> getAllHooks(String context) {
List<String> result = new ArrayList<>();
if (context == null)
return Collections.emptyList();
// Add built-in hooks
List<String> builtIn = builtInHooks.get(context);
if (builtIn != null) {
result.addAll(builtIn);
}
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
if (contextDefs == null || contextDefs.isEmpty())
return Collections.emptyList();
// Add addon hooks
List<String> addon = addonHooks.get(context);
if (addon != null) {
for (String hook : addon) {
if (!result.contains(hook)) {
result.add(hook);
}
}
}
return result;
return new ArrayList<>(contextDefs.keySet());
}
@Override
public boolean hasHook(String context, String functionName) {
if (context == null || functionName == null) {
if (context == null || functionName == null)
return false;
}
return isBuiltInHook(context, functionName) || isAddonHook(context, functionName);
Map<String, HookDefinition> contextDefs = hookDefinitions.get(context);
return contextDefs != null && contextDefs.containsKey(functionName);
}
@Override
public String[] getContexts() {
return builtInHooks.keySet().toArray(new String[0]);
}
private boolean isBuiltInHook(String context, String functionName) {
List<String> hooks = builtInHooks.get(context);
return hooks != null && hooks.contains(functionName);
}
private boolean isAddonHook(String context, String functionName) {
List<String> hooks = addonHooks.get(context);
return hooks != null && hooks.contains(functionName);
}
/**
* Get built-in hooks for a context (used by GUIs for backwards compatibility).
*/
public List<String> getBuiltInHooks(String context) {
List<String> hooks = builtInHooks.get(context);
return hooks != null ? Collections.unmodifiableList(hooks) : Collections.emptyList();
return hookDefinitions.keySet().toArray(new String[0]);
}
}
@@ -48,16 +48,9 @@ public class JaninoScriptHandler<S extends JaninoScript<?>> extends ScriptHandle
}
public void deleteScript() {
unloadScript();
script = null;
}
public void unloadScript() {
if (script != null) {
script.unload();
}
}
// -------------------- NBT helpers --------------------
public void readFromNBT(NBTTagCompound compound) {
@@ -7,20 +7,16 @@ import java.lang.reflect.Modifier;
import java.util.*;
/**
* Resolves script hook methods for compiled script classes using runtime
* argument values. Resolution favors exact matches and then the "closest"
* assignable parameter types (measured by inheritance distance).
*
* Methods are resolved dynamically from the compiled class - no interface
* definitions required.
* Resolves script hook methods for compiled script classes.
* Optimized for high-frequency hooks like TICK with fast O(1) lookups.
*/
public final class JaninoHookResolver {
private final Class<?> interfaceType;
/**
* Cache for methods found on compiled classes (keyed by signature).
* Primary cache: hookName -> CachedHandle
* Fast O(1) lookup without string building for non-overloaded hooks.
*/
private final Map<String, Method> compiledClassCache = new HashMap<>();
private final Map<String, CachedHandle> handleCache = new HashMap<>();
/**
* Track which compiled class we've cached methods for.
@@ -28,164 +24,78 @@ public final class JaninoHookResolver {
*/
private Class<?> lastCompiledClass;
// MethodHandle caches
private final Map<String, MethodHandle> compiledHandleCache = new HashMap<>();
// Method -> MethodHandle for identity-based deduplication
private final Map<Method, MethodHandle> methodToHandle = new IdentityHashMap<>();
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
/**
* Create a resolver for the provided script interface type.
* @param interfaceType non-null interface class that scripts implement
* Cached handle with expected parameter count for quick validation.
*/
public JaninoHookResolver(Class<?> interfaceType) {
this.interfaceType = Objects.requireNonNull(interfaceType, "interfaceType");
private static final class CachedHandle {
final MethodHandle handle;
final int paramCount;
CachedHandle(MethodHandle handle, int paramCount) {
this.handle = handle;
this.paramCount = paramCount;
}
}
public JaninoHookResolver() {
}
/**
* Clears internal resolution caches so future calls perform fresh
* method resolution. Call when scripts or available methods change.
* Clears internal resolution caches.
*/
public void clearResolutionCaches() {
compiledClassCache.clear();
compiledHandleCache.clear();
methodToHandle.clear();
handleCache.clear();
lastCompiledClass = null;
}
/**
* Resolve a hook method by name, searching the compiled class.
*
* <p>Resolution order:</p>
* <ol>
* <li>Compiled class methods (user-defined)</li>
* <li>Fallback to no-arg versions</li>
* </ol>
*
* @param hookName hook method name
* @param args runtime arguments to use for overload resolution
* @param compiledInstance the compiled script instance
* @return the resolved {@link Method} or {@code null} if none matched
*/
public Method resolveHookMethod(String hookName, Object[] args, Object compiledInstance) {
if (hookName == null || hookName.isEmpty() || compiledInstance == null)
return null;
Object[] safeArgs = args == null ? new Object[0] : args;
String signatureKey = buildSignatureKey(hookName, safeArgs);
Class<?> compiledClass = compiledInstance.getClass();
// Clear cache if compiled class changed (recompilation)
if (lastCompiledClass != compiledClass) {
compiledClassCache.clear();
compiledHandleCache.clear();
methodToHandle.clear();
lastCompiledClass = compiledClass;
}
// Check compiled class cache
Method method = compiledClassCache.get(signatureKey);
if (method != null)
return method;
// Search compiled class for matching method
method = resolveHookMethodInternal(compiledClass, hookName, safeArgs);
if (method != null) {
compiledClassCache.put(signatureKey, method);
return method;
}
// Try no-arg version on compiled class
String noArgKey = buildSignatureKey(hookName, new Object[0]);
method = compiledClassCache.get(noArgKey);
if (method != null)
return method;
method = resolveHookMethodInternal(compiledClass, hookName, new Object[0]);
if (method != null) {
compiledClassCache.put(noArgKey, method);
return method;
}
return null;
}
/**
* Resolve a MethodHandle for the given hook. Faster than Method.invoke().
* Uses existing Method resolution, then converts to cached MethodHandle.
* Resolve a MethodHandle for the given hook.
* Optimized for repeated calls with same hook name - O(1) after first resolution.
*/
public MethodHandle resolveHookHandle(String hookName, Object[] args, Object compiledInstance) {
if (hookName == null || hookName.isEmpty() || compiledInstance == null)
return null;
Object[] safeArgs = args == null ? new Object[0] : args;
String signatureKey = buildSignatureKey(hookName, safeArgs);
Class<?> compiledClass = compiledInstance.getClass();
// Clear cache if compiled class changed (recompilation)
if (lastCompiledClass != compiledClass) {
compiledClassCache.clear();
compiledHandleCache.clear();
methodToHandle.clear();
handleCache.clear();
lastCompiledClass = compiledClass;
}
// Check handle cache
MethodHandle handle = compiledHandleCache.get(signatureKey);
if (handle != null)
return handle;
int argCount = args == null ? 0 : args.length;
// Resolve Method first
Method method = resolveHookMethod(hookName, args, compiledInstance);
// Fast path: check primary cache by hookName only
CachedHandle cached = handleCache.get(hookName);
if (cached != null) {
// Verify arg count matches (handles most cases without full signature check)
if (cached.paramCount == argCount) {
return cached.handle;
}
// Arg count mismatch - need full resolution for potential overload
}
// Slow path: resolve method and cache
Method method = resolveMethod(compiledClass, hookName, args);
if (method == null)
return null;
// Convert Method to MethodHandle (deduplicated by Method identity)
handle = methodToHandle.get(method);
if (handle == null) {
try {
handle = LOOKUP.unreflect(method);
methodToHandle.put(method, handle);
} catch (IllegalAccessException e) {
return null;
}
try {
MethodHandle handle = LOOKUP.unreflect(method);
handleCache.put(hookName, new CachedHandle(handle, method.getParameterCount()));
return handle;
} catch (IllegalAccessException e) {
return null;
}
compiledHandleCache.put(signatureKey, handle);
return handle;
}
/**
* Build a cache key for a hook name and runtime argument list.
* Find the best matching method on the compiled class.
*/
private static String buildSignatureKey(String hookName, Object[] args) {
StringBuilder sb = new StringBuilder();
sb.append(hookName).append('#');
if (args == null || args.length == 0)
return sb.append('0').toString();
sb.append(args.length).append(':');
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (i > 0)
sb.append(',');
sb.append(arg == null ? "null" : arg.getClass().getName());
}
return sb.toString();
}
/**
* Internal resolution routine. Attempts to find the best matching method
* on the provided class by comparing parameter counts and a simple
* match scoring function.
*/
private static Method resolveHookMethodInternal(Class<?> targetClass, String hookName, Object[] args) {
private Method resolveMethod(Class<?> targetClass, String hookName, Object[] args) {
Object[] safeArgs = args == null ? new Object[0] : args;
Method best = null;
@@ -202,18 +112,31 @@ public final class JaninoHookResolver {
continue;
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != safeArgs.length)
continue;
int score = scoreMethodMatch(paramTypes, safeArgs);
if (score == Integer.MAX_VALUE)
continue;
// Try exact arg count match first
if (paramTypes.length == safeArgs.length) {
int score = scoreMethodMatch(paramTypes, safeArgs);
if (score != Integer.MAX_VALUE && score < bestScore) {
bestScore = score;
best = method;
if (score == 0)
return best; // Perfect match
}
}
}
if (score < bestScore) {
bestScore = score;
best = method;
if (score == 0)
return best;
// If no match with args, try no-arg version
if (best == null && safeArgs.length > 0) {
for (Method method : targetClass.getMethods()) {
if (!method.getName().equals(hookName))
continue;
if (Modifier.isFinal(method.getModifiers()))
continue;
if (method.getDeclaringClass() == Object.class)
continue;
if (method.getParameterCount() == 0) {
return method;
}
}
}
@@ -221,8 +144,8 @@ public final class JaninoHookResolver {
}
/**
* Score how well a method's parameter types match the provided runtime arguments.
* Lower scores are better; Integer.MAX_VALUE indicates an incompatible parameter.
* Score how well parameter types match runtime arguments.
* Lower is better; MAX_VALUE means incompatible.
*/
private static int scoreMethodMatch(Class<?>[] paramTypes, Object[] args) {
int score = 0;
@@ -233,7 +156,6 @@ public final class JaninoHookResolver {
if (arg == null) {
if (paramType.isPrimitive())
return Integer.MAX_VALUE;
score += 1;
continue;
}
@@ -251,36 +173,26 @@ public final class JaninoHookResolver {
return Integer.MAX_VALUE;
}
return score;
}
private static Class<?> boxType(Class<?> type) {
if (!type.isPrimitive())
return type;
if (type == boolean.class)
return Boolean.class;
if (type == byte.class)
return Byte.class;
if (type == short.class)
return Short.class;
if (type == int.class)
return Integer.class;
if (type == long.class)
return Long.class;
if (type == float.class)
return Float.class;
if (type == double.class)
return Double.class;
if (type == char.class)
return Character.class;
if (type == boolean.class) return Boolean.class;
if (type == byte.class) return Byte.class;
if (type == short.class) return Short.class;
if (type == int.class) return Integer.class;
if (type == long.class) return Long.class;
if (type == float.class) return Float.class;
if (type == double.class) return Double.class;
if (type == char.class) return Character.class;
return type;
}
private static int inheritanceDistance(Class<?> child, Class<?> parent) {
if (child.equals(parent))
return 0;
if (!parent.isAssignableFrom(child))
return 1000;
@@ -16,10 +16,9 @@ import org.codehaus.commons.compiler.InternalCompilerException;
import org.codehaus.commons.compiler.Sandbox;
import java.lang.invoke.MethodHandle;
import java.security.*;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public abstract class JaninoScript<T> implements IScriptUnit {
@@ -67,7 +66,7 @@ public abstract class JaninoScript<T> implements IScriptUnit {
this.scriptBody = builder.build();
this.hookResolver = new JaninoHookResolver(type);
this.hookResolver = new JaninoHookResolver();
}
protected JaninoScript(Class<T> type, String[] defaultImports) {
@@ -151,49 +150,6 @@ public abstract class JaninoScript<T> implements IScriptUnit {
return scriptBody.get();
}
public <R> R call(Function<T, R> fn) {
ensureCompiled();
T t = getUnsafe();
if (t == null)
return null;
// CodeSource cs = t.getClass().getProtectionDomain().getCodeSource();
// ProtectionDomain pd = new ProtectionDomain(cs, new Permissions());
try {
return sandbox.confine((PrivilegedAction<R>) () -> fn.apply(t));
// return AccessController.doPrivileged((PrivilegedAction<? extends R>) () -> fn.apply(t), new AccessControlContext(
// new ProtectionDomain[] {
// pd
// }
// ));
} catch (Exception e) {
appendConsole("Runtime Error: " + e.getMessage());
return null;
}
}
public void run(Consumer<T> fn) {
ensureCompiled();
T t = getUnsafe();
if (t == null)
return;
try {
sandbox.confine((PrivilegedAction<Void>) () -> {
fn.accept(t);
return null;
});
} catch (Exception e) {
appendConsole("Runtime Error: " + e.getMessage());
}
}
public void unload() {
}
/**
* Feed the code into the engine and compile it.
* Rebuilds imports from hook definitions before compilation.
@@ -205,6 +161,8 @@ public abstract class JaninoScript<T> implements IScriptUnit {
String[] allImports = collectAllImports();
builder.setDefaultImports(allImports);
// Rebuild scriptBody to apply new imports
this.scriptBody = builder.build();
scriptBody.setScript(code);
} catch (InternalCompilerException e ) {
Throwable parentCause = null;