Hook Definition

This commit is contained in:
Kam committed 2026-01-22 17:58:06 -05:00
1 parent b90df20fc4
commit 7a337a5704
2 files changed
+168 -11

No files matched your search

@@ -0,0 +1,106 @@
package noppes.npcs.api.handler;
/**
* Defines metadata for a script hook, enabling rich hook registration with proper
* type information for stub generation, imports, and documentation.
*
* <h3>Design Decision</h3>
* Uses {@code String eventClassName} instead of {@code Class<?>} in the API to avoid
* classloading issues with addons (addon classes may not be loaded when hooks are registered).
*
* <h3>Usage Example</h3>
* <pre>{@code
* // Addon registration with full metadata
* IScriptHookHandler hooks = NpcAPI.Instance().getScriptHooks();
* hooks.registerHookDefinition("player", HookDefinition.builder("onDBCTransform")
* .eventClass("com.dbc.api.event.IDBCEvent$TransformEvent")
* .paramNames("event")
* .requiredImports("com.dbc.api.event.IDBCEvent")
* .cancelable(true)
* .build());
* }</pre>
*/
public interface IHookDefinition {
/**
* The hook name (function name in scripts).
*
* @return Hook name, e.g., "questStart", "onDBCTransform"
*/
String hookName();
/**
* Full qualified class name of the event type.
* Uses '$' for nested classes (e.g., "noppes.npcs.api.event.IQuestEvent$QuestStartEvent").
*
* @return Fully qualified event class name, or null if unknown
*/
String eventClassName();
/**
* Parameter names for stub generation.
*
* @return Array of parameter names, defaults to ["event"]
*/
String[] paramNames();
/**
* Imports required for this hook's event type.
* These will be added to the script's default imports.
*
* @return Array of fully qualified class/package names to import
*/
String[] requiredImports();
/**
* Whether the event is cancelable (has @Cancelable annotation).
*
* @return true if event can be canceled
*/
boolean isCancelable();
/**
* Lazily resolve the event class. Returns null if class is not available
* (e.g., addon not loaded).
*
* @return The event class, or null if unavailable
*/
default Class<?> getEventClass() {
String className = eventClassName();
if (className == null || className.isEmpty()) {
return null;
}
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* Generate a usable type name for stub generation.
* Handles nested classes by converting '$' to '.'.
*
* <p>Examples:</p>
* <ul>
* <li>"noppes.npcs.api.event.IQuestEvent$QuestStartEvent" → "IQuestEvent.QuestStartEvent"</li>
* <li>"com.example.MyEvent" → "MyEvent"</li>
* </ul>
*
* @return The usable type name for code generation, or null if no event class
*/
default String getUsableTypeName() {
String className = eventClassName();
if (className == null || className.isEmpty()) {
return null;
}
int lastDot = className.lastIndexOf('.');
if (lastDot < 0) {
return className.replace('$', '.');
}
String simplePart = className.substring(lastDot + 1);
return simplePart.replace('$', '.');
}
}
@@ -6,21 +6,72 @@ import java.util.List;
* Handler for registering and retrieving script hooks.
* Addon mods can register custom hooks that will appear in the script editor GUIs.
*
* Available contexts:
* - "npc" - NPC script editor
* - "player" - Player scripts editor
* - "block" - Scripted block editor
* - "item" - Scripted item editor
* - "linked_item" - Linked item editor
* - "forge" - Forge scripts editor
* - "global_npc" - Global NPC scripts editor
* - "recipe" - Recipe scripts editor
* - "effect" - Custom effect scripts editor
* <h3>Available contexts:</h3>
* <ul>
* <li>"npc" - NPC script editor</li>
* <li>"player" - Player scripts editor</li>
* <li>"block" - Scripted block editor</li>
* <li>"item" - Scripted item editor</li>
* <li>"linked_item" - Linked item editor</li>
* <li>"forge" - Forge scripts editor</li>
* <li>"global_npc" - Global NPC scripts editor</li>
* <li>"recipe" - Recipe scripts editor</li>
* <li>"effect" - Custom effect scripts editor</li>
* </ul>
*
* <h3>Rich Hook Registration (Recommended)</h3>
* Use {@link #registerHookDefinition(String, IHookDefinition)} for full metadata support:
* <pre>{@code
* hooks.registerHookDefinition("player", HookDefinition.builder("onDBCTransform")
* .eventClass(IDBCEvent.TransformEvent.class)
* .requiredImports("com.dbc.api.event.IDBCEvent")
* .cancelable(true)
* .build());
* }</pre>
*/
public interface IScriptHookHandler {
// ==================== RICH HOOK REGISTRATION (NEW) ====================
/**
* Register a hook for a single context.
* Register a hook with full metadata including event type, imports, and cancelability.
* This is the recommended way to register addon hooks.
*
* @param context The context identifier (e.g., "npc", "player", "block")
* @param definition The hook definition containing all metadata
*/
void registerHookDefinition(String context, IHookDefinition definition);
/**
* Get the hook definition for a specific hook.
*
* @param context The context identifier
* @param hookName The hook function name
* @return The hook definition, or null if not found or no metadata available
*/
IHookDefinition getHookDefinition(String context, String hookName);
/**
* Get all hook definitions for a context.
*
* @param context The context identifier
* @return List of all hook definitions (may be empty, never null)
*/
List<IHookDefinition> getAllHookDefinitions(String context);
/**
* Get the current hook revision number.
* This increments each time a hook is registered, allowing caches to invalidate.
*
* @return The current revision number
*/
int getHookRevision();
// ==================== LEGACY HOOK REGISTRATION ====================
/**
* Register a hook for a single context (legacy method).
* Creates a minimal definition without event type metadata.
*
* @param context The context identifier (e.g., "npc", "player", "block")
* @param functionName The script function name (e.g., "onMyCustomEvent")