Merge pull request #17192 from IntelOrca/fix/13997-network-track-design

Fix #13997: Placing a track design interferes with other players building a ride

A bit of a hack due to track design placement code using and sharing global variables with the UI code. Eventually this will change, when windows get upgrade to classes and when NTDF is implemented.
This commit is contained in:
Ted John 2022-05-14 11:43:42 +01:00 committed by GitHub
commit 16585ecaf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 22 deletions

View File

@ -9,6 +9,7 @@
- Improved: [#17059] Show Tile Inspector usage hint when nothing is selected.
- Change: [#16952] Make “Object Selection” order more coherent.
- Removed: [#16864] Title sequence editor (replaced by plug-in).
- Fix: [#13997] Placing a track design interferes with other players building a ride.
- Fix: [#16934] Park size displayed incorrectly in Park window.
- Fix: [#16974] Small scenery ghosts can be deleted.
- Fix: [#17005] Unable to set patrol area for first staff member in park.

View File

@ -162,7 +162,8 @@ public:
// Check if tool map position has changed since last update
if (mapCoords == _placementLoc)
{
TrackDesignPreviewDrawOutlines(tds, _trackDesign.get(), GetOrAllocateRide(PreviewRideId), { mapCoords, 0 });
TrackDesignPreviewDrawOutlines(
tds, _trackDesign.get(), GetOrAllocateRide(PreviewRideId), { mapCoords, 0, _currentTrackPieceDirection });
return;
}
@ -170,7 +171,7 @@ public:
// Get base Z position
mapZ = GetBaseZ(mapCoords);
CoordsXYZ trackLoc = { mapCoords, mapZ };
CoordsXYZD trackLoc = { mapCoords, mapZ, _currentTrackPieceDirection };
if (game_is_not_paused() || gCheatsBuildInPauseMode)
{
@ -180,7 +181,7 @@ public:
if (res.Error == GameActions::Status::Ok)
{
// Valid location found. Place the ghost at the location.
auto tdAction = TrackDesignAction({ trackLoc, _currentTrackPieceDirection }, *_trackDesign);
auto tdAction = TrackDesignAction(trackLoc, *_trackDesign);
tdAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
tdAction.SetCallback([&](const GameAction*, const GameActions::Result* result) {
if (result->Error == GameActions::Status::Ok)
@ -327,7 +328,7 @@ public:
{
if (_hasPlacementGhost)
{
auto tdAction = TrackDesignAction({ _placementGhostLoc, _currentTrackPieceDirection }, *_trackDesign);
auto tdAction = TrackDesignAction({ _placementGhostLoc }, *_trackDesign);
tdAction.SetFlags(GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST);
auto res = GameActions::Execute(&tdAction);
if (res.Error != GameActions::Status::Ok)
@ -382,7 +383,7 @@ private:
RideId _placementGhostRideId;
bool _hasPlacementGhost;
money32 _placementCost;
CoordsXYZ _placementGhostLoc;
CoordsXYZD _placementGhostLoc;
std::vector<uint8_t> _miniPreview;
@ -421,7 +422,9 @@ private:
if (surfaceElement->GetWaterHeight() > 0)
z = std::max(z, surfaceElement->GetWaterHeight());
return z + TrackDesignGetZPlacement(_trackDesign.get(), GetOrAllocateRide(PreviewRideId), { loc, z });
return z
+ TrackDesignGetZPlacement(
_trackDesign.get(), GetOrAllocateRide(PreviewRideId), { loc, z, _currentTrackPieceDirection });
}
void DrawMiniPreviewTrack(TrackDesign* td6, int32_t pass, const CoordsXY& origin, CoordsXY min, CoordsXY max)

View File

@ -55,7 +55,6 @@ GameActions::Result TrackDesignAction::Query() const
res.Position.y = _loc.y + 16;
res.Position.z = _loc.z;
res.Expenditure = ExpenditureType::RideConstruction;
_currentTrackPieceDirection = _loc.direction;
if (!LocationValid(_loc))
{

View File

@ -315,7 +315,7 @@ rct_string_id TrackDesign::CreateTrackDesignTrack(TrackDesignState& tds, const R
}
}
TrackDesignPreviewDrawOutlines(tds, this, GetOrAllocateRide(PreviewRideId), { 4096, 4096, 0 });
TrackDesignPreviewDrawOutlines(tds, this, GetOrAllocateRide(PreviewRideId), { 4096, 4096, 0, _currentTrackPieceDirection });
// Resave global vars for scenery reasons.
tds.Origin = startPos;
@ -434,7 +434,7 @@ rct_string_id TrackDesign::CreateTrackDesignMaze(TrackDesignState& tds, const Ri
// Save global vars as they are still used by scenery????
int32_t startZ = tds.Origin.z;
TrackDesignPreviewDrawOutlines(tds, this, GetOrAllocateRide(PreviewRideId), { 4096, 4096, 0 });
TrackDesignPreviewDrawOutlines(tds, this, GetOrAllocateRide(PreviewRideId), { 4096, 4096, 0, _currentTrackPieceDirection });
tds.Origin = { startLoc.x, startLoc.y, startZ };
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT;
@ -1623,7 +1623,7 @@ static GameActions::Result TrackDesignPlaceRide(TrackDesignState& tds, TrackDesi
}
auto trackPlaceAction = TrackPlaceAction(
_currentRideIndex, trackType, ride->type, { newCoords, tempZ, static_cast<uint8_t>(rotation) }, brakeSpeed,
ride->id, trackType, ride->type, { newCoords, tempZ, static_cast<uint8_t>(rotation) }, brakeSpeed,
trackColour, seatRotation, liftHillAndAlternativeState, true);
trackPlaceAction.SetFlags(flags);
@ -1821,7 +1821,7 @@ static GameActions::Result TrackDesignPlaceRide(TrackDesignState& tds, TrackDesi
* rct2: 0x006D01B3
*/
static GameActions::Result TrackDesignPlaceVirtual(
TrackDesignState& tds, TrackDesign* td6, uint8_t ptdOperation, bool placeScenery, Ride* ride, const CoordsXYZ& coords)
TrackDesignState& tds, TrackDesign* td6, uint8_t ptdOperation, bool placeScenery, Ride* ride, const CoordsXYZD& coords)
{
_trackDesignPlaceStateSceneryUnavailable = false;
_trackDesignPlaceStateEntranceExitPlaced = false;
@ -1843,7 +1843,11 @@ static GameActions::Result TrackDesignPlaceVirtual(
tds.PlaceScenery = false;
}
// NOTE: We need to save this, in networked games this would affect all clients otherwise.
auto savedRideId = _currentRideIndex;
auto savedTrackPieceDirection = _currentTrackPieceDirection;
_currentRideIndex = ride->id;
_currentTrackPieceDirection = coords.direction;
GameActions::Result trackPlaceRes;
if (td6->type == RIDE_TYPE_MAZE)
@ -1854,6 +1858,8 @@ static GameActions::Result TrackDesignPlaceVirtual(
{
trackPlaceRes = TrackDesignPlaceRide(tds, td6, coords, ride);
}
_currentRideIndex = savedRideId;
_currentTrackPieceDirection = savedTrackPieceDirection;
if (trackPlaceRes.Error != GameActions::Status::Ok)
{
@ -1882,7 +1888,7 @@ static GameActions::Result TrackDesignPlaceVirtual(
return res;
}
GameActions::Result TrackDesignPlace(TrackDesign* td6, uint32_t flags, bool placeScenery, Ride* ride, const CoordsXYZ& coords)
GameActions::Result TrackDesignPlace(TrackDesign* td6, uint32_t flags, bool placeScenery, Ride* ride, const CoordsXYZD& coords)
{
uint32_t ptdOperation = (flags & GAME_COMMAND_FLAG_APPLY) != 0 ? PTD_OPERATION_PLACE : PTD_OPERATION_PLACE_QUERY;
if ((flags & GAME_COMMAND_FLAG_APPLY) != 0 && (flags & GAME_COMMAND_FLAG_GHOST) != 0)
@ -1896,18 +1902,18 @@ GameActions::Result TrackDesignPlace(TrackDesign* td6, uint32_t flags, bool plac
return TrackDesignPlaceVirtual(tds, td6, ptdOperation, placeScenery, ride, coords);
}
void TrackDesignPreviewRemoveGhosts(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords)
void TrackDesignPreviewRemoveGhosts(TrackDesign* td6, Ride* ride, const CoordsXYZD& coords)
{
TrackDesignState tds{};
TrackDesignPlaceVirtual(tds, td6, PTD_OPERATION_REMOVE_GHOST, true, ride, coords);
}
void TrackDesignPreviewDrawOutlines(TrackDesignState& tds, TrackDesign* td6, Ride* ride, const CoordsXYZ& coords)
void TrackDesignPreviewDrawOutlines(TrackDesignState& tds, TrackDesign* td6, Ride* ride, const CoordsXYZD& coords)
{
TrackDesignPlaceVirtual(tds, td6, PTD_OPERATION_DRAW_OUTLINES, true, ride, coords);
}
static int32_t TrackDesignGetZPlacement(TrackDesignState& tds, TrackDesign* td6, Ride* ride, const CoordsXYZ& coords)
static int32_t TrackDesignGetZPlacement(TrackDesignState& tds, TrackDesign* td6, Ride* ride, const CoordsXYZD& coords)
{
TrackDesignPlaceVirtual(tds, td6, PTD_OPERATION_GET_PLACE_Z, true, ride, coords);
@ -1916,7 +1922,7 @@ static int32_t TrackDesignGetZPlacement(TrackDesignState& tds, TrackDesign* td6,
return tds.PlaceZ - tds.PlaceSceneryZ;
}
int32_t TrackDesignGetZPlacement(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords)
int32_t TrackDesignGetZPlacement(TrackDesign* td6, Ride* ride, const CoordsXYZD& coords)
{
TrackDesignState tds{};
return TrackDesignGetZPlacement(tds, td6, ride, coords);
@ -2001,7 +2007,8 @@ static bool TrackDesignPlacePreview(TrackDesignState& tds, TrackDesign* td6, mon
auto mapSize = TileCoordsXY{ gMapSize.x * 16, gMapSize.y * 16 };
_currentTrackPieceDirection = 0;
int32_t z = TrackDesignGetZPlacement(tds, td6, GetOrAllocateRide(PreviewRideId), { mapSize.x, mapSize.y, 16 });
int32_t z = TrackDesignGetZPlacement(
tds, td6, GetOrAllocateRide(PreviewRideId), { mapSize.x, mapSize.y, 16, _currentTrackPieceDirection });
if (tds.HasScenery)
{
@ -2018,7 +2025,8 @@ static bool TrackDesignPlacePreview(TrackDesignState& tds, TrackDesign* td6, mon
}
auto res = TrackDesignPlaceVirtual(
tds, td6, PTD_OPERATION_PLACE_TRACK_PREVIEW, placeScenery, ride, { mapSize.x, mapSize.y, z });
tds, td6, PTD_OPERATION_PLACE_TRACK_PREVIEW, placeScenery, ride,
{ mapSize.x, mapSize.y, z, _currentTrackPieceDirection });
gParkFlags = backup_park_flags;
if (res.Error == GameActions::Status::Ok)

View File

@ -222,10 +222,10 @@ extern RideId gTrackDesignSaveRideIndex;
void TrackDesignMirror(TrackDesign* td6);
GameActions::Result TrackDesignPlace(TrackDesign* td6, uint32_t flags, bool placeScenery, Ride* ride, const CoordsXYZ& coords);
void TrackDesignPreviewRemoveGhosts(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords);
void TrackDesignPreviewDrawOutlines(TrackDesignState& tds, TrackDesign* td6, Ride* ride, const CoordsXYZ& coords);
int32_t TrackDesignGetZPlacement(TrackDesign* td6, Ride* ride, const CoordsXYZ& coords);
GameActions::Result TrackDesignPlace(TrackDesign* td6, uint32_t flags, bool placeScenery, Ride* ride, const CoordsXYZD& coords);
void TrackDesignPreviewRemoveGhosts(TrackDesign* td6, Ride* ride, const CoordsXYZD& coords);
void TrackDesignPreviewDrawOutlines(TrackDesignState& tds, TrackDesign* td6, Ride* ride, const CoordsXYZD& coords);
int32_t TrackDesignGetZPlacement(TrackDesign* td6, Ride* ride, const CoordsXYZD& coords);
///////////////////////////////////////////////////////////////////////////////
// Track design preview