mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #19683 from ZehMatt/parallel-ride-ratings
Improve ride rating calculation
This commit is contained in:
commit
e8ec7b6c89
|
@ -76,9 +76,9 @@ set(OPENMSX_VERSION "1.1.0")
|
|||
set(OPENMSX_URL "https://github.com/OpenRCT2/OpenMusic/releases/download/v${OPENMSX_VERSION}/openmusic.zip")
|
||||
set(OPENMSX_SHA1 "8f0cf6b2fd4727e91b0d4062e7f199a43d15e777")
|
||||
|
||||
set(REPLAYS_VERSION "0.0.75")
|
||||
set(REPLAYS_VERSION "0.0.76")
|
||||
set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip")
|
||||
set(REPLAYS_SHA1 "D1701450AE0FE84B144236243A925801B67D92ED")
|
||||
set(REPLAYS_SHA1 "AE5808DE726D27F5311731677A20C96A8FF9101F")
|
||||
|
||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||
option(WITH_TESTS "Build tests")
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
- Improved: [#19463] Added ‘W’ and ‘Y’ with circumflex to sprite font (for Welsh).
|
||||
- Improved: [#19549] Enable large address awareness for 32 bit Windows builds allowing to use 4 GiB of virtual memory.
|
||||
- Improved: [#19668] Decreased the minimum map size from 13 to 3.
|
||||
- Improved: [#19683] The delays for ride ratings to appear has been reduced drastically.
|
||||
- Change: [#19018] Renamed actions to fit the naming scheme.
|
||||
- Change: [#19091] [Plugin] Add game action information to callback arguments of custom actions.
|
||||
- Change: [#19233] Reduce lift speed minimum and maximum values for “Classic Wooden Coaster”.
|
||||
|
|
|
@ -51,8 +51,8 @@
|
|||
<OpenSFXSha1>64EF7E0B7785602C91AEC66F005C035B05A2133B</OpenSFXSha1>
|
||||
<OpenMSXUrl>https://github.com/OpenRCT2/OpenMusic/releases/download/v1.1.0/openmusic.zip</OpenMSXUrl>
|
||||
<OpenMSXSha1>8f0cf6b2fd4727e91b0d4062e7f199a43d15e777</OpenMSXSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.75/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>D1701450AE0FE84B144236243A925801B67D92ED</ReplaysSha1>
|
||||
<ReplaysUrl>https://github.com/OpenRCT2/replays/releases/download/v0.0.76/replays.zip</ReplaysUrl>
|
||||
<ReplaysSha1>AE5808DE726D27F5311731677A20C96A8FF9101F</ReplaysSha1>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
// It is used for making sure only compatible builds get connected, even within
|
||||
// single OpenRCT2 version.
|
||||
|
||||
#define NETWORK_STREAM_VERSION "12"
|
||||
#define NETWORK_STREAM_VERSION "13"
|
||||
|
||||
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
|
||||
|
||||
|
|
|
@ -536,7 +536,25 @@ namespace OpenRCT2
|
|||
cs.ReadWrite(gGrassSceneryTileLoopPosition);
|
||||
cs.ReadWrite(gWidePathTileLoopPosition);
|
||||
|
||||
ReadWriteRideRatingCalculationData(cs, gRideRatingUpdateState);
|
||||
auto& rideRatings = RideRatingGetUpdateStates();
|
||||
if (os.GetHeader().TargetVersion >= 21)
|
||||
{
|
||||
cs.ReadWriteArray(rideRatings, [this, &cs](RideRatingUpdateState& calcData) {
|
||||
ReadWriteRideRatingCalculationData(cs, calcData);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only single state was stored prior to version 20.
|
||||
if (os.GetMode() == OrcaStream::Mode::READING)
|
||||
{
|
||||
// Since we read only one state ensure the rest is reset.
|
||||
RideRatingResetUpdateStates();
|
||||
}
|
||||
auto& rideRatingUpdateState = rideRatings[0];
|
||||
ReadWriteRideRatingCalculationData(cs, rideRatingUpdateState);
|
||||
}
|
||||
|
||||
if (os.GetHeader().TargetVersion >= 14)
|
||||
{
|
||||
|
|
|
@ -9,10 +9,10 @@ struct ObjectRepositoryItem;
|
|||
namespace OpenRCT2
|
||||
{
|
||||
// Current version that is saved.
|
||||
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 20;
|
||||
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 21;
|
||||
|
||||
// The minimum version that is forwards compatible with the current version.
|
||||
constexpr uint32_t PARK_FILE_MIN_VERSION = 19;
|
||||
constexpr uint32_t PARK_FILE_MIN_VERSION = 21;
|
||||
|
||||
// The minimum version that is backwards compatible with the current version.
|
||||
// If this is increased beyond 0, uncomment the checks in ParkFile.cpp and Context.cpp!
|
||||
|
|
|
@ -1097,7 +1097,10 @@ namespace RCT2
|
|||
void ImportRideRatingsCalcData()
|
||||
{
|
||||
const auto& src = _s6.RideRatingsCalcData;
|
||||
auto& dst = gRideRatingUpdateState;
|
||||
// S6 has only one state, ensure we reset all states before reading the first one.
|
||||
RideRatingResetUpdateStates();
|
||||
auto& rideRatingStates = RideRatingGetUpdateStates();
|
||||
auto& dst = rideRatingStates[0];
|
||||
dst = {};
|
||||
dst.Proximity = { src.ProximityX, src.ProximityY, src.ProximityZ };
|
||||
dst.ProximityStart = { src.ProximityStartX, src.ProximityStartY, src.ProximityStartZ };
|
||||
|
|
|
@ -77,7 +77,12 @@ struct ShelteredEights
|
|||
uint8_t TotalShelteredEighths;
|
||||
};
|
||||
|
||||
RideRatingUpdateState gRideRatingUpdateState;
|
||||
static RideRatingUpdateStates gRideRatingUpdateStates;
|
||||
|
||||
// Amount of updates allowed per updating state on the current tick.
|
||||
// The total amount would be MaxRideRatingSubSteps * RideRatingMaxUpdateStates which
|
||||
// would be currently 80, this is the worst case of sub-steps and may break out earlier.
|
||||
static constexpr size_t MaxRideRatingUpdateSubSteps = 20;
|
||||
|
||||
static void ride_ratings_update_state(RideRatingUpdateState& state);
|
||||
static void ride_ratings_update_state_0(RideRatingUpdateState& state);
|
||||
|
@ -90,9 +95,21 @@ static void ride_ratings_begin_proximity_loop(RideRatingUpdateState& state);
|
|||
static void RideRatingsCalculate(RideRatingUpdateState& state, Ride& ride);
|
||||
static void RideRatingsCalculateValue(Ride& ride);
|
||||
static void ride_ratings_score_close_proximity(RideRatingUpdateState& state, TileElement* inputTileElement);
|
||||
|
||||
static void ride_ratings_add(RatingTuple* rating, int32_t excitement, int32_t intensity, int32_t nausea);
|
||||
|
||||
RideRatingUpdateStates& RideRatingGetUpdateStates()
|
||||
{
|
||||
return gRideRatingUpdateStates;
|
||||
}
|
||||
|
||||
void RideRatingResetUpdateStates()
|
||||
{
|
||||
RideRatingUpdateState nullState{};
|
||||
nullState.State = RIDE_RATINGS_STATE_FIND_NEXT_RIDE;
|
||||
|
||||
std::fill(gRideRatingUpdateStates.begin(), gRideRatingUpdateStates.end(), nullState);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a small hack function to keep calling the ride rating processor until
|
||||
* the given ride's ratings have been calculated. Whatever is currently being
|
||||
|
@ -124,9 +141,17 @@ void RideRatingsUpdateAll()
|
|||
if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
|
||||
return;
|
||||
|
||||
// NOTE: With the new save format more than one ride can be updated at once, but this has not yet been implemented.
|
||||
// The SV6 format could store only a single state.
|
||||
ride_ratings_update_state(gRideRatingUpdateState);
|
||||
for (auto& updateState : gRideRatingUpdateStates)
|
||||
{
|
||||
for (size_t i = 0; i < MaxRideRatingUpdateSubSteps; ++i)
|
||||
{
|
||||
ride_ratings_update_state(updateState);
|
||||
|
||||
// We need to abort the loop if the state machine requested to find the next ride.
|
||||
if (updateState.State == RIDE_RATINGS_STATE_FIND_NEXT_RIDE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ride_ratings_update_state(RideRatingUpdateState& state)
|
||||
|
@ -154,6 +179,42 @@ static void ride_ratings_update_state(RideRatingUpdateState& state)
|
|||
}
|
||||
}
|
||||
|
||||
static bool RideRatingIsUpdatingRide(RideId id)
|
||||
{
|
||||
return std::any_of(gRideRatingUpdateStates.begin(), gRideRatingUpdateStates.end(), [id](auto& state) {
|
||||
return state.CurrentRide == id && state.State != RIDE_RATINGS_STATE_FIND_NEXT_RIDE;
|
||||
});
|
||||
}
|
||||
|
||||
static bool ShouldSkipRatingCalculation(const Ride& ride)
|
||||
{
|
||||
// Skip anything that isn't a real ride.
|
||||
if (ride.GetClassification() != RideClassification::Ride)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip rides that are closed.
|
||||
if (ride.status == RideStatus::Closed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip anything that is already updating.
|
||||
if (RideRatingIsUpdatingRide(ride.id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip rides that have a fixed rating.
|
||||
if (ride.lifecycle_flags & RIDE_LIFECYCLE_FIXED_RATINGS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static RideId GetNextRideToUpdate(RideId currentRide)
|
||||
{
|
||||
auto rm = GetRideManager();
|
||||
|
@ -161,14 +222,31 @@ static RideId GetNextRideToUpdate(RideId currentRide)
|
|||
{
|
||||
return RideId::GetNull();
|
||||
}
|
||||
// Skip all empty ride ids
|
||||
auto nextRide = std::next(rm.get(currentRide));
|
||||
// If at end, loop around
|
||||
if (nextRide == rm.end())
|
||||
|
||||
auto it = rm.get(currentRide);
|
||||
if (it == rm.end())
|
||||
{
|
||||
nextRide = rm.begin();
|
||||
// Start at the beginning, ride is missing.
|
||||
it = rm.begin();
|
||||
}
|
||||
return (*nextRide).id;
|
||||
else
|
||||
{
|
||||
it = std::next(it);
|
||||
}
|
||||
|
||||
// Filter out rides to avoid wasting a tick to find the next ride.
|
||||
while (it != rm.end() && ShouldSkipRatingCalculation(*it))
|
||||
{
|
||||
it++;
|
||||
}
|
||||
|
||||
// If we reached the end of the list we start over,
|
||||
// in case the next ride doesn't pass the filter function it will
|
||||
// look for the next matching ride in the next tick.
|
||||
if (it == rm.end())
|
||||
it = rm.begin();
|
||||
|
||||
return (*it).id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,11 +263,11 @@ static void ride_ratings_update_state_0(RideRatingUpdateState& state)
|
|||
state.CurrentRide = {};
|
||||
}
|
||||
|
||||
auto nextRideId = GetNextRideToUpdate(state.CurrentRide);
|
||||
auto nextRide = GetRide(nextRideId);
|
||||
if (nextRide != nullptr && nextRide->status != RideStatus::Closed
|
||||
&& !(nextRide->lifecycle_flags & RIDE_LIFECYCLE_FIXED_RATINGS))
|
||||
const auto nextRideId = GetNextRideToUpdate(state.CurrentRide);
|
||||
const auto* nextRide = GetRide(nextRideId);
|
||||
if (nextRide != nullptr && !ShouldSkipRatingCalculation(*nextRide))
|
||||
{
|
||||
Guard::Assert(!RideRatingIsUpdatingRide(nextRideId));
|
||||
state.State = RIDE_RATINGS_STATE_INITIALISE;
|
||||
}
|
||||
state.CurrentRide = nextRideId;
|
||||
|
|
|
@ -54,7 +54,12 @@ struct RideRatingUpdateState
|
|||
uint16_t StationFlags;
|
||||
};
|
||||
|
||||
extern RideRatingUpdateState gRideRatingUpdateState;
|
||||
static constexpr size_t RideRatingMaxUpdateStates = 4;
|
||||
|
||||
using RideRatingUpdateStates = std::array<RideRatingUpdateState, RideRatingMaxUpdateStates>;
|
||||
|
||||
RideRatingUpdateStates& RideRatingGetUpdateStates();
|
||||
void RideRatingResetUpdateStates();
|
||||
|
||||
void RideRatingsUpdateRide(const Ride& ride);
|
||||
void RideRatingsUpdateAll();
|
||||
|
|
Loading…
Reference in New Issue