#grf-py 0.3.1 - a new way to make NewGRFs (with Python)
1 messages ยท Page 1 of 1 (latest)
Version 0.2.1 is available on pypi and github (https://github.com/citymania-org/grf-py).
Nothing too big, just a whole bunch of bugfixes and QoL improvements.
-
Fix: Add articulated callback to purchase chain as well.
-
Fix: Don't write data for same real sprite object multiple times.
-
Fix incorrect encoding of empty sprite.
-
Fix duplicating actions that were added to grf manually.
-
Fix
Labelvalue validation. -
Fix error in action generator for vehicle name.
-
Fix compilation for
railtype_table,lang_gendersandlang_casesglobal vars. -
Fix vox house example.
-
Allow specifying fallbacks in the railtype table.
-
Add a
cropparameter to sprites (Trueby default). -
Support new
variant_groupandextra_flagAction 0 vehicle properties. -
Add encoder for
advanced_layoutaction 0 station property. -
Return railtype ids in
NewGRF.set_railtype_table. -
Add functions to manage railtype tables to
NewGRFclass (set_railtype_tableandget_railtype_id). -
Add
get_cargo_idmethod toNewGRFclass. -
Allow to use nml-like comparison operators in the
Switchcode. -
Allow to pass code to
Switchas a list of lines. -
Add
DEFAULT_CARGO_FIRST_REFITTABLEconstant. -
Allow passing bytes value to actions 7, 9 and D.
-
Check that articulated part id doesn't exceed the max value (0x4000).
-
Allow to omit sprite width and height when they can be auto-detected.
-
Add support for Action B (
ErrorMessage). -
Add
idproperty to theDefineclass. -
Rename
Action0properties forOBJECTfeature to match NML names. -
Export
StringRef,open_image,find_best_color,SpriteRef,SpriteLayout,SpriteLayoutList,GroundSprite,ParentSprite,ChildSpriteclasses. -
Check that first parameter of
Mapaction isDefineMultiple. -
Cache palette remap when fixing sprite palette.
-
When fixing palette check for exact color first.
-
Add some handling for sprites without any image.
-
Update numpy version to one that has Python 10 builds.
- lib: Fix
CallbackManagernot writing some callbacks. - lib: Fix
CallbackManagernot setting purchase graphics without purchase callbacks. - lib: Add
skip_props_checkargument toTrain.add_articulated_partto skip validation of properties. - lib: Make
Trainarticulated parts liveries optional. - lib: Allow specifying callbacks for
Trainarticulated parts. - lib: Make liveries argument optional for
TrainandRoadVehicle. - lib: Add
callbacksproperty toTrainandRoadVehicle. - lib: Add optional callback argument to
CallbackManagerconstructor. - lib: Add
CallbackManager.make_map_actionto makeMap(Action3) forDefine(Action0). - lib: Make graphics and purchase graphics properties of
CallbackManagerinstead ofmake_switchesarguments. - lib: Allow using
StringRefas a name forTrainorRoadVehicle. - lib: Allow using
StringRefas a vehicle additional text.
grftopy: Fix value decompilation in action 7/9.
grftopy: Fix sprite sheet filename generation.
grftopy: Fix RandomSwitch decompilation for vehicles.
grftopy: Fix python generation for properties of custom type.
grftopy: Assign variables to referenceable actions and use them for references.
grftopy: Write climate bits as constants.
grftopy: Don't write ref_id=None in generated python.
grftopy: Decomplile introduction_date property into a datetime object.
grftopy: Print value as a label in comment for actions 7, 9 and D.
grftopy: Convert grftopy script into decompile sub-module.
grf-py 0.2.1 - a new way to make NewGRFs
Version 0.2.2 is available on pypi and github (https://github.com/citymania-org/grf-py).
A bunch of minor additions, changes and bugfixes before (hopefully) heading into 0.3.0
-
Change license to GPL v2+ (same as nml) instead of v3 to allow reusing v2 code/resources.
-
Fix graphics sprite composition.
-
Fix Train weight Action 0 properties (low and high bytes).
-
Fix compilation of generic var parameter in Action 2.
-
Fix
var(...)call inSwitchcode not acceptingparamvalue without parentheses. -
Fix default purchase sprite for auto-articulated trains.
-
Rename
speedAction 0 property for ships tomax_speedfor consinstency with other vehile types. -
Rename Action 0 ship properties to match nml:
cargo_typetodefault_cargo_typesoundtosound_effectocean_speedtoocean_speed_fractioncanal_speedtocanal_speed_fractionflagstomisc_flagsrefit_classestorefittable_cargo_classesnon_refit_classestonon_refittable_cargo_classes
-
Add
id_map_fileparameter toBaseNewGRFconstructor andreserve_idsandresolve_idmethods to manage auto-assigned (string) IDs. -
Use
AlternativeSpritesinstead of sprite tuples. -
Add Action0 properties for road types.
-
Add
NewGRF.add_railtypeto add railtypes one-by-one. -
Add
VEHICLE_NEVER_EXPIRESconstant. -
Add
AIFlagsandTrainRunningCostenums. -
Add
Flags,AIFlags,RuningCostenums for Trains. -
Add
Paletteenum. -
Add
Train.hpandTrain.tonmethods for converting metric units. -
Add visual effect constants and methods.
-
Make
NewGRF.bindto make a subclass of the type instead of function and exposebound_newgrfproperty. -
Change Switch parameter order from to
code, ranges, default. -
Rename
is_dual_headedAction 0 Train property todual_headedto match nml. -
Add
NewGRF.grfid_valueproperty. -
Pass grf as an argument to
Vehicle._set_callbacks.
-
Allow
visual_effect_and_poweredforTrainarticulated parts. -
Don't check for sprite type when adding it for now (messes up decompiling).
-
Use setuptools-git-versioning to manage versions.
-
Update documentation.
-
Allow to use objects with id as a variant_group value in Aciton0.
-
Use IDProperty for
sort_purchase_listin Action 0 for vehicles. -
lib: Add
Shipsprite generator. -
lib: Rename
kmhishphmethod tokmhishinTrainandRoadVehicle. -
lib: Make
_set_callbacksreturn list of sprites to allow adding graphics. -
lib: Make auto-articulated parts use auto-assigned(string) IDs.
-
lib: Support road vehicle property callbacks in
CallbackMananger. -
lib: Fix RoadVehicle name.
-
lib: Fix
CallbackManagerexceptions. -
lib: Fix incorect livery for
Trainwagons. -
lib: Add
VehicleGroupclass to define vehicle groups inSetPurchaseOrder. -
lib: Add
lengthproperty to aTrainconstructor, auto-articulate if > 8 (up to 24). -
lib: Add
lengthproperty toRoadVehicleconstructor (1..8). -
lib: Add
purchase_spriteproperty toTrainandRoadVehicle. -
lib: Allow to use length > 8 (but <= 24) for articulated parts.
-
lib: Allow specifying property callbacks individually in
CallbackManager. -
lib: Add
SetPurchaseOrdersprite generator. -
lib: Rename
POWERED_WAGONScallback toVISUAL_EFFECT_AND_POWERED. -
lib: Allow to use
StringRefas a livery name. -
lib: Add
_set_articulated_part_callbacksmethod toTrain. -
lib: Use assigned id for the first part when auto-articulating.
-
lib: Add
SetGlobalTrainDepotYOffsetsprite generator. -
lib: Add
GlobalTrainMiscFlagenum andSetGlobalTrainMiscFlagsprite generator. -
vox: Fix vox house example.
-
vox: Experimental .vox renderer for trains.
grf-py 0.2.2 - a new way to make NewGRFs (with Python)
What does NewGRF.add_railtype do?
adds a single railtype to the railtype table
may need a better name I guess
same as set_railtype_table but for a single entry
I wanted to share my idea which is the blueprint system. People should be able to share copy paste their blueprints via a file like .blueprint etc. I have researched some stuff and i don't think it would be managable by newgrf and should be added directly to the game
Yes, it's not doable with newgrf or gamescript. But I have another project - patched OpenTTD version, fully compatible with vanilla, that implements copy-paste (https://citymania.org/downloads). It doesn't allow to save them yet though.
Hey @prime haven ! I just cloned this repo to try it out. I'm hoping to use this to automate getting traditional 3d models from blender into OpenTTD. I have a couple of friends that make assets for Cities Skylines and other games that'd love to see their stuff in OpenTTD.
I gave the vehicle example a try, worked great! However I'm running into difficulty running the vox_house.py example. It seems like some unexpected sprites are getting packed? Any ideas of stuff I'm doing wrong?
Hello! Yeah, vox house example got pretty outdated. I'm not sure how you even got it to compile. Are you using 0.2.2 version? If you do switch to the latest from the github https://github.com/citymania-org/grf-py it's getting close to 0.3.0 already and lots of stuff changed. Anyway I fixed the vox house example, should work now.
Though the closest for your usecase is probably not the voxel stuff as that just uses custom renderer that grf-py has but this part in BonkyGFX: https://github.com/lukaskrepel/BonkyGFX/blob/567174b97620e606dba0698dfcf545a1f63e0512/lib.py#L798-L848 As it runs an external program "aseprite" to generate the image files with all the requested options (layers and frames in this case). BonkyGFX in general is a great example of the latest trends in grf-py develepment. It may be a bit overwhelming due to the size of the project but most of the code is pretty modular and I will be moving some stuff from it into grf-py pretty soon.
Anyway, let me know if you need any help with the code, I don't mind writing some of it and, in fact, would like to have a wrapper for blender rendering in the grf-py itself eventually.
Cool! Thanks for your help, I'll try updating it this morning. I'll take a look at BonkyGFX too, that sounds like what I want to do.
Do you accept PRs for this project? I could definitely contribute. I'm thinking that some docstrings would be an easy thing to add, and some sort of build pipeline might make testing/shipping that doc easier.
Sure, I accept PRs pretty easily, though keep in mind the licensing part: https://github.com/citymania-org/grf-py/?tab=readme-ov-file#licensing
For docs so far my hope was to just wait until some LLM can write them for me xD
What a coincidence!
I started looking into making NewGRFs the day before yesterday, got irritated by NFO after 2 hours, got surprised at there not being a higher level language (than NML) or even GUI interface and I find this on discord with an announcment for a version 0.3.0? What a rollercoaster of emotions ๐
I haven't been able to look into the code as I'm quite busy with work still, but I was planning on modelling and creating some Swiss stations, so I might be back soon to ask some questions @prime haven ^^
Stations do happen to be the most complicated feature to code in any language so maybe you should try and start with something else first
A friend of mine said the same thing, having asked a similar question in another channel before ๐
I already had a surge of motivation when I got GIMP to work with the color palette, or when my first (modified) NML created GRF worked.
I'll go about the task slowly and see where it takes me ๐
well, the most complicated part in case of grf-py is that noone used it for stations yet so there are no high-level classes and no examples but probably plenty of bugs
though I did have an extremely simple station example somewhere
I'll look for it tomorrow
I added an example for a eyecandy station https://github.com/citymania-org/grf-py/blob/main/examples/eyecandy_station.py it does have the beginnings of a Station class but it's nowhere near completion ofc
I have checked out the train example and your freshly uploaded one. Makes sense so far to me. I will probably not have time to delve deeper until Sunday, but I'll test it further and try and see where I could contribute ๐
Thanks @prime haven, appreciated
Following
Ah, I should check it out! ๐ฎ
EDIT: it helped a lot, thanks!
What does it do exactly?
just adds a simple eyecandy station class (doesn't allow trains in, purely decorative)
Oh
can this be used to make industry chains
grf-py has full support for all newgrf features on a low level so in theory it can be used to make anything. High-level support for industries is somewhat lacking though so it may not be that simple.
here is an example of grf that adds some industries https://github.com/citymania-org/cmevent-grf/blob/main/cmevent.py#L608
somewhat tricky one actually as one of the industries has a randomized cargo acceptance
ok
just wondering if this can be remade with grf.py : https://github.com/cFlour/cflour-openttd-industries-set
Version 0.3.0 is available on pypi and github (https://github.com/citymania-org/grf-py).
This release has been long overdue and a lot of changes got accumulated. Main feature this time is the addition of sprite caching with support for custom sprite classes and procedural sprites. But there are also a lot of bugfixes, new additions and some API changes in an attempt to stabilize it a bit.
Full changelog:
- Reorganize base sprite/action hierarchy so it better reflects newgrf structure. Also rename classes to use common terms rather than grf-specific ones (real/pseudo sprite).
- Rename
BaseSpritetoAction. - Rename
IntermediateSpritetoFakeAction. - Rename
RealSpritetoResourceAction. - Add new base class
Resourcethat resources now inherit instead ofRealSprite. - Make
ResourceActionandAlternativeSpritescontainers for theResourceobjects. - Rename
SoundSpritetoSound. - Rename
GraphicsSpritetoSprite. - Rename
EmptyGraphicsSpritetoEmptySprite. - Remove
LazyAcitonandAction.get_data_sizeas no longer necessary.
- Rename
- Fix auto-assigned IDs overlapping when adding vehicles.
- Fix encoding of label lists in Action0 properties.
- Fix encoding and decoding of Action 5.
- Fix
min_lifeAction0 property size for houses (spec error). - Fix
Switchcode using wrong feature for related scope. - Fix
Switchcode grammar issues. - Fix alpha generation when using colourkey.
- Fix encoding of
min_bridge_heightAction 0 station property (#33). - Fix imageSprite conversion for non-P and non-RGBA images (#43).
- Add sprite cache.
- Optimize memory usage when writing NewGRF.
- Optimize grf file size by removing duplicate sprites (by data).
- Allow defining named temporary variables in
Switchcode.
- Allow defining named temporary variables in
Switchcode. - Rename zoom constants to use natural/nml order:
ZOOM_4X->ZOOM_2X->ZOOM_NORMAL->ZOOM_OUT_2X->ZOOM_OUT_4X->ZOOM_OUT_8X. - Rename
PALETTEtoPIL_PALETTE, addPALETTEas a list of (r, g, b) tuples. - Add
OKLAB_PALETTE,NP_PALETTE,PALETTE_IDXconstants. - Add
srgb_to_linear,linear_to_srgb,srgb_to_oklab,oklab_to_srgbcolour conversion functions. - Add
modeargument toMaskwith option to overdraw sprite. - Add
ShipFlagsenum. - Support extended format in Action 1.
- Support ids > 255 in Action 3 (#42).
- Add
mainfunction to handle command line arguments. - Add support for road stop feature (#44).
- Add some VarAction2 variables for houses.
- Add
station_nameandstation_class_nameAction 0 properties for stations. - Add
TTDStringandTTDIndustryconstants. - Add
TownGrowthEffectconstants. - Add
Evalas a version ofSwitchwithout ranges. - Add
subroutinesargument toSwitchand allowname()call syntax. - Add
debug_zoom_levelsargument toBaseNewGRF.writeto recolour sprites according to their zoom level: 4x - red, 2x - blue, 1x - green, out-2x - cyan, out-4x - yellow, out-8x - magenta. - Add
--debug-zoom-levelscommand line argument tobuildcommand ofmainfunction. - Add
WithMasksprite class to add mask layer to images. - Add
SpriteWrapperclass to simplify writing sprite modifiers. - Add
MoveSpritemodifier to change sprite offsets. - Support using StringRef in Action 0x14 (
SetProperties). - Support using StringRef as
NewGRFnameanddescription. - Support encoding of bridge layouts.
- Support encoding of industry layouts.
- Support encoding of tile acceptance lists for houses and industry tiles.
- Support expressions for register value in PERM and TEMP access.
- Support parameter expressions for vars60+ in
Switchcode (via var7b). - Support cropping 24bpp sprites.
-
Add
preferred_blitterargument toNewGRFconstructor, possible valuesNewGRF.BLITTER_BPP_8andNewGRF.BLITTER_BPP_32. -
Add
StringManager.get_persistent_idfunction to register strings in "persistent" range (0xDCxx). -
Add
Sprite.save_gifmethod to generate palette animated images. -
Add
Sprite.make_rgba_imagemethod to generate static PILImage. -
Add init_id_map command line command to initialize id_map.json.
-
Add
Datetype to represent dates that don't fit intodatetime.date. -
Add example of a simple eyecandy station.
-
Start auto-assiged IDs from 0 for INDUSTRY_TILE feature.
-
Rename
AlternativeSprites.get_zoomtoget_spriteand add bpp argument. -
Rename some of the Action0 properties for
CARGOto match nml. -
Don't write redundant actions for railtypes without fallbacks in railtype table.
-
Return cargo type ids in
NewGRF.set_cargo_table. -
Remove all uses of spectra in favour of own colour submodule using OKLAB colour space.
-
Only replace .grf file when build succeeded.
-
lib: Fix
CallbackManager.make_switchesfor non-vehicle features. -
lib: Fix incorrect 2cc colors for auto-articulated parts.
-
lib: Fix unicode vehicle names.
-
lib: Don't change callbacks passed to
CallbackMananger. -
lib: Set correct flags and track_type on auto-articulated parts.
-
lib: Fix auto-articulation for vehicles without liveries.
-
lib: Fix: Make station availability a purchase callback.
-
lib: Add high-level
Industryclass. -
lib:
CallbackManagerrewrite:- Support all features (non-vehicles may still be incomplete).
- Make
CallbackManagerabstract class, usemake_callback_managerfunction instead. - Support splitting callbacks for default and purchase branch with
DualCallback. - Use
graphics.purchaseinstead ofpurchase_graphicsattribute.
-
lib: Add
Ship.FlagsandRoadVehicle.Flagsfor unified access to flags. -
lib: Add
EngineOverridesprite generator.
-
lib: Add
reverse_build_probabilityvehicle callback. -
lib: Allow omitting
idsinDisableDefaultto disable all items. -
lib: Support
HOUSE,INDUSTRYandCARGOfeatures inDisableDefault. -
lib: Add
chunk_sizeparameter tocombine_ranges. -
grftopy: Fix missing sprite zoom
-
grftopy: Improve decoding of industry layouts.
-
grftopy: Fix decompilation of ActionB.
-
grftopy: Fix decompilation of action 7/9 with value > 4 bytes.
-
grftopy: Add -p/--palette cli option to set output palette for 8bpp images.
-
grftopy: Decompile
cargo_(dis)allow_refitproperties as a tuple of cargo indexes. -
dev: Add new
devsubmodule for extending newgrf spec support. -
dev: Add
dev.add_featurefunction.
grf-py 0.3.0 - a new way to make NewGRFs (with Python)
Version 0.3.1 is available on pypi and github (https://github.com/citymania-org/grf-py).
This is just a small release with accumulated fixes before heading into 0.4.0 development that will eventually drop support for Python < 3.12 and OpenTTD < 15.0.
Changelog:
- Fix duplicate sprite counter in build report not counting individual alternative sprites like total does.
- Fix unsigned parent sprite offsets in advanced layout (#45).
- Fix exception when handling property encoding errors.
- Fix error in
Sprite.make_rgba_imagefor sprites with rgb and mask. - Fix Comment and Label actions (#49).
- Fix length calculation for auto-articulated parts on articulated parts.
- Add
QuantizeSpritewrapper andquantizefunction to convert 32/24bpp sprites into 8bpp with openttd palette. - Add some code comments and documentation.
- Update
srgb_color_distanceto use colour tuples. - grftopy: Fix decompilation error.
It's a Python framework that aims to cover the whole cycle of NewGRF development, from resource generation and low-level GRF actions to convenient templating and compilation. Having it all in the one place, powered by one of the best programming languages helps to keep it simple but flexible, minimize repeating code and achieve great readability and maintainability of the code.
As grf-py covers pretty much the whole range of GRF format capabilities its primary application are the most complex projects that benefit the most from the ease of development and maintenance while keeping full control over GRF performance. But in the future, as grf-py gains more high-level classes it should make it pretty approachable for beginners as well, better than nml at least.
Also, grf-py includes grftopy`decompiler that can produce low-level grf-py code for a .grf file.
Some examples of GRFs with grf-py:
Simple examples: https://github.com/citymania-org/grf-py/tree/main/examples
Road vehicles: https://github.com/citymania-org/uk-dk-busses
Trains: https://github.com/citymania-org/robs-trains
Trees and procedural sprites: https://github.com/citymania-org/debug-trees-grf
Objects and low-level API: https://github.com/citymania-org/cmclient/tree/master/grf/alpine
You can find grf-py on the github: https://github.com/citymania-org/grf-py
or pypi: pip install grf
I find it quite boring and even somewhat counter-productive to develop the API without a specific application for it and at this point, I've run out of my own grfs to make. So I'm looking for people who are willing to support further development of grf-py and try to make their own projects with it. Though I fully understand that it's not easy to learn grf-py as it is since documentation is lacking and API is not very stable so I'm ready to provide all the support you need and even code some things for you. In fact, if you can make good sprites, I'm ready to do all the heavy-lifting so you don't even need to code anything complex at all, just learn some git and python basics to copy-paste and fine-tune simple code like this: https://github.com/citymania-org/uk-dk-busses/blob/main/generate.py#L46 So if you have some good idea just hit me up and we'll make it work. It can be pretty much anything: porting old projects from nfo/nml, tweaks, and addons for other grfs, making a bridge or station sets, voxel stuff, anything goes. Though I'm mostly interested in things I haven't done yet, i.e. not trains and road vehicles, it's fine to have some variety of those as well.
Is it possible to use vehicle variable 61 in grf-py?
yes, like any unmapped variable with var(num, shift, add) and similar https://github.com/citymania-org/grf-py/blob/main/grf/parser.py#L586
well, var(num, shift, and, param) since it's 60+
and you'll need to assign TEMP[0x10f] and TEMP[0x10e] beforehand
Nice