Esempio n. 1
0
        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);
            }
        }
Esempio n. 3
0
        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()})";
            }
Esempio n. 6
0
        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);
                }
            })));
        }
Esempio n. 7
0
            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());
            }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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));
        }
Esempio n. 10
0
        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));
        }
Esempio n. 11
0
 public string GetNumberString(int count)
 {
     return(PluralizingConverter.PluralizeExt(count, GetSubject()));
 }
Esempio n. 12
0
        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();
            }
        }
Esempio n. 13
0
        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");
Esempio n. 15
0
        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);
            }
        }
Esempio n. 16
0
 /// <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;
 }
Esempio n. 17
0
 private string GetSpecsPitboxesDisplay()
 {
     return(PluralizingConverter.PluralizeExt(SpecsPitboxesValue, ToolsStrings.TrackBaseObject_Specs_PitsNumber));
 }
Esempio n. 18
0
 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")));
 }
Esempio n. 19
0
 protected override string GetStatus()
 {
     return(PluralizingConverter.PluralizeExt(MainList.Count, AppStrings.List_Skins));
 }
Esempio n. 20
0
 /// <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;
 }
Esempio n. 21
0
 protected override string GetStatus() => PluralizingConverter.PluralizeExt(MainList.Count, AppStrings.List_Showrooms);
Esempio n. 22
0
        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();
                }
            }
        }