Refactor in-memory track design element (#21010)

This commit is contained in:
Michael Steenbeek 2023-12-02 18:43:03 +01:00 committed by GitHub
parent ee5055a422
commit baf88ef490
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 140 additions and 74 deletions

View File

@ -441,14 +441,8 @@ private:
uint8_t curTrackRotation = rotation;
for (const auto& trackElement : td6->track_elements)
{
int32_t trackType = trackElement.type;
if (trackType == TrackElemType::InvertedUp90ToFlatQuarterLoopAlias)
{
trackType = TrackElemType::MultiDimInvertedUp90ToFlatQuarterLoop;
}
// Follow a single track piece shape
const auto& ted = GetTrackElementDescriptor(trackType);
const auto& ted = GetTrackElementDescriptor(trackElement.Type);
const PreviewTrack* trackBlock = ted.Block;
while (trackBlock->index != 255)
{

View File

@ -675,18 +675,26 @@ template<> struct DataSerializerTraitsT<TrackDesignTrackElement>
{
static void encode(OpenRCT2::IStream* stream, const TrackDesignTrackElement& val)
{
stream->Write(&val.flags);
stream->Write(&val.type);
stream->Write(&val.Type);
stream->Write(&val.Flags);
stream->Write(&val.ColourScheme);
stream->Write(&val.StationIndex);
stream->Write(&val.BrakeBoosterSpeed);
stream->Write(&val.SeatRotation);
}
static void decode(OpenRCT2::IStream* stream, TrackDesignTrackElement& val)
{
stream->Read(&val.flags);
stream->Read(&val.type);
stream->Read(&val.Type);
stream->Read(&val.Flags);
stream->Read(&val.ColourScheme);
stream->Read(&val.StationIndex);
stream->Read(&val.BrakeBoosterSpeed);
stream->Read(&val.SeatRotation);
}
static void log(OpenRCT2::IStream* stream, const TrackDesignTrackElement& val)
{
char msg[128] = {};
snprintf(msg, sizeof(msg), "TrackDesignTrackElement(type = %d, flags = %d)", val.type, val.flags);
snprintf(msg, sizeof(msg), "TrackDesignTrackElement(type = %d, flags = %d)", val.Type, val.Flags);
stream->Write(msg, strlen(msg));
}
};
@ -924,4 +932,4 @@ template<> struct DataSerializerTraitsT<Banner>
msg, sizeof(msg), "Banner(x = %d, y = %d, text = %s)", banner.position.x, banner.position.y, banner.text.c_str());
stream->Write(msg, strlen(msg));
}
};
};

View File

@ -43,7 +43,7 @@
// It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version.
#define NETWORK_STREAM_VERSION "9"
#define NETWORK_STREAM_VERSION "10"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION

View File

@ -266,8 +266,8 @@ namespace RCT1
_stream.SetPosition(_stream.GetPosition() - 1);
_stream.Read(&t4TrackElement, sizeof(TD46TrackElement));
TrackDesignTrackElement trackElement{};
trackElement.type = RCT1TrackTypeToOpenRCT2(t4TrackElement.Type, td->type);
trackElement.flags = t4TrackElement.Flags;
trackElement.Type = RCT1TrackTypeToOpenRCT2(t4TrackElement.Type, td->type);
ConvertFromTD46Flags(trackElement, t4TrackElement.Flags);
td->track_elements.push_back(trackElement);
}
}

View File

@ -16,6 +16,7 @@
#include "../rct2/RCT2.h"
#include "../ride/Ride.h"
#include "../ride/Track.h"
#include "../ride/TrackDesign.h"
#include "../scenario/Scenario.h"
#include "../world/Banner.h"
#include "../world/Footpath.h"
@ -869,3 +870,57 @@ ResearchItem RCT12ResearchItem::ToResearchItem() const
return newResearchItem;
}
void ConvertFromTD46Flags(TrackDesignTrackElement& target, uint8_t flags)
{
target.BrakeBoosterSpeed = kRCT2DefaultBlockBrakeSpeed;
if (TrackTypeIsStation(target.Type))
{
auto stationIndex = flags & EnumValue(TD46Flags::StationId);
target.StationIndex = StationIndex::FromUnderlying(stationIndex);
}
else
{
auto speedOrSeatRotation = flags & EnumValue(TD46Flags::SpeedOrSeatRotation);
if (TrackTypeHasSpeedSetting(target.Type) && target.Type != TrackElemType::BlockBrakes)
{
target.BrakeBoosterSpeed = speedOrSeatRotation << 1;
}
else
{
target.SeatRotation = speedOrSeatRotation;
}
}
target.ColourScheme = (flags & EnumValue(TD46Flags::ColourScheme)) >> 4;
if (flags & EnumValue(TD46Flags::IsInverted))
target.SetFlag(TrackDesignTrackElementFlag::IsInverted);
if (flags & EnumValue(TD46Flags::HasChain))
target.SetFlag(TrackDesignTrackElementFlag::HasChain);
}
uint8_t ConvertToTD46Flags(const TrackDesignTrackElement& source)
{
uint8_t trackFlags = 0;
if (TrackTypeIsStation(source.Type))
{
trackFlags = (source.StationIndex.ToUnderlying() & EnumValue(TD46Flags::StationId));
}
else if (TrackTypeHasSpeedSetting(source.Type) && source.Type != TrackElemType::BlockBrakes)
{
trackFlags = (source.BrakeBoosterSpeed >> 1);
}
else
{
trackFlags = source.SeatRotation;
}
trackFlags |= source.ColourScheme << 4;
if (source.HasFlag(TrackDesignTrackElementFlag::HasChain))
trackFlags |= EnumValue(TD46Flags::HasChain);
if (source.HasFlag(TrackDesignTrackElementFlag::IsInverted))
trackFlags |= EnumValue(TD46Flags::IsInverted);
return trackFlags;
}

View File

@ -74,6 +74,8 @@ constexpr uint8_t RCT12PeepThoughtItemNone = std::numeric_limits<uint8_t>::max()
constexpr uint8_t RCT12GuestsInParkHistoryFactor = 20;
constexpr uint8_t RCT12ParkHistoryUndefined = std::numeric_limits<uint8_t>::max();
struct TrackDesignTrackElement;
enum class RCT12TrackDesignVersion : uint8_t
{
TD4,
@ -900,3 +902,15 @@ template<typename T> std::vector<RideId> RCT12GetRidesBeenOn(T* srcPeep)
}
return ridesBeenOn;
}
enum class TD46Flags : uint8_t
{
StationId = 0b00000011,
SpeedOrSeatRotation = 0b00001111,
ColourScheme = 0b00110000,
IsInverted = 0b01000000,
HasChain = 0b10000000,
};
void ConvertFromTD46Flags(TrackDesignTrackElement& target, uint8_t flags);
uint8_t ConvertToTD46Flags(const TrackDesignTrackElement& source);

View File

@ -111,13 +111,14 @@ namespace RCT2
{
for (const auto& trackElement : _trackDesign->track_elements)
{
auto trackType = OpenRCT2TrackTypeToRCT2(trackElement.type);
auto trackType = OpenRCT2TrackTypeToRCT2(trackElement.Type);
if (trackType == TrackElemType::MultiDimInvertedUp90ToFlatQuarterLoop)
{
trackType = TrackElemType::InvertedUp90ToFlatQuarterLoopAlias;
}
tempStream.WriteValue<uint8_t>(static_cast<uint8_t>(trackType));
tempStream.WriteValue<uint8_t>(trackElement.flags);
auto flags = ConvertToTD46Flags(trackElement);
tempStream.WriteValue<uint8_t>(flags);
}
tempStream.WriteValue<uint8_t>(0xFF);

View File

@ -171,8 +171,8 @@ namespace RCT2
trackType = TrackElemType::MultiDimInvertedUp90ToFlatQuarterLoop;
}
trackElement.type = trackType;
trackElement.flags = t6TrackElement.Flags;
trackElement.Type = trackType;
ConvertFromTD46Flags(trackElement, t6TrackElement.Flags);
td->track_elements.push_back(trackElement);
}

View File

@ -82,12 +82,6 @@ enum
RCT_PREVIEW_TRACK_FLAG_IS_VERTICAL = (1 << 2),
};
enum
{
TRACK_ELEMENT_FLAG_TERMINAL_STATION = 1 << 3,
TD6_TRACK_ELEMENT_FLAG_INVERTED = 1 << 6,
};
enum
{
TRACK_ELEMENT_FLAGS2_CHAIN_LIFT = 1 << 0,

View File

@ -214,43 +214,35 @@ ResultWithMessage TrackDesign::CreateTrackDesignTrack(TrackDesignState& tds, con
do
{
const auto& element = trackElement.element->AsTrack();
// Remove this check for new track design format
if (trackElement.element->AsTrack()->GetTrackType() > TrackElemType::HighestAlias)
if (element->GetTrackType() > TrackElemType::HighestAlias)
{
return { false, STR_TRACK_ELEM_UNSUPPORTED_TD6 };
}
TrackDesignTrackElement track{};
track.type = trackElement.element->AsTrack()->GetTrackType();
uint8_t trackFlags;
// This if-else block only applies to td6. New track design format will always encode speed and seat rotation.
if (TrackTypeHasSpeedSetting(track.type) && track.type != TrackElemType::BlockBrakes)
{
trackFlags = trackElement.element->AsTrack()->GetBrakeBoosterSpeed() >> 1;
}
else
{
trackFlags = trackElement.element->AsTrack()->GetSeatRotation();
}
track.Type = element->GetTrackType();
track.ColourScheme = element->GetColourScheme();
track.StationIndex = element->GetStationIndex();
track.BrakeBoosterSpeed = element->GetBrakeBoosterSpeed();
track.SeatRotation = element->GetSeatRotation();
// This warning will not apply to new track design format
if (track.type == TrackElemType::BlockBrakes
&& trackElement.element->AsTrack()->GetBrakeBoosterSpeed() != kRCT2DefaultBlockBrakeSpeed)
if (track.Type == TrackElemType::BlockBrakes && element->GetBrakeBoosterSpeed() != kRCT2DefaultBlockBrakeSpeed)
{
warningMessage = STR_TRACK_DESIGN_BLOCK_BRAKE_SPEED_RESET;
}
if (trackElement.element->AsTrack()->HasChain())
trackFlags |= RCT12_TRACK_ELEMENT_TYPE_FLAG_CHAIN_LIFT;
trackFlags |= trackElement.element->AsTrack()->GetColourScheme() << 4;
if (ride.GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_ALTERNATIVE_TRACK_TYPE)
&& trackElement.element->AsTrack()->IsInverted())
if (element->HasChain())
track.SetFlag(TrackDesignTrackElementFlag::HasChain);
if (ride.GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_HAS_ALTERNATIVE_TRACK_TYPE) && element->IsInverted())
{
trackFlags |= TD6_TRACK_ELEMENT_FLAG_INVERTED;
track.SetFlag(TrackDesignTrackElementFlag::IsInverted);
}
track.flags = trackFlags;
track_elements.push_back(track);
if (!TrackBlockGetNext(&trackElement, &trackElement, nullptr, nullptr))
@ -898,8 +890,8 @@ static void TrackDesignMirrorRide(TrackDesign* td6)
{
for (auto& track : td6->track_elements)
{
const auto& ted = GetTrackElementDescriptor(track.type);
track.type = ted.MirrorElement;
const auto& ted = GetTrackElementDescriptor(track.Type);
track.Type = ted.MirrorElement;
}
for (auto& entrance : td6->entrance_elements)
@ -1595,7 +1587,7 @@ static GameActions::Result TrackDesignPlaceRide(TrackDesignState& tds, TrackDesi
auto newCoords = origin;
for (const auto& track : td6->track_elements)
{
auto trackType = track.type;
auto trackType = track.Type;
const auto& ted = GetTrackElementDescriptor(trackType);
TrackDesignUpdatePreviewBounds(tds, newCoords);
@ -1632,26 +1624,13 @@ static GameActions::Result TrackDesignPlaceRide(TrackDesignState& tds, TrackDesi
// di
int16_t tempZ = newCoords.z - trackCoordinates->z_begin;
uint32_t trackColour = (track.flags >> 4) & 0x3;
uint32_t brakeSpeed;
// RCT2-created track designs write brake speed to all tracks; block brake speed must be treated as
// garbage data.
if (trackType == TrackElemType::BlockBrakes)
{
brakeSpeed = kRCT2DefaultBlockBrakeSpeed;
}
else
{
brakeSpeed = (track.flags & 0x0F) * 2;
}
uint32_t seatRotation = track.flags & 0x0F;
int32_t liftHillAndAlternativeState = 0;
if (track.flags & RCT12_TRACK_ELEMENT_TYPE_FLAG_CHAIN_LIFT)
if (track.HasFlag(TrackDesignTrackElementFlag::HasChain))
{
liftHillAndAlternativeState |= 1;
}
if (track.flags & TD6_TRACK_ELEMENT_FLAG_INVERTED)
if (track.HasFlag(TrackDesignTrackElementFlag::IsInverted))
{
liftHillAndAlternativeState |= 2;
}
@ -1678,8 +1657,8 @@ static GameActions::Result TrackDesignPlaceRide(TrackDesignState& tds, TrackDesi
}
auto trackPlaceAction = TrackPlaceAction(
ride.id, trackType, ride.type, { newCoords, tempZ, static_cast<uint8_t>(rotation) }, brakeSpeed,
trackColour, seatRotation, liftHillAndAlternativeState, true);
ride.id, trackType, ride.type, { newCoords, tempZ, static_cast<uint8_t>(rotation) },
track.BrakeBoosterSpeed, track.ColourScheme, track.SeatRotation, liftHillAndAlternativeState, true);
trackPlaceAction.SetFlags(flags);
auto res = flags & GAME_COMMAND_FLAG_APPLY ? GameActions::ExecuteNested(&trackPlaceAction)

View File

@ -62,15 +62,36 @@ struct TrackDesignSceneryElement
}
};
/**
* Track design structure.
*/
enum class TrackDesignTrackElementFlag : uint8_t
{
HasChain = (1 << 0),
IsInverted = (1 << 1),
IsCovered = (1 << 2), // Reserved
};
/* Track Element entry size: 0x03 */
struct TrackDesignTrackElement
{
track_type_t type; // 0x00
uint8_t flags; // 0x02
track_type_t Type = 0;
uint8_t Flags = 0;
uint8_t ColourScheme = 0;
::StationIndex StationIndex = StationIndex::FromUnderlying(0);
uint8_t BrakeBoosterSpeed = 0;
uint8_t SeatRotation = 4;
constexpr bool HasFlag(const TrackDesignTrackElementFlag flag) const
{
return Flags & EnumValue(flag);
}
constexpr void SetFlag(const TrackDesignTrackElementFlag flag)
{
Flags |= EnumValue(flag);
}
constexpr void ClearFlag(const TrackDesignTrackElementFlag flag)
{
Flags &= ~EnumValue(flag);
}
};
/* Maze Element entry size: 0x04 */