Wrapper around a bank

BlitzMax Forums/BlitzMax Programming/Wrapper around a bank

deps(Posted 2005) [#1]
Hi,

I'm writing a small wrapper around a bank to make it a bit easier to use it.
When my wrapper is used, the programmer creates a layout of how the information in the bank is stored. Here is some code to show how:
(In a RPG looking way)
Local save:TGameSave = TGameSave.create()

' Format the layout
' name (string), hp, hpmax, mana, manamax, gold
Local layout:Int[] = [ 8, GSL_INT, GSL_INT, GSL_INT, GSL_INT, GSL_INT ]

save.create_layout( layout )

GSL_INT is equal to 4, since an Int uses 4 bytes. I also have GSL_BYTE, GSL_SHORT, GSL_FLOAT and so on...
I don't have one for strings, so the 8 in the array means 8 bytes (chars) is used for the name.

Everything works just fine. I also have a method in the type that returns the offset in bytes:
	Method get_offset( fs_index )
		Local off = 0
		If fs_index < 0 Or fs_index >= Len( bank_layout ) Then Return -1 ' error
		
		For Local i = 0 Until fs_index
			off:+bank_layout[i]
		Next
	
		Return off
	EndMethod


Using that method I can get the offset i should peek/poke in the bank. But my "problem" comes when I want to use all this:

Print "Pokes some stuff into the savefile..."
save.bank.PokeInt( save.get_offset(1), 73 )
save.bank.PokeInt( save.get_offset(2), 100 )
save.bank.PokeInt( save.get_offset(3), 20 )
save.bank.PokeInt( save.get_offset(4), 20 )
save.bank.PokeInt( save.get_offset(5), 143 )

Print "Peeks some stuff from the savefile:"
Print "HP  : "+save.bank.PeekInt( save.get_offset(1) )+"/"+save.bank.PeekInt( save.get_offset(2) )
Print "MANA: "+save.bank.PeekInt( save.get_offset(3) )+"/"+save.bank.PeekInt( save.get_offset(4) )
Print "GOLD: "+save.bank.PeekInt( save.get_offset(5) )

This is not a pretty sight. This is what I want some help with. How should I do to simplify it?
I could creade peekint/pokeint, peekbyte/pokebyte and so on in my type but I am looking for something better. If at all possible.

What I want is something like this:
local hero_hp = save.get( 1 )
local hero_mana = save.get( 3 )

But the "get" method needs to be able to return bytes,ints,floats,etc and that isn't possible, afaik.

Anyone got any idea?


gman(Posted 2005) [#2]
greetings deps :) this is just one way to do it but you could use a map to create a readable index system (this is untested and will need your Type functionality added in).
Import BRL.Map

Type BankWrap
	Field index:TMap
	Field bank:TBank
	
	Method create_layout(layout:Int[],keys:String[])
		' do your layout creation stuff here
		
		' create the index map
		If Not index Then index=New TMap Else index.clear()

		' map each key to an index in your layout array
		Local layout_idx:Int=0  ' this is the index into your layout array
		For Local key:String=EachIn keys
			index.Insert(key,String.FromInt(layout_idx))
			layout_idx:+1 
		Next		
	EndMethod

	Method getByte:Byte(key:String)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		Return bank.PeekByte(get_offset(Int(idx)))
	EndMethod
	Method getDouble:Double(key:String)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		Return bank.PeekDouble(get_offset(Int(idx)))
	EndMethod
	Method getFloat:Float(key:String)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		Return bank.PeekFloat(get_offset(Int(idx)))
	EndMethod
	Method getInt:Int(key:String)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		Return bank.PeekInt(get_offset(Int(idx)))
	EndMethod
	Method getLong:Long(key:String)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		Return bank.PeekLong(get_offset(Int(idx)))
	EndMethod
	Method getShort:Short(key:String)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		Return bank.PeekShort(get_offset(Int(idx)))
	EndMethod
	
	Method setByte(key:String,val:Byte)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		bank.PokeByte(get_offset(Int(idx)),val)
	EndMethod
	Method setDouble(key:String,val:Double)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		bank.PokeDouble(get_offset(Int(idx)),val)		
	EndMethod
	Method setFloat(key:String,val:Float)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		bank.PokeFloat(get_offset(Int(idx)),val)		
	EndMethod
	Method setInt(key:String,val:Int)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		bank.PokeInt(get_offset(Int(idx)),val)		
	EndMethod
	Method setLong(key:String,val:Long)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		bank.PokeLong(get_offset(Int(idx)),val)		
	EndMethod
	Method setShort(key:String,val:Short)
		Local idx:String=String(index.ValueForKey(key))
		If Not idx Then RuntimeError "Invalid Key"
		bank.PokeShort(get_offset(Int(idx)),val)		
	EndMethod

EndType

it then reduces your gets and sets to something like:
save.setInt("HP",23)
save.setInt("MANA",150)
...
Local hero_hp:Int=save.getInt("HP")
Local hero_mana:Int=save.getInt("MANA")


HTH.


gman(Posted 2005) [#3]
an alternative would be to extend your wrapper type and define Type constants (or global if you want):
Type herobank Extends BankWrap
	Const HP:Int=0
	Const MANA:Int=1
	
	Method getByte:Byte(idx:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		Return bank.PeekByte(get_offset(idx))
	EndMethod
	Method getDouble:Double(idx:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		Return bank.PeekDouble(get_offset(idx))
	EndMethod
	Method getFloat:Float(idx:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		Return bank.PeekFloat(get_offset(idx))
	EndMethod
	Method getInt:Int(idx:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		Return bank.PeekInt(get_offset(idx))
	EndMethod
	Method getLong:Long(idx:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		Return bank.PeekLong(get_offset(idx))
	EndMethod
	Method getShort:Short(idx:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		Return bank.PeekShort(get_offset(idx))
	EndMethod
	
	Method setByte(idx:Int,val:Byte)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		bank.PokeByte(get_offset(idx),val)		
	EndMethod
	Method setDouble(idx:Int,val:Double)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		bank.PokeDouble(get_offset(idx),val)		
	EndMethod
	Method setFloat(idx:Int,val:Float)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		bank.PokeFloat(get_offset(idx),val)		
	EndMethod
	Method setInt(idx:Int,val:Int)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		bank.PokeInt(get_offset(idx),val)		
	EndMethod
	Method setLong(idx:Int,val:Long)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		bank.PokeLong(get_offset(idx),val)		
	EndMethod
	Method setShort(idx:Int,val:Short)
		If idx>=layout_arr.length Then RuntimeError "Invalid Index"
		bank.PokeShort(get_offset(idx),val)		
	EndMethod
	
EndType

your calls then look something like:
save.setInt(herobank.HP,23)
save.setInt(herobank.MANA,150)
...
Local hero_hp:Int=save.getInt(herobank.HP)
Local hero_mana:Int=save.getInt(herobank.MANA)



deps(Posted 2005) [#4]
you could use a map to create a readable index system

This sounds interesting. Looks like I'm stuck with get<type>/set<type> methods but at least it looks a bit cooler. :)

Thanks.