ReDragon2013 Posted January 15, 2022 Share Posted January 15, 2022 (edited) Unfortuantely papyrus script language is not always very easy to understand. Very often is an 'improvement' of vanilla scripts, a step forward to get runtime errors with improved version.But here we have a papyrus compiler bug. https://web.archive.org/web/20200216210550/http://forums.bethsoft.com/topic/1610844-ckse-persisting-script-engine-bugs/ THHIS BUG WAS NEVER SOLVED by any release of UNOFFICIAL PATCHES! Inci wrote (2016-Nov-01):"The compiler for SSE is still unable to properly manage temporary variables, when it compiles a nested function call inside an array index evaluation. Such a statement is compiled in a way, which causes temporary variable corruption during execution. This is the issue of 'myArray[myArray.Find(none)] = newValue' not working properly (although the same issue would actually affect a larger range of possible cases). Unfortunately, as the forum search functionality is still unavailable, I am unable to find and link to the thread, where this was originally discussed." DLC1ReferenceAliasArrayScript (vanilla code) Scriptname DLC1ReferenceAliasArrayScript extends Quest ;jduvall -- please talk to me before changing this script ReferenceAlias[] Property AliasArray auto {All the arrays that make up the "array"} objectReference[] Property RefArray auto ;we are using a seperate array to hold references and shuffling refs around in that because its much less overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin {IMPORTANT! This needs to be an array of empty values with the same number of values as the number of aliases in AliasArray.} bool Property TraceAliasRefs auto {Debug: default = false, if true will debug.trace() contents of all the aliases in the array after ForceRefInto() or ClearRefFrom()} bool threadLock Function LockThread() while threadLock utility.wait(1) endWhile threadLock = true EndFunction Function UnlockThread() threadLock = false EndFunction bool Function ForceRefInto(objectReference RefToAdd) LockThread() bool ReturnBool int foundRefIndex = RefArray.find(RefToAdd) if foundRefIndex >= 0 Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) is already in alias [" + AliasArray[foundRefIndex] + "], so NOT forcing into anything and will RETURN FALSE.") returnBool = false else objectReference RefToReplace = PromoteRefs() ReferenceAlias AliasToReplace = FindRef(RefToReplace) Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) will and force reference into " + AliasToReplace) RefArray[0] = RefToAdd AliasToReplace.ForceRefTo(RefToAdd) returnBool = true endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction bool Function ClearRefFrom(objectReference RefToClear) LockThread() bool ReturnBool ReferenceAlias FoundAlias = FindRef(RefToClear) if FoundAlias Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) found Reference in Alias [" + FoundAlias + "], so will clear alias and RETURN TRUE") FoundAlias.Clear() RefArray[RefArray.Find(RefToClear)] = None ; !!! PAPYRUS !!! returnBool = true else Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) did NOT find reference in any aliases, will NOT clear anything, and will RETURN FALSE") returnBool = false endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction ReferenceAlias Function FindRef(objectReference RefToFind) debug.Trace(self + "FindRef([" + RefToFind + "])") int index = 0 bool found = false ReferenceAlias AliasToReturn while (index < AliasArray.Length) && found == false if AliasArray[index].GetReference() == RefToFind AliasToReturn = AliasArray[index] found = true endif index += 1 endWhile Debug.Trace(self + "FindRef([" + RefToFind + "]) found in alias " + AliasToReturn) RETURN AliasToReturn EndFunction objectReference Function PromoteRefs() Debug.Trace(self + "PromoteRefs()") int index = RefArray.Length - 1 objectReference RefToReturn = RefArray[index] while (index > 0) objectReference currentRef = RefArray[index - 1] if currentRef RefArray[index] = (currentRef) endif index -= 1 endWhile return RefToReturn EndFunction function TraceArrayRefs() int index = 0 while (index < AliasArray.Length) debug.trace("Alias: " + AliasArray[Index] + " has reference: " + AliasArray[Index].GetReference()) index += 1 endWhile EndFunction DLC1ReferenceAliasArrayScript (Usleep version) Scriptname DLC1ReferenceAliasArrayScript extends Quest ;jduvall -- please talk to me before changing this script ReferenceAlias[] Property AliasArray auto {All the arrays that make up the "array"} objectReference[] Property RefArray auto ;we are using a seperate array to hold references and shuffling refs around in that because its much less overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin {IMPORTANT! This needs to be an array of empty values with the same number of values as the number of aliases in AliasArray.} bool Property TraceAliasRefs auto {Debug: default = false, if true will debug.trace() contents of all the aliases in the array after ForceRefInto() or ClearRefFrom()} bool threadLock Function LockThread() while threadLock utility.wait(1) endWhile threadLock = true EndFunction Function UnlockThread() threadLock = false EndFunction bool Function ForceRefInto(objectReference RefToAdd) LockThread() bool ReturnBool int foundRefIndex = RefArray.find(RefToAdd) if foundRefIndex >= 0 ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) is already in alias [" + AliasArray[foundRefIndex] + "], so NOT forcing into anything and will RETURN FALSE.") returnBool = false else objectReference RefToReplace = PromoteRefs() ReferenceAlias AliasToReplace = FindRef(RefToReplace) ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) will and force reference into " + AliasToReplace) RefArray[0] = RefToAdd AliasToReplace.ForceRefTo(RefToAdd) returnBool = true endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction bool Function ClearRefFrom(objectReference RefToClear) LockThread() bool ReturnBool ReferenceAlias FoundAlias = FindRef(RefToClear) if FoundAlias ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) found Reference in Alias [" + FoundAlias + "], so will clear alias and RETURN TRUE") FoundAlias.Clear() RefArray[RefArray.Find(RefToClear)] = None ; !!! PAPYRUS !!! returnBool = true else ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) did NOT find reference in any aliases, will NOT clear anything, and will RETURN FALSE") returnBool = false endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction ReferenceAlias Function FindRef(objectReference RefToFind) ;debug.Trace(self + "FindRef([" + RefToFind + "])") int index = 0 bool found = false ReferenceAlias AliasToReturn while (index < AliasArray.Length) && found == false if AliasArray[index].GetReference() == RefToFind AliasToReturn = AliasArray[index] found = true endif index += 1 endWhile ;Debug.Trace(self + "FindRef([" + RefToFind + "]) found in alias " + AliasToReturn) RETURN AliasToReturn EndFunction objectReference Function PromoteRefs() ;Debug.Trace(self + "PromoteRefs()") int index = RefArray.Length - 1 objectReference RefToReturn = RefArray[index] while (index > 0) objectReference currentRef = RefArray[index - 1] if currentRef RefArray[index] = (currentRef) endif index -= 1 endWhile return RefToReturn EndFunction function TraceArrayRefs() int index = 0 while (index < AliasArray.Length) ;debug.trace("Alias: " + AliasArray[Index] + " has reference: " + AliasArray[Index].GetReference()) index += 1 endWhile EndFunction DLC1ReferenceAliasArrayScript (subhuman version) Scriptname DLC1ReferenceAliasArrayScript extends Quest ;jduvall -- please talk to me before changing this script ReferenceAlias[] Property AliasArray auto {All the arrays that make up the "array"} objectReference[] Property RefArray auto ;we are using a seperate array to hold references and shuffling refs around in that because its much less overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin {IMPORTANT! This needs to be an array of empty values with the same number of values as the number of aliases in AliasArray.} bool Property TraceAliasRefs auto {Debug: default = false, if true will debug.trace() contents of all the aliases in the array after ForceRefInto() or ClearRefFrom()} bool threadLock Function LockThread() while threadLock ; VSmO subhuman - 1 second is far too long to wait for array accesses, when papyrus can do thousands per second ; utility.wait(1) utility.wait(0.1) endWhile threadLock = true EndFunction Function UnlockThread() threadLock = false EndFunction bool Function ForceRefInto(objectReference RefToAdd) LockThread() bool ReturnBool int foundRefIndex = RefArray.find(RefToAdd) if foundRefIndex >= 0 ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) is already in alias [" + AliasArray[foundRefIndex] + "], so NOT forcing into anything and will RETURN FALSE.") returnBool = false else objectReference RefToReplace = PromoteRefs() ReferenceAlias AliasToReplace = FindRef(RefToReplace) ;Debug.Trace(self + "ForceRefInto([" + RefToAdd + "]) will and force reference into " + AliasToReplace) RefArray[0] = RefToAdd AliasToReplace.ForceRefTo(RefToAdd) returnBool = true endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction bool Function ClearRefFrom(objectReference RefToClear) LockThread() bool ReturnBool ReferenceAlias FoundAlias = FindRef(RefToClear) if FoundAlias ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) found Reference in Alias [" + FoundAlias + "], so will clear alias and RETURN TRUE") FoundAlias.Clear() RefArray[RefArray.Find(RefToClear)] = None returnBool = true else ;Debug.Trace(self + "ClearRefFrom([" + RefToClear + "]) did NOT find reference in any aliases, will NOT clear anything, and will RETURN FALSE") returnBool = false endif if TraceAliasRefs TraceArrayRefs() endif UnlockThread() return returnBool EndFunction ReferenceAlias Function FindRef(objectReference RefToFind) ;debug.Trace(self + "FindRef([" + RefToFind + "])") ; VSmO subhuman int index = 0 while index < AliasArray.Length if AliasArray[index].GetReference() == RefToFind return AliasArray[index] endIf index += 1 endWhile return none ;/ int index = 0 bool found = false ReferenceAlias AliasToReturn while (index < AliasArray.Length) && found == false if AliasArray[index].GetReference() == RefToFind AliasToReturn = AliasArray[index] found = true endif index += 1 endWhile ;Debug.Trace(self + "FindRef([" + RefToFind + "]) found in alias " + AliasToReturn) RETURN AliasToReturn/; EndFunction objectReference Function PromoteRefs() ;Debug.Trace(self + "PromoteRefs()") int index = RefArray.Length - 1 objectReference RefToReturn = RefArray[index] while (index > 0) objectReference currentRef = RefArray[index - 1] if currentRef RefArray[index] = (currentRef) endif index -= 1 endWhile return RefToReturn EndFunction function TraceArrayRefs() ;/ int index = 0 while (index < AliasArray.Length) ;debug.trace("Alias: " + AliasArray[Index] + " has reference: " + AliasArray[Index].GetReference()) index += 1 endWhile/; EndFunction Edited January 15, 2022 by ReDragon2013 Link to comment Share on other sites More sharing options...
ReDragon2013 Posted January 15, 2022 Author Share Posted January 15, 2022 (edited) I would suggest next code for this script. Keep in mind the script "DLC2ReferenceAliasArrayScript" has the same bug! DLC1ReferenceAliasArrayScript Scriptname DLC1ReferenceAliasArrayScript extends Quest {v1.5 ReDragon 2021} ; *** jduvall -- please talk to me before changing this script ; IMPORTANT! This needs to be an array of empty values with the same number of values as aliases in AliasArray. ReferenceAlias[] PROPERTY AliasArray auto ; All the aliases that make up the "array" ObjectReference[] PROPERTY RefArray auto ; "We are using a seperate array to hold references and shuffling refs around in that because it's much less ; overhead than shuffling refs into and out of aliases - requested by mlipari and jlundin" (Bethesda) Bool threadLock ; -- FUNCTIONs -- 3 + 1 + 2 Bool PROPERTY TraceAliasRefs auto ; [Default=False] for debugging ; if TRUE, will debug.trace() all the aliases in the array after 'ForceRefInto()' or 'ClearRefFrom()' ;------------------------ FUNCTION TraceArrayRefs() ; for debugging only ;------------------------ ;int i = 0 ; WHILE (i < AliasArray.Length) ;;; Debug.Trace("Alias: "+AliasArray[i]+" has "+AliasArray[i].GetReference()) ; i = i + 1 ; ENDWHILE ENDFUNCTION ;FUNCTION LockThread() ; UnUSED by now ;ENDFUNCTION ;---------------------- FUNCTION UnlockThread() ;---------------------- threadLock = False ENDFUNCTION ;---------------------------------------------------- ReferenceAlias FUNCTION FindRef(ObjectReference oRef) ; oRef = RefToFind ;---------------------------------------------------- int i = 0 ; i = index, search now from bottom to top WHILE (i < AliasArray.Length) referenceAlias RA = AliasArray[i] ; RA = AliasToReturn IF ( RA ) IF (oRef == RA.GetReference()) RETURN RA ; objRef was found (could be an unassigned alias, if oRef == None) ENDIF ENDIF i = i + 1 ENDWHILE ;; Debug.Trace(self+" FindRef() - Could not found " +oRef+ ".. RETURN <None>") RETURN None ENDFUNCTION ;################ ;### ClearRef ######################################################################################## ;################ ;----------------------------------------------- Bool FUNCTION ClearRefFrom(ObjectReference oRef) ; oRef = RefToClear ;----------------------------------------------- WHILE (threadLock) Utility.Wait(1.0) ENDWHILE threadLock = TRUE ; *T* ;======================= referenceAlias RA = FindRef(oRef) ; RA = FoundAlias IF ( RA ) RA.Clear() ; unassigned objRef from Alias ELSE ;; Debug.Trace(self+" ClearRefFrom() - Did not find " +oRef+ " in any aliases.. RETURN False.") threadLock = False ; *** Return False ENDIF ;--------- int i = RefArray.Find(oRef) ; find position RefArray[i] = None ; and clear the entry right now ;;; RefArray[RefArray.Find(RefToClear)] = None ; Buggy! (ReDragon) ;;================================================== ; http://www.creationkit.com/Arrays_%28Papyrus%29 ; http://www.creationkit.com/index.php?title=Arrays_(Papyrus) ; The array Find() function cannot be used within an arrays element index brackets !!! ; ; myArray[myArray.Find(none)] = newValue ; no error on compiling, but ingame it will not work correctly and the value is not filled as expected. ; ; int i = myArray.Find(None) ; find the first blank element ; myArray[i] = newValue ; and fill it with our newValue ;;================================================== threadLock = False ; *** Return TRUE ENDFUNCTION ;################ ;### ForceRef ######################################################################################## ;################ 2 ;----------------------------------------------- Bool FUNCTION ForceRefInto(ObjectReference oRef) ; oRef = RefToAdd ;----------------------------------------------- ; called by "DLC1VampireMesmerizeScript", "DLC1VampireTurnScript" WHILE (threadLock) Utility.Wait(1.0) ENDWHILE threadLock = TRUE ; *T* ;======================= int i = RefArray.Find(oRef) ; i = foundRefIndex IF (i >= 0) ;; Debug.Trace(self+" ForceRefInto("+i+") - " +oRef+ " was already found in RefArray.. RETURN False.") threadLock = False ; *** Return False ENDIF ;--------- objectReference lastRef = PromoteRefs() ; lastRef = RefToReplace referenceAlias RA = FindRef(lastRef) ; RA = AliasToReplace lastRef = None IF ( RA ) ;; Debug.Trace(self + "ForceRefInto([" +oRef+ "]) will force reference into " +RA+ " which is also returned") RefArray[0] = oRef RA.ForceRefTo(oRef) ENDIF threadLock = False ; *** RETURN (RA as Bool) ; returns TRUE or False, depends on valid RefAlias ENDFUNCTION ;------------------------------------- ObjectReference FUNCTION PromoteRefs() ; internal only ;------------------------------------- objectReference lastRef ; lastRef = RefToReturn objectReference oRef ; oRef = currentRef int i = RefArray.Length - 1 ; i = index IF (i >= 0) lastRef = RefArray[i] ENDIF WHILE (i > 0) ; Do not allow a negative value here !!! oRef = RefArray[i - 1] IF ( oRef ) RefArray[i] = oRef ENDIF i = i - 1 ENDWHILE RETURN lastRef ENDFUNCTION Edited January 15, 2022 by ReDragon2013 Link to comment Share on other sites More sharing options...
Recommended Posts