-
-
Notifications
You must be signed in to change notification settings - Fork 958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
16 cargo types in and out for industries #6867
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I covered all locations referencing to specific indices of the production/acceptance arrays, but my only testing so far is "compiles" and "does not crash loading an old save".
src/newgrf_industries.cpp
Outdated
cargo_type == ind->accepts_cargo[4] || cargo_type == ind->accepts_cargo[5] || cargo_type == ind->accepts_cargo[6] || cargo_type == ind->accepts_cargo[7] || | ||
cargo_type == ind->accepts_cargo[8] || cargo_type == ind->accepts_cargo[9] || cargo_type == ind->accepts_cargo[10] || cargo_type == ind->accepts_cargo[11] || | ||
cargo_type == ind->accepts_cargo[12] || cargo_type == ind->accepts_cargo[13] || cargo_type == ind->accepts_cargo[14] || cargo_type == ind->accepts_cargo[15] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really ugly, but it also feels wrong to have a for loop nothing but an assert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to put the loop inside the assert:
assert(std::find(ind->accepts_cargo, endof(ind->accepts_cargo), cargo_type) != endof(ind->accepts_cargo));
src/saveload/industry_sl.cpp
Outdated
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, 200, SL_MAX_VERSION), | ||
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, 70, 199), | ||
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, 200, SL_MAX_VERSION), | ||
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, 0, 199), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is correct, but not entirely sure, converting SLE_ARR to SLE_CONDARR starting at version 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the savegames stores the size of the array.
So it may not even need the condition. Just changing 2 to 16 may be enough.
But needs trying and possibly proper initialisation of the array with CT_INVALID.
if (num_cargos == 0) return false; // industry produces nothing | ||
int cargo_num = RandomRange(num_cargos) + 1; | ||
int cargo_index; | ||
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This algorithm feels overly complicated. Does it seem right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"ci" and "cargo_index" for the same thing is a bit weird.
But otherwise I see nothing wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
This PR does not seem to extend the NewGRF stuff, so no NewGRF can make use of this. |
Needs nml patched too. I can probs do that. |
Okay here's an attempt at implementing the NewGRF spec changes @frosch123 suggests. I skipped var 6E for now since that requires additional logic to record the data, currently there is only an "any cargo last accepted" date for each industry. |
An open question about GUI: The Industry chain window sizes itself after the max number of cargo types in/out possible, and with 16 types this results in some ridiculously large windows. It can't fit with standard font and 1x GUI on 1024x768 resolution. |
I think it would be worth looking at extending tile callbacks 2B and 2C, to allow more accepted cargos per tile. https://newgrf-specs.tt-wiki.net/wiki/Callbacks#Get_accepted_cargo_types_.282A.2F2C.29 I suggest allowing return value to be either
I've played grfs with the 'multiple tiles are required for acceptance' and it's not as fun as it might sound imho. Also, putting gameplay aside, FIRS tends to split tile IDs for different animation cycles, or for building on different land shapes (water, slope, flat etc). It could be quite faffy to combine that with splitting IDs for tile acceptance and then also giving a visual cue to the player. :) As far as I can see in docs, cargo acceptance for the tile is not stored in the map, so I am hoping it would be relatively simple to extend :) This would probably make more sense as a separate PR. |
I wonder if it would really be so bad to introduce a couple new Action0 properties to set acceptance. If you're developing a NewIndustries set that depends on 64 cargo type and 16-in-16-out, chance is you won't be compatible with OpenTTD 1.8 and earlier anyway, so shouldn't the NewGRF failing to load on older versions be a non-problem? |
I agree. The failing-to-load seems to be a non-problem. With or without new action 0 props, the CBs would need extended for the 'stop accepting cargo according to conditions' case for industries, which tiles also need to handle :) |
Suggestion for new Action0 properties:
|
src/industry_cmd.cpp
Outdated
/* Query actual types */ | ||
uint maxcargoes = 3; | ||
if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) maxcargoes = lengthof(i->accepts_cargo); | ||
for (uint j = 0; j < maxcargoes; j++) { | ||
uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE); | ||
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break; | ||
if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) { | ||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res); | ||
break; | ||
} | ||
i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly also check for duplicate results.
src/industry_cmd.cpp
Outdated
/* Query actual types */ | ||
uint maxcargoes = 2; | ||
if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) maxcargoes = lengthof(i->produced_cargo); | ||
for (uint j = 0; j < maxcargoes; j++) { | ||
uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE); | ||
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break; | ||
if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) { | ||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res); | ||
break; | ||
} | ||
i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly also check for duplicate results.
src/newgrf.cpp
Outdated
break; | ||
} | ||
for (uint i = 0; i < group->num_input; i++) { | ||
/* XXX: maybe check for same cargo id used multiple times and warn/error? */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is useful to allow passing 255 here, to skip cargotypes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't want a cargo type to participate in a production callback, don't include it in the parameters to the callback, I don't see what a "skip" value would do.
src/newgrf.cpp
Outdated
break; | ||
} | ||
for (uint i = 0; i < group->num_output; i++) { | ||
group->cargo_output[i] = buf->ReadByte(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is useful to allow passing 255 here, to skip cargotypes.
src/newgrf.cpp
Outdated
ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res); | ||
break; | ||
} | ||
indsp->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indsp->grf_prop.grffile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for duplicates?
src/newgrf_spritegroup.h
Outdated
uint8 again; | ||
|
||
// version 2 extensions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comment is not useful in the future
src/newgrf_spritegroup.h
Outdated
// version 2 extensions | ||
uint8 num_input; | ||
uint8 num_output; | ||
uint8 cargo_input[INDUSTRY_NUM_INPUTS]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cargo_input/output are CargoID, not uint8?
if (num_cargos == 0) return false; // industry produces nothing | ||
int cargo_num = RandomRange(num_cargos) + 1; | ||
int cargo_index; | ||
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
src/newgrf.cpp
Outdated
} else if (type == 2) { | ||
group->num_input = buf->ReadByte(); | ||
if (group->num_input > lengthof(group->subtract_input)) { | ||
grfmsg(1, "NewSpriteGroup: Industry production wants more inputs than possible, given=%d, max=%d, skipping", group->num_input, lengthof(group->subtract_input)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
src/newgrf.cpp
Outdated
} | ||
group->num_output = buf->ReadByte(); | ||
if (group->num_output > lengthof(group->add_output)) { | ||
grfmsg(1, "NewSpriteGroup: Industry production wants more outputs than possible, given=%d, max=%d, skipping", group->num_output, lengthof(group->add_output)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
The industry directory also needs some love. |
Summary of NewGRF spec changes was moved to first post. |
Small side note: Our commit message style allows "Add:" and discourages "Change:". Maybe change some of your "Change: Add ..." messages? |
@michicc Good point. I'll have to squash some of these commit eventually regardless. More on topic, I made a little test NewGRF that lets the power station burn several more things. |
I managed to make a slightly more complex NewGRF exercising some of the new properties: oilstuff.zip (It introduces new cargo types so you'll want a vehicle set/extension that supports more than the standard ones.) It highlighted another issue with the industry chain window, which is now fixed, at least partially. It also appears that something prevents town houses from accepting more than 3 cargoes despite them being supposed to. The above NewGRF should make three house types accept a new "diesel oil" cargo, but they don't. I haven't debugged that yet. |
Looks like the stray squares are from the "Draw the other_produced/other_accepted cargoes." loop in CargoesField::Draw(), but right now I can't understand the code well enough to realize a fix. |
About the spec:
Anyway, now that house stuff got added I think this PR has kind of derailed. There are tons of new stuff, but with no use case on the horizon. For now I suggest:
|
Whelp here's a large squashing into much fewer commits. The house accepts is removed and moved to PR #6872 instead. I'll remove some of the callback nonsense later too. All issues of the Industry chain window should be fixed too now. |
Changing industry property 28 to use a direct matrix form instead of a list for a sparse matrix. Here's an updated test GRF using the new property format: oilstuff.zip |
There are nml patches here https://github.com/nielsmh/nml/commits/indcargonum There's no clean reference nml file, but I have a patched FIRS that builds ok and appears to do the right thing (GPL 2). I am unclear whether prop 28 in the nml patch is correct, it dates from August 5th, but the comment about changing from list to direct matrix is 13th August. I don't understand enough to judge that. |
c2515fe
to
1b0f879
Compare
Bumped savegame version again and squashed the various changes since last squashing. Since @andythenorth claims to have tested the callback functionality and found it working, I think this should be ready for a final review. @frosch123 ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking over the code again there's definitely things to improve.
CargoID cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile); | ||
if (std::find(indspec->accepts_cargo, endof(indspec->accepts_cargo), cargo) == endof(indspec->accepts_cargo)) { | ||
/* Cargo not in spec, error in NewGRF */ | ||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I've actually tested that these error conditions trigger correctly.
} | ||
if (std::find(i->accepts_cargo, i->accepts_cargo + j, cargo) == i->accepts_cargo + j) { | ||
/* Duplicate cargo */ | ||
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't tested this error conditions triggers correctly.
int num_cargos = 0; | ||
uint cargo_index; | ||
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) { | ||
if (src_ind->produced_cargo[cargo_index] != CT_INVALID) num_cargos++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why such a weird algorithm to select a random cargo type. Could as well add valid types to a std::vector and select an element from that.
…e number of cargoes in/out isn't large either
All points should be addressed now
there seem to be a few vars missing here.
|
Since the number of cargo types was increased to 64, allowing industries to have more input and output types is natural so fewer industry types can service more cargo types.
The internal macros to set accepts/produces remain unchanged only supporting 3 in/2 out, but the generated structures do have full 16 slots, the remaining filled with "invalid". The new features require NewGRFs to be exploited.
Summary of current NewGRF spec changes:
Action0 Industry properties:
B n*B
, first byte is a count of how many cargo ids follow. Set cargoes produced by industry. If fewer cargoes are supplied than max, all remaining are set to "invalid". Deprecates property 10.B n*B
, first byte is a count of how many cargo ids follow. Set cargoes accepted by industry. If fewer cargoes are supplied than max, all remaining are set to "invalid". Deprecates property 11.B n*B
, first byte is a count of how many production rate values follow. Set production rates of cargoes produced by industry. If fewer cargoes are supplied than max (or set in prop 25), all remaining are set to zero. Deprecates properties 12 and 13.B<n> B<m> n*m*W
, first byte is number of input cargo rows, second byte is number of output cargo columns, the cargo multiplier words are arranged in row-major order. Total property length is 2+2nm bytes. Multipliers are specified in 256ths of a cargo unit, so a value of 0100h produces 1 unit of output for each unit of input. Input and output cargoes are ordered as in properties 25 and 26. Multiplier values outside the provided matrix are zeroed. Deprecates properties 1C, 1D, 1E.Action0 Industry tile properties:
B n*(B B)
, first byte is a count of how many accepted cargo structures follow. Total property length is 1+2n bytes. In each structure, first byte is a cargo id the tile accepts, the second byte is acceptance rate in 1/8 units. If fewer cargoes are supplies than max, all remaining are set to "invalid"/zero. Acceptance rate is a signed int8, it can be negative to counteract the "accepts all" flag in prop 12. Deprecates properties 0A, 0B, 0C.Industry callbacks 14B and 14C:
Industry callback 37:
Industry tile callbacks 2B and 2C:
Industry production callback:
<Sprite-number> * <Length> 02 0A <set-id> <version> <num-inputs> [<input-cargo-1> <subtract-in-1> ...] <num-outputs> [<output-cargo-1> <add-out-1> ...] <again>
num-inputs
andnum-outputs
values specify how many cargo/units pairs follow. (Number of pairs, not number of bytes.)input-cargo-n
andoutput-cargo-n
are byte values specifying valid cargo ids that participate in the production callback.subtract-in-n
andadd-out-n
are byte values with same meaning as in production callback version 01, except they apply to the immediately preceding cargo id.New VA2 variables for industries: