- Code: Select all
[Serializable]
public class ValveMap
{
[Serializable]
public class VersionInfoClass
{
public Int32 EditorVersion;
public Int32 EditorBuild;
public Int32 MapVersion;
public Int32 FormatVersion;
public Int32 Prefab;
}
public VersionInfoClass VersionInfo;
[Serializable]
public class EntityClass
{
public Int32 ID;
public String Classname;
public Int32? SpawnFlags;
public List<KeyValuePair<String, String>> KeyValues;
public VectorClass Origin;
[Serializable]
public class IOConnectionClass
{
public String TargetEntityNameOrClass;
public String TargetEntityInput;
public String ParameterOverride;
public Int32 TriggerDelay;
public Int32 NumberOfTimesToFire;
public override string ToString()
{
return TargetEntityNameOrClass + "," + TargetEntityInput + "," + ParameterOverride + "," + TriggerDelay + "," + NumberOfTimesToFire;
}
public static IOConnectionClass FromString(String text)
{
IOConnectionClass temp = new IOConnectionClass();
String[] components = text.Split(',');
if (components.Length < 4 || components.Length > 5) throw new FormatException("IO Connection should have at least 4 parameters, and normally 5");
temp.TargetEntityNameOrClass = components[0];
temp.TargetEntityInput = components[1];
temp.ParameterOverride = components[2];
temp.TriggerDelay = Convert.ToInt32(components[3]);
if (components.Length == 5) temp.NumberOfTimesToFire = Convert.ToInt32(components[4]);
return temp;
}
}
public List<KeyValuePair<String, IOConnectionClass>> Connections;
public SolidClass Solid;
public HiddenClass Hidden;
public EditorClass Editor;
}
public List<EntityClass> Entity;
}
It uses reflection and generics, and supports user made classes marked with [Serializable], List<>, List<KeyValuePair<,>>, Nullable<>, and the built in types: int, single, string, and boolean.
When you have a KeyValues member in a class that is of type List<KeyValuePair<String, String>> it will not embed the list in it's own braces (like "connections" for entities in the VMF format) but will place them in the current scope, like keyvalue "renderfx" for entities. The example, renderfx, is a legitimate keyvalue, where as connections is a node of it's own. This special KeyValues member is used to distinguish it.
You may want to use this code (as seen in the complete code) to make a shortcut for List<KeyValuePair<String, String>>:
- Code: Select all
using KeyValues = System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<System.String, System.String>>;
So you can instead just type:
- Code: Select all
public KeyValues KeyValues;
The functionality can be accessed by creating a formatter similar to how it is done with SoapFormatter or BinaryFormatter, except that instead of specifying the Type to serialize/deserialize in the constructor, it is specified as a generic argument and then using it normally:
- Code: Select all
KeyValueFormatter<ValveMap> serializer = new KeyValueFormatter<ValveMap>();
ValveMap myMap = (ValveMap)serializer.Deserialize(myStream);
There is also a convenience option:
- Code: Select all
ValveMap myMap = KeyValueFormatter<ValveMap>.ReadFromFile("C:\\foobar.vmf")
Unlike the other formatters, this one is trivial to instantiate and has a very small memory footprint, so it is safe to instantiate many wherever needed or convenient and allow garbage collection to dispose of them. There is also no run time code generation as is used in the other formatters, also keeping instantiation and debugging trivial. As it stands, output reflects the order of the data members of the class, though this is not guaranteed behavior as it is simply a result of the reflection provided by .Net. It is also not necessary to specify that other classes that will be serialized, as they will be identified and serialized automatically.
The code for the formatter and the VMF file definition have been provided as functional samples. They've had little testing, so be careful.
http://dl.dropbox.com/u/5105767/KeyValu ... xample.rar





