XML Alternative

I needed a way to define objects without having to code them from scratch each time. I used xml in my previous imagine cup entry and it looked like a complete mess. What i did was was to define ‘skins‘ for objects. With this concept, when creating GameObjects i’d pass Skins loaded from xml that would define parameters for the objects, instead of defining them with code. It worked, but i hated how unreadable xml can get, and parsing the file was a pain. I was using XmlReader. So, i wrote an alternative. I’m not so good with coming up with names (evident from the name of my blog) so i just called it ParamList.

Here’s what a skin defined in xml looks like:


<?xml version="1.0" encoding="utf-8" ?>

<skin name="push_barrel_1">
 <model>levels/level1_1/models/barrel</model>
 <tex>tex/tile</tex>
 <data name="size" value="4,5.5,4"/>
 <data name="axes" value="1,0,0"/>
 <data name="min_bound" value="-5,0,0"/>
 <data name="max_bound" value="1,0,0"/>
 <data name="friction" value="0.1"/>
</skin>

Now here’s what the ParamList alternative look like:


name = push_barrel_1
model = levels/level1_1/models/barrel
tex = tex/tile

size = 4 5.5 4
axes = 1 0 0
min_bound = -5 0 0
max_bound = 1 0 0

friction = 0.1

the format is


param = value

It’s easier to parse as well. I have to create a custom function or class to parse the xml for whatever reason i’m using it for. With ParamList, parsing the code is just calling ParamList.parseFile(fileName). Comments are done like c/c++’s single line comments. I added variable system as well, this should come in handy when tweaking multiple values at the same time. Here’s an example of both in action:


//this is a comment

//player's name
name=player

//variable
@size=5

//use variables
scale = <height>
step_size = <height>

ParamList parses string, integer, float, Vector2,Vector3,Vector4 and Color variables. You get values from it like this:


ParamList list = ParamList.parseFile("Content/objects/house.object");

//test parsing
string name = list.getInt("name", null);
int mass = list.getInt("mass", 0);
float damp = list.getFloat("damp", 0);
Vector2 uvOffset = list.getVector2("uv_offset", Vector2.Zero);
Vector3 pos = list.getVector3("pos", Vector3.Zero);
Vector3 rot = list.getVector3("rot", Vector3.Zero);
Vector4 hiCol = list.getVector4("highlight_color", Vector4.Zero);
Color hColor = list.getColor("highlight_color", Color.White);

The first argument for each of those functions is the name of the param you want, the second is the default value if the param you are trying to wasnt defined. This comes in handy when you want to define objects but dont want to be bothered to define all the params.

I plan on adding support for #include statements like c/c++, in the event you want to split definitions across multiple files.


var=some_value

#include common_params.list

value=something else

This beats using xml any day. I’m not saying this should completely replace xml, but it’s a good alternative for this ocasion. Here’s the code:


/// <summary>
 /// This class holds a list of parameters
 /// Parameters can be parsed as a string, float, int, Vector2, Vector3, Vector4 or Color
 /// </summary>
 public class ParamList
 {
 Dictionary<string, string> paramList;
 Dictionary<string, string> values;

public ParamList()
 {
 paramList = new Dictionary<string, string>();
 values = new Dictionary<string, string>();
 }

/// <summary>
 /// sets a value, adds it if it doesnt exist
 /// </summary>
 /// <param name="name">name of value</param>
 /// <param name="value">value</param>
 public void setValue(string name, string value)
 {
 if (!values.ContainsKey(name))
 values.Add(name, value);
 else
 values[name] = value;
 }

public string getValue(string name)
 {
 return values[name];
 }

/// <summary>
 /// Adds a string parameter
 /// </summary>
 /// <param name="name"> name of parameter</param>
 /// <param name="param"> value of parameter</param>
 public void addParam(string name, string param)
 {
 paramList.Add(name, param);
 }

/// <summary>
 /// gets parameter
 /// </summary>
 /// <param name="name">name of parameter</param>
 /// <returns>returns param, null if not found</returns>
 public string getParam(string name)
 {
 if (!paramList.ContainsKey(name))
 return null;

string param = paramList[name];

//if the param is in a format like <name>, then replace with name value
 if (param.StartsWith("<") && param.EndsWith(">"))
 {
 //strip < and > and any extra space
 string valName = param.TrimStart('<').TrimEnd('>').Trim();

//replace with value
 param = values[valName];
 }

return param;
 }
 public string getString(string name, string def="")
 {
 if (paramList.ContainsKey(name))
 return getParam(name);
 return def;
 }

public bool getBool(string name, bool def=false)
 {
 if (paramList.ContainsKey(name))
 {
 if (getParam(name) == "true")
 return true;
 return false;
 }
 return def;
 }

public int getInt(string name, int def=0)
 {
 if (paramList.ContainsKey(name))
 return int.Parse(getParam(name));
 return def;
 }

public float getFloat(string name, float def=0)
 {
 if (paramList.ContainsKey(name))
 return float.Parse(getParam(name));
 return def;
 }

public Vector2 getVector2(string name)
 {
 return getVector2(name, Vector2.Zero);
 }
 public Vector2 getVector2(string name, Vector2 def)
 {
 if (paramList.ContainsKey(name))
 {
 string[] parts = getParam(name).Trim().Split(' ');
 if (parts.Length == 1)
 return new Vector2(float.Parse(parts[0]));
 else if (parts.Length == 2)
 return new Vector2(float.Parse(parts[0]), float.Parse(parts[1]));
 else
 return def;
 }
 return def;
 }

public Vector3 getVector3(string name)
 {
 return getVector3(name, Vector3.Zero);
 }
 public Vector3 getVector3(string name, Vector3 def)
 {
 if (paramList.ContainsKey(name))
 {
 string[] parts = getParam(name).Trim().Split(' ');
 if (parts.Length == 1)
 return new Vector3(float.Parse(parts[0]));
 else if (parts.Length == 3)
 return new Vector3(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]));
 else
 return def;
 }
 return def;
 }

public Vector4 getVector4(string name)
 {
 return getVector4(name, Vector4.Zero);
 }

public Vector4 getVector4(string name, Vector4 def)
 {
 if (paramList.ContainsKey(name))
 {
 string[] parts = getParam(name).Trim().Split(' ');
 if (parts.Length == 1)
 return new Vector4(float.Parse(parts[0]));
 else if (parts.Length == 4)
 return new Vector4(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]), float.Parse(parts[3]));
 else
 return def;
 }
 return def;
 }

public Color getColor(string name)
 {
 return getColor(name, Color.Black);
 }
 public Color getColor(string name, Color def)
 {
 if (paramList.ContainsKey(name))
 {
 string[] parts = getParam(name).Trim().Split(' ');
 if (parts.Length == 1)
 return new Color(new Vector4(float.Parse(parts[0])));
 else if (parts.Length == 3)
 return new Color(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]),1f);
 else if (parts.Length == 4)
 return new Color(new Vector4(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]), float.Parse(parts[3])));
 else
 return def;
 }
 return def;
 }
 /// <summary>
 /// parses parameter list from a file
 /// </summary>
 /// <param name="filename">the name of the file to be parsed</param>
 /// <returns>returns parsed paraeter list</returns>
 public static ParamList parseFile(string filename)
 {
 ParamList list = new ParamList();
 string line;
 StreamReader reader = new StreamReader(filename);

while((line = reader.ReadLine())!=null)
 {
 //ignore comments
 if (line.TrimStart().StartsWith("//"))
 continue;

//must contain an equal sign to be a valid parameter definition
 if (line.Contains("="))
 {
 string[] parts = line.Split('=');
 string lhs = parts[0].Trim();
 string value = parts[1].Trim();

//eval is its a var, directive or just a value
 if (lhs.StartsWith("@"))
 {
 //its a var
 list.setValue(lhs.TrimStart('@'), value);
 }
 /*
 else if (lhs.StartsWith("#"))
 {
 //its a directive
 //carry out directive
 var dirName = lhs.TrimStart('#');
 }
 * */
 else
 list.addParam(lhs,value);
 }
 }

return list;
 }

/// <summary>
 /// Returns amount of parameters in the list
 /// </summary>
 /// <returns>number of params</returns>
 public int getCount()
 {
 return paramList.Count;
 }
 }

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s