VarAction2: Cache refit capacity callback results which depend only on cargo
This commit is contained in:
@@ -207,7 +207,19 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16 *mail_capacity) const
|
||||
/* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
|
||||
if (HasBit(this->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
|
||||
(new_multipliers || default_cargo != cargo_type || (v != nullptr && v->cargo_subtype != 0))) {
|
||||
uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
|
||||
uint16 callback;
|
||||
if (this->refit_capacity_values != nullptr) {
|
||||
const EngineRefitCapacityValue *caps = this->refit_capacity_values.get();
|
||||
while (true) {
|
||||
if (HasBit(caps->cargoes, cargo_type)) {
|
||||
callback = caps->capacity;
|
||||
break;
|
||||
}
|
||||
caps++;
|
||||
}
|
||||
} else {
|
||||
callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
|
||||
}
|
||||
if (callback != CALLBACK_FAILED) return callback;
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,11 @@ struct WagonOverride {
|
||||
typedef Pool<Engine, EngineID, 64, 64000> EnginePool;
|
||||
extern EnginePool _engine_pool;
|
||||
|
||||
struct EngineRefitCapacityValue {
|
||||
CargoTypes cargoes;
|
||||
uint32 capacity;
|
||||
};
|
||||
|
||||
struct Engine : EnginePool::PoolItem<&_engine_pool> {
|
||||
TinyString name; ///< Custom name of engine.
|
||||
Date intro_date; ///< Date of introduction of the engine.
|
||||
@@ -72,6 +77,8 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
|
||||
uint64 cb36_properties_used = UINT64_MAX;
|
||||
btree::btree_map<const SpriteGroup *, uint64> sprite_group_cb36_properties_used;
|
||||
|
||||
std::unique_ptr<EngineRefitCapacityValue, FreeDeleter> refit_capacity_values;
|
||||
|
||||
Engine() {}
|
||||
Engine(VehicleType type, EngineID base);
|
||||
bool IsEnabled() const;
|
||||
|
@@ -111,7 +111,10 @@ bool LinkRefresher::HandleRefit(CargoID refit_cargo)
|
||||
CargoID temp_cid = v->cargo_type;
|
||||
byte temp_subtype = v->cargo_subtype;
|
||||
v->cargo_type = this->cargo;
|
||||
v->cargo_subtype = GetBestFittingSubType(v, v, this->cargo);
|
||||
if (e->refit_capacity_values == nullptr || !(e->callbacks_used & SGCU_REFIT_CB_ALL_CARGOES) || this->cargo == e->GetDefaultCargoType() || (e->type == VEH_AIRCRAFT && IsCargoInClass(this->cargo, CC_PASSENGERS))) {
|
||||
/* This can be omitted when the refit capacity values are already determined, and the capacity is definitely from the refit callback */
|
||||
v->cargo_subtype = GetBestFittingSubType(v, v, this->cargo);
|
||||
}
|
||||
|
||||
uint16 mail_capacity = 0;
|
||||
uint amount = e->DetermineCapacity(v, &mail_capacity);
|
||||
|
@@ -335,11 +335,12 @@ struct GRFFileProps : GRFFilePropsBase<1> {
|
||||
|
||||
enum SpriteGroupCallbacksUsed : uint8 {
|
||||
SGCU_NONE = 0,
|
||||
SGCU_ALL = 0xFF,
|
||||
SGCU_ALL = 0xF,
|
||||
SGCU_VEHICLE_32DAY_CALLBACK = 1 << 0,
|
||||
SGCU_VEHICLE_REFIT_COST = 1 << 1,
|
||||
SGCU_RANDOM_TRIGGER = 1 << 2,
|
||||
SGCU_CB36_SPEED_RAILTYPE = 1 << 3,
|
||||
SGCU_REFIT_CB_ALL_CARGOES = 1 << 4,
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(SpriteGroupCallbacksUsed)
|
||||
|
||||
|
@@ -1587,13 +1587,18 @@ void FillNewGRFVehicleCache(const Vehicle *v)
|
||||
void AnalyseEngineCallbacks()
|
||||
{
|
||||
btree::btree_map<const SpriteGroup *, uint64> sg_cb36;
|
||||
btree::btree_map<uint32, CargoTypes> cb_refit_cap_values;
|
||||
for (Engine *e : Engine::Iterate()) {
|
||||
sg_cb36.clear();
|
||||
e->sprite_group_cb36_properties_used.clear();
|
||||
e->refit_capacity_values.reset();
|
||||
|
||||
SpriteGroupCallbacksUsed callbacks_used = SGCU_NONE;
|
||||
uint64 cb36_properties_used = 0;
|
||||
auto process_sg = [&](const SpriteGroup *sg) {
|
||||
bool refit_cap_whitelist_ok = true;
|
||||
bool refit_cap_no_var_47 = true;
|
||||
uint non_purchase_groups = 0;
|
||||
auto process_sg = [&](const SpriteGroup *sg, bool is_purchase) {
|
||||
if (sg == nullptr) return;
|
||||
|
||||
AnalyseCallbackOperation op;
|
||||
@@ -1601,13 +1606,16 @@ void AnalyseEngineCallbacks()
|
||||
callbacks_used |= op.callbacks_used;
|
||||
cb36_properties_used |= op.properties_used;
|
||||
sg_cb36[sg] = op.properties_used;
|
||||
if ((op.result_flags & ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND) && !is_purchase) refit_cap_whitelist_ok = false;
|
||||
if ((op.result_flags & ACORF_CB_REFIT_CAP_SEEN_VAR_47) && !is_purchase) refit_cap_no_var_47 = false;
|
||||
if (!is_purchase) non_purchase_groups++;
|
||||
};
|
||||
|
||||
for (uint i = 0; i < NUM_CARGO + 2; i++) {
|
||||
process_sg(e->grf_prop.spritegroup[i]);
|
||||
process_sg(e->grf_prop.spritegroup[i], i == CT_PURCHASE);
|
||||
}
|
||||
for (const WagonOverride &wo : e->overrides) {
|
||||
process_sg(wo.group);
|
||||
process_sg(wo.group, false);
|
||||
}
|
||||
e->callbacks_used = callbacks_used;
|
||||
e->cb36_properties_used = cb36_properties_used;
|
||||
@@ -1616,6 +1624,33 @@ void AnalyseEngineCallbacks()
|
||||
e->sprite_group_cb36_properties_used[iter.first] = iter.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (refit_cap_whitelist_ok && non_purchase_groups <= 1 && HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && e->grf_prop.spritegroup[CT_DEFAULT] != nullptr) {
|
||||
const SpriteGroup *purchase_sg = e->grf_prop.spritegroup[CT_PURCHASE];
|
||||
e->grf_prop.spritegroup[CT_PURCHASE] = nullptr; // Temporarily disable separate purchase sprite group
|
||||
if (refit_cap_no_var_47) {
|
||||
cb_refit_cap_values[GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, e->index, nullptr)] = ALL_CARGOTYPES;
|
||||
} else {
|
||||
const CargoID default_cb = e->info.cargo_type;
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) {
|
||||
e->info.cargo_type = c;
|
||||
cb_refit_cap_values[GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, e->index, nullptr)] |= (static_cast<CargoTypes>(1) << c);
|
||||
}
|
||||
e->info.cargo_type = default_cb;
|
||||
}
|
||||
e->grf_prop.spritegroup[CT_PURCHASE] = purchase_sg;
|
||||
bool all_ok = true;
|
||||
uint index = 0;
|
||||
e->refit_capacity_values.reset(MallocT<EngineRefitCapacityValue>(cb_refit_cap_values.size()));
|
||||
for (const auto &iter : cb_refit_cap_values) {
|
||||
if (iter.first == CALLBACK_FAILED) all_ok = false;
|
||||
e->refit_capacity_values.get()[index] = { iter.second, iter.first };
|
||||
index++;
|
||||
}
|
||||
if (all_ok) e->callbacks_used |= SGCU_REFIT_CB_ALL_CARGOES;
|
||||
|
||||
cb_refit_cap_values.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -343,6 +343,10 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co
|
||||
|
||||
if (check_1A_range()) return;
|
||||
|
||||
if ((op.mode == ACOM_CB_VAR || op.mode == ACOM_CB_REFIT_CAPACITY) && this->var_scope != VSG_SCOPE_SELF) {
|
||||
op.result_flags |= ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND;
|
||||
}
|
||||
|
||||
auto find_cb_result = [&](const SpriteGroup *group, AnalyseCallbackOperation::FindCBResultData data) -> bool {
|
||||
if (group == nullptr) return false;
|
||||
AnalyseCallbackOperation cbr_op;
|
||||
@@ -356,6 +360,7 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co
|
||||
const auto &adjust = this->adjusts[0];
|
||||
if (op.mode == ACOM_CB_VAR && adjust.variable == 0xC) {
|
||||
if (adjust.shift_num == 0 && (adjust.and_mask & 0xFF) == 0xFF && adjust.type == DSGA_TYPE_NONE) {
|
||||
bool found_refit_cap = false;
|
||||
for (const auto &range : this->ranges) {
|
||||
if (range.low == range.high) {
|
||||
switch (range.low) {
|
||||
@@ -380,12 +385,30 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co
|
||||
op.callbacks_used |= cb36_op.callbacks_used;
|
||||
}
|
||||
break;
|
||||
|
||||
case CBID_VEHICLE_REFIT_CAPACITY:
|
||||
found_refit_cap = true;
|
||||
if (range.group != nullptr) {
|
||||
AnalyseCallbackOperation cb_refit_op;
|
||||
cb_refit_op.mode = ACOM_CB_REFIT_CAPACITY;
|
||||
range.group->AnalyseCallbacks(cb_refit_op);
|
||||
op.result_flags |= (cb_refit_op.result_flags & (ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND | ACORF_CB_REFIT_CAP_SEEN_VAR_47));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (range.group != nullptr) range.group->AnalyseCallbacks(op);
|
||||
}
|
||||
}
|
||||
if (this->default_group != nullptr) this->default_group->AnalyseCallbacks(op);
|
||||
if (this->default_group != nullptr) {
|
||||
AnalyseCallbackOperationResultFlags prev_result = op.result_flags;
|
||||
this->default_group->AnalyseCallbacks(op);
|
||||
if (found_refit_cap) {
|
||||
const AnalyseCallbackOperationResultFlags save_mask = ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND | ACORF_CB_REFIT_CAP_SEEN_VAR_47;
|
||||
op.result_flags &= ~save_mask;
|
||||
op.result_flags |= (prev_result & save_mask);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -516,6 +539,12 @@ void DeterministicSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) co
|
||||
op.properties_used |= UINT64_MAX;
|
||||
}
|
||||
}
|
||||
if ((op.mode == ACOM_CB_VAR || op.mode == ACOM_CB_REFIT_CAPACITY) && !(adjust.variable == 0xC || adjust.variable == 0x1A || adjust.variable == 0x47 || adjust.variable == 0x7D || adjust.variable == 0x7E)) {
|
||||
op.result_flags |= ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND;
|
||||
}
|
||||
if ((op.mode == ACOM_CB_VAR || op.mode == ACOM_CB_REFIT_CAPACITY) && adjust.variable == 0x47) {
|
||||
op.result_flags |= ACORF_CB_REFIT_CAP_SEEN_VAR_47;
|
||||
}
|
||||
if (adjust.variable == 0x7E && adjust.subroutine != nullptr) {
|
||||
adjust.subroutine->AnalyseCallbacks(op);
|
||||
}
|
||||
@@ -571,6 +600,8 @@ const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const
|
||||
|
||||
void RandomizedSpriteGroup::AnalyseCallbacks(AnalyseCallbackOperation &op) const
|
||||
{
|
||||
op.result_flags |= ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND;
|
||||
|
||||
if (op.mode == ACOM_CB_VAR) op.callbacks_used |= SGCU_RANDOM_TRIGGER;
|
||||
|
||||
for (const SpriteGroup *group: this->groups) {
|
||||
|
@@ -55,6 +55,7 @@ enum AnalyseCallbackOperationMode {
|
||||
ACOM_FIND_CB_RESULT,
|
||||
ACOM_CB36_SPEED,
|
||||
ACOM_INDUSTRY_TILE,
|
||||
ACOM_CB_REFIT_CAPACITY,
|
||||
};
|
||||
|
||||
struct AnalyseCallbackOperationIndustryTileData;
|
||||
@@ -62,6 +63,8 @@ struct AnalyseCallbackOperationIndustryTileData;
|
||||
enum AnalyseCallbackOperationResultFlags {
|
||||
ACORF_NONE = 0,
|
||||
ACORF_CB_RESULT_FOUND = 1 << 0,
|
||||
ACORF_CB_REFIT_CAP_NON_WHITELIST_FOUND = 1 << 1,
|
||||
ACORF_CB_REFIT_CAP_SEEN_VAR_47 = 1 << 2,
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(AnalyseCallbackOperationResultFlags)
|
||||
|
||||
|
@@ -373,6 +373,16 @@ class NIHVehicle : public NIHelper {
|
||||
output.print(buffer);
|
||||
}
|
||||
}
|
||||
if (e->refit_capacity_values != nullptr) {
|
||||
const EngineRefitCapacityValue *caps = e->refit_capacity_values.get();
|
||||
CargoTypes seen = 0;
|
||||
while (seen != ALL_CARGOTYPES) {
|
||||
seprintf(buffer, lastof(buffer), " Refit capacity cache: cargoes: 0x" OTTD_PRINTFHEX64 " --> 0x%X", caps->cargoes, caps->capacity);
|
||||
output.print(buffer);
|
||||
seen |= caps->cargoes;
|
||||
caps++;
|
||||
}
|
||||
}
|
||||
YearMonthDay ymd;
|
||||
ConvertDateToYMD(e->intro_date, &ymd);
|
||||
seprintf(buffer, lastof(buffer), " Intro: %4i-%02i-%02i, Age: %u, Base life: %u, Durations: %u %u %u (sum: %u)",
|
||||
|
Reference in New Issue
Block a user