-
Notifications
You must be signed in to change notification settings - Fork 3
Parser Generation
Most of the parsing code for chunks and custom structs in GameBox files is not written by hand, but automatically generated using attributes on property definitions as described here.
To generate a parser, the properties in the class that the parsing code is being generated for are analyzed via reflection via the Fields.GetFields<T>()
method. To be included in the parsing code, a property must be decorated with the Property
attribute. For more advanced data structures, the Array
, Condition
attributes are also available which further specify the parsing behaviour. If the parsing of a specific property is too complex for the attribute-based system, a custom parsing method can be provided via the CustomParserMethod
attribute. All of this information is stored in a Field
object for each property and returned collectively.
From this collection of Field
instances, the parsing code for the chunk is generated. First, code for creating the instance of the chunk/custom struct is generated, then the code for parsing each of the fields is generated. There are two methods for code generation included in ManiaPlanetSharp
This method uses Linq Expressions to generate expression trees that represent the parsing code. These are then compiled dynamically and loaded into memory. This API can be used to generate parsers for arbitrary chunk/custom struct layouts at runtime.
This method emits a string containing plain C# code for parsing the specified chunk/custom struct. This API is used for generating the pre-compiled parsers.
ManiaPlanetSharp includes the ManiaPlanetSharp.GameBox.AutoGenerated
project, which is used for providing pre-compiled parsers for all chunks and custom structs implemented in ManiaPlanetSharp. This project uses T4 to load the ManiaPlanetSharp library after its compilation, create a list of all present chunks and custom structs and then emit parsing code for all of them and then compiles them into the ManiaPlanetSharp.GameBox.AutoGenerated
library. When the ParserFactory
class of the main ManiaPlanetSharp library, which manages parsers for chunks and custom structs, is initialized, this library is loaded (if present) and the parser classes are then served via the various methods of the ParserFactory
class instead of generating them at runtime. This helps reducing the memory footprint of the application significantly, as each chunk and struct parser would be compiled into a separate assembly if the pre-compiled parsers are not included. Performance is also improved, as the chunk parsers don't have to be generated and compiled at runtime.
For most use cases, the pre-compiled parsers are the better way to go - the dynamically compiled parsers are primarily meant for development purposes where you might want to try out different chunk layouts at runtime without having to recompile the project or for projects which implement their own chunks or structs on top of the ones that ManiaPlanetSharp provides. For the latter use case, including the pre-compiled parsers still makes sense to speed up the parsing of the chunks that are implemented in ManiaPlanetSharp - for the ones which are not included in ManiaPlanetSharp, the parsers will be generated at runtime automatically, so you still get most of the performance advantages while being able to add your own chunks.