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 8b6c08c0c..974e25b29 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 @@ -2241,13 +2241,23 @@ public class ScriptDocument { if (isExcluded(segPos[0])) continue; + boolean isLastSegment = (i == chainSegments.size() - 1); + boolean isStaticAccessSeg = false; + if (i - 1 >= 0) { + String prev = chainSegments.get(i - 1); + if (!prev.isEmpty() && Character.isUpperCase(prev.charAt(0))) + isStaticAccessSeg = true; + } + // Handle the first segment if we're marking it (i.e., when preceded by dot) if (i == 0 && firstIsPrecededByDot) { // This is a field access on a receiver (e.g., the "thePlayer" in "getMinecraft().thePlayer") TypeInfo receiverType = resolveReceiverChain(chainStart); if (receiverType != null && receiverType.hasField(segment)) { FieldInfo fieldInfo = receiverType.getFieldInfo(segment); - marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, fieldInfo)); + FieldAccessInfo accessInfo = createFieldAccessInfo(segment, segPos[0], segPos[1], receiverType, fieldInfo, isLastSegment, isStaticAccessSeg); + + marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, accessInfo)); currentType = (fieldInfo != null) ? fieldInfo.getTypeInfo() : null; } else { marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.UNDEFINED_VAR)); @@ -2270,26 +2280,9 @@ public class ScriptDocument { FieldInfo fieldInfo = currentType.getFieldInfo(segment); // Check if this is the last segment and if it's in an assignment context - boolean isLastSegment = (i == chainSegments.size() - 1); - if (isLastSegment) { - // Create FieldAccessInfo for validation - boolean isStaticAccess = Character.isUpperCase(chainSegments.get(i-1).charAt(0)); - FieldAccessInfo accessInfo = new FieldAccessInfo( - segment, segPos[0], segPos[1], currentType, fieldInfo, isStaticAccess - ); - - // Set expected type from assignment context - TypeInfo expectedType = findExpectedTypeAtPosition(segPos[0]); - if (expectedType != null) { - accessInfo.setExpectedType(expectedType); - } - - accessInfo.validate(); - fieldAccesses.add(accessInfo); - marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, accessInfo)); - } else { - marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, fieldInfo)); - } + // Create and mark FieldAccessInfo for this segment (last or intermediate) + FieldAccessInfo accessInfo = createFieldAccessInfo(segment, segPos[0], segPos[1], currentType, fieldInfo, isLastSegment, isStaticAccessSeg); + marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, accessInfo)); // Update currentType for next segment currentType = (fieldInfo != null) ? fieldInfo.getTypeInfo() : null; @@ -2368,25 +2361,14 @@ public class ScriptDocument { hasMoreSegments = true; } - if (!hasMoreSegments) { - // This is the final field - create FieldAccessInfo for validation - boolean isStaticAccess = false; // Determine based on receiver - FieldAccessInfo accessInfo = new FieldAccessInfo( - firstField, identStart, identEnd, receiverType, fInfo, isStaticAccess - ); - - // Set expected type from assignment context - TypeInfo expectedType = findExpectedTypeAtPosition(identStart); - if (expectedType != null) { - accessInfo.setExpectedType(expectedType); - } - - accessInfo.validate(); - fieldAccesses.add(accessInfo); - marks.add(new ScriptLine.Mark(identStart, identEnd, TokenType.GLOBAL_FIELD, accessInfo)); - } else { - marks.add(new ScriptLine.Mark(identStart, identEnd, TokenType.GLOBAL_FIELD, fInfo)); + boolean isStaticAccessFirst = false; + if (receiverType != null) { + String recvName = receiverType.getSimpleName(); + if (recvName != null && !recvName.isEmpty() && Character.isUpperCase(recvName.charAt(0))) + isStaticAccessFirst = true; } + FieldAccessInfo accessInfoFirst = createFieldAccessInfo(firstField, identStart, identEnd, receiverType, fInfo, !hasMoreSegments, isStaticAccessFirst); + marks.add(new ScriptLine.Mark(identStart, identEnd, TokenType.GLOBAL_FIELD, accessInfoFirst)); } else { marks.add(new ScriptLine.Mark(identStart, identEnd, TokenType.UNDEFINED_VAR)); } @@ -2435,25 +2417,14 @@ public class ScriptDocument { if (currentType != null && currentType.isResolved() && currentType.hasField(seg)) { FieldInfo segInfo = currentType.getFieldInfo(seg); - if (isLastSegment) { - // Create FieldAccessInfo for validation - boolean isStaticAccess = false; - FieldAccessInfo accessInfo = new FieldAccessInfo( - seg, nStart, nEnd, currentType, segInfo, isStaticAccess - ); - - // Set expected type from assignment context - TypeInfo expectedType = findExpectedTypeAtPosition(nStart); - if (expectedType != null) { - accessInfo.setExpectedType(expectedType); - } - - accessInfo.validate(); - fieldAccesses.add(accessInfo); - marks.add(new ScriptLine.Mark(nStart, nEnd, TokenType.GLOBAL_FIELD, accessInfo)); - } else { - marks.add(new ScriptLine.Mark(nStart, nEnd, TokenType.GLOBAL_FIELD, segInfo)); + boolean isStaticAccessSeg2 = false; + if (currentType != null) { + String tn = currentType.getSimpleName(); + if (tn != null && !tn.isEmpty() && Character.isUpperCase(tn.charAt(0))) + isStaticAccessSeg2 = true; } + FieldAccessInfo accessInfoSeg = createFieldAccessInfo(seg, nStart, nEnd, currentType, segInfo, isLastSegment, isStaticAccessSeg2); + marks.add(new ScriptLine.Mark(nStart, nEnd, TokenType.GLOBAL_FIELD, accessInfoSeg)); currentType = (segInfo != null) ? segInfo.getTypeInfo() : null; } else { @@ -2626,6 +2597,25 @@ public class ScriptDocument { // ==================== UTILITY METHODS ==================== + /** + * Helper to create and validate a FieldAccessInfo. Does NOT add marks or register the info — + * callers should add to `fieldAccesses` and `marks` as appropriate so marking logic remains in-place. + */ + private FieldAccessInfo createFieldAccessInfo(String name, int start, int end, + TypeInfo receiverType, FieldInfo fieldInfo, + boolean isLastSegment, boolean isStaticAccess) { + FieldAccessInfo accessInfo = new FieldAccessInfo(name, start, end, receiverType, fieldInfo, isStaticAccess); + if (isLastSegment) { + TypeInfo expectedType = findExpectedTypeAtPosition(start); + if (expectedType != null) { + accessInfo.setExpectedType(expectedType); + } + } + accessInfo.validate(); + fieldAccesses.add(accessInfo); + return accessInfo; + } + private FieldInfo resolveVariable(String name, int position) { // Find containing method MethodInfo containingMethod = findMethodAtPosition(position); 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 8a66f69f0..ac42241b8 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 @@ -155,6 +155,8 @@ public class ScriptLine { token.setMethodCallInfo((MethodCallInfo) mark.metadata); } else if (mark.metadata instanceof ImportData) { token.setImportData((ImportData) mark.metadata); + }else if (mark.metadata instanceof FieldAccessInfo) { + token.setFieldAccessInfo((FieldAccessInfo) mark.metadata); } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/Token.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/Token.java index f55d906e6..cbbb1645e 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/Token.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/Token.java @@ -25,7 +25,9 @@ public class Token { private MethodInfo methodInfo; // For method calls/declarations private MethodCallInfo methodCallInfo; // For method calls with argument info private ImportData importData; // For import statements - + private FieldAccessInfo fieldAccessInfo; //For fields like Minecraft.getMinecraft.thePlayer + + // Navigation - set by ScriptLine private Token prev; private Token next; @@ -115,6 +117,7 @@ public class Token { public FieldInfo getFieldInfo() { return fieldInfo; } public MethodInfo getMethodInfo() { return methodInfo; } public MethodCallInfo getMethodCallInfo() { return methodCallInfo; } + public FieldAccessInfo getFieldAccessInfo() { return fieldAccessInfo; } public ImportData getImportData() { return importData; } public ScriptLine getParentLine() { return parentLine; } @@ -123,6 +126,7 @@ public class Token { public void setType(TokenType type) { this.type = type; } public void setTypeInfo(TypeInfo info) { this.typeInfo = info; } public void setFieldInfo(FieldInfo info) { this.fieldInfo = info; } + public void setFieldAccessInfo(FieldAccessInfo info) { this.fieldAccessInfo = info; } public void setMethodInfo(MethodInfo info) { this.methodInfo = info; } public void setMethodCallInfo(MethodCallInfo info) { this.methodCallInfo = info; } public void setImportData(ImportData data) { this.importData = data; }