diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a0f85ae227..4e0746e289 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -235,6 +235,7 @@ add_files( newgrf_airporttiles.h newgrf_animation_base.h newgrf_animation_type.h + newgrf_cache_check.h newgrf_callbacks.h newgrf_canal.cpp newgrf_canal.h diff --git a/src/aircraft.h b/src/aircraft.h index a77fcf846a..c44d02f041 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -67,6 +67,7 @@ int GetAircraftFlightLevel(T *v, bool takeoff = false); struct AircraftCache { uint32 cached_max_range_sqr; ///< Cached squared maximum range. uint16 cached_max_range; ///< Cached maximum range. + byte image_movement_state; ///< Cached image aircraft movement state }; /** diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index eaef2d9e2d..332c827fbb 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -1276,6 +1276,7 @@ static void HandleAircraftSmoke(Aircraft *v, bool mode) if (v->state != FLYING && v->state != LANDING && v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED) { v->vehstatus &= ~VS_AIRCRAFT_BROKEN; v->breakdown_ctr = 0; + v->InvalidateImageCacheOfChain(); return; } @@ -1334,7 +1335,7 @@ TileIndex Aircraft::GetOrderStationLocation(StationID station) void Aircraft::MarkDirty() { this->colourmap = PAL_NONE; - this->cur_image_valid_dir = INVALID_DIR; + this->InvalidateImageCache(); this->UpdateViewport(true, false); if (this->subtype == AIR_HELICOPTER) { Aircraft *rotor = this->Next()->Next(); @@ -2161,6 +2162,15 @@ bool Aircraft::Tick() if (!AircraftEventHandler(this, i)) return false; } + if (HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE)) { + extern byte MapAircraftMovementState(const Aircraft *v); + byte state = MapAircraftMovementState(this); + if (state != this->acache.image_movement_state) { + this->InvalidateImageCacheOfChain(); + this->acache.image_movement_state = state; + } + } + return true; } diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index f9e73cac1c..6bfbfee2ec 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -1045,7 +1045,10 @@ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, /* Company colour data is indirectly cached. */ for (Vehicle *v : Vehicle::Iterate()) { - if (v->owner == _current_company) v->InvalidateNewGRFCache(); + if (v->owner == _current_company) { + v->InvalidateNewGRFCache(); + v->InvalidateImageCache(); + } } extern void UpdateObjectColours(const Company *c); diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 1ed32e80da..7278a1e41f 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -204,7 +204,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z) this->z_pos = z; this->tile = TileVirtXY(x, y); - this->cur_image_valid_dir = INVALID_DIR; + this->InvalidateImageCache(); this->UpdateImage(); this->UpdatePositionAndViewport(); @@ -218,7 +218,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z) safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); u->z_pos = GetSlopePixelZ(safe_x, safe_y); u->direction = this->direction; - u->cur_image_valid_dir = INVALID_DIR; + u->InvalidateImageCache(); u->UpdateImage(); u->UpdatePositionAndViewport(); diff --git a/src/economy.cpp b/src/economy.cpp index 81d43224f3..ecaa224704 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -466,6 +466,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) /* Owner changes, clear cache */ v->colourmap = PAL_NONE; v->InvalidateNewGRFCache(); + v->InvalidateImageCache(); if (v->IsEngineCountable()) { GroupStatistics::CountEngine(v, 1); diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index c75d2e8785..00d47b9ebe 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -108,7 +108,7 @@ void GroundVehicle::CargoChanged() weight += current_weight; /* Slope steepness is in percent, result in N. */ u->gcache.cached_slope_resistance = current_weight * u->GetSlopeSteepness() * 100; - u->cur_image_valid_dir = INVALID_DIR; + u->InvalidateImageCache(); } ClrBit(this->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST); diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 798c66d0b3..196c96d61d 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -398,6 +398,9 @@ struct GroundVehicle : public SpecializedVehicle { if (this->cur_speed != this->gcache.last_speed) { SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); this->gcache.last_speed = this->cur_speed; + if (HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE)) { + this->InvalidateImageCacheOfChain(); + } } } diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index ab57ace201..2096bc2c1d 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -278,6 +278,7 @@ void PropagateChildLivery(const Group *g) for (Vehicle *u = v; u != nullptr; u = u->Next()) { u->colourmap = PAL_NONE; u->InvalidateNewGRFCache(); + u->InvalidateImageCache(); } } } @@ -544,6 +545,7 @@ static void AddVehicleToGroup(Vehicle *v, GroupID new_g) for (Vehicle *u = v; u != nullptr; u = u->Next()) { u->colourmap = PAL_NONE; u->InvalidateNewGRFCache(); + u->InvalidateImageCache(); u->UpdateViewport(true); } break; @@ -794,6 +796,7 @@ void SetTrainGroupID(Train *v, GroupID new_g) u->group_id = new_g; u->colourmap = PAL_NONE; u->InvalidateNewGRFCache(); + u->InvalidateImageCache(); u->UpdateViewport(true); } @@ -821,6 +824,7 @@ void UpdateTrainGroupID(Train *v) u->group_id = new_g; u->colourmap = PAL_NONE; u->InvalidateNewGRFCache(); + u->InvalidateImageCache(); } /* Update the Replace Vehicle Windows */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp index e33d1e7301..281f23c37e 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -6354,6 +6354,19 @@ static void SkipAct5(ByteReader *buf) */ bool GetGlobalVariable(byte param, uint32 *value, const GRFFile *grffile) { + if (_sprite_group_resolve_check_veh_check) { + switch (param) { + case 0x00: + case 0x02: + case 0x09: + case 0x0A: + case 0x20: + case 0x23: + _sprite_group_resolve_check_veh_check = false; + break; + } + } + switch (param) { case 0x00: // current date *value = max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0); diff --git a/src/newgrf_airport.cpp b/src/newgrf_airport.cpp index 61ad46ac0e..e49ab5902a 100644 --- a/src/newgrf_airport.cpp +++ b/src/newgrf_airport.cpp @@ -38,7 +38,7 @@ struct AirportScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; void StorePSA(uint pos, int32 value) override; }; @@ -197,14 +197,14 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) } } -/* virtual */ uint32 AirportScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 AirportScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { case 0x40: return this->layout; } if (this->st == nullptr) { - *available = false; + extra->available = false; return UINT_MAX; } @@ -216,7 +216,7 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); } - return this->st->GetNewGRFVariable(this->ro, variable, parameter, available); + return this->st->GetNewGRFVariable(this->ro, variable, parameter, &(extra->available)); } /* virtual */ const SpriteGroup *AirportResolverObject::ResolveReal(const RealSpriteGroup *group) const diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp index 3059174a86..88231c255d 100644 --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -158,7 +158,7 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32 return 0xFF << 8 | ats->grf_prop.subst_id; // so just give him the substitute } -/* virtual */ uint32 AirportTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 AirportTileScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { assert(this->st != nullptr); @@ -195,7 +195,7 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32 DEBUG(grf, 1, "Unhandled airport tile variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_airporttiles.h b/src/newgrf_airporttiles.h index 37460622d4..84b1234753 100644 --- a/src/newgrf_airporttiles.h +++ b/src/newgrf_airporttiles.h @@ -38,7 +38,7 @@ struct AirportTileScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; }; /** Resolver for tiles of an airport. */ diff --git a/src/newgrf_cache_check.h b/src/newgrf_cache_check.h new file mode 100644 index 0000000000..8850d48f09 --- /dev/null +++ b/src/newgrf_cache_check.h @@ -0,0 +1,15 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_cache_check.h NewGRF caching checks. */ + +#ifndef NEWGRF_CACHE_CHECK_H +#define NEWGRF_CACHE_CHECK_H + +extern bool _sprite_group_resolve_check_veh_check; + +#endif /* NEWGRF_CACHE_CHECK_H */ diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp index 7295e5551b..08366c236c 100644 --- a/src/newgrf_canal.cpp +++ b/src/newgrf_canal.cpp @@ -30,7 +30,7 @@ struct CanalScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; }; /** Resolver object for canals. */ @@ -61,7 +61,7 @@ struct CanalResolverObject : public ResolverObject { return IsTileType(this->tile, MP_WATER) ? GetWaterTileRandomBits(this->tile) : 0; } -/* virtual */ uint32 CanalScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 CanalScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { /* Height of tile */ @@ -104,7 +104,7 @@ struct CanalResolverObject : public ResolverObject { DEBUG(grf, 1, "Unhandled canal variable 0x%02X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index d61f3b3f8f..3b2bd90eee 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -167,7 +167,7 @@ public: * @param avail Return whether the variable is available. * @return The resolved variable's value. */ - virtual uint Resolve(uint index, uint var, uint param, bool *avail) const = 0; + virtual uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const = 0; /** * Used to decide if the PSA needs a parameter or not. @@ -492,11 +492,11 @@ struct NewGRFInspectWindow : Window { if (nif->variables != nullptr) { this->DrawString(r, i++, "Variables:"); for (const NIVariable *niv = nif->variables; niv->name != nullptr; niv++) { - bool avail = true; + GetVariableExtra extra; uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0; - uint value = nih->Resolve(index, niv->var, param, &avail); + uint value = nih->Resolve(index, niv->var, param, &extra); - if (!avail) continue; + if (!extra.available) continue; if (HasVariableParameter(niv->var)) { this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name); diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 46021f0d2d..77d7310174 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -22,10 +22,13 @@ #include "company_base.h" #include "newgrf_railtype.h" #include "newgrf_roadtype.h" +#include "newgrf_cache_check.h" #include "ship.h" #include "safeguards.h" +bool _sprite_group_resolve_check_veh_check = false; + struct WagonOverride { EngineID *train_id; uint trains; @@ -162,7 +165,7 @@ enum TTDPAircraftMovementStates { * Map OTTD aircraft movement states to TTDPatch style movement states * (VarAction 2 Variable 0xE2) */ -static byte MapAircraftMovementState(const Aircraft *v) +byte MapAircraftMovementState(const Aircraft *v) { const Station *st = GetTargetAirportIfValid(v); if (st == nullptr) return AMS_TTDP_FLIGHT_TO_TOWER; @@ -343,6 +346,14 @@ static byte MapAircraftMovementAction(const Aircraft *v) /* virtual */ uint32 VehicleScopeResolver::GetTriggers() const { + if (this->v == nullptr) { + return 0; + } else { + if (_sprite_group_resolve_check_veh_check) { + SetBit(const_cast(this->v->First())->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER); + } + return this->v->waiting_triggers; + } return this->v == nullptr ? 0 : this->v->waiting_triggers; } @@ -444,8 +455,118 @@ static uint32 PositionHelper(const Vehicle *v, bool consecutive) return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16; } -static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, byte variable, uint32 parameter, bool *available) +static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, byte variable, uint32 parameter, GetVariableExtra *extra) { + if (_sprite_group_resolve_check_veh_check) { + switch (variable) { + case 0xC: + case 0x10: + case 0x18: + case 0x1A: + case 0x1C: + case 0x25: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4D: + case 0x60: + case 0x61: + case 0x7D: + case 0x7F: + case 0x80 + 0x0: + case 0x80 + 0x1: + case 0x80 + 0x4: + case 0x80 + 0x5: + case 0x80 + 0xA: // dubious + case 0x80 + 0xB: // dubious + case 0x80 + 0x39: + case 0x80 + 0x3A: + case 0x80 + 0x3B: + case 0x80 + 0x3C: + case 0x80 + 0x3D: + case 0x80 + 0x44: + case 0x80 + 0x45: + case 0x80 + 0x46: + case 0x80 + 0x47: + case 0x80 + 0x5A: + case 0x80 + 0x72: + case 0x80 + 0x7A: + case 0xFF: + break; + + case 0x80 + 0x32: + if (extra->mask & (VS_HIDDEN | VS_TRAIN_SLOWING)) { + _sprite_group_resolve_check_veh_check = false; + } + break; + + case 0x80 + 0x34: + case 0x80 + 0x35: + if (v->type == VEH_AIRCRAFT) { + _sprite_group_resolve_check_veh_check = false; + } else { + SetBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE); + } + break; + + case 0x5F: + case 0x80 + 0x7B: + SetBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER); + break; + + case 0x80 + 0x48: + // VRF_REVERSE_DIRECTION + if (v->type != VEH_TRAIN) { + _sprite_group_resolve_check_veh_check = false; + } + break; + + case 0x80 + 0x62: + switch (v->type) { + case VEH_TRAIN: + case VEH_SHIP: + if (extra->mask & 0x7F) { + _sprite_group_resolve_check_veh_check = false; + } + break; + + case VEH_ROAD: + break; + + case VEH_AIRCRAFT: + if (v == v->First()) { + SetBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE); + } else { + _sprite_group_resolve_check_veh_check = false; + } + break; + + default: + _sprite_group_resolve_check_veh_check = false; + break; + } + break; + + case 0xFE: + // vehicle is unloading, VF_CARGO_UNLOADING may disappear without the vehicle being marked dirty + // the vehicle is always marked dirty when VF_CARGO_UNLOADING is set + if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING)) { + _sprite_group_resolve_check_veh_check = false; + } + break; + + default: + _sprite_group_resolve_check_veh_check = false; + break; + } + } + /* Calculated vehicle parameters */ switch (variable) { case 0x25: // Get engine GRF ID @@ -667,9 +788,12 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, if (parameter == 0x5F) { /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */ + if (_sprite_group_resolve_check_veh_check) { + SetBit(u->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER); + } return (u->random_bits << 8) | u->waiting_triggers; } else { - return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available); + return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), extra); } } /* Not available */ @@ -891,11 +1015,11 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, DEBUG(grf, 1, "Unhandled vehicle variable 0x%X, type 0x%X", variable, (uint)v->type); - *available = false; + extra->available = false; return UINT_MAX; } -/* virtual */ uint32 VehicleScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 VehicleScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { if (this->v == nullptr) { /* Vehicle does not exist, so we're in a purchase list */ @@ -922,11 +1046,11 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, case 0xF2: return 0; // Cargo subtype } - *available = false; + extra->available = false; return UINT_MAX; } - return VehicleGetVariable(const_cast(this->v), this, variable, parameter, available); + return VehicleGetVariable(const_cast(this->v), this, variable, parameter, extra); } @@ -1206,6 +1330,9 @@ void TriggerVehicle(Vehicle *v, VehicleTrigger trigger) v->InvalidateNewGRFCacheOfChain(); DoTriggerVehicle(v, trigger, 0, true); + if (HasBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER)) { + v->First()->InvalidateImageCacheOfChain(); + } v->InvalidateNewGRFCacheOfChain(); } @@ -1325,8 +1452,8 @@ void FillNewGRFVehicleCache(const Vehicle *v) for (size_t i = 0; i < lengthof(cache_entries); i++) { /* Only resolve when the cache isn't valid. */ if (HasBit(v->grf_cache.cache_valid, cache_entries[i][1])) continue; - bool stub; - ro.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entries[i][0], 0, &stub); + GetVariableExtra extra; + ro.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entries[i][0], 0, &extra); } /* Make sure really all bits are set. */ diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index f830ff499d..3442f98875 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -39,7 +39,7 @@ struct VehicleScopeResolver : public ScopeResolver { void SetVehicle(const Vehicle *v) { this->v = v; } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; uint32 GetTriggers() const override; }; diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index 488925b5f1..78a5d1d444 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -42,7 +42,7 @@ struct GenericScopeResolver : public ScopeResolver { { } - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; private: bool ai_callback; ///< Callback comes from the AI. @@ -121,7 +121,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g _gcl[feature].push_front(GenericCallback(file, group)); } -/* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { if (this->ai_callback) { switch (variable) { @@ -143,7 +143,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index fc1738dfa1..84e4c93873 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -322,7 +322,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI /** * @note Used by the resolver to get values for feature 07 deterministic spritegroups. */ -/* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { /* Construction stage. */ @@ -438,7 +438,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI DEBUG(grf, 1, "Unhandled house variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } @@ -446,7 +446,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI /** * @note Used by the resolver to get values for feature 07 deterministic spritegroups. */ -/* virtual */ uint32 FakeHouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 FakeHouseScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { /* Construction stage. */ @@ -500,7 +500,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI DEBUG(grf, 1, "Unhandled house variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_house.h b/src/newgrf_house.h index 3bba3b7177..090a0d71f1 100644 --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -50,7 +50,7 @@ struct HouseScopeResolver : public CommonHouseScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; uint32 GetTriggers() const override; }; @@ -70,7 +70,7 @@ struct FakeHouseScopeResolver : public CommonHouseScopeResolver { : CommonHouseScopeResolver(ro, house_id) { } - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const; }; /** Resolver object to be used for houses (feature 07 spritegroups). */ diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index a8748a4953..5429bd83a1 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -155,7 +155,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout return count << 16 | GB(closest_dist, 0, 16); } -/* virtual */ uint32 IndustriesScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 IndustriesScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { if (this->ro.callback == CBID_INDUSTRY_LOCATION) { /* Variables available during construction check. */ @@ -201,7 +201,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout if (this->industry == nullptr) { DEBUG(grf, 1, "Unhandled variable 0x%X (no available industry) in callback 0x%x", variable, this->ro.callback); - *available = false; + extra->available = false; return UINT_MAX; } @@ -401,7 +401,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout DEBUG(grf, 1, "Unhandled industry variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_industries.h b/src/newgrf_industries.h index 01a185aa19..cfc2318074 100644 --- a/src/newgrf_industries.h +++ b/src/newgrf_industries.h @@ -33,7 +33,7 @@ struct IndustriesScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; uint32 GetTriggers() const override; void StorePSA(uint pos, int32 value) override; }; diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp index cefac348f5..2b7ae4131d 100644 --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -58,7 +58,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) return ((y & 0xF) << 20) | ((x & 0xF) << 16) | (y << 8) | x; } -/* virtual */ uint32 IndustryTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 IndustryTileScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { /* Construction state of the tile: a value between 0 and 3 */ @@ -95,7 +95,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) DEBUG(grf, 1, "Unhandled industry tile variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_industrytiles.h b/src/newgrf_industrytiles.h index e5494ea302..3e23e2a2d4 100644 --- a/src/newgrf_industrytiles.h +++ b/src/newgrf_industrytiles.h @@ -31,7 +31,7 @@ struct IndustryTileScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; uint32 GetTriggers() const override; }; diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index 8827245d36..e1dd3d87ca 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -230,7 +230,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, } /** Used by the resolver to get values for feature 0F deterministic spritegroups. */ -/* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { /* We get the town from the object, or we calculate the closest * town if we need to when there's no object. */ @@ -337,7 +337,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, unhandled: DEBUG(grf, 1, "Unhandled object variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_object.h b/src/newgrf_object.h index 1776b760ab..d048472251 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -116,7 +116,7 @@ struct ObjectScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; }; /** A resolver object to be used with feature 0F spritegroups. */ diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 2a98948e7b..7b1634dca0 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -22,7 +22,7 @@ return GB(tmp, 0, 2); } -/* virtual */ uint32 RailTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 RailTypeScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { if (this->tile == INVALID_TILE) { switch (variable) { @@ -54,7 +54,7 @@ DEBUG(grf, 1, "Unhandled rail type tile variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_railtype.h b/src/newgrf_railtype.h index 1e0ff01d82..adb8ad684e 100644 --- a/src/newgrf_railtype.h +++ b/src/newgrf_railtype.h @@ -32,7 +32,7 @@ struct RailTypeScopeResolver : public ScopeResolver { } uint32 GetRandomBits() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; }; /** Resolver object for rail types. */ diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp index c49faa59f1..a9c717fe19 100644 --- a/src/newgrf_roadtype.cpp +++ b/src/newgrf_roadtype.cpp @@ -22,7 +22,7 @@ return GB(tmp, 0, 2); } -/* virtual */ uint32 RoadTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 RoadTypeScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { if (this->tile == INVALID_TILE) { switch (variable) { @@ -54,7 +54,7 @@ DEBUG(grf, 1, "Unhandled road type tile variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_roadtype.h b/src/newgrf_roadtype.h index 07451f6566..fdbf262497 100644 --- a/src/newgrf_roadtype.h +++ b/src/newgrf_roadtype.h @@ -23,7 +23,7 @@ struct RoadTypeScopeResolver : public ScopeResolver { RoadTypeScopeResolver(ResolverObject &ro, const RoadTypeInfo *rti, TileIndex tile, TileContext context); /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const; }; /** Resolver object for road types. */ diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index aef4cf1d28..f66a8069dc 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -14,6 +14,8 @@ #include "newgrf_profiling.h" #include "core/pool_func.hpp" #include "vehicle_type.h" +#include "newgrf_cache_check.h" +#include "scope_info.h" #include "safeguards.h" @@ -72,7 +74,7 @@ RandomizedSpriteGroup::~RandomizedSpriteGroup() free(this->groups); } -static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *scope, byte variable, uint32 parameter, bool *available) +static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *scope, byte variable, uint32 parameter, GetVariableExtra *extra) { uint32 value; switch (variable) { @@ -93,7 +95,7 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc /* First handle variables common with Action7/9/D */ if (variable < 0x40 && GetGlobalVariable(variable, &value, object.grffile)) return value; /* Not a common variable, so evaluate the feature specific variables */ - return scope->GetVariable(variable, parameter, available); + return scope->GetVariable(variable, parameter, extra); } } @@ -122,10 +124,10 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc * @param[out] available Set to false, in case the variable does not exist. * @return Value */ -/* virtual */ uint32 ScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 ScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { DEBUG(grf, 1, "Unhandled scope variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } @@ -199,9 +201,6 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ScopeResolver } } -bool _sprite_group_resolve_check_veh_check = false; -VehicleType _sprite_group_resolve_check_veh_type; - static bool RangeHighComparator(const DeterministicSpriteGroupRange& range, uint32 value) { return range.high < value; @@ -219,9 +218,8 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con DeterministicSpriteGroupAdjust *adjust = &this->adjusts[i]; /* Try to get the variable. We shall assume it is available, unless told otherwise. */ - bool available = true; + GetVariableExtra extra(adjust->and_mask << adjust->shift_num); if (adjust->variable == 0x7E) { - _sprite_group_resolve_check_veh_check = false; const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object, false); if (subgroup == nullptr) { value = CALLBACK_FAILED; @@ -232,59 +230,12 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con /* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */ } else if (adjust->variable == 0x7B) { _sprite_group_resolve_check_veh_check = false; - value = GetVariable(object, scope, adjust->parameter, last_value, &available); + value = GetVariable(object, scope, adjust->parameter, last_value, &extra); } else { - if (_sprite_group_resolve_check_veh_check) { - switch (adjust->variable) { - // whitelist of variables which can be checked without requiring an immediate re-check on the next tick - case 0xC: - case 0x1A: - case 0x1C: - case 0x25: - case 0x40: - case 0x41: - case 0x42: - case 0x47: - case 0x49: - case 0x4B: - case 0x4D: - case 0x60: - case 0x7D: - case 0x7F: - case 0x80 + 0x0: - case 0x80 + 0x1: - case 0x80 + 0x4: - case 0x80 + 0x5: - case 0x80 + 0x39: - case 0x80 + 0x3A: - case 0x80 + 0x3B: - case 0x80 + 0x3C: - case 0x80 + 0x3D: - case 0x80 + 0x44: - case 0x80 + 0x45: - case 0x80 + 0x46: - case 0x80 + 0x47: - case 0x80 + 0x5A: - case 0x80 + 0x72: - case 0x80 + 0x7A: - break; - - case 0x80 + 0x62: - // RoadVehicle::state - if (_sprite_group_resolve_check_veh_type != VEH_ROAD) { - _sprite_group_resolve_check_veh_check = false; - } - break; - - default: - _sprite_group_resolve_check_veh_check = false; - break; - } - } - value = GetVariable(object, scope, adjust->variable, adjust->parameter, &available); + value = GetVariable(object, scope, adjust->variable, adjust->parameter, &extra); } - if (!available) { + if (!extra.available) { /* Unsupported variable: skip further processing and return either * the group from the first range or the default group. */ return SpriteGroup::Resolve(this->error_group, object, false); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 80f70df55d..8f6f47a7c2 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -287,6 +287,14 @@ struct IndustryProductionSpriteGroup : SpriteGroup { }; +struct GetVariableExtra { + bool available; + uint32 mask; + + GetVariableExtra(uint32 mask_ = 0xFFFFFFFF) + : available(true), mask(mask_) {} +}; + /** * Interface to query and set values specific to a single #VarSpriteGroupScope (action 2 scope). * @@ -302,7 +310,7 @@ struct ScopeResolver { virtual uint32 GetRandomBits() const; virtual uint32 GetTriggers() const; - virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + virtual uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const; virtual void StorePSA(uint reg, int32 value); }; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index fa1761233c..1270210bee 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -268,7 +268,7 @@ TownScopeResolver *StationResolverObject::GetTown() return this->town_scope; } -/* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { if (this->st == nullptr) { /* Station does not exist, so we're in a purchase list or the land slope check callback. */ @@ -296,7 +296,7 @@ TownScopeResolver *StationResolverObject::GetTown() case 0xFA: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Build date, clamped to a 16 bit value } - *available = false; + extra->available = false; return UINT_MAX; } @@ -386,7 +386,7 @@ TownScopeResolver *StationResolverObject::GetTown() case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); } - return this->st->GetNewGRFVariable(this->ro, variable, parameter, available); + return this->st->GetNewGRFVariable(this->ro, variable, parameter, &(extra->available)); } uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const diff --git a/src/newgrf_station.h b/src/newgrf_station.h index b5e2c18b2f..18b46a74bf 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -45,7 +45,7 @@ struct StationScopeResolver : public ScopeResolver { uint32 GetRandomBits() const override; uint32 GetTriggers() const override; - uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override; }; /** Station resolver. */ diff --git a/src/newgrf_town.cpp b/src/newgrf_town.cpp index a2084e47bf..a2464ed9a2 100644 --- a/src/newgrf_town.cpp +++ b/src/newgrf_town.cpp @@ -14,7 +14,7 @@ #include "safeguards.h" -/* virtual */ uint32 TownScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 TownScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { /* Larger towns */ @@ -113,7 +113,7 @@ DEBUG(grf, 1, "Unhandled town variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } @@ -148,7 +148,7 @@ t->psa_list.push_back(psa); } -/* virtual */ uint32 FakeTownScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +/* virtual */ uint32 FakeTownScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const { switch (variable) { /* Town index */ @@ -168,7 +168,7 @@ DEBUG(grf, 1, "Unhandled town variable 0x%X", variable); - *available = false; + extra->available = false; return UINT_MAX; } diff --git a/src/newgrf_town.h b/src/newgrf_town.h index 087be30e77..82f6b5cc56 100644 --- a/src/newgrf_town.h +++ b/src/newgrf_town.h @@ -34,7 +34,7 @@ struct TownScopeResolver : public ScopeResolver { { } - virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + virtual uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const; virtual void StorePSA(uint reg, int32 value); }; @@ -53,7 +53,7 @@ struct FakeTownScopeResolver : public ScopeResolver { FakeTownScopeResolver(ResolverObject &ro) : ScopeResolver(ro) { } - virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + virtual uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const; }; /** Resolver of town properties. */ diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 19f01819c1..e3679dff68 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -2362,7 +2362,7 @@ static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int RoadVehicle *rv = RoadVehicle::From(v); if (rv->frame == RVC_DEPOT_STOP_FRAME && _roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) { - rv->cur_image_valid_dir = INVALID_DIR; + rv->InvalidateImageCache(); rv->state = RVSB_IN_DEPOT; rv->vehstatus |= VS_HIDDEN; rv->direction = ReverseDir(rv->direction); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index cb74f8d254..9c62e9550a 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -415,7 +415,7 @@ void RoadVehicle::MarkDirty() { for (RoadVehicle *v = this; v != nullptr; v = v->Next()) { v->colourmap = PAL_NONE; - v->cur_image_valid_dir = INVALID_DIR; + v->InvalidateImageCache(); v->UpdateViewport(true, false); } this->CargoChanged(); @@ -1119,7 +1119,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first) } v->vehstatus &= ~VS_HIDDEN; - v->cur_image_valid_dir = INVALID_DIR; + v->InvalidateImageCache(); v->state = tdir; v->frame = RVC_DEPOT_START_FRAME; v->UpdateIsDrawn(); @@ -1437,7 +1437,7 @@ again: } if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { - v->cur_image_valid_dir = INVALID_DIR; + v->InvalidateImageCache(); TileIndex old_tile = v->tile; v->tile = tile; @@ -1513,7 +1513,7 @@ again: return false; } - v->cur_image_valid_dir = INVALID_DIR; + v->InvalidateImageCache(); v->state = dir; v->frame = turn_around_start_frame; diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 1a658ee29f..a702f044eb 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -277,7 +277,7 @@ Trackdir Ship::GetVehicleTrackdir() const void Ship::MarkDirty() { this->colourmap = PAL_NONE; - this->cur_image_valid_dir = INVALID_DIR; + this->InvalidateImageCache(); this->UpdateViewport(true, false); this->UpdateCache(); } diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index ec82e96d0d..e184331ab6 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -78,11 +78,11 @@ class NIHVehicle : public NIHelper { void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); } uint32 GetGRFID(uint index) const override { return Vehicle::Get(index)->GetGRFID(); } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { Vehicle *v = Vehicle::Get(index); VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } /* virtual */ void ExtraInfo(uint index, std::function print) const override @@ -170,6 +170,9 @@ class NIHVehicle : public NIHelper { e->duration_phase_1 + e->duration_phase_2 + e->duration_phase_3); print(buffer); } + + seprintf(buffer, lastof(buffer), " Current image cacheable: %s", v->cur_image_valid_dir != INVALID_DIR ? "yes" : "no"); + print(buffer); } }; @@ -229,10 +232,10 @@ class NIHStation : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { StationResolverObject ro(GetStationSpec(index), Station::GetByTile(index), index, INVALID_RAILTYPE); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } }; @@ -294,10 +297,10 @@ class NIHHouse : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); } uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? HouseSpec::Get(GetHouseType(index))->grf_prop.grffile->grfid : 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { HouseResolverObject ro(GetHouseType(index), index, Town::GetByTile(index)); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } void ExtraInfo(uint index, std::function print) const override @@ -359,10 +362,10 @@ class NIHIndustryTile : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); } uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile->grfid : 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { IndustryTileResolverObject ro(GetIndustryGfx(index), index, Industry::GetByTile(index)); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } }; @@ -458,11 +461,11 @@ class NIHIndustry : public NIHelper { void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); } uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile->grfid : 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { Industry *i = Industry::Get(index); IndustriesResolverObject ro(i->location.tile, i, i->type); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); } @@ -546,10 +549,10 @@ class NIHObject : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); } uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { ObjectResolverObject ro(ObjectSpec::GetByTile(index), Object::GetByTile(index), index); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } }; @@ -580,12 +583,12 @@ class NIHRailType : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } uint32 GetGRFID(uint index) const override { return 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { /* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype. * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */ RailTypeResolverObject ro(nullptr, index, TCX_NORMAL, RTSG_END); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } void ExtraInfo(uint index, std::function print) const override @@ -644,10 +647,10 @@ class NIHAirportTile : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile->grfid : 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { AirportTileResolverObject ro(AirportTileSpec::GetByTile(index), index, Station::GetByTile(index)); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } }; @@ -684,10 +687,10 @@ class NIHTown : public NIHelper { bool PSAWithParameter() const override { return true; } uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { TownResolverObject ro(nullptr, Town::Get(index), true); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const override @@ -738,7 +741,7 @@ class NIHStationStruct : public NIHelper { void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_STATION_NAME, index); } uint32 GetGRFID(uint index) const override { return 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { return 0; } @@ -803,12 +806,12 @@ class NIHRoadType : public NIHelper { void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } uint32 GetGRFID(uint index) const override { return 0; } - uint Resolve(uint index, uint var, uint param, bool *avail) const override + uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override { /* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype. * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */ RoadTypeResolverObject ro(nullptr, index, TCX_NORMAL, ROTSG_END); - return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra); } }; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 9023df76ae..674c403b31 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1832,7 +1832,7 @@ static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2) */ static void UpdateStatusAfterSwap(Train *v) { - v->cur_image_valid_dir = INVALID_DIR; + v->InvalidateImageCache(); /* Reverse the direction. */ if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction); @@ -3418,7 +3418,7 @@ void Train::MarkDirty() Train *v = this; do { v->colourmap = PAL_NONE; - v->cur_image_valid_dir = INVALID_DIR; + v->InvalidateImageCache(); v->UpdateViewport(true, false); } while ((v = v->Next()) != nullptr); diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index cfda2c5c17..c07f4e2ae0 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -2695,7 +2695,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti assert_msg(frame == rv->frame + 1 || rv->frame == _tunnel_turnaround_pre_visibility_frame[dir], "frame: %u, rv->frame: %u, dir: %u, _tunnel_turnaround_pre_visibility_frame[dir]: %u", frame, rv->frame, dir, _tunnel_turnaround_pre_visibility_frame[dir]); rv->tile = tile; - rv->cur_image_valid_dir = INVALID_DIR; + rv->InvalidateImageCache(); rv->state = RVSB_WORMHOLE; if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(rv->gv_flags, GVF_CHUNNEL_BIT); rv->vehstatus |= VS_HIDDEN; @@ -2710,7 +2710,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti if (dir == ReverseDiagDir(vdir) && frame == (int) (_tunnel_visibility_frame[dir] - 1) && z == 0) { if (rv->tile != tile && GetOtherTunnelEnd(rv->tile) != tile) return VETSB_CONTINUE; // In chunnel rv->tile = tile; - rv->cur_image_valid_dir = INVALID_DIR; + rv->InvalidateImageCache(); rv->state = DiagDirToDiagTrackdir(vdir); rv->frame = TILE_SIZE - (frame + 1); rv->vehstatus &= ~VS_HIDDEN; @@ -2753,7 +2753,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti if (HasRoadTypeTram(tile) && HasBit(rv->compatible_roadtypes, GetRoadTypeTram(tile))) bits |= GetCustomBridgeHeadRoadBits(tile, RTT_TRAM); if (!(bits & DiagDirToRoadBits(GetTunnelBridgeDirection(tile)))) return VETSB_CONTINUE; } - rv->cur_image_valid_dir = INVALID_DIR; + rv->InvalidateImageCache(); rv->state = RVSB_WORMHOLE; /* There are no slopes inside bridges / tunnels. */ ClrBit(rv->gv_flags, GVF_GOINGUP_BIT); @@ -2790,7 +2790,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti v->tile = tile; RoadVehicle *rv = RoadVehicle::From(v); if (rv->state == RVSB_WORMHOLE) { - rv->cur_image_valid_dir = INVALID_DIR; + rv->InvalidateImageCache(); rv->state = DiagDirToDiagTrackdir(DirToDiagDir(v->direction)); rv->frame = 0; return VETSB_ENTERED_WORMHOLE; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 14e32a7755..b79b94abc5 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -340,6 +340,7 @@ uint Vehicle::Crash(bool flooded) if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount(); v->vehstatus |= VS_CRASHED; v->MarkAllViewportsDirty(); + v->InvalidateImageCache(); } this->ClearSeparation(); @@ -3757,6 +3758,8 @@ char *Vehicle::DumpVehicleFlags(char *b, const char *last, bool include_tile) co dump('l', HasBit(this->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT)); dump('z', HasBit(this->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)); dump('d', HasBit(this->vcache.cached_veh_flags, VCF_IS_DRAWN)); + dump('t', HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER)); + dump('s', HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE)); if (this->IsGroundVehicle()) { uint16 gv_flags = this->GetGroundVehicleFlags(); b += seprintf(b, last, ", gvf:"); diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 4acefb6f41..e1871d23b0 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -22,6 +22,7 @@ #include "group_type.h" #include "timetable.h" #include "base_consist.h" +#include "newgrf_cache_check.h" #include "network/network.h" #include #include @@ -137,6 +138,8 @@ enum VehicleCacheFlags { VCF_LAST_VISUAL_EFFECT = 0, ///< Last vehicle in the consist with a visual effect. VCF_GV_ZERO_SLOPE_RESIST = 1, ///< GroundVehicle: Consist has zero slope resistance (valid only for the first engine), may be false negative. VCF_IS_DRAWN = 2, ///< Vehicle is currently drawn + VCF_REDRAW_ON_TRIGGER = 3, ///< Clear cur_image_valid_dir on changes to waiting_triggers (valid only for the first engine) + VCF_REDRAW_ON_SPEED_CHANGE = 4, ///< Clear cur_image_valid_dir on changes to cur_speed (ground vehicles) or aircraft movement state (aircraft) (valid only for the first engine) }; /** Cached often queried values common to all vehicles. */ @@ -502,6 +505,28 @@ public: } } + /** + * Invalidates cached image + * @see InvalidateNewGRFCacheOfChain + */ + inline void InvalidateImageCache() + { + this->cur_image_valid_dir = INVALID_DIR; + } + + /** + * Invalidates cached image of all vehicles in the chain (after the current vehicle) + * @see InvalidateImageCache + */ + inline void InvalidateImageCacheOfChain() + { + ClrBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE); + ClrBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER); + for (Vehicle *u = this; u != nullptr; u = u->Next()) { + u->InvalidateImageCache(); + } + } + /** * Check if the vehicle is a ground vehicle. * @return True iff the vehicle is a train or a road vehicle. @@ -1242,16 +1267,12 @@ struct SpecializedVehicle : public Vehicle { /* Skip updating sprites on dedicated servers without screen */ if (_network_dedicated) return; - extern bool _sprite_group_resolve_check_veh_check; - extern VehicleType _sprite_group_resolve_check_veh_type; - /* Explicitly choose method to call to prevent vtable dereference - * it gives ~3% runtime improvements in games with many vehicles */ if (update_delta) ((T *)this)->T::UpdateDeltaXY(); const Direction current_direction = ((T *)this)->GetMapImageDirection(); if (this->cur_image_valid_dir != current_direction) { _sprite_group_resolve_check_veh_check = true; - _sprite_group_resolve_check_veh_type = EXPECTED_TYPE; VehicleSpriteSeq seq; ((T *)this)->T::GetImage(current_direction, EIT_ON_MAP, &seq); this->cur_image_valid_dir = _sprite_group_resolve_check_veh_check ? current_direction : INVALID_DIR;