The International Simutrans Forum

PakSets and Customization => General Resources and Tools => Topic started by: TygerFish on December 14, 2012, 07:13:11 PM

Title: SimutransPak.dll -- A C# library for parsing Simutrans paks
Post by: TygerFish on December 14, 2012, 07:13:11 PM

What it is and why

I've been working with JamesPetts and The Hood on some balance changes to pak128.Britain-Experimental and found it difficult to see how values looked in context.  I started with a couple spreadsheets, but that quickly became unwieldy and had the continued burden of making sure I kept them updated with the values I was changing in the pak.

Being a C# programmer by day, I'm a big fan of LINQPad:
http://www.linqpad.net/ (http://www.linqpad.net/)
LINQPad is one part lightweight C# sandbox, one part database frontend.  C# is a joy to use in part because of its hybrid nature; one of its pseudo-functional components is LINQPad's namesake (http://en.wikipedia.org/wiki/Language_Integrated_Query (http://en.wikipedia.org/wiki/Language_Integrated_Query)).  This allows you to combine the procedural ease of C-family languages with the set-focused operations of SQL languages.

So I wrote a plugin to parse Simutrans pak files as C# objects so that I could query them in LINQPad.

https://github.com/calvin-fisher/SimutransPak (https://github.com/calvin-fisher/SimutransPak)

A precompiled Windows .dll is attached to this message.

How to use it

LINQPad can be downloaded here:

http://www.linqpad.net/ (http://www.linqpad.net/)

To set up my library in LINQPad, go to Query > Query Properties.  On the Additional References tab (it should start as the visible one), click  Add... and browse to the location of the SimutransDat.dll.  Then just click OK and start querying.

Once you're set up, simply create a new instance of the Pak object and pass in the path of the folder as the first parameter.  Notice that the translated name is also included; if you pass in a second string parameter (the default is "en" if not specified), it will use that translation file in the text diretory.  The pak has an Objects property that serves as the main data source -- it gives you access to all recognized Simutrans objects that were in .dat files.  Then, you write your query from there... here's a LINQ tutorial to help you get started:
http://msdn.microsoft.com/en-us/library/vstudio/bb397927.aspx (http://msdn.microsoft.com/en-us/library/vstudio/bb397927.aspx)

Why it's cool

Here are a couple concrete examples of what you can do with this.  First, a simple question: "give me all train engines, ordered by introduction date."

https://dl.dropbox.com/u/7182124/simutrans_linqpad.PNG (https://dl.dropbox.com/u/7182124/simutrans_linqpad.PNG)

This illustrates one the basic features of LINQPad that I'm using: the Dump() method inspects a C# object and translates all of its public properties into columns.  As for the query itself, we first have to filter by objects that are vehicles, then only ones that travel on the track waytype, then ones that have an engine_type declared (i.e., travel under their own power), then only ones with cost above zero (to filter out tender vehicles).

This is much easier than having to poke through .dat files, and it took about a third of a second on my computer to scan all of the pak's subdirectories, parse the files, and filter the results.

Next, a slightly more complicated question: "show me all train cars (not engines), ordered by introduction date, and include the running cost per unit of cargo."

https://dl.dropbox.com/u/7182124/simutrans_linqpad_2.PNG (https://dl.dropbox.com/u/7182124/simutrans_linqpad_2.PNG)

Rather than using the native DatObject type for this one, I created my own anonymous type (http://msdn.microsoft.com/en-us/library/bb397696.aspx (http://msdn.microsoft.com/en-us/library/bb397696.aspx)).  This is where the hybrid nature of the language really helps us out.  First, for the name and freight columns, I use the C# ?? operator (http://msdn.microsoft.com/en-us/library/ms173224(v=vs.80).aspx (http://msdn.microsoft.com/en-us/library/ms173224(v=vs.80).aspx)) to say "use the first value... unless it's null, in which case use the second one."  For the RunningcostPerUnit column, I wrote an expression that includes OvercrowdedCapacity in the total and round to three decimal places.  That allows us to easily see what the relative running cost is for each vehicle and make informed decisions about how to tweak the balance.

And for a third example, you can query multiple paks at the same time.  Since I'm merging some of The Hood's work on pak128.Britain-standard into pak128.Britain-experimental right now, it's going to be very useful to see at a glance what objects are in -standard that aren't in -experimental:

https://dl.dropbox.com/u/7182124/simutrans_linqpad_3.PNG (https://dl.dropbox.com/u/7182124/simutrans_linqpad_3.PNG)

This one uses the LINQ correlate of a SQL left join: http://stackoverflow.com/questions/9171063/convert-sql-to-linq-left-join-with-null (http://stackoverflow.com/questions/9171063/convert-sql-to-linq-left-join-with-null)

Future plans

Currently, I've included a bunch of properties on the DatObject class that I personally find useful in my present work with vehicles.  But I'm planning on expanding the library so that it allows you to have a set of properties more appropriate to whatever you're querying.  Other areas of interest include config files and saving changes.
Title: Re: SimutransPak.dll -- A C# library for parsing Simutrans paks
Post by: Dwachs on December 14, 2012, 09:53:29 PM
Is this a parser of dat-Files or pak-Files?

Great work!
Title: Re: SimutransPak.dll -- A C# library for parsing Simutrans paks
Post by: Combuijs on December 14, 2012, 10:37:44 PM
Reading the code it parses *.dat files, not *.pak files.
Title: Re: SimutransPak.dll -- A C# library for parsing Simutrans paks
Post by: sdog on December 15, 2012, 12:17:21 AM
mentioned on g+:


*Tool: pak file parser library*
_C# library to parse .dat files of a pak-set_

TygerFish wrote a library to parse .dat files. When developing and balancing pak-sets it is often difficult to keep the overview of the properties of the large number of objects. This library helps to parse the .dat files and work with the data in your own C# tools.
Title: Re: SimutransPak.dll -- A C# library for parsing Simutrans paks
Post by: TygerFish on December 18, 2012, 01:31:43 PM
Attached new version to first post with a duplicate-property bugfix.  Included several more examples on the github readme.
Title: Re: SimutransPak.dll -- A C# library for parsing Simutrans paks
Post by: Zeno on December 18, 2012, 01:45:44 PM
Hey TygerFish, this looks interesting.

Maybe you want to take a look at my mass editor project at sourceforge: http://sourceforge.net/projects/st-mass-dat/
It is done in more a manual way, but it includes many more options; most of them aren't 100% finished though, but basically reads DAT files massively and allows massive editing and saving.

Feel free to browse my code and use any part that you find useful (if you find any). Also, let me know if I can help somehow :)