Type fields

BlitzMax Forums/BlitzMax Beginners Area/Type fields

Ghost Dancer(Posted 2005) [#1]
OK, I'm not sure if this is possible, but here goes. I've got a data file which contains lots of options for my program. E.g.

fieldName1: some data
fieldName2: more data
fieldName3: even more data

etc.


This file is basically a mirror of a user defined type:

Type TMyData
 Field fieldName1$, fieldName2$, fieldName3$ 'etc...
End Type


I've got a function that reads each line and splits the data into the identifier (field name) and the value, storing it in another type. I then have a Select satement to put the data in the correct field:

While Not Eof(dataFile)
	getFileOption(ReadLine(dataFile))
	
	Select fopt.identifier$
	Case "fieldName1"
		dat.fieldName1$ = fopt.value$
	Case "fieldName2"
		dat.fieldName2$ = fopt.value$
	Case "fieldName3"
		dat.fieldName3$ = fopt.value$
	End Select
Wend


This just seems a very inefficient way of doing this since the identifier from the data file is always the same name as the type field. Plus, the data file will end up with lots of field values and this will just be a massive Select statement plus I have to make sure I manually code in each field.

Is there any way of setting the type fields according the identifier? I need to be able to do something like:

(pseudo code)
While Not Eof(dataFile)
	getFileOption(ReadLine(dataFile))
	
	dat.[fopt.identifier$] = fopt.value$
Wend


Is it possible to do something like this? I'm having a slow brain day today so any help would be appreciated.


Beaker(Posted 2005) [#2]
After Blitz has created the compiled code it doesnt know what the field names are anymore. One solution is to not use fields at all and create your own 'variable' type held in a list, with Getters and Setters. Something like this:


You can speed things up using a binary tree.

OR you can use the built in one in Bmax:
Strict

Import BRL.Map


Local map:TMap = New TMap

map.Insert("blah","20")
Print String(map.ValueForKey("blah"))



Ghost Dancer(Posted 2005) [#3]
After Blitz has created the compiled code it doesnt know what the field names are anymore.


Yeah, that's what I thought, but I've only just started using Max and thought there might be some clever way of doing it ;-)


PowerPC603(Posted 2005) [#4]
I used to do the same for my game (in B3D).
I also have a massive Select statement for each type of object in the game (a 3D spacegame), one for loading waretypes, one for missiletypes, one for shieldtypes, ...

Since yesterday, I decided to use a binary file, where all fields are just written after eachother.
Now the file is much smaller (1.5Kb instead of 8Kb).
The file will be much bigger when the game is operational, I have only a few items in there right now for testing the loadroutines and such.
Afterwards, I can simply put in more objects and the game adapts automatically.

The editor for the game will be written in VB6.0 (right now, I'm using Notepad), which outputs a textfile, like this:

[WareType]
Name = Ore
Description = ...
DefaultPrice = 55
CargoSpace = 2
[EndWareType]

[WareType]
Name = Food
Description = ...
DefaultPrice = 24
CargoSpace = 1
[EndWareType]

[ShieldType]
Name = 5MW Shield
Description = ...
DefaultPrice = 25000
Strength = 5000000
[EndShieldType]

...

I could write the editor to output the binary file directly, but I don't really know if VB outputs integers as 4 bytes and with the LSB first.
And strings must be preceded by the number of characters, otherwise Blitz cannot read it correctly.
So it will output a textfile, which will be converted with a program in B3D (the converter).

The [WareType] and [EndWareType] are used to indicate the start and end of each block of data.
When a [WareType] is found, a new TWareType instance will be created, the fields will be loaded, until [EndWareType] is reached.
Unknown identifiers or simply text (or comments) is ignored.

Then I will have a converter that reads this file and converts it to a binary file.
It only writes the field-values in a binary format, without the identifiers.
This way, a large number (like 125000000) will be written using only 4 bytes instead of 9.
Then the game can simply load all fields right after eachother.
The converter writes this (pseudo-code):
WriteString(waretype\Name$)
WriteString(waretype\Description$)
WriteInt(waretype\DefaultPrice%)
WriteByte(waretype\CargoSpace%)

The cargospace uses only 1 byte, because none of the wares in my game will ever use more than 255 units of cargospace onboard a station or ship.

Then the game reads them using the same method.
It's still a long loadroutine, but much simpler, because all fields stay in the exact order, thanks to the way the converter writes the file.

All waretype-instances are written right after eachother, followed by the ShieldTypes.
After that, other data will come, defining the structure for my universe (not worked out yet).

Each big block of data is preceded by a Short (2 bytes), which indicates the number of objects of that kind.

So the game uses this to read the file (B3D code):

NumberOfWareTypes = ReadShort(file)

For i = 1 to NumberOfWareTypes
waretype.TWareType = New TWareType
waretype\Name$ = ReadString(file)
waretype\Description = ReadString(file)
waretype\DefaultPrice% = ReadInt(file)
waretype\CargoSpace% = ReadByte(file)
Next

NumberOfShieldTypes = ReadShort(file) ; Read the number of ShieldTypes in the file

For i = 1 to NumberOfShieldTypes
shieldtype.TShieldType = New TShieldType
shieldtype\Name$ = ReadString(file)
shieldtype\Description = ReadString(file)
shieldtype\DefaultPrice% = ReadInt(file)
shieldtype\Strength% = ReadInt(file)
Next

...


Or, if your fields in your datafile are all in the exact same order everytime, you could use arrays.
I helped another forum-user once who had trouble, because he uses massive amounts of fields and he wanted to clone an existing object with all field-values intact.
You could use this example and adapt it for loading data:
http://www.blitzbasic.com/Community/posts.php?topic=48391#538411


(pseudo code)
While Not Eof(dataFile)
i = i + 1
getFileOption(ReadLine(dataFile))
dat.Array$[i] = fopt.value$
Wend


This could work.
Afterwards, use constants to address the array's indexes.
Then it will be the same as addressing an instance's fields.
Before:

instance.fieldname = ...

Now:

instance.array[fieldname] = ...



Ghost Dancer(Posted 2005) [#5]
Thanks for your reply powerpc. I had also considered doing something like that but I want the file to be user editable which creates certain restrictions - it needs to be readable (text only) and in any order. I guess I just can't have my cake and eat it ;-)