User:QQuix/Array sample code

From the Oblivion ConstructionSet Wiki
< User:QQuix
Revision as of 10:06, 16 June 2009 by imported>QQuix (Sample code added - Array walk)
Jump to navigation Jump to search
This is a piece of code I wrote for my tests and thought might be of use to somebody else.

Feel free to edit/rephrase/correct/rename/move/whatever the contents of this page as you see fit.

QQuix 18:38, 24 May 2009 (EDT)

Array deep dump

Introduction

With the availability of arrays in OBSE 0017, it is quite easy (an useful) to create tree-like arrays to keep data available and organized.

OBSE 0017 also has a great debugging function to dump an array contents into the console: ar_Dump

This code has the same debugging purpose as ar_Dump, but intended to show the contents of nested arrays, or arrays within arrays.

It dumps the array to the console and to a text file (requires Pluggy), but either can be easily removed, if you prefer. It is also easy to customize the contents and formatting to your liking.

Optionally, you may limit the number of levels to dump.

It has two modes.

Mode 1

Shows the Keys within brackets, followed by: #Array ID and array size (if an array) or the contents

===== Deep dump Mode 1 - Array: [ObjectTree] =====
[Architecture]  #410  2
= [Anvil]  #415  3
= = [AnvilFightersGuild01]  #416  3
= = = [EditorID] = 'AnvilFightersGuild01'
= = = [FormID] = 000496C5 <no name>
= = = [Size] = 22
= = [AnvilHouseMC01]  #417  0
= = [AnvilLighthouse01]  #418  0
= [Chorrol]  #419  1
= = [Interior]  #420  1
= = = [ChorrolHouseMiddle03Interior]  #421  3
= = = = [EditorID] = 'ChorrolHouseMiddle03Interior'
= = = = [FormID] = 0002B75F <no name>
= = = = [Size] = 11
[Clutter]  #414  0

Mode 2

Shows one line for every end-of branch

===== Deep dump Mode 2 - Array: [ObjectTree] =====
[ObjectTree][Architecture][Anvil][AnvilFightersGuild01][EditorID] = 'AnvilFightersGuild01'
[ObjectTree][Architecture][Anvil][AnvilFightersGuild01][FormID] = 000496C5 <no name>
[ObjectTree][Architecture][Anvil][AnvilFightersGuild01][Size] = 22
[ObjectTree][Architecture][Anvil][AnvilHouseMC01] = #Empty#
[ObjectTree][Architecture][Anvil][AnvilLighthouse01] = #Empty#
[ObjectTree][Architecture][Chorrol][Interior][ChorrolHouseMiddle03Interior][EditorID] =  ChorrolHouseMiddle03Interior'
[ObjectTree][Architecture][Chorrol][Interior][ChorrolHouseMiddle03Interior][FormID] = 0002B75F <no name>
[ObjectTree][Architecture][Chorrol][Interior][ChorrolHouseMiddle03Interior][Size] = 11
[ObjectTree][Clutter] = #Empty#

Setup

The following script must be attached to some persistent objects.

You need one object for each level of array depth you may have.

The first object handles arrays at level 0 and also holds the 'global' variables used for iteration. A different object handles level 1 and so forth.

For this example, we are considering a 5-level deep array called ObjectTree.

It is presumed that:

  • six activators were created called: aaqqArrayDumpBase and aaqqArrayDumpL1Base to aaqqArrayDumpL5Base. All six base objects use the same script.
  • six persistent references were created called aaqqArrayDump and aaqqArrayDumpL1 to aaqqArrayDumpL5


This code shows how to set the variables and activate the first object:

array_var aLibObjectTree

let aaqqArrayDump.iaArray := aLibObjectTree      ; set array to dump
let aaqqArrayDump.isArrayName := "ObjectTree"    ; set array name - for the header
let aaqqArrayDump.iMode := 1                     ; set Mode
let aaqqArrayDump.iDepth := 3                    ; Number of levels to dump (0 = All)
aaqqArrayDump.activate player 1


Script

scn aaqqArrayDumpSCRIPT

array_var iaArray
string_var isArrayName
short iMode

array_var gaKeys
array_var gaArrays 
short gMaxLevel

ref xSelf
ref xNext
ref xRef
 
array_var aArray
array_var aEntry
array_var aTemp

string_var sKey
string_var sKey1
string_var sType
string_var sText
string_var sLine
string_var sTab
string_var sTab0
string_var sTab1
string_var sTab2
string_var sTab3
string_var sTab4
string_var sTab5

float xVal

short xLevel
short xNextLevel
short xMaxLevel

;=== Pluggy string vars ===
long psFile 
long psLine


begin onactivate
  set iMode to aaqqArrayDump.iMode 

  if xSelf == 0 || getgameloaded
    ;=== Initialize ===
    ;==============
    set xSelf to getself

    set psFile to CreateString -1 "QQuix Library - Array dump.log" 1 1
    set psLine to CreateString -1 0  1 1

    let sTab0 := "" 
    let sTab1 := "= " 
    let sTab2 := "= = " 
    let sTab3 := "= = = " 
    let sTab4 := "= = = = "
    let sTab5 := "= = = = =" 


    if xSelf == aaqqArrayDump
      set xLevel to 0
      let sTab := sTab0
      set xNext to aaqqArrayDumpL1

      ;=== Init 'global' vars ===
      let gaKeys := ar_Construct Array
      let gaArrays := ar_Construct Array
      let gaKeys [0] := isArrayName
      let gaArrays [0] := iaArray
    elseif xSelf == aaqqArrayDumpL1
      set xLevel to 1
      let sTab := sTab1
      set xNext to aaqqArrayDumpL2
    elseif xSelf == aaqqArrayDumpL2
      set xLevel to 2
      let sTab := sTab2
      set xNext to aaqqArrayDumpL3
    elseif xSelf == aaqqArrayDumpL3
      set xLevel to 3
      let sTab := sTab3
      set xNext to aaqqArrayDumpL4
    elseif xSelf == aaqqArrayDumpL4
      set xLevel to 4
      let sTab := sTab4
      set xNext to aaqqArrayDumpL5
    elseif xSelf == aaqqArrayDumpL5
      set xLevel to 5
      let sTab := sTab5
      set xNext to 0
    ;=== Add additional ElseIf's here to to handle deeper arrays ===
    endif

  endif

  if xLevel == 0
    ;=== Init MaxLevel ===
    ;==============
    set gMaxLevel to iDepth - 1
    if  gMaxLevel < 0 || xMaxLevel > 5
      set gMaxLevel to 5
    endif
    ;=== Print Header ===
    ;==============
    let sLine :=  "===== Deep dump Mode " + ( tostring iMode ) + " - Depth= " + ( tostring gMaxLevel + 1 ) + " - Array: [" + gaKeys [0] + "] ====="
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile psLine
  endif
  set xMaxLevel to aaqqArrayDump.gMaxLevel 

  ;=== Setup array and key ===
  ;=======================
  let aArray := aaqqArrayDump.gaArrays [xLevel]
  if iMode  == 1
    let sKey := aaqqArrayDump.gaKeys [xLevel]
  else
    let sKey := ""
    foreach aEntry <- aaqqArrayDump.gaKeys
      let sKey := sKey + "[" + aEntry [Value] + "]"
    loop
  endif

  if  0 == ar_size aArray  
    ;=== Empty array ===
    ;=================
    if iMode  == 2
      let sLine := sKey + " = " + "#Empty#"
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile  psLine
    endif
  else
    foreach aEntry <- aArray
      ;=== Get key ===
      ;=============
      let sType := typeof aEntry [Key]  
      if eval (sType == "String")
        let sKey1 := aEntry [Key]
      else  
        let sKey1 := tostring aEntry [Key]
      endif

      let sType := typeof aEntry [Value]  

      if eval (sType == "String")
        ;=== Print string contents ===
        ;=======================
        let sText := aEntry [Value]
        if iMode  == 1
          let sLine := sTab + "[" + sKey1 + "]" + " = '" + sText + "'"
        else
          let sLine := sKey + "[" + sKey1 + "]" + " = '" + sText + "'"
        endif
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile  psLine
      elseif eval (sType == "Number")
        ;=== Print number contents ===
        ;=========================
        let xVal := aEntry [Value]
        if iMode  == 1
          let sLine := sTab + "[" + sKey1 + "]" + " = " + tostring xVal
        else
          let sLine := sKey + "[" + sKey1 + "]" + " = " + tostring xVal
        endif
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile  psLine
      elseif eval (sType == "Form")
        ;=== Print form contents ===
        ;=========================
        let xRef := aEntry [Value]
        set sText to sv_Construct "%i %n" xRef xRef 
        if iMode  == 1
          let sLine := sTab + "[" + sKey1 + "]" + " = " + sText
        else
          let sLine := sKey + "[" + sKey1 + "]" + " = " + sText
        endif
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile  psLine
      else
        ;=== Print array contents ===
        ;=========================
        if iMode  == 1
          let aTemp := aEntry[Value]
          let sLine := sTab + "[" + sKey1 + "]  #" + sv_construct "%g" aTemp + "  " + ( tostring ar_size ( aEntry [Value]  )  )  
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile  psLine
        endif
        if xLevel < xMaxLevel	  ; stops recursion at the last level initialized
          set xNextLevel to xLevel + 1
          let aaqqArrayDump.gaKeys [xNextLevel] := sKey1
          let aaqqArrayDump.gaArrays [xNextLevel] := aEntry [Value] 
          xNext.activate2 xSelf 1
          ar_Erase aaqqArrayDump.gaKeys xNextLevel
          ar_Erase aaqqArrayDump.gaArrays xNextLevel
        elseif xLevel == xMaxLevel &&  iMode  == 2
          let sLine := sKey + "[" + sKey1  + "]" + " . . ."
                              printc "PrintArray>> %z " sLine
                              setString psLine $sLine
                              StringToTxtFile psFile  psLine
        endif
      endif
    loop

  endif
end


Array walk

Introduction

This sample code allows walking a tree-like array structure

Useful when one needs to access array data sequentially, one at a time, over many frames.

The code allow for returning the previous or the next entry in the structure. When one branch ends, it jumps to the first entry of the next branch.

This sample works on a multi level, tree like array. Each 'branch' of the tree being a StringMap array. The object at the end of the branch must not be a StringMap. Branches mey have different sizes.

Setup

This sample uses the following objects:

  • qqArrayWalk - a persistent object that holds the script.
  • qqGetNext, qqGetPrev and qqReset - persistent objects to be used as actionref

Usage

To get the next entry:

qqArrayWalk.Activate qqGetNext 1
let MyObject := qqArrayWalk.aReturnObject 

To get the previous entry:

qqArrayWalk.Activate qqGetPrev  1
let MyObject := qqArrayWalk.aReturnObject 

To reset the loop to the first entry of the first branch:

qqArrayWalk.Activate qqGetNext, 1
let MyObject := qqArrayWalk.aReturnObject 


Script

scn qqArrayTreeWalkSCRIPT

array_var aReturnObject   

ref xSelf

;-------------------------------------------------------
; These arrays hold the branch and key data for each level as the loop goes down a branch
; Used to walk the branch back up
;-------------------------------------------------------
array_var aBranches
array_var aKeys

;-------------------------------------------------------
; These vars hold the current position
;-------------------------------------------------------
array_var aBranch
string_var sKey
short xLevel

string_var sType
short xForward 

begin onactivate

  if getactionref == qqGetNext
    set xForward to 1
  elseif getactionref == qqGetPrev
    set xForward to 0
  endif

  if getactionref == qqReset || xSelf == 0
    ;-----------------------------------------------
    ;  [Re]initialize the loop
    ;-----------------------------------------------
    set xSelf to getself

    if aBranches == 0
      let aBranches  := ar_construct array
      let aKeys := ar_construct array
    endif

    set xLevel to 0
    let aBranch := g.gaObjectTree  ; The array to be walked
    let sKey := ar_Last aBranch 
    set xForward to 1

  endif

  if xForward 
    let sKey :=  ar_Next aBranch sKey
  else
    let sKey :=  ar_Prev aBranch sKey
  endif

  saveip 4

  if eval ( sKey == ar_BadStringIndex )
    set xLevel to xLevel - 1
    if xLevel >= 0 
      ;-----------------------------------------------------------
      ;  End of array - go up one level 
      ;-----------------------------------------------------------
      let aBranch := aBranches [xLevel]
      let sKey := aKeys [xLevel]
      if xForward 
        let sKey :=  ar_Next aBranch sKey
      else
        let sKey :=  ar_Prev aBranch sKey
      endif

      goto 4
    else
      ;-----------------------------------------------------------
      ;  End of last array - start over 
      ;-----------------------------------------------------------
      set xLevel to 0
      let aBranch := g.gaObjectTree 
      if xForward 
        let sKey := ar_First aBranch 
      else
        let sKey := ar_Last aBranch 
      endif

      goto 4
    endif
  endif

          
  let sType := typeof aBranch [sKey]

  if eval (sType == "StringMap")
    ;-----------------------------------------------------------
    ;  Entry is an array - go down one level
    ;-----------------------------------------------------------
    let aBranches [xLevel] := aBranch 
    let aKeys [xLevel] := sKey
    set xLevel to xLevel + 1
    let aBranch := aBranch [sKey]

    if xForward
      let sKey := ar_First aBranch 
    else
      let sKey := ar_Last aBranch 
    endif

    goto 4

  else 
    ;-----------------------------------------------------------
    ;  End of branch - set aReturnObject 
    ;-----------------------------------------------------------
    let aReturnObject :=  aBranch [sKey] 

  endif
end