private static string GetSessionName(Game.BaseModeProperties properties) { switch (properties) { case Game.TrackdayProperties _: return("Track day"); case Game.HotlapProperties _: return("Hotlap"); case Game.TimeAttackProperties _: return("Time attack"); case Game.PracticeProperties _: return("Practice"); case Game.WeekendProperties _: return("Weekend"); case Game.DriftProperties _: return("Drift"); case Game.DragProperties drag: return($"Drag race | {PluralizingConverter.PluralizeExt(drag.MatchesCount, "{0} run")}"); case Game.RaceProperties race: return($"Quick race | {PluralizingConverter.PluralizeExt(race.RaceLaps, "{0} lap")}"); default: return("Race"); } }
private static async Task <ArgumentHandleResult> ProcessImportWebsite(string[] data) { var result = await ModsWebBrowser.ImportWebsitesAsync(data, names => { return(Task.FromResult(ModernDialog.ShowMessage( $"Details for {names.Select(x => $"“{x}”").JoinToReadableString()} contain scripts which will have access to your data on those websites. Do you trust the source? You can verify scripts later in Content/Browser section.", "Details with scripts", MessageBoxButton.YesNo) == MessageBoxResult.Yes)); }).ConfigureAwait(false); switch (result) { case null: return(ArgumentHandleResult.Failed); case 0: Toast.Show("Nothing to import", data.Length == 1 ? "That website is already added" : "Those websites are already added"); return(ArgumentHandleResult.Successful); case 1: Toast.Show("Imported", "Website has been added"); return(ArgumentHandleResult.Successful); default: Toast.Show("Imported", $"Added {PluralizingConverter.PluralizeExt(result.Value, @"{0} website")}"); return(ArgumentHandleResult.Successful); } }
public void PluralizingTest() { CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en"); Assert.AreEqual("hour", PluralizingConverter.PluralizeExt(1, "hour")); Assert.AreEqual("hours", PluralizingConverter.PluralizeExt(5, "hour")); Assert.AreEqual("1 hour", PluralizingConverter.PluralizeExt(1, "{0} hour")); Assert.AreEqual("2 hours", PluralizingConverter.PluralizeExt(2, "{0} hour")); Assert.AreEqual("5 hours", PluralizingConverter.PluralizeExt(5, "{0} hour")); Assert.AreEqual("11 hours", PluralizingConverter.PluralizeExt(11, "{0} hour")); Assert.AreEqual("21 hours", PluralizingConverter.PluralizeExt(21, "{0} hour")); CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("ru"); Assert.AreEqual("1 час", PluralizingConverter.PluralizeExt(1, "{0} час")); Assert.AreEqual("2 часа", PluralizingConverter.PluralizeExt(2, "{0} час")); Assert.AreEqual("5 часов", PluralizingConverter.PluralizeExt(5, "{0} час")); Assert.AreEqual("11 часов", PluralizingConverter.PluralizeExt(11, "{0} час")); Assert.AreEqual("21 час", PluralizingConverter.PluralizeExt(21, "{0} час")); CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("es"); Assert.AreEqual("1 libro", PluralizingConverter.PluralizeExt(1, "{0} libro")); Assert.AreEqual("5 libros", PluralizingConverter.PluralizeExt(5, "{0} libro")); Assert.AreEqual("5 borradores", PluralizingConverter.PluralizeExt(5, "{0} borrador")); Assert.AreEqual("4 los aviones", PluralizingConverter.PluralizeExt(4, "{0} {el avión}")); /* no-break version */ Assert.AreEqual("5 los aviones", PluralizingConverter.PluralizeExt(5, "{0} el avión")); Assert.AreEqual("5 los lápices", PluralizingConverter.PluralizeExt(5, "{0} el lápiz")); Assert.AreEqual("5 los aviones", PluralizingConverter.PluralizeExt(5, "{0} el avión")); }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || parameter == null) { return(null); } var number = value.AsInt(); return(number != 0 ? PluralizingConverter.PluralizeExt(number, parameter.ToString()) : ""); }
private void UpdateSummary() { var total = 0; var totalSize = 0L; foreach (var entry in Images.Where(x => x.IsSelected)) { total++; totalSize += entry.Size; } DisplaySummary = total == 0 ? null : $"{PluralizingConverter.PluralizeExt(total, "{0} texture")} selected ({totalSize.ToReadableSize()})"; }
private static LapTimesExtraTool CreateSidekickFixTool(Func <string> appDirectoryCallback) { return(new LapTimesExtraTool("Fix lap times", "Older CM versions could break some records, sorry about it. But now, you can use this button to quickly fix them!", new AsyncCommand(async() => { try { var fixedCount = 0; using (var waiting = WaitingDialog.Create("Fixing values")) { var directory = Path.Combine(appDirectoryCallback(), "personal_best"); if (Directory.Exists(directory)) { var files = await Task.Run(() => new DirectoryInfo(directory).GetFiles("*_pb.ini")); for (var i = 0; i < files.Length; i++) { var file = files[i]; if (file.Length != 11) { continue; } var bytes = File.ReadAllBytes(file.FullName); if (bytes.Length != 11 || bytes[0] != 0x80 || bytes[1] != 3 || bytes[2] != (byte)'L') { continue; } waiting.Report(file.Name, i, files.Length); var value = BitConverter.ToInt64(bytes, 3); using (var writer = new BinaryWriter(File.Create(file.FullName))) { writer.Write(new byte[] { 0x80, 3, (byte)'L' }); writer.Write(Encoding.ASCII.GetBytes(value.As <string>())); writer.Write((byte)'\n'); writer.Write((byte)'.'); } fixedCount++; await Task.Yield(); } } } Toast.Show("Records fixed", fixedCount > 0 ? PluralizingConverter.PluralizeExt(fixedCount, "{0} error") + " fixed" : "No errors found"); } catch (Exception e) { NonfatalError.Notify("Can’t fix records", e); } }))); }
private IEnumerable <string> GetDetails(int currentIndex, CarObject car, CarSkinObject skin, int?currentEntrySkinsLeft) { var left = LeftSkins(currentIndex) + (currentEntrySkinsLeft ?? _approximateSkinsPerCarSkins / _approximateSkinsPerCarCars); var speed = _shotSkins / _started.Elapsed.TotalMinutes; var remainingTime = speed < 0.0001 ? "Unknown" : $"About {TimeSpan.FromMinutes(left / speed).ToReadableTime()}"; var remainingItems = $"About {left} {PluralizingConverter.Pluralize(left, ControlsStrings.CustomShowroom_SkinHeader).ToSentenceMember()}"; return(new[] { $"Car: {car?.DisplayName}", $"Skin: {skin?.DisplayName ?? "?"}", $"Speed: {speed:F2} {PluralizingConverter.Pluralize(10, ControlsStrings.CustomShowroom_SkinHeader).ToSentenceMember()}/{"min"}", $"Time remaining: {remainingTime}", $"Items remaining: {remainingItems}", _recyclingWarning ? "[i]Recycling seems to take too long? If so, it can always be disabled in Settings.[/i]" : null }.NonNull()); }
protected override ContentRepairSuggestion GetObsoletableAspect(CarObject car, DataWrapper data) { var ini = data.GetIniFile(@"tyres.ini"); var tyresCount = ini.GetExistingSectionNames("FRONT", -1).Count(); var defaultIndex = ini["COMPOUND_DEFAULT"].GetInt("INDEX", 0); if (defaultIndex >= tyresCount || defaultIndex < 0) { return(new ContentObsoleteSuggestion("COMPOUND_DEFAULT/INDEX in tyres.ini is wrong", tyresCount == 1 ? $"There are only a single set of tyres available, but default set is {defaultIndex} (index is zero-based)" : $"There are only {PluralizingConverter.PluralizeExt(tyresCount, "{0} set")} of tyres available, but default set is {defaultIndex} (index is zero-based)", (p, c) => FixAsync(car, p, c)) { AffectsData = true }); } return(null); }
public static string ToReadableTime(this TimeSpan span, bool considerMilliseconds) { var result = new List <string>(); var days = (int)span.TotalDays; var months = days / 30; if (months > 30) { result.Add(PluralizingConverter.PluralizeExt(months, UiStrings.Time_Month)); days = days % 30; } if (days > 0) { result.Add(days % 7 == 0 ? PluralizingConverter.PluralizeExt(days / 7, UiStrings.Time_Week) : PluralizingConverter.PluralizeExt(days, UiStrings.Time_Day)); } if (span.Hours > 0 && months == 0) { result.Add(PluralizingConverter.PluralizeExt(span.Hours, UiStrings.Time_Hour)); } if (span.Minutes > 0 && months == 0) { result.Add(PluralizingConverter.PluralizeExt(span.Minutes, UiStrings.Time_Minute)); } if (span.Seconds > 0 && span.Hours == 0 && months == 0 && days == 0) { result.Add(PluralizingConverter.PluralizeExt(span.Seconds, UiStrings.Time_Second)); } if (considerMilliseconds && span.Milliseconds > 0 && result.Count == 0) { result.Add($@"{span.Milliseconds} ms"); } return(result.Count > 0 ? string.Join(@" ", result.Take(2)) : PluralizingConverter.PluralizeExt(0, UiStrings.Time_Second)); }
public static string ToReadableTime(this TimeSpan span) { var result = new List <string>(); var days = (int)span.TotalDays; var months = days / 30; if (months > 30) { result.Add(PluralizingConverter.PluralizeExt(months, UiStrings.Time_Month)); days = days % 30; } if (days > 0) { result.Add(days % 7 == 0 ? PluralizingConverter.PluralizeExt(days / 7, UiStrings.Time_Week) : PluralizingConverter.PluralizeExt(days, UiStrings.Time_Day)); } if (span.Hours > 0) { result.Add(PluralizingConverter.PluralizeExt(span.Hours, UiStrings.Time_Hour)); } if (span.Minutes > 0) { result.Add(PluralizingConverter.PluralizeExt(span.Minutes, UiStrings.Time_Minute)); } if (span.Seconds > 0) { result.Add(PluralizingConverter.PluralizeExt(span.Seconds, UiStrings.Time_Second)); } return(result.Any() ? string.Join(@" ", result.Take(2)) : PluralizingConverter.PluralizeExt(0, UiStrings.Time_Second)); }
public string GetNumberString(int count) { return(PluralizingConverter.PluralizeExt(count, GetSubject())); }
private void GameWrapper_Finished(object sender, GameFinishedArgs e) { Logging.Write("Race finished"); var careerProperties = e.StartProperties.GetAdditional <ChampionshipProperties>(); if (careerProperties == null) { Logging.Write("Not a championship race"); return; } if (e.Result == null) { Logging.Write("Result=null"); return; } Logging.Write($"Championship: {careerProperties.ChampionshipId}"); var career = GetById(careerProperties.ChampionshipId); var ev = career?.ExtendedRounds.FirstOrDefault(x => x.Index == careerProperties.RoundIndex); if (ev == null) { Logging.Warning("Can’t find championship or round by ID."); return; } switch (career.Type) { case KunosCareerObjectType.SingleEvents: throw new NotSupportedException(); case KunosCareerObjectType.Championship: if (e.Result.NumberOfSessions > 0) { var places = e.Result.Sessions?.Last().GetTakenPlacesPerCar(); ev.TakenPlace = places?[0] +1 ?? 0; ev.IsPassed = true; var nextEvent = career.ExtendedRounds.FirstOrDefault(x => x.Index == careerProperties.RoundIndex + 1); if (nextEvent != null) { nextEvent.IsAvailable = true; } var pointsPerPlace = career.Rules.Points; var playerPointsDelta = pointsPerPlace.ArrayElementAtOrDefault(places?[0] ?? -1); if (career.PointsForBestLap != 0) { var bestLap = e.Result.Sessions?.SelectMany(x => x.BestLaps).MinEntryOrDefault(x => x.Time); if (bestLap == null) { Logging.Debug("Best lap: not set"); } else { Logging.Debug($"Best lap: set by {bestLap.CarNumber}, {bestLap.Time}"); var driver = career.Drivers.ElementAtOrDefault(bestLap.CarNumber); if (driver == null) { Logging.Warning("Best lap: driver not found!"); } else { Logging.Debug($"So, {PluralizingConverter.PluralizeExt(career.PointsForBestLap, "{0} bonus point")} for {driver.Name}!"); if (bestLap.CarNumber == 0) { playerPointsDelta += career.PointsForBestLap; } else { driver.Points += career.PointsForBestLap; } } } } if (career.PointsForPolePosition != 0) { var bestLap = e.Result.Sessions?.Where(x => x.Type == Game.SessionType.Qualification) .SelectMany(x => x.BestLaps) .MinEntryOrDefault(x => x.Time); if (bestLap == null) { Logging.Debug("Pole position: not set"); } else { Logging.Debug($"Pole position: set by {bestLap.CarNumber}, {bestLap.Time}"); var driver = career.Drivers.ElementAtOrDefault(bestLap.CarNumber); if (driver == null) { Logging.Warning("Pole position: driver not found!"); } else { Logging.Debug($"So, {PluralizingConverter.PluralizeExt(career.PointsForPolePosition, "{0} bonus point")} for {driver.Name}!"); if (bestLap.CarNumber == 0) { playerPointsDelta += career.PointsForPolePosition; } else { driver.Points += career.PointsForPolePosition; } } } } career.ChampionshipPoints += playerPointsDelta; for (var i = career.Drivers.Count - 1; i >= 0; i--) { var driver = career.Drivers[i]; if (driver.IsPlayer) { continue; } driver.Points += pointsPerPlace.ArrayElementAtOrDefault(places?.ArrayElementAtOrDefault(i) ?? -1); } career.UpdateTakenPlaces(); career.SaveProgress(true); } else { throw new NotImplementedException(); } break; default: throw new ArgumentOutOfRangeException(); } }
private static BaseFinishedData GetFinishedData(Game.StartProperties properties, Game.Result result) { var conditions = properties?.GetAdditional <PlaceConditions>(); var takenPlace = conditions?.GetTakenPlace(result) ?? PlaceConditions.UnremarkablePlace; Logging.Debug($"Place conditions: {conditions?.GetDescription()}, result: {result.GetDescription()}"); if (result.GetExtraByType <Game.ResultExtraDrift>(out var drift)) { return(new DriftFinishedData { Points = drift.Points, MaxCombo = drift.MaxCombo, MaxLevel = drift.MaxLevel, TakenPlace = takenPlace }); } if (result.GetExtraByType <Game.ResultExtraTimeAttack>(out var timeAttack)) { var bestLapTime = result.Sessions?.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); return(new TimeAttackFinishedData { Points = timeAttack.Points, Laps = result.Sessions?.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0) ?? 0, BestLapTime = bestLapTime == TimeSpan.Zero ? null : bestLapTime, TakenPlace = takenPlace }); } if (result.GetExtraByType <Game.ResultExtraBestLap>(out var bestLap) && bestLap.IsNotCancelled && result.Sessions?.Length == 1 && result.Players?.Length == 1) { var bestLapTime = result.Sessions.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); var sectorsPerSections = result.Sessions.SelectMany(x => from lap in x.Laps where lap.CarNumber == 0 select lap.SectorsTime).ToList(); var theoreticallLapTime = sectorsPerSections.FirstOrDefault()?.Select((x, i) => sectorsPerSections.Select(y => y[i]).Min()).Sum(); return(result.Sessions[0].Name == AppStrings.Rsr_SessionName ? new RsrFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace } : new HotlapFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace }); } var isOnline = properties?.ModeProperties is Game.OnlineProperties; var playerName = isOnline && SettingsHolder.Drive.DifferentPlayerNameOnline ? SettingsHolder.Drive.PlayerNameOnline : SettingsHolder.Drive.PlayerName; if (result.Sessions?.Length == 1 && result.Sessions[0].Name == Game.TrackDaySessionName && result.Players?.Length > 1) { var session = result.Sessions[0]; var playerLaps = session.LapsTotalPerCar?[0] ?? 1; session.LapsTotalPerCar = session.LapsTotalPerCar?.Select(x => Math.Min(x, playerLaps)).ToArray(); session.Laps = session.Laps?.Where(x => x.LapId < playerLaps).ToArray(); session.BestLaps = session.BestLaps?.Select(x => { if (x.LapId < playerLaps) { return(x); } var best = session.Laps?.Where(y => y.CarNumber == x.CarNumber).MinEntryOrDefault(y => y.Time); if (best == null) { return(null); } return(new Game.ResultBestLap { Time = best.Time, LapId = best.LapId, CarNumber = x.CarNumber }); }).NonNull().ToArray(); } var dragExtra = result.GetExtraByType <Game.ResultExtraDrag>(); var sessionsData = result.Sessions?.Select(session => { int[] takenPlaces; SessionFinishedData data; if (dragExtra != null) { data = new DragFinishedData { BestReactionTime = dragExtra.ReactionTime, Total = dragExtra.Total, Wins = dragExtra.Wins, Runs = dragExtra.Runs, }; var delta = dragExtra.Wins * 2 - dragExtra.Runs; takenPlaces = new[] { delta >= 0 ? 0 : 1, delta <= 0 ? 0 : 1 }; } else { data = new SessionFinishedData(session.Name?.ApartFromLast(@" Session")); takenPlaces = session.GetTakenPlacesPerCar(); } var sessionBestLap = session.BestLaps?.MinEntryOrDefault(x => x.Time); var sessionBest = sessionBestLap?.Time; data.PlayerEntries = ( from player in result.Players let car = CarsManager.Instance.GetById(player.CarId ?? "") let carSkin = car?.GetSkinById(player.CarSkinId ?? "") select new { Player = player, Car = car, CarSkin = carSkin } ).Select((entry, i) => { var bestLapTime = session.BestLaps?.Where(x => x.CarNumber == i).MinEntryOrDefault(x => x.Time)?.Time; var laps = session.Laps?.Where(x => x.CarNumber == i).Select(x => new SessionFinishedData.PlayerLapEntry { LapNumber = x.LapId + 1, Sectors = x.SectorsTime, Cuts = x.Cuts, TyresShortName = x.TyresShortName, Total = x.Time, DeltaToBest = bestLapTime.HasValue ? x.Time - bestLapTime.Value : (TimeSpan?)null, DeltaToSessionBest = sessionBest.HasValue ? x.Time - sessionBest.Value : (TimeSpan?)null, }).ToArray(); var lapTimes = laps?.Skip(1).Select(x => x.Total.TotalSeconds).Where(x => x > 10d).ToList(); double?progress, spread; if (lapTimes == null || lapTimes.Count < 2) { progress = null; spread = null; } else { var firstHalf = lapTimes.Count / 2; var firstMedian = lapTimes.Take(firstHalf).Median(); var secondMedian = lapTimes.Skip(firstHalf).Median(); progress = 1d - secondMedian / firstMedian; spread = (lapTimes.Max() - lapTimes.Min()) / bestLapTime?.TotalSeconds; } return(new SessionFinishedData.PlayerEntry { Name = i == 0 ? playerName : entry.Player.Name, IsPlayer = i == 0, Index = i, Car = entry.Car, CarSkin = entry.CarSkin, TakenPlace = i < takenPlaces?.Length ? takenPlaces[i] + 1 : DefinitelyNonPrizePlace, PrizePlace = takenPlaces?.Length > 1, LapsCount = session.LapsTotalPerCar?.ArrayElementAtOrDefault(i) ?? 0, BestLapTime = bestLapTime, DeltaToSessionBest = sessionBestLap?.CarNumber == i ? null : bestLapTime - sessionBest, TotalTime = session.Laps?.Where(x => x.CarNumber == i).Select(x => x.SectorsTime.Sum()).Sum(), Laps = laps, LapTimeProgress = progress, LapTimeSpread = spread }); }).OrderBy(x => x.TakenPlace).ToList(); if (data.PlayerEntries.Count > 0) { var maxLaps = data.PlayerEntries.Select(x => x.Laps.Length).Max(); var bestTotalTime = data.PlayerEntries.Where(x => x.Laps.Length == maxLaps).MinEntryOrDefault(x => x.TotalTime ?? TimeSpan.MaxValue); foreach (var entry in data.PlayerEntries) { var lapsDelta = maxLaps - entry.Laps.Length; if (bestTotalTime == entry) { entry.TotalTimeDelta = "-"; } else if (lapsDelta > 0) { entry.TotalTimeDelta = $"+{lapsDelta} {PluralizingConverter.Pluralize(lapsDelta, "lap")}"; } else { var t = entry.TotalTime - bestTotalTime?.TotalTime; var v = t?.ToMillisecondsString(); entry.TotalTimeDelta = t == TimeSpan.Zero ? "" : v != null ? $"+{v}" : null; } } } var bestProgress = (from player in data.PlayerEntries where player.LapTimeProgress > 0.03 orderby player.LapTimeProgress descending select player).FirstOrDefault(); var bestConsistent = (from player in data.PlayerEntries where player.LapTimeSpread < 0.02 orderby player.LapTimeSpread descending select player).FirstOrDefault(); data.RemarkableNotes = new[] { sessionBestLap == null ? null : new SessionFinishedData.RemarkableNote("[b]Best lap[/b] made by ", data.PlayerEntries.GetByIdOrDefault(sessionBestLap.CarNumber), null), new SessionFinishedData.RemarkableNote("[b]The Best Off-roader Award[/b] goes to ", (from player in data.PlayerEntries let cuts = (double)player.Laps.Sum(x => x.Cuts) / player.Laps.Length where cuts > 1.5 orderby cuts descending select player).FirstOrDefault(), null), new SessionFinishedData.RemarkableNote("[b]Remarkable progress[/b] shown by ", bestProgress, null), new SessionFinishedData.RemarkableNote("[b]The most consistent[/b] is ", bestConsistent, null), }.Where(x => x?.Player != null).ToList(); return(data); }).ToList(); return(sessionsData?.Count == 1 ? (BaseFinishedData)sessionsData.First() : sessionsData?.Any() == true ? new SessionsFinishedData(sessionsData) : null); }
protected override string GetStatus() => PluralizingConverter.PluralizeExt(MainList.Count, "{0} championship");
public async Task <IReadOnlyList <ServerInformationComplete> > ScanForServers(string address, IProgress <AsyncProgressEntry> progress, CancellationToken cancellation) { if (address == null) { throw new ArgumentNullException(nameof(address)); } // assume address is something like [HOSTNAME]:[HTTP PORT] if (!KunosApiProvider.ParseAddress(address, out var ip, out var port)) { throw new Exception(ToolsStrings.Online_CannotParseAddress); } if (port > 0) { progress?.Report(AsyncProgressEntry.FromStringIndetermitate(ToolsStrings.Online_GettingInformationDirectly)); ServerInformationComplete information; try { information = await KunosApiProvider.GetInformationDirectAsync(ip, port); } catch (WebException) { if (cancellation.IsCancellationRequested) { return(null); } // assume address is [HOSTNAME]:[TCP PORT] progress?.Report(AsyncProgressEntry.FromStringIndetermitate(ToolsStrings.Online_TryingToFindOutHttpPort)); var pair = await KunosApiProvider.TryToPingServerAsync(ip, port, SettingsHolder.Online.PingTimeout); if (cancellation.IsCancellationRequested) { return(null); } if (pair != null) { progress?.Report(AsyncProgressEntry.FromStringIndetermitate(ToolsStrings.Online_GettingInformationDirectly_SecondAttempt)); try { information = await KunosApiProvider.GetInformationDirectAsync(ip, pair.Item1); } catch (WebException) { information = null; } } else { information = null; } } if (cancellation.IsCancellationRequested) { return(null); } return(information == null ? new ServerInformationComplete[0] : new [] { information }); } else { var result = new List <ServerInformationComplete>(); // assume address is [HOSTNAME] progress?.Report(AsyncProgressEntry.FromStringIndetermitate(ToolsStrings.Common_Scanning)); var scanned = 0; var portsDiapason = PortsDiapason.Create(SettingsHolder.Online.PortsEnumeration); var total = portsDiapason.Count(); await portsDiapason.Select(async p => { var pair = await KunosApiProvider.TryToPingServerAsync(ip, p, SettingsHolder.Online.ScanPingTimeout); if (pair != null && pair.Item1 > 1024 && pair.Item1 < 65536) { if (cancellation.IsCancellationRequested) { return; } try { var information = await KunosApiProvider.GetInformationDirectAsync(ip, pair.Item1); if (cancellation.IsCancellationRequested) { return; } result.Add(information); } catch (WebException) { } } scanned++; progress?.Report(new AsyncProgressEntry(string.Format(ToolsStrings.Online_ScanningProgress, scanned, total, PluralizingConverter.PluralizeExt(result.Count, ToolsStrings.Online_ScanningProgress_Found)), scanned, total)); }).WhenAll(200, cancellation); return(result); } }
/// <summary> /// Create new instance. /// </summary> /// <param name="rating">If null, favourites mode.</param> public SelectRating(int?rating) : base(rating.HasValue ? PluralizingConverter.PluralizeExt(rating.Value, "{0} Star") : "Favourites") { Rating = rating; }
private string GetSpecsPitboxesDisplay() { return(PluralizingConverter.PluralizeExt(SpecsPitboxesValue, ToolsStrings.TrackBaseObject_Specs_PitsNumber)); }
public static Uri RatingUri(double rating) { return(UriExtension.Create("/Pages/Miscellaneous/AcObjectSelectList.xaml?Type=car&Filter={0}&Title={1}", $"rating≥{Filter.Encode(rating.FloorToInt().ToInvariantString())} & rating<{Filter.Encode((rating.FloorToInt() + 1).ToInvariantString())}", PluralizingConverter.PluralizeExt(rating.FloorToInt(), "{0} Star"))); }
protected override string GetStatus() { return(PluralizingConverter.PluralizeExt(MainList.Count, AppStrings.List_Skins)); }
/// <summary> /// Create new instance. /// </summary> /// <param name="rating">If null, favourites mode.</param> public SelectRating(int?rating) : base(rating.HasValue ? PluralizingConverter.PluralizeExt(rating.Value, ControlsStrings.SelectDialog_RatingTitle) : "Favourites") { Rating = rating; }
protected override string GetStatus() => PluralizingConverter.PluralizeExt(MainList.Count, AppStrings.List_Showrooms);
private static async Task <IReadOnlyList <UpdatePreviewError> > UpdatePreview(IReadOnlyList <ToUpdatePreview> entries, DarkPreviewsOptions options, string presetName = null, DarkPreviewsUpdater updater = null) { var localUpdater = updater == null; if (localUpdater) { updater = new DarkPreviewsUpdater(AcRootDirectory.Instance.RequireValue, options); } else { updater.SetOptions(options); } var errors = new List <UpdatePreviewError>(); try { if (options.Showroom != null && ShowroomsManager.Instance.GetById(options.Showroom) == null) { if (options.Showroom == "at_previews" && MissingShowroomHelper != null) { await MissingShowroomHelper.OfferToInstall("Kunos Previews Showroom (AT Previews Special)", "at_previews", "http://www.assettocorsa.net/assetto-corsa-v1-5-dev-diary-part-33/"); if (ShowroomsManager.Instance.GetById(options.Showroom) != null) { goto Action; } } throw new InformativeException("Can’t update preview", $"Showroom “{options.Showroom}” is missing"); } Action: var checksum = options.GetChecksum(); var finished = false; var j = 0; using (var waiting = new WaitingDialog()) { var cancellation = waiting.CancellationToken; var singleMode = entries.Count == 1; var verySingleMode = singleMode && entries[0].Skins?.Count == 1; var recycled = 0; if (!verySingleMode) { waiting.SetImage(null); if (SettingsHolder.CustomShowroom.PreviewsRecycleOld) { waiting.SetMultiline(true); } } var step = 1d / entries.Count; var postfix = string.Empty; var started = Stopwatch.StartNew(); var approximateSkinsPerCarCars = 1; var approximateSkinsPerCarSkins = 10; Action <int> updateApproximate = skinsPerCar => { approximateSkinsPerCarCars++; approximateSkinsPerCarSkins += skinsPerCar; }; Func <int, int> leftSkins = currentEntry => { var skinsPerCar = (double)approximateSkinsPerCarSkins / approximateSkinsPerCarCars; var result = 0d; for (var k = currentEntry; k < entries.Count; k++) { var entry = entries[k]; result += entry.Skins?.Count ?? skinsPerCar; } return(result.RoundToInt()); }; var shotSkins = 0; var recyclingWarning = false; Func <CarObject, CarSkinObject, int?, IEnumerable <string> > getDetails = (car, skin, currentEntrySkinsLeft) => { var left = leftSkins(j) + (currentEntrySkinsLeft ?? approximateSkinsPerCarSkins / approximateSkinsPerCarCars); // ReSharper disable once AccessToModifiedClosure var speed = shotSkins / started.Elapsed.TotalMinutes; var remainingTime = speed < 0.0001 ? "Unknown" : $"About {TimeSpan.FromMinutes(left / speed).ToReadableTime()}"; var remainingItems = $"About {left} {PluralizingConverter.Pluralize(left, ControlsStrings.CustomShowroom_SkinHeader).ToSentenceMember()}"; return(new[] { $"Car: {car?.DisplayName}", $"Skin: {skin?.DisplayName ?? "?"}", $"Speed: {speed:F2} {PluralizingConverter.Pluralize(10, ControlsStrings.CustomShowroom_SkinHeader).ToSentenceMember()}/{"min"}", $"Time remaining: {remainingTime}", $"Items remaining: {remainingItems}", // ReSharper disable once AccessToModifiedClosure recyclingWarning ? "[i]Recycling seems to take too long? If so, it can always be disabled in Settings.[/i]" : null }.NonNull()); }; for (j = 0; j < entries.Count; j++) { if (cancellation.IsCancellationRequested) { goto Cancel; } var entry = entries[j]; var progress = step * j; var car = entry.Car; var skins = entry.Skins; if (skins == null) { waiting.Report(new AsyncProgressEntry("Loading skins…" + postfix, verySingleMode ? 0d : progress)); waiting.SetDetails(getDetails(car, null, null)); await car.SkinsManager.EnsureLoadedAsync(); if (cancellation.IsCancellationRequested) { goto Cancel; } skins = car.EnabledOnlySkins.ToList(); updateApproximate(skins.Count); } var halfstep = step * 0.5 / skins.Count; for (var i = 0; i < skins.Count; i++) { if (cancellation.IsCancellationRequested) { goto Cancel; } var skin = skins[i]; waiting.SetDetails(getDetails(car, skin, skins.Count - i)); var subprogress = progress + step * (0.1 + 0.8 * i / skins.Count); if (SettingsHolder.CustomShowroom.PreviewsRecycleOld && File.Exists(skin.PreviewImage)) { if (++recycled > 5) { recyclingWarning = true; } waiting.Report(new AsyncProgressEntry($"Recycling current preview for {skin.DisplayName}…" + postfix, verySingleMode ? 0d : subprogress)); await Task.Run(() => FileUtils.Recycle(skin.PreviewImage)); } waiting.Report(new AsyncProgressEntry($"Updating skin {skin.DisplayName}…" + postfix, verySingleMode ? 0d : subprogress + halfstep)); try { await updater.ShotAsync(car.Id, skin.Id, skin.PreviewImage, car.AcdData, GetInformation(car, skin, presetName, checksum), () => { if (!verySingleMode) { ActionExtension.InvokeInMainThreadAsync(() => { // ReSharper disable once AccessToModifiedClosure if (!finished) { // ReSharper disable once AccessToDisposedClosure waiting.SetImage(skin.PreviewImage); } }); } }); shotSkins++; } catch (Exception e) { if (errors.All(x => x.ToUpdate != entry)) { errors.Add(new UpdatePreviewError(entry, e.Message, null)); } } } } waiting.Report(new AsyncProgressEntry("Saving…" + postfix, verySingleMode ? 0d : 0.999999d)); await updater.WaitForProcessing(); finished = true; } if (errors.Count > 0) { NonfatalError.Notify("Can’t update previews:\n" + errors.Select(x => @"• " + x.Message.ToSentence()).JoinToString(";" + Environment.NewLine)); } goto End; Cancel: for (; j < entries.Count; j++) { errors.Add(new UpdatePreviewError(entries[j], ControlsStrings.Common_Cancelled, null)); } End: return(errors); } catch (Exception e) { NonfatalError.Notify("Can’t update preview", e); return(null); } finally { if (localUpdater) { updater.Dispose(); GC.Collect(); } } }