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 |