jazzisparis / JIP-LN-NVSE

An extension for the New Vegas Script Extender (NVSE)
GNU General Public License v3.0
50 stars 14 forks source link

Make Ar_Cat work for Map-type arrays #12

Closed Demorome closed 3 years ago

Demorome commented 3 years ago

Previously, Ar_Cat tried to append elements to Map-type arrays, but it didn't work since SetElement needs to be used for those types of arrays.

So now, it checks if both arrays are of the same type, using the recently exported GetContainerType() ArrayAPI function (which was merged into master for xNVSE a couple minutes ago). Which means if this was merged into JIP, it would now require xNVSE v6.2.1+

If they are the same type, it will copy the key::value pairs from one array to the next.

Default behaviour is unchanged for appending a regular array to a regular array, or a null array to a regular array, or vice-versa.

By default, if both arrays are Map-type, and both the first and second array share an element with the same key, the array that's being appended to will have that key's value be replaced by the second array's. This "overriding" behaviour can be shut off by setting the new optional bOverrideOldKeys argument to 0.

Oh, and I also made it return 1/0 to check if the second array was successfully appended to the first.

The only thing I'm not confident about is the array memory allocation for GetArrayDataFull(), as I pretty much just copied how it was done for SetINISection.

NOTE: I also merged the branch from this pull request in here: https://github.com/jazzisparis/JIP-LN-NVSE/pull/11 Can be removed if needed.

To test, I used the following 2 scripts:

scn TestArCatDumpTest

array_var aTest
array_var aSolution

begin Function {aTest, aSolution}

     let int iTestNum := player.AuxVarGetFlt "*ArCatTestNum" + 1
     player.AuxVarSetFlt "*ArCatTestNum" iTestNum

     let string_var sDebugPath := player.AuxVarGetStr "*ArCatDebugPath"

     ;* Debug dump stuff
     let short bFailure:= !(Ar_DeepCompare aTest, aSolution)
     PrintF $sDebugPath, "Test #" + $iTestNum + ", success: " + $(!bFailure)
     if (bFailure)
          Ar_DumpF aTest $sDebugPath
          Ar_DumpF aSolution $sDebugPath 
     endif
end
scn TestArCat

array_var aTest1
array_var aTest2
array_var aSolution

begin Function { }

     let string_var sDebugPath := "TestArCat.txt"
     print "Ran, check the file: " + $sDebugPath
     WriteStringToFile $sDebugPath 0 "=======%r"  ;* Nuke the file

     player.AuxVarSetStr "*ArCatDebugPath" $sDebugPath
     player.AuxVarSetFlt "*ArCatTestNum" 0

     ;* Test regular array + regular array
     let aTest1 := ar_List 1, 1, 2
     let aTest2 := ar_List 10, "lol", SunnyREF 
     ar_Cat aTest1, aTest2
     let aSolution := ar_List 1, 1, 2, 10, "lol", SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     let aTest1 := ar_List EasyPeteREF
     let aTest2 := ar_List 10, "lol", SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_List EasyPeteREF, 10, "lol", SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test invalid array + regular array_var
     let aTest1 := ar_Null
     let aTest2 := ar_List 10, "lol", SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_Null
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test regular array + invalid array
     let aTest1 := ar_List 10, "lol", SunnyREF
     let aTest2 := ar_Null
     ar_Cat aTest1, aTest2
     let aSolution := ar_List 10, "lol", SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test stringmap + regular array
     let aTest1 := ar_Map "test"::1
     let aTest2 := ar_List 10, "lol", SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map "test"::1
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test regular array + stringmap
     let aTest1 := ar_List 10, "lol", SunnyREF
     let aTest2 := ar_Map "test"::1
     ar_Cat aTest1, aTest2
     let aSolution := ar_List 10, "lol", SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test stringmap + stringmap
     let aTest1 := ar_Map "test"::1
     let aTest2 := ar_Map "aString"::SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map "test"::1, "aString"::SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     let aTest1 := ar_Map "test"::1, "heck"::"stringValue"
     let aTest2 := ar_Map "aString"::SunnyREF, "anotherString"::5
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map "test"::1, "heck"::"stringValue", "aString"::SunnyREF, "anotherString"::5
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test overriding existing key::value pair for Stringmap arrays.
     let aTest1 := ar_Map "test"::1, "string"::"stringValue"
     let aTest2 := ar_Map "string"::SunnyREF, "anotherString"::5
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map "test"::1, "string"::SunnyREF, "anotherString"::5
     Call TestArCatDumpTest aTest1, aSolution

     let aTest1 := ar_Map "test"::1, "string"::"stringValue"
     let aTest2 := ar_Map "string"::SunnyREF, "anotherString"::5
     ar_Cat aTest1, aTest2 0
     let aSolution := ar_Map "test"::1, "string"::"stringValue", "anotherString"::5
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test map + stringmap
     let aTest1 := ar_Map 2::1
     let aTest2 := ar_Map "aString"::SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map 2::1
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test map + map
     let aTest1 := ar_Map 2::1
     let aTest2 := ar_Map 5::SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map 2::1, 5::SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test overriding existing key::value pair for Map arrays.
     let aTest1 := ar_Map 2::1, 3::1, 5::"string"
     let aTest2 := ar_Map 5::SunnyREF
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map 2::1, 3::1, 5::SunnyREF
     Call TestArCatDumpTest aTest1, aSolution

     let aTest1 := ar_Map 2::1, 3::1, 5::"string"
     let aTest2 := ar_Map 5::SunnyREF
     ar_Cat aTest1, aTest2, 0
     let aSolution := ar_Map 2::1, 3::1, 5::"string"
     Call TestArCatDumpTest aTest1, aSolution

     ;===Test Multidimensional Arrays===

     ;* Test multi regular array + regular array
     let aTest1 := ar_List 1, 2, 5, (ar_List 1, 5)
     let aTest2 := ar_List 3, 6
     ar_Cat aTest1, aTest2
     let aSolution := ar_List 1, 2, 5, (ar_List 1, 5), 3, 6
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test regular array + multi regular array
     let aTest1 := ar_List 3, 6
     let aTest2 := ar_List 1, 2, 5, (ar_List 1, 5)
     ar_Cat aTest1, aTest2
     let aSolution := ar_List 3, 6, 1, 2, 5, (ar_List 1, 5)
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test multi regular array + multi regular array
     let aTest1 := ar_List 1, 2, 5, (ar_List 1, 5)
     let aTest2 := ar_List "test", 2, SunnyREF, (ar_List 1, 5)
     ar_Cat aTest1, aTest2
     let aSolution := ar_List 1, 2, 5, (ar_List 1, 5), "test", 2, SunnyREF, (ar_List 1, 5)
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test multi Stringmap array + multi regular array
     let aTest1 := ar_Map "test"::1, "key"::SunnyREF, "map"::(Ar_Map "Test"::3)
     let aTest2 := ar_List "test", 2, SunnyREF, (ar_List 1, 5)
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map "test"::1, "key"::SunnyREF, "map"::(Ar_Map "Test"::3)
     Call TestArCatDumpTest aTest1, aSolution

     ;* Test multi Stringmap array + multi Stringmap
     let aTest1 := ar_Map "test"::1, "key"::SunnyREF, "map"::(Ar_Map "Test"::3)
     let aTest2 := ar_Map "snig"::EasyPeteREF, "aMap"::(Ar_Map "snig2"::"return of snig")
     ar_Cat aTest1, aTest2
     let aSolution := ar_Map "test"::1, "key"::SunnyREF, "map"::(Ar_Map "Test"::3), "snig"::EasyPeteREF, "aMap"::(Ar_Map "snig2"::"return of snig")
     Call TestArCatDumpTest aTest1, aSolution

     ;* I got bored.

end

When I did call TestArCat from console, it printed the following (feel free to verify on your end, but make sure to update xNVSE to latest unreleased build!):

=======
Test #1, success: 1
Test #2, success: 1
Test #3, success: 1
Test #4, success: 1
Test #5, success: 1
Test #6, success: 1
Test #7, success: 1
Test #8, success: 1
Test #9, success: 1
Test #10, success: 1
Test #11, success: 1
Test #12, success: 1
Test #13, success: 1
Test #14, success: 1
Test #15, success: 1
Test #16, success: 1
Test #17, success: 1
Test #18, success: 1
Test #19, success: 1

edit: I realize now that it might look a little suspicious if every test passes, perhaps I should've included some to intentionally fail? In any case, I promise that it can return false, like when I forgot that I was using an xNVSE build that didn't export GetContainerType :snig:.

jazzisparis commented 3 years ago

I incorporated your changes (and will credit you in the next release). Thank you!