Jump to content

DLC1ReferenceAliasArrayScript (subhuman VSmO 1.14)


Recommended Posts

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 by ReDragon2013
Link to comment
Share on other sites

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 by ReDragon2013
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...