private async Task UpdateVehicleAction(QueuedVehicleAction queuedVehicleAction) { if (queuedVehicleAction.Handled) { // this queuedVehicleAction has already been handled return; } // This function must be re-entrant as it's running as a timer interval handler await _VehiclePositionsLock.WaitAsync(); try { if (!_updatingVehiclePositions) { _updatingVehiclePositions = true; foreach (var vehicle in this._gameScenario.Vehicles .Where(v => v.Key == queuedVehicleAction.Name) .Select(x => x.Value)) { if (TryUpdateVehicleAction(vehicle, queuedVehicleAction)) { if (this._constants.allowSubjectNextInsideGameLoop) { _subject.OnNext(vehicle.ToModel()); } if (queuedVehicleAction.VehicleAction == VehicleAction.TurnLeft || queuedVehicleAction.VehicleAction == VehicleAction.TurnRight) { await CheckVehicleForUnsafeVehiclesToSave(vehicle); } } } // very important!! don't forget to mark this as handled queuedVehicleAction.Handled = true; _updatingVehiclePositions = false; } } finally { _VehiclePositionsLock.Release(); } }
private bool TryUpdateVehicleAction(Vehicle host, QueuedVehicleAction action) { if (host.DrivingStatus == DrivingStatus.Crashed.ToString()) { return(false); } switch (action.VehicleAction) { case VehicleAction.IncreaseSpeed_CruiseInitiated: if (!host.IsGoingDesiredMph) { // accelerating to desired speed host.AddMph(_constants.VEHICLE_MPH_ACCELERATION_INCREMENT_RATE, isHumanInitiating: false); if (host.DrivingStatus != DrivingStatus.Resuming.ToString()) { host.Status = $"resuming to {host.AdaptiveCruiseDesiredMph} mph"; host.DrivingStatus = DrivingStatus.Resuming.ToString(); if (this._constants.allowSubjectNextInsideGameLoop) { _subject.OnNext(host.ToModel()); } } this._gameScenario.Vehicles[host.Name] = host; } break; case VehicleAction.IncreaseSpeed_UserInitiated: if (TryIncreaseVehicleMph(host, this._constants.VEHICLE_MPH_ACCELERATION_INCREMENT_RATE)) { host.DrivingStatus = DrivingStatus.Accelerating.ToString(); if (host.AdaptiveCruiseOn) { // keep in AdaptiveCruiseMph insync w/ human accelerating host.AdaptiveCruiseDesiredMph = host.Mph; } } break; case VehicleAction.DecreaseSpeed_CruiseInitiated: if (host.AdaptiveCruiseDesiredMph == 0) { // store original speed (so we can return to it when the slow car moves) host.AdaptiveCruiseDesiredMph = host.Mph; } host.SubtractMph(this._constants.VEHICLE_GRADUAL_MPH_BRAKE_RATE); if (host.Mph == 0) { if (host.DrivingStatus != DrivingStatus.Stopped.ToString()) { host.Status = $"stopped for {action.leadVehicleName}"; host.DrivingStatus = DrivingStatus.Stopped.ToString(); if (this._constants.allowSubjectNextInsideGameLoop) { _subject.OnNext(host.ToModel()); } } this._gameScenario.Vehicles[host.Name] = host; } else { if (host.DrivingStatus != DrivingStatus.AutoBraking.ToString()) { host.Status = $"autobraking for {action.leadVehicleName}"; host.DrivingStatus = DrivingStatus.AutoBraking.ToString(); if (this._constants.allowSubjectNextInsideGameLoop) { _subject.OnNext(host.ToModel()); } } this._gameScenario.Vehicles[host.Name] = host; } break; case VehicleAction.DecreaseSpeed_UserInitiated: if (TryDecreaseVehicleMph(host, this._constants.VEHICLE_GRADUAL_MPH_BRAKE_RATE)) { if (host.Mph == 0) { if (host.DrivingStatus != DrivingStatus.Stopped.ToString()) { TryUpdateVehicleDrivingStatus(host, DrivingStatus.Stopped); host.DrivingStatus = DrivingStatus.Stopped.ToString(); host.Status = $"stopped by {action.leadVehicleName}"; if (this._constants.allowSubjectNextInsideGameLoop) { _subject.OnNext(host.ToModel()); } } this._gameScenario.Vehicles[host.Name] = host; } else { TryUpdateVehicleDrivingStatus(host, DrivingStatus.Braking); } if (host.AdaptiveCruiseOn) { // keep in AdaptiveCruiseMph insync w/ human deaccelaration host.AdaptiveCruiseDesiredMph = host.Mph; } } break; case VehicleAction.TurnLeft: if (host.Mph > 0 && host.Y >= 3) { host.Y -= 1; TryUpdateVehicleDrivingStatus(host, DrivingStatus.TurningLeft); CheckVehicleForUnsafeVehiclesToSave(host); } break; case VehicleAction.TurnRight: if (host.Mph > 0 && host.Y < 8) { host.Y += 1; TryUpdateVehicleDrivingStatus(host, DrivingStatus.TurningRight); CheckVehicleForUnsafeVehiclesToSave(host); } break; case VehicleAction.ToggleAdaptiveCruise: host.AdaptiveCruiseOn = !host.AdaptiveCruiseOn; if (host.Mph == 0) { host.AdaptiveCruiseDesiredMph = 0; } else if (host.AdaptiveCruiseOn && host.Mph > 0) { TryUpdateVehicleDrivingStatus(host, DrivingStatus.Cruising); // keep AdaptiveCruiseMph insync w/ human initiated events, like enabled AC host.AdaptiveCruiseDesiredMph = host.Mph; } else if (!host.AdaptiveCruiseOn && host.Mph > 0) { TryUpdateVehicleDrivingStatus(host, DrivingStatus.Driving); host.AdaptiveCruiseDesiredMph = 0; } break; } return(true); }