User:QQuix/Array sample code
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 walk[edit | edit source]
Introduction[edit | edit source]
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[edit | edit source]
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[edit | edit source]
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[edit | edit source]
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
Array deep dump[edit | edit source]
Deprecated. Replaced by ArrayDeepDump (User Function) |
Introduction[edit | edit source]
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[edit | edit source]
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[edit | edit source]
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[edit | edit source]
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[edit | edit source]
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