GRF: Add property mapping ID extension mechanism

Bump property_mapping feature version to 3
pull/491/head
Jonathan G Rennison 1 year ago
parent 5a877b49b4
commit 2ffb245b33

@ -206,6 +206,11 @@ public:
* as there may not be any more data read. */
if (data > end) throw OTTDByteReaderSignal();
}
inline void ResetReadPosition(byte *pos)
{
data = pos;
}
};
typedef void (*SpecialSpriteHandler)(ByteReader *buf);
@ -927,8 +932,10 @@ static bool MappedPropertyLengthMismatch(ByteReader *buf, uint expected_size, co
uint length = buf->ReadExtendedByte();
if (length != expected_size) {
if (mapping_entry != nullptr) {
grfmsg(2, "Ignoring use of mapped property: %s, feature: %s, mapped to: %X, with incorrect data size: %u instead of %u",
mapping_entry->name, GetFeatureString(mapping_entry->feature), mapping_entry->property_id, length, expected_size);
grfmsg(2, "Ignoring use of mapped property: %s, feature: %s, mapped to: %X%s, with incorrect data size: %u instead of %u",
mapping_entry->name, GetFeatureString(mapping_entry->feature),
mapping_entry->property_id, mapping_entry->extended ? " (extended)" : "",
length, expected_size);
}
buf->Skip(length);
return true;
@ -5400,6 +5407,38 @@ static GRFFilePropertyDescriptor ReadAction0PropertyID(ByteReader *buf, uint8 fe
error->param_value[2] = raw_prop;
} else if (prop == A0RPI_UNKNOWN_IGNORE) {
grfmsg(2, "Ignoring unimplemented mapped property: %s, feature: %s, mapped to: %X", def.name, GetFeatureString(def.feature), raw_prop);
} else if (prop == A0RPI_ID_EXTENSION) {
byte *outer_data = buf->Data();
size_t outer_length = buf->ReadExtendedByte();
uint16 mapped_id = buf->ReadWord();
byte *inner_data = buf->Data();
size_t inner_length = buf->ReadExtendedByte();
if (inner_length + (inner_data - outer_data) != outer_length) {
grfmsg(2, "Ignoring extended ID property with malformed lengths: %s, feature: %s, mapped to: %X", def.name, GetFeatureString(def.feature), raw_prop);
buf->ResetReadPosition(outer_data);
return GRFFilePropertyDescriptor(A0RPI_UNKNOWN_IGNORE, &def);
}
auto ext = _cur.grffile->action0_extended_property_remaps.find((((uint32)feature) << 16) | mapped_id);
if (ext != _cur.grffile->action0_extended_property_remaps.end()) {
buf->ResetReadPosition(inner_data);
const GRFFilePropertyRemapEntry &ext_def = ext->second;
prop = ext_def.id;
if (prop == A0RPI_UNKNOWN_ERROR) {
grfmsg(0, "Error: Unimplemented mapped extended ID property: %s, feature: %s, mapped to: %X (via %X)", ext_def.name, GetFeatureString(ext_def.feature), mapped_id, raw_prop);
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_PROPERTY);
error->data = stredup(ext_def.name);
error->param_value[1] = ext_def.feature;
error->param_value[2] = 0xE0000 | mapped_id;
} else if (prop == A0RPI_UNKNOWN_IGNORE) {
grfmsg(2, "Ignoring unimplemented mapped extended ID property: %s, feature: %s, mapped to: %X (via %X)", ext_def.name, GetFeatureString(ext_def.feature), mapped_id, raw_prop);
}
return GRFFilePropertyDescriptor(prop, &ext_def);
} else {
grfmsg(2, "Ignoring unknown extended ID property: %s, feature: %s, mapped to: %X (via %X)", def.name, GetFeatureString(def.feature), mapped_id, raw_prop);
buf->ResetReadPosition(outer_data);
return GRFFilePropertyDescriptor(A0RPI_UNKNOWN_IGNORE, &def);
}
}
return GRFFilePropertyDescriptor(prop, &def);
} else {
@ -9362,6 +9401,7 @@ struct GRFPropertyMapAction {
GrfSpecFeature feature;
int prop_id;
int ext_prop_id;
std::string name;
GRFPropertyMapFallbackMode fallback_mode;
uint8 ttd_ver_var_bit;
@ -9379,6 +9419,7 @@ struct GRFPropertyMapAction {
this->feature = GSF_INVALID;
this->prop_id = -1;
this->ext_prop_id = -1;
this->name.clear();
this->fallback_mode = GPMFM_IGNORE;
this->ttd_ver_var_bit = 0;
@ -9446,7 +9487,7 @@ struct GRFPropertyMapAction {
grfmsg(2, "Action 14 %s remapping: no feature defined, doing nothing", this->descriptor);
return;
}
if (this->prop_id < 0) {
if (this->prop_id < 0 && this->ext_prop_id < 0) {
grfmsg(2, "Action 14 %s remapping: no property ID defined, doing nothing", this->descriptor);
return;
}
@ -9458,12 +9499,22 @@ struct GRFPropertyMapAction {
const char *str = this->name.c_str();
extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[];
for (const GRFPropertyMapDefinition *info = _grf_action0_remappable_properties; info->name != nullptr; info++) {
if (info->feature == this->feature && strcmp(info->name, str) == 0) {
GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_property_remaps[this->feature].Entry(this->prop_id);
entry.name = info->name;
entry.id = info->id;
entry.feature = this->feature;
entry.property_id = this->prop_id;
if ((info->feature == GSF_INVALID || info->feature == this->feature) && strcmp(info->name, str) == 0) {
if (this->prop_id > 0) {
GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_property_remaps[this->feature].Entry(this->prop_id);
entry.name = info->name;
entry.id = info->id;
entry.feature = this->feature;
entry.property_id = this->prop_id;
}
if (this->ext_prop_id > 0) {
GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_extended_property_remaps[(((uint32)this->feature) << 16) | this->ext_prop_id];
entry.name = info->name;
entry.id = info->id;
entry.feature = this->feature;
entry.extended = true;
entry.property_id = this->ext_prop_id;
}
success = true;
break;
}
@ -9475,22 +9526,34 @@ struct GRFPropertyMapAction {
include(_cur.grffile->var91_values, this->test_91_value);
}
if (!success) {
uint mapped_to = (this->prop_id > 0) ? this->prop_id : this->ext_prop_id;
const char *extended = (this->prop_id > 0) ? "" : " (extended)";
if (this->fallback_mode == GPMFM_ERROR_ON_DEFINITION) {
grfmsg(0, "Error: Unimplemented mapped %s: %s, feature: %s, mapped to: %X", this->descriptor, str, GetFeatureString(this->feature), this->prop_id);
grfmsg(0, "Error: Unimplemented mapped %s: %s, feature: %s, mapped to: %X%s", this->descriptor, str, GetFeatureString(this->feature), mapped_to, extended);
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_UNIMPLEMETED_MAPPED_PROPERTY);
error->data = stredup(str);
error->param_value[1] = this->feature;
error->param_value[2] = this->prop_id;
error->param_value[2] = ((this->prop_id > 0) ? 0 : 0xE0000) | mapped_to;
} else {
const char *str_store = stredup(str);
grfmsg(2, "Unimplemented mapped %s: %s, feature: %s, mapped to: %X, %s on use",
this->descriptor, str, GetFeatureString(this->feature), this->prop_id, (this->fallback_mode == GPMFM_IGNORE) ? "ignoring" : "error");
grfmsg(2, "Unimplemented mapped %s: %s, feature: %s, mapped to: %X%s, %s on use",
this->descriptor, str, GetFeatureString(this->feature), mapped_to, extended, (this->fallback_mode == GPMFM_IGNORE) ? "ignoring" : "error");
_cur.grffile->remap_unknown_property_names.emplace_back(str_store);
GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_property_remaps[this->feature].Entry(this->prop_id);
entry.name = str_store;
entry.id = (this->fallback_mode == GPMFM_IGNORE) ? A0RPI_UNKNOWN_IGNORE : A0RPI_UNKNOWN_ERROR;
entry.feature = this->feature;
entry.property_id = this->prop_id;
if (this->prop_id > 0) {
GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_property_remaps[this->feature].Entry(this->prop_id);
entry.name = str_store;
entry.id = (this->fallback_mode == GPMFM_IGNORE) ? A0RPI_UNKNOWN_IGNORE : A0RPI_UNKNOWN_ERROR;
entry.feature = this->feature;
entry.property_id = this->prop_id;
}
if (this->ext_prop_id > 0) {
GRFFilePropertyRemapEntry &entry = _cur.grffile->action0_extended_property_remaps[(((uint32)this->feature) << 16) | this->ext_prop_id];
entry.name = str_store;
entry.id = (this->fallback_mode == GPMFM_IGNORE) ? A0RPI_UNKNOWN_IGNORE : A0RPI_UNKNOWN_ERROR;;
entry.feature = this->feature;
entry.extended = true;
entry.property_id = this->ext_prop_id;
}
}
}
}
@ -9616,6 +9679,19 @@ static bool ChangePropertyRemapPropertyId(size_t len, ByteReader *buf)
return true;
}
/** Callback function for ->'XPRP' to set the extended property ID to which this item is being mapped. */
static bool ChangePropertyRemapExtendedPropertyId(size_t len, ByteReader *buf)
{
GRFPropertyMapAction &action = _current_grf_property_map_action;
if (len != 2) {
grfmsg(2, "Action 14 %s mapping: expected 2 bytes for '%s'->'XPRP' but got " PRINTF_SIZE ", ignoring this field", action.descriptor, action.tag_name, len);
buf->Skip(len);
} else {
action.ext_prop_id = buf->ReadWord();
}
return true;
}
/** Callback function for ->'FTID' to set the feature ID to which this feature is being mapped. */
static bool ChangePropertyRemapFeatureId(size_t len, ByteReader *buf)
{
@ -9792,6 +9868,7 @@ AllowedSubtags _tags_a0pm[] = {
AllowedSubtags('NAME', ChangePropertyRemapName),
AllowedSubtags('FEAT', ChangePropertyRemapFeature),
AllowedSubtags('PROP', ChangePropertyRemapPropertyId),
AllowedSubtags('XPRP', ChangePropertyRemapExtendedPropertyId),
AllowedSubtags('FLBK', ChangePropertyRemapSetFallbackMode),
AllowedSubtags('SETT', ChangePropertyRemapSetTTDVerVarBit),
AllowedSubtags('SVAL', ChangePropertyRemapSuccessResultValue),

@ -175,7 +175,8 @@ struct GRFFilePropertyRemapEntry {
const char *name = nullptr;
int id = 0;
GrfSpecFeature feature = (GrfSpecFeature)0;
uint8 property_id = 0;
bool extended = false;
uint16 property_id = 0;
};
struct GRFFilePropertyRemapSet {
@ -324,6 +325,7 @@ struct GRFFile : ZeroedMemoryAllocator {
GRFFeatureMapRemapSet feature_id_remaps;
GRFFilePropertyRemapSet action0_property_remaps[GSF_END];
btree::btree_map<uint32, GRFFilePropertyRemapEntry> action0_extended_property_remaps;
Action5TypeRemapSet action5_type_remaps;
std::vector<GRFVariableMapEntry> grf_variable_remaps;
std::vector<std::unique_ptr<const char, FreeDeleter>> remap_unknown_property_names;

@ -17,7 +17,7 @@
/** Action14 feature list */
extern const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("feature_test", 2),
GRFFeatureInfo("property_mapping", 2),
GRFFeatureInfo("property_mapping", 3),
GRFFeatureInfo("variable_mapping", 3),
GRFFeatureInfo("feature_id_mapping", 2),
GRFFeatureInfo("action5_type_id_mapping", 2),
@ -74,6 +74,7 @@ extern const GRFFeatureMapDefinition _grf_remappable_features[] = {
/** Action14 Action0 remappable property list */
extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_INVALID, A0RPI_ID_EXTENSION, "id_extension"),
GRFPropertyMapDefinition(GSF_STATIONS, A0RPI_STATION_MIN_BRIDGE_HEIGHT, "station_min_bridge_height"),
GRFPropertyMapDefinition(GSF_STATIONS, A0RPI_STATION_DISALLOWED_BRIDGE_PILLARS, "station_disallowed_bridge_pillars"),
GRFPropertyMapDefinition(GSF_BRIDGES, A0RPI_BRIDGE_MENU_ICON, "bridge_menu_icon"),

@ -13,6 +13,7 @@
enum Action0RemapPropertyIds {
A0RPI_UNKNOWN_IGNORE = 0x200,
A0RPI_UNKNOWN_ERROR,
A0RPI_ID_EXTENSION,
A0RPI_STATION_MIN_BRIDGE_HEIGHT,
A0RPI_STATION_DISALLOWED_BRIDGE_PILLARS,

Loading…
Cancel
Save