[Closed] converting string back to an array struct
I managed to save an array to a CA def as a data string, but parsing it back to an array when needed is way too much work. Is there a way I can save an array(struct) as data to a def…
if I save it as an array directly it is not persistently saved between sessions of max.
Here’s something we did to dump any struct data to a string and then be able to execute the string to recover the struct. There are three things you need to setup:
- A function to convert basic data types to string.
- A function to convert structure parameters and values to string (using first function).
- A function in structure that uses the second generic function to convert parameters and values of structure instance.
What’s provided below pretty much covers most 3dsMax data types you’ll want to store. Note that node types are trickier and you might want to change what gets executed based on you project needs…
fn valueToString val =
(
local classOfVal = classOf val
if ( isStruct val ) then classOfVal = #Struct
if ( isValidNode val ) then classOfVal = #Node
local str
case classOfVal of
(
String: ( str = "\"" + val + "\"" )
Name: ( str = "#'" + ( val as string ) + "'" )
Array: (
str = "#("
for i = 1 to val.count do
(
str += ( valueToString val[i] )
if ( i < val.count ) then ( str += ", " )
)
str += ")"
)
#Struct: ( str = val.toString() )
#Node: ( str = "(maxOps.getNodeByHandle " + ( val.inode.handle as string ) + ")" )
Default: ( str = val as string )
)
str
)
fn structToString structName params values =
(
local str = "(" + structName
for i = 1 to params.count do str += " " + params[i] + ":" + ( valueToString values[i] )
str += ")"
str
)
-- sample structure with function to dump parameters and values to a string
struct myStruct
(
name = "myNewStruct",
position = [100, 200],
indices = #( 1, 2, 3, 4 ),
obj = box(),
fn toString =
(
structToString "myStruct" #("name", "position", "indices", "obj") #(name, position, indices, obj)
)
)
-- test case
testStruct = myStruct()
str = testStruct.toString()
-- you can store str to appdata or wherever really
copyOftestStruct = execute str
Hope this helps.
how is about materials, modifiers, base objects, trackviewpicks, controllers… etc… you still have a lot of thing to support
I have done something similar but using XML. Where I had similar functions for converting values, you can also use readValue (string as stringStream) and a function that built an XML node that contained all the data and value types if you want for the data with in. Still can be a fair amount of work depending on what you want to do. Consider that a struct can contain functions.
is any problem with converting a structure to string and execute the string back to the structure?
Claudio …thnx but your test struct didn’t work in that the element in quotes, viz ‘mynewstruct’, was simply eliminated when executed, and came out as undefined. I also don’t quite see the need to create the struct that way / I already have the elements of the struct, my real problem is storing it as a string while preserving the array when executed. All the struct elements in my array are names, hence they have quotes, hence your script simply eliminates the quotes to create valid string but this doesn’t really help me in the end…also one of my elements is a name of a node address…$.material[2] for eg, which simply threw an error before doing anything else when using your script .
PEN / Interesting XML is prob the way to go… could you give simple example Paul, as my knowledge of XML is rudimentary.
Denis …well my array has quotes /name fields within it… so I don’t even get to execute the string without an error being thrown…I tried using single quotes but didn’t seem to execute …and i think this is what claudios script does …
sorry but im in a place far away that has mad keyboard with errant keys,like no quote marks…>(
struct child
(
name, id
)
struct Test
(
name, children = #(), transform,
fn getName = name
)
fn getScructAsString str =
(
fn wipeMaxObjects d = if isstruct do
(
for p in (getpropnames) do ()
)
str = deepcopy str
)
/*
delete objects
b = box()
d = Test name:b.name transform:b.transform
for k=1 to 100 do
(
t = teapot()
append d.children (child name:t.name id:k)
)
str = with printallelements on (d as string)
dd = execute str
dd.getname()
dd.children.count
*/
is it not enough? but you have to understand that the structure will be converted to string, the string will be executed. so if you have any MaxObject type properties they have to be converted to something that can be executed (id, name, expression, etc).
Holy Mackerel! Is it really that simple…now I feel like a dunderhead! thnx denis…you r the resource
You’re right, and you would have to define all types you plan on storing. I guess it depends on your needs. I definitely didn’t need to store trackViewPicks…
I just copied and pasted my code and everything worked. It shouldn’t eliminate quotes. I’m using 2012…
However in your case, what DenisT wrote is much more efficient. What I proposed is a catch all for (almost) any struct. But as DenisT mentioned, it would require including all types you are possibly going to store. Pen’s method is probably even better in terms of versatility as an XML allows for quick look ups and you can probably selectively populate the structure.
Good luck!
thnx claudio. For my purposes, the denis solution is all I need and saves me headaches. Really its just that i didnt know about printallelements command, it was actually a very simple problem that I was complicating…