Transistor tool: automatic publishing of the hardcoded data from spreadsheets to the source code on pre-build step

In game development performance is very important factor, especially in case of hi-load on-line multi player games in social networks. As we know one of useful tricks is to hard code as much as possible to avoid huge reading or initialization.

In the other hand, it’s hard to support such hard-coded solution (they even call it anti-pattern). For example, we have list of items in the game. It should be the same on servers side and on client side. If list is pretty long then it’s easy to make a fatal mistake, so, lists would be different. Better approach is to hold all the data in single place handy to modify/support and automation system to synchronize the data with all other places in the source code. There are a lot of benefits. As it’s single place then it’s easy to support and avoid difference mistakes. As it automated then we don’t need developer to spend his time to update it.

I created such system. I called it transistor. There are 3 parts:

  • The python script transistor.py
  • Data composed into CSV
  • Source code with hard coded section and template to fill it

We can use one or more CSV tables. One table may have reference(s) as index(es) to another. CSV content should be available via HTTP or locally. I use Google Docs Spreadsheets for that. First line of each CSV table should have case-sensitive fields (columns) names. Other rows have the data. Later the script will parse those data into the list of dictionaries.

My first try was using of pure python string formatting as template. It means that the template and its logic were in python code on the script side. There were bad design and huge ugly implementation. Well, if you have a lot of code then it is almost always bad architecture. There should be very small amount of code. So, I declined that prototype. The second (and the best) design approach was to make that script universal and move all specific template data and logic to the template situated in the same source code file (in comments).

/*// gunTypes begin{% set gunTypes = tables.gunTypes -%}{%- for g in gunTypes -%}{%- if g.shoot_width -%}{%- if loop.index0 > 0 %},{% endif -%}new GunType({{g.id}}, new Shape({{g.base_width}}, {{g.base_height}}, new byte[]{                        {{g.base_shape|replace('n', 'n                                                        ')}}        }), new Shape({{g.shoot_width}}, {{g.shoot_height}}, new byte[]{                        {{g.shoot_shape|replace('n', 'n                                                        ')}}        })){%- endif %}{%- endfor %}// gunTypes template end */        // ... here would be generated content ...// gunTypes end

Hard-coded section in the source code file has header, footer and template delimiter. There are the template between header and template delimiter and the generated content between delimiter and the footer. Usage example:

python transistor.py --file=GunTypesDict.cs --section=gunTypes                --table=gunTypes                --url="https://docs.google.com/spreadsheet/pub?...&output=csv"
or more complicated with 2 tables:
python transistor.py --file=LocationsDict.cs --section=locations                --table=fields --table=locations                --url="https://docs.google.com/spreadsheet/pub?...&output=csv"                --url="https://docs.google.com/spreadsheet/pub?...&output=csv"
After such data publishing we have the same source code like:
/*// gunTypes begin{% set gunTypes = tables.gunTypes -%}{%- for g in gunTypes -%}{%- if g.shoot_width -%}{%- if loop.index0 > 0 %},{% endif -%}new GunType({{g.id}}, new Shape({{g.base_width}}, {{g.base_height}}, new byte[]{                        {{g.base_shape|replace('n', 'n                                                        ')}}        }), new Shape({{g.shoot_width}}, {{g.shoot_height}}, new byte[]{                        {{g.shoot_shape|replace('n', 'n                                                        ')}}        })){%- endif %}{%- endfor %}// gunTypes template end */new GunType(0, new Shape(1, 2, new byte[]{                        1,1        }), new Shape(1, 1, new byte[]{                        5        })),new GunType(1, new Shape(2, 1, new byte[]{                        1,1        }), new Shape(2, 2, new byte[]{                        0,5,                        5,0        }))// gunTypes end
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

%d bloggers like this: