loading and saving types

BlitzMax Forums/BlitzMax Programming/loading and saving types

Craig H. Nisbet(Posted 2007) [#1]
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



FlameDuck(Posted 2007) [#2]
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?


Craig H. Nisbet(Posted 2007) [#3]
What's the advantage of using xml?


FlameDuck(Posted 2007) [#4]
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 Type
In 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.


N(Posted 2007) [#5]
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.


Derron(Posted 2007) [#6]
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


Craig H. Nisbet(Posted 2007) [#7]
Where is does that "TAudienceQuotes" type live? The compiler is stopping on it.


Craig H. Nisbet(Posted 2007) [#8]
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?


tonyg(Posted 2007) [#9]
Its an example from MichaelB's app.
<edit> The advantage of XML is it's a standard format.


Craig H. Nisbet(Posted 2007) [#10]
bah, screw standard format. Noones going to use my stuff, but me.


Derron(Posted 2007) [#11]
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