Property has range 0-255 but callback is uint16. Revelations!?

Discussions about the technical aspects of graphics development, including NewGRF tools and utilities.

Moderator: Graphics Moderators

Post Reply
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Property has range 0-255 but callback is uint16. Revelations!?

Post by Cadde »

I just noticed today that, for example, the running_cost_factor on vehicles (trains) property's limitations of 0-255 is "lifted" if one uses a callback.

When using the property as is in NML...

Code: Select all

property {
...
    running_cost_factor: 256;
...
}
It would either error out or it would be zero due to overflow or something else entirely... It doesn't matter.
But if i use a callback...

Code: Select all

switch(FEAT_TRAINS, PARENT, switch_running_cost_factor, 0) {
    256;
}
...
    graphics {
...
        running_cost_factor: switch_running_cost_factor;
...
    }
...
Then it would actually be "set" to 256. Or rather, it would internally in code be applied to the "GetRunningCost()" (in engine.cpp @~ 314) function in source code where the storage variable is uint and the callback return variable is uint16.
And that uint variable is "cost_factor" which is later used as...

Code: Select all

return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
... Or, in other words, there's no byte sized limitation anymore.

So here's a couple of questions for you guru's out there...

1) Does returning values > 255 in the callback have any possible negative implications?
2) Are there any other implications other than the limits of uint16 to consider, like the bit shifting of GetPrice?
3) How come this behavior isn't documented anywhere? Or did i miss it? Should it be documented?
4) In NML, can i rely on that the property value of "running_cost_factor" will remain the same once declared? For example, can i...

Code: Select all

return current_speed * 100 / max_speed * running_cost_factor / 100;
And assuming the running cost factor was set to 25 in properties, that's the value that would be passed to the callback every time? Regardless of what the return of the callback is?
5) Is this common knowledge in the "circles" or did i stumble on something new even for you?

... One more question...

6) The NewGRF debug windows are great and all. But is there any other way to debug grf's? I want to know what the values in the temporary registers are at evaluation time so i can actually verify some assumptions i've made.

Thanks!
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: Property has range 0-255 but callback is uint16. Revelations!?

Post by Cadde »

I will answer my own question number 4 here... There is no variable for running_cost_factor. Not in NML and not in NewGRF itself. So that goes out the window.
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 988
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: Property has range 0-255 but callback is uint16. Revelations!?

Post by frosch »

The range and units of the properties are arbitrary.
  • Properties have arbitrary size of 8 or 16 bits.
  • Callbacks alwayshave 15 bits. (since GRF version 8 )
  • So, for the raw value range: 8 bit properties < 15 bit callbacks < 16 bit properties
  • NML provides unit conversion for properties, so you can set a property to "15 km/h" and NML will convert that according to train/road vehicle/whatever units.
    Callbacks on the other hand always use raw values, NML is unable to supply unit conversions for callbacks.
  • Independent of the size of a property or callback result (8, 15, 16 bit), the values have limits.
    The limits are mostly undocumented, and usually not reached when using "normal values".
    For example, ships won't be able to travel faster than 128 mph, even if the callback allows returning way larger numbers.
  • The usual approach is to just try the values, and if they do not work, patch OpenTTD to support larger values.
    However, to save compatibility hassle we do not change properties, but only allow larger values via callbacks.
About debugging stuff:
In the past I worked on patches for NewGRF performance profilers (aug 2011), and for printing callback backtraces (feb 2014).
Some old screenshots: But neither of them were finished. If you know how to compile, I can likely find the old patches/queues somewhere.

All debugging facilities provided by the official branch are described here:
https://wiki.openttd.org/NewGRF_Debugging
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: Property has range 0-255 but callback is uint16. Revelations!?

Post by Cadde »

Thanks a lot for that frosch.
  • What does the 16th bit do? Surely it's not for signed values as that is being used arbitrarily depending on the callback? EDIT: Oh wait, without looking, it's for CB_FAILED isn't it?
  • Surely, for running cost factor in this case, the limits for the value itself are massive as there's either Price or Money structs involved holding said values for deduction from the bank account? But yes, of course ships won't turn into aircrafts any time soon.
  • "Normal" values. What are normal values anyways? Yes, i am trying it but at the same time i would like to know how far to take things before they break.
For instance, currently the base values are in the 0-255 range for running cost factor. Then i multiply those by 64 (currently) as in a 6,400% increase in locomotive running costs. Sure, i could just increase the running cost for trains modifier instead but then wagons (which currently have running cost factors as well) would also cost 64 times as much. I am looking to keep wagons as is and make locomotives 64 times as expensive while reducing the running cost modifier.
And there's the problem with small base values to begin with. If i linearly interpolate between 0 and 9 from zero to max speed then there's going to be 9 distinct steps. If i could prior to running the callback, multiply each base value by 8 so that 9 becomes a 72 instead. Or a 128 becomes a 1024. Now i can tell right away that any base value of 128, multiplied by 8 and then getting a 6400% modifier slapped on top would reach the limits right there. There is no "normal" when dealing with OTTD because one cannot use floating point numbers in callbacks in any usable manner. In fact, a lot of values are too restricted IMHO, I.E the 8 time bits of cargo profit calculations to name one. There i would be happy to see enough time bits to cover a weeks worth in minutes. (1440*7 whatever that turns out as in number of bits, heck... Why is there even amount in var18 to begin with?)

I technically could compile, i've done it before and when i do i end up spending a lot of time in code BREAKING compatibilities. If i bothered compiling myself i wouldn't be asking for GRF debugging as i would indeed add all the missing stuff in the GRF debug window myself.
And as far as compatibility goes, i would be happy to break it to get rid of "all" the limitations. But sitting there trying to work over NewGRF code would be as fun as writing my own game from scratch anyways, where all properties would be either float or even doubles. I've left 4:86 processors behind long ago. ;)
frosch
OpenTTD Developer
OpenTTD Developer
Posts: 988
Joined: 20 Dec 2006 13:31
Location: Aschaffenburg

Re: Property has range 0-255 but callback is uint16. Revelations!?

Post by frosch »

Bit 16 is for "return value" vs "link to next switch".
⢇⡸⢸⠢⡇⡇⢎⡁⢎⡱⢸⡱⢸⣭⠀⢸⢜⢸⢸⣀⢸⣀⢸⣭⢸⡱⠀⢰⠭⡆⣫⠰⣉⢸⢸⠀⢰⠭⡆⡯⡆⢹⠁⠀⢐⠰⡁
Cadde
Transport Coordinator
Transport Coordinator
Posts: 290
Joined: 07 Oct 2004 12:51

Re: Property has range 0-255 but callback is uint16. Revelations!?

Post by Cadde »

Bit 16 can't be accidentally set in NML can it? Sorry for all the questions but it's hard enough debugging without having to consider "random" catches along the way.
Sure, maybe one should stick to the expected ranges of values in the first place. But the fact that i can return something in the range 32768 instead of 255 is really going to help me fine tune a few things.
Post Reply

Return to “NewGRF Technical Discussions”

Who is online

Users browsing this forum: Auge and 18 guests