loading and saving types
BlitzMax Forums/BlitzMax Programming/loading and saving types
| ||
| I'm trying to make a loading and saving system that is generic. Anyone know how to go about making blitz max create a type instance from a string that looks something like "new agent"? This is text that would be in a text file that I would load to recreate my type data here's what my save data file looks like... new agent state 500 x 304.000000 y 100.000000 z 50.0000000 the "new" is in there just to denote that a new type is to be created, the "agent" is the name of the type in my code. Then below is all the fields and that data. here is my non-working code for both parts of the process as I have now. Function saveType(instance:Object,file:TStream)
Local id:TTypeId=TTypeId.ForObject(instance)
Local fList:TList = id.EnumFields()
WriteLine file,"new " + id.name()
For Local myField:TField = EachIn fList
WriteLine file,myField.name() + " " + myField.getString(instance)
Next
End Function
Function loadTypes(filename:String)
Local file:TStream = ReadFile(filename)
Local myLine:String
Local myAgent:agent
While Not file.Eof()
myLine = ReadLine(file)
Local myCom:String[] = myLine.split(" ")
Select myCom[0]
Case "new"
Local id:TTypeId=TTypeId.ForName(myCom[1])
Print id.name()
myAgent:agent = id.newObject()
Default
setAttr(myAgent,myCom[0],myCom[1])
End Select
Wend
CloseFile file
End Function
Function setAttr(instance:Object,fieldName:String,value:String)
Local id:TTypeId=TTypeId.ForObject(instance)
Local myField:TField=id.FindField(fieldName)
myField.setInt(instance,Int(value))
End Function |
| ||
| Anyone know how to go about making blitz max create a type instance from a string that looks something like "new agent"? Yes, use the new Reflection stuff, that you'll never need. I believe there's an example floating around somewhere, but unfortunately I haven't had much time to look at it. I'll take a crack at it on the way to and from work, if you haven't come up with a solution in about 15 hours' time. This is text that would be in a text file that I would load to recreate my type data Could I get you to reconsider using XML? |
| ||
| What's the advantage of using xml? |
| ||
It's more structured, and can store compound objects in a simple and intuitive (for people who understand SGML) way. Consider this type:Type point Field x:Int Field y:Int Field connected:TList End TypeIn XML it would be trivial to store the list. In CraigScript, it isn't (currently) possible. I don't think there's any reason to reinvent the wheel, for this particular purpose. |
| ||
| What's the advantage of using xml? Looks pretty. It's pretty useless as far as reasons for using it are concerned, since it's not much better than other text-based formats with visible structure other than that more people use it (unfortunately, this also means more people use it poorly -- if your experience with XML is close to nil, you'll be one of them most likely).I'd just use a binary format unless you want to modify the saved types outside of the program. If you don't want the bloat of XML, consider looking at my SParse module. |
| ||
| XML-Way: I'm using this (you will have to modify it coz the zip-thing is handcoded): You also need: 'MaXML 2.22 'Copyright (C) 2006 John Judnich
Type TSaveFile
Field file:xmlDocument
Field node:xmlNode
Field currentnode:xmlNode
Field root:xmlNode
Field Nodes:xmlNode[10]
Field NodeDepth:Int = 0
Field lastNode:xmlNode
Function Create:TSaveFile()
Local tmpobj:TSaveFile = New TSaveFile
Return tmpobj
End Function
Method InitSave()
Self.file = New xmlDocument
Self.root = Self.file.root()
Self.root.name = "savegame"
Self.Nodes[0] = Self.root
Self.lastNode = Self.root
End Method
Method InitLoad(filename:String="save.xml", zipped:Byte=0)
Self.file = xmlDocument.Create(filename, zipped)
Self.root = Self.file.root()
Self.NODE = Self.root
End Method
Method xmlWrite(typ:String="unknown",str:String, newDepth:Byte=0, depth:Int=-1)
If depth <=-1 Or depth >=10 Then depth = Self.NodeDepth ';newDepth=False
If newDepth
Self.Nodes[Self.NodeDepth+1] = Self.Nodes[depth].AddNode(typ)
Self.Nodes[Self.NodeDepth+1].Attribute("var").value = str
Self.NodeDepth:+1
Else
Self.Nodes[depth].AddNode(typ).Attribute("var").value = str
EndIf
End Method
Method xmlCloseNode()
Self.NodeDepth:-1
End Method
Method xmlBeginNode(str:String)
Self.Nodes[Self.NodeDepth+1] = Self.Nodes[Self.NodeDepth].AddNode(str)
' Self.Nodes[Self.NodeDepth+1] = Self.Nodes[Self.NodeDepth].addTextChild(str, Null, "")
Self.NodeDepth:+1
End Method
Method xmlSave(filename:String="-", zipped:Byte=0)
If filename = "-" Then Print "nodes:"+Self.file.NodeCount() Else Self.file.Save(filename,FORMAT_XML, zipped)
End Method
End Type
Global LoadSaveFile:TSaveFile = TSaveFile.Create()
Example code in my app:
LoadSaveFile.InitLoad("savegame.zip", True)
...
Function Load:TAudienceQuotes(pnode:xmlNode)
Local audience:TAudienceQuotes = New TAudienceQuotes
Local NODE:xmlNode = pnode.FirstChild()
While NODE <> Null
Local nodevalue:String = ""
If node.HasAttribute("var", False) Then nodevalue = node.Attribute("var").value
Local typ:TTypeId = TTypeId.ForObject(audience)
For Local t:TField = EachIn typ.EnumFields()
If (t.MetaData("saveload") <> "nosave" Or t.MetaData("saveload") = "normal") And Upper(t.name()) = NODE.name
t.Set(audience, nodevalue)
EndIf
Next
NODE = NODE.nextSibling()
Wend
TAudienceQuotes.List.AddLast(audience)
Return audience
End Function
Function LoadAll()
TAudienceQuotes.List.Clear()
Local Children:TList = LoadSaveFile.NODE.ChildList
For Local NODE:xmlNode = EachIn Children
If NODE.name = "AUDIENCEQUOTE"
TAudienceQuotes.Load(NODE)
End If
Next
PrintDebug ("TAudienceQuotes.LoadAll()", "AudienceQuotes eingeladen", DEBUG_SAVELOAD)
End Function
Function SaveAll()
TFinancials.List.Sort()
LoadSaveFile.xmlBeginNode("ALLAUDIENCEQUOTES")
For Local i:Int = 0 To TAudienceQuotes.List.Count()-1
' Local audience:TAudienceQuotes = TAudienceQuotes(TAudienceQuotes.List.Items[i] )
Local audience:TAudienceQuotes = TAudienceQuotes(TAudienceQuotes.List.ValueAtIndex(i))
If audience<> Null Then audience.Save()
Next
LoadSaveFile.xmlCloseNode()
End Function
Method Save()
LoadSaveFile.xmlBeginNode("AUDIENCEQUOTE")
Local typ:TTypeId = TTypeId.ForObject(Self)
For Local t:TField = EachIn typ.EnumFields()
If t.MetaData("saveload") <> "nosave" Or t.MetaData("saveload") = "normal"
LoadSaveFile.xmlWrite(Upper(t.name()), String(t.Get(Self)))
EndIf
Next
LoadSaveFile.xmlCloseNode()
End Method
If you use a Global List to store all your elements then you may generalize the load/save-functions. bye MB |
| ||
| Where is does that "TAudienceQuotes" type live? The compiler is stopping on it. |
| ||
| Ok, I'm looking over the xml docs here and I have to say, this seem like major overkill for what I need to do. Honestly, I don't even find the format that "pretty" so to speak. It looks like an over complicated mess! What is the real advantage of using xml as your save game format? |
| ||
| Its an example from MichaelB's app. <edit> The advantage of XML is it's a standard format. |
| ||
| bah, screw standard format. Noones going to use my stuff, but me. |
| ||
| TAudienceQuote is like mentioned only an example type... XML has nearly the same advantage as ini ... it's human readable. Imagine you get a report of one of your users ... the savegame wont load, application is crashing. That happens imho when using binary savegames like streams. Or just change something and you will have to write a new parser for each savegame-version. With XML you just have to encrypt or pack it... let you send the savegame, decrypt/unpack it and look through the text to see the error (a value of 2.3423432424 instead of 2 because you saved float instead of integer ...). The disadvantage is the increase of the savegame-filesize, the rest is a much more structable filecontent... you see each type and nested children instead of hex-war. bye MB |