GRFv9

From GRFSpecs
Jump to navigationJump to search

Introduction

This page describes work so far, design considerations and other items of interest for a potential version 9 of the GRF specification (GRFv9), or equivalent specification evolution.

This page is a not a guarantee that any such changes will be occur in future, or that any such future work will closely match that described here.

Existing Work

GRFv9 PRs (closed) https://github.com/OpenTTD/OpenTTD/pull/13309 (NML: https://github.com/OpenTTD/nml/pull/357)

For 15.0: Add explicit (Var)Action2 results for "callback failed" and "calculated result". https://github.com/OpenTTD/OpenTTD/pull/14149

Design Considerations

The current GRF specification has several areas which are not ideal and could be improved in a subsequent specification version.

This section should list current pain points and non-idea specification aspects, and where possible suggest improvements or general design principles for future additions. This section is non-exhaustive.

Concurrent Action2 ID Limit

GRFs are currently limited to 256 simultaneous action2 IDs. This is a common pain point for NewGRF authors. NewGRF authors are encouraged to needlessly duplicate action2s (e.g. by use of templating mechanisms) to mitigate this, this results in larger GRF files which has a negative impact on content distribution and run-time performance. Moving to 16 bit Action2 IDs would remove this problem without imposing significant technical difficulty.

General Design Comments on VariationalAction2

Currently only variables 60 to 7F are parameterised, this ID space is too small and should be expanded. Currently many 60x variables are multiplexed to return multiple unrelated or only partially related values, this is a non-ideal for the following reasons.

  • Some 60x variables sub-parts are too small in order to fit them into a single 32-bit variable, this leads to surprising/buggy behaviour in some GRFs (e.g. house variables 60/61 and 44).
  • 60x variable sub-parts can become too small when ID ranges are extended, creating a need for a replacement variable and more work than would otherwise be necessary (e.g. station variable 6B).
  • Some 60x variables are needlessly expensive at run-time because expensive sub-parts are calculated even when the GRF only needed another part of the variable (e.g. industry variable 67/68) (this can be reasonably mitigated without a spec change).

The current "error group" behaviour for unavailable variables is unintuitive, especially when working from a higher abstraction layer such as NML. This also interacts unfavourably with the suggested callback topology where unhandled callbacks are routed onto the graphics chain.

Code patterns very commonly used by NewGRF authors such as flag ? a : b in NML read and immediately throw away the value of a when flag is false. The generated VarationalAction2 sequence for this is also overly verbose. It may be useful to consider adding operators or other mechanisms to enable these types of patterns to be expressed more efficiently.

Likewise, adding simple relational operators (as opposed to the current cmp/ucmp) could reduce the need for verbose sequences to do comparisons.

Procedure calls (variable 7E) truncate the result value to 15 bits, this is a source of surprising behaviour for NewGRF authors. Avoiding this requires using variable 1C. It may be useful to remove the need for this truncation.