Fix hook signatures to follow runtime hook registrations in ScriptHookController.

This fixes broken unresolved DBC addon hook event types
This commit is contained in:
bigguy345 committed 2026-03-02 02:28:01 +02:00
1 parent 36f7233297
commit 32fd6af04f
5 files changed
+115 -10

No files matched your search

@@ -25,6 +25,7 @@ import noppes.npcs.client.gui.util.IGuiData;
import noppes.npcs.client.gui.util.IJTextAreaListener;
import noppes.npcs.client.gui.util.ITextChangeListener;
import noppes.npcs.client.gui.util.ITextfieldListener;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSTypeRegistry;
import noppes.npcs.constants.ScriptContext;
import noppes.npcs.controllers.ScriptContainer;
import noppes.npcs.controllers.ScriptController;
@@ -115,6 +116,12 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
// Initialize hooks from handler
gui.hookList = new ArrayList<>(handler.getHooks());
JSTypeRegistry registry = JSTypeRegistry.getInstance();
if (!registry.isInitialized()) {
registry.initializeFromResources();
}
registry.syncHooksFromScriptHookControllerIfNeeded();
// Request data from server
if (handler instanceof IScriptHandlerPacket)
((IScriptHandlerPacket) handler).requestData();
@@ -26,6 +26,7 @@ import noppes.npcs.client.gui.util.script.interpreter.type.synthetic.SyntheticTy
import noppes.npcs.client.gui.util.script.ScopeInfo;
import noppes.npcs.constants.ScriptContext;
import noppes.npcs.controllers.data.DataScript;
import noppes.npcs.controllers.ScriptHookController;
import java.util.*;
import java.util.function.Function;
@@ -925,20 +926,38 @@ public class ScriptDocument {
TypeInfo returnType = TypeInfo.fromPrimitive("void");
List<String> namespaces = scriptContext != null ? scriptContext.getNamespaces() : Collections.singletonList("Global");
if (typeResolver.isJSHook(namespaces, funcName)) {
List<JSTypeRegistry.HookSignature> sigs = typeResolver.getJSHookSignatures(namespaces, funcName);
if (!sigs.isEmpty()) {
JSTypeRegistry.HookSignature sig = sigs.get(0);
documentation = sig.doc;
// Infer parameter types from hook signature
boolean runtimeHook = false;
if (ScriptHookController.Instance != null && scriptContext != null) {
String hookContext = scriptContext.hookContext;
if (hookContext != null && !hookContext.isEmpty()) {
runtimeHook = ScriptHookController.Instance.hasHook(hookContext, funcName);
}
}
if (runtimeHook) {
if (typeResolver.isJSHook(namespaces, funcName)) {
List<JSTypeRegistry.HookSignature> sigs = typeResolver.getJSHookSignatures(namespaces, funcName);
if (!sigs.isEmpty()) {
JSTypeRegistry.HookSignature sig = sigs.get(0);
documentation = sig.doc;
if (paramList != null && !paramList.trim().isEmpty()) {
String[] paramNames = paramList.split(",");
if (paramNames.length > 0) {
String paramName = paramNames[0].trim();
TypeInfo paramType = typeResolver.resolveJSType(sig.paramType);
int paramStart = m.start(2) + paramList.indexOf(paramName);
params.add(FieldInfo.parameter(paramName, paramType, paramStart, null));
}
}
}
} else {
if (paramList != null && !paramList.trim().isEmpty()) {
String[] paramNames = paramList.split(",");
if (paramNames.length > 0) {
String paramName = paramNames[0].trim();
TypeInfo paramType = typeResolver.resolveJSType(sig.paramType);
int paramStart = m.start(2) + paramList.indexOf(paramName);
params.add(FieldInfo.parameter(paramName, paramType, paramStart, null));
params.add(FieldInfo.parameter(paramName, TypeInfo.unresolved("any", "any"), paramStart, null));
}
}
}
@@ -4,6 +4,8 @@ import net.minecraft.client.Minecraft;
import net.minecraft.util.ResourceLocation;
import noppes.npcs.scripted.NpcAPI;
import noppes.npcs.client.gui.util.script.interpreter.bridge.DtsJavaBridge;
import noppes.npcs.api.handler.IHookDefinition;
import noppes.npcs.controllers.ScriptHookController;
import java.io.*;
import java.net.URL;
@@ -59,6 +61,7 @@ public class JSTypeRegistry {
private boolean initialized = false;
private boolean initializationAttempted = false;
private int lastSyncedHookRevision = -1;
private String currentSource = null;
@@ -845,6 +848,80 @@ public class JSTypeRegistry {
initialized = false;
initializationAttempted = false;
currentSource = null;
lastSyncedHookRevision = -1;
}
/**
* Sync hook signatures from ScriptHookController into this registry.
* Uses revision-gating so repeated calls are no-ops when nothing changed.
*/
public void syncHooksFromScriptHookControllerIfNeeded() {
try {
if (ScriptHookController.Instance == null) {
return;
}
int currentRevision = ScriptHookController.Instance.getHookRevision();
if (currentRevision == lastSyncedHookRevision) {
return;
}
hooks.clear();
contextHooks.clear();
Set<String> seen = new HashSet<>();
String[] contexts = ScriptHookController.Instance.getContexts();
if (contexts != null) {
for (String context : contexts) {
if (context == null || context.isEmpty()) {
continue;
}
List<IHookDefinition> defs = ScriptHookController.Instance.getAllHookDefinitions(context);
if (defs == null || defs.isEmpty()) {
continue;
}
for (IHookDefinition def : defs) {
if (def == null) {
continue;
}
String hookName = def.hookName();
if (hookName == null || hookName.isEmpty()) {
continue;
}
String usableTypeName = def.getUsableTypeName();
String namespace;
String paramType;
if (usableTypeName != null && usableTypeName.contains(".")) {
namespace = usableTypeName.substring(0, usableTypeName.indexOf('.'));
} else {
namespace = GLOBAL_NAMESPACE;
}
paramType = usableTypeName != null ? usableTypeName : "any";
String[] paramNames = def.paramNames();
String paramName = (paramNames != null && paramNames.length > 0 && paramNames[0] != null && !paramNames[0].isEmpty())
? paramNames[0]
: "event";
String dedupKey = namespace + "|" + hookName + "|" + paramType + "|" + paramName;
if (!seen.add(dedupKey)) {
continue;
}
registerHook(namespace, hookName, paramName, paramType);
}
}
}
lastSyncedHookRevision = currentRevision;
} catch (Throwable t) {
System.err.println("[JSTypeRegistry] Failed to sync runtime hooks: " + t.getMessage());
t.printStackTrace();
}
}
private void setCurrentSource(String source) {
@@ -123,7 +123,8 @@ public class TypeScriptDefinitionParser {
public void parseDefinitionFile(String content, String fileName) {
// Special handling for hooks.d.ts - extract function signatures
if (fileName.contains("hooks.d.ts")) {
parseHooksFile(content);
// Commented out as hooks are now parsed through ScriptHookController which is the universal source of truth for registered hooks.
// parseHooksFile(content);
return;
}
@@ -141,6 +141,7 @@ public class TypeResolver {
if (!jsTypeRegistry.isInitialized()) {
jsTypeRegistry.initializeFromResources();
}
jsTypeRegistry.syncHooksFromScriptHookControllerIfNeeded();
}
return jsTypeRegistry;
}