private void UpdateOpponentsNumber() { if (!Mode.CandidatesMode) { SetOpponentsNumberInternal(NonfilteredList.ApartFrom(_playerEntry).Count()); } }
private void UpdatePlayerEntry() { if (_playerCar != _playerEntry?.Car) { if (_playerEntry != null) { NonfilteredList.Remove(_playerEntry); _playerEntry = null; } if (Mode != BuiltInGridMode.Custom || IgnoreStartingPosition) { return; } _playerEntry = _playerCar == null ? null : new RaceGridPlayerEntry(_playerCar); } if (_playerEntry == null) { return; } if (Mode == BuiltInGridMode.Custom) { var index = NonfilteredList.IndexOf(_playerEntry); var pos = StartingPosition - 1; if (index == -1) { if (pos > NonfilteredList.Count) { NonfilteredList.Add(_playerEntry); } else if (pos >= 0) { NonfilteredList.Insert(pos, _playerEntry); } } else { if (pos < 0) { NonfilteredList.RemoveAt(index); } else if (pos != index) { NonfilteredList.Move(index, pos); } } } else if (NonfilteredList.Contains(_playerEntry)) { NonfilteredList.Remove(_playerEntry); _playerEntry = null; } }
private void UpdateExceeded() { if (Mode.CandidatesMode) { foreach (var entry in NonfilteredList.Where(x => x.ExceedsLimit)) { entry.ExceedsLimit = false; } } else { var left = OpponentsNumberLimit; foreach (var entry in NonfilteredList.ApartFrom(_playerEntry)) { entry.ExceedsLimit = --left < 0; } } }
public void DeleteEntry(RaceGridEntry entry) { if (entry is RaceGridPlayerEntry) { StartingPosition = 0; return; } NonfilteredList.Remove(entry); if (Mode == BuiltInGridMode.Custom) { UpdateOpponentsNumber(); } else { Mode = BuiltInGridMode.CandidatesManual; } UpdateExceeded(); }
private async Task RebuildGridAsyncInner() { try { await Task.Delay(50); OnPropertyChanged(nameof(IsBusy)); ErrorMessage = null; again: var mode = Mode; var candidates = await FindCandidates(); if (mode != Mode) { goto again; } // I’ve seen that XKCD comic, but I still think goto is more // suitable than a loop here if (candidates == null) { return; } NonfilteredList.ReplaceEverythingBy(candidates); } catch (SyntaxErrorException e) { ErrorMessage = string.Format(ToolsStrings.Common_SyntaxErrorFormat, e.Message); NonfatalError.Notify(ToolsStrings.RaceGrid_CannotUpdate, e); } catch (ScriptRuntimeException e) { ErrorMessage = e.Message; } catch (InformativeException e) when(e.SolutionCommentary == null) { ErrorMessage = e.Message; } catch (Exception e) { ErrorMessage = e.Message; NonfatalError.Notify(ToolsStrings.RaceGrid_CannotUpdate, e); } finally { _rebuildingTask = null; OnPropertyChanged(nameof(IsBusy)); } }
public RaceGridViewModel(bool ignoreStartingPosition = false, [CanBeNull] string keySaveable = KeySaveable) { IgnoreStartingPosition = ignoreStartingPosition; _saveable = new SaveHelper <SaveableData>(keySaveable, () => { var data = new SaveableData { ModeId = Mode.Id, FilterValue = FilterValue, ShuffleCandidates = ShuffleCandidates, AiLevelFixed = AiLevelFixed, AiLevelArrangeRandom = AiLevelArrangeRandom, AiLevelArrangeReverse = AiLevelArrangeReverse, AiLevel = AiLevel, AiLevelMin = AiLevelMin, OpponentsNumber = OpponentsNumber, StartingPosition = StartingPosition, }; if (Mode == BuiltInGridMode.CandidatesManual) { var priority = false; data.CarIds = NonfilteredList.Select(x => { if (x.CandidatePriority != 1) { priority = true; } return(x.Car.Id); }).ToArray(); if (priority) { data.CandidatePriorities = NonfilteredList.Select(x => x.CandidatePriority).ToArray(); } } else if (Mode == BuiltInGridMode.Custom) { data.CarIds = NonfilteredList.Where(x => !x.SpecialEntry).Select(x => x.Car.Id).ToArray(); } if (data.CarIds != null) { var filtered = NonfilteredList.Where(x => !x.SpecialEntry).ToList(); if (filtered.Any(x => x.AiLevel.HasValue)) { data.AiLevels = filtered.Select(x => x.AiLevel ?? -1).ToArray(); } if (filtered.Any(x => x.Name != null)) { data.Names = filtered.Select(x => x.Name).ToArray(); } if (filtered.Any(x => x.Nationality != null)) { data.Nationalities = filtered.Select(x => x.Nationality).ToArray(); } if (filtered.Any(x => x.CarSkin != null)) { data.SkinIds = filtered.Select(x => x.CarSkin?.Id).ToArray(); } } return(data); }, data => { ShuffleCandidates = data.ShuffleCandidates ?? true; AiLevelFixed = data.AiLevelFixed ?? false; AiLevelArrangeRandom = data.AiLevelArrangeRandomly.HasValue ? (data.AiLevelArrangeRandomly.Value ? 1d : 0d) : data.AiLevelArrangeRandom ?? 0.1d; AiLevelArrangeReverse = data.AiLevelArrangeReverse ?? false; AiLevel = data.AiLevel ?? 95; AiLevelMin = data.AiLevelMin ?? 85; FilterValue = data.FilterValue; ErrorMessage = null; var mode = Modes.GetByIdOrDefault <IRaceGridMode>(data.ModeId); if (mode == null) { NonfatalError.NotifyBackground(ToolsStrings.RaceGrid_GridModeIsMissing, string.Format(ToolsStrings.RaceGrid_GridModeIsMissing_Commentary, data.ModeId)); Mode = BuiltInGridMode.SameCar; } else { Mode = mode; } if (Mode.CandidatesMode) { if (Mode == BuiltInGridMode.CandidatesManual && data.CarIds != null) { // TODO: Async? NonfilteredList.ReplaceEverythingBy(data.CarIds.Select(x => CarsManager.Instance.GetById(x)).Select((x, i) => { if (x == null) { return(null); } var aiLevel = data.AiLevels?.ElementAtOrDefault(i); var carSkinId = data.SkinIds?.ElementAtOrDefault(i); return(new RaceGridEntry(x) { CandidatePriority = data.CandidatePriorities?.ElementAtOr(i, 1) ?? 1, AiLevel = aiLevel >= 0 ? aiLevel : (int?)null, Name = data.Names?.ElementAtOrDefault(i), Nationality = data.Nationalities?.ElementAtOrDefault(i), CarSkin = carSkinId != null ? x.GetSkinById(carSkinId) : null, }); }).NonNull()); } else { NonfilteredList.Clear(); } SetOpponentsNumberInternal(data.OpponentsNumber ?? 7); } else { NonfilteredList.ReplaceEverythingBy(data.CarIds?.Select(x => CarsManager.Instance.GetById(x)).Select((x, i) => { if (x == null) { return(null); } var aiLevel = data.AiLevels?.ElementAtOrDefault(i); var carSkinId = data.SkinIds?.ElementAtOrDefault(i); return(new RaceGridEntry(x) { AiLevel = aiLevel >= 0 ? aiLevel : null, Name = data.Names?.ElementAtOrDefault(i), Nationality = data.Nationalities?.ElementAtOrDefault(i), CarSkin = carSkinId != null ? x.GetSkinById(carSkinId) : null, }); }).NonNull() ?? new RaceGridEntry[0]); } StartingPosition = data.StartingPosition ?? 7; FinishLoading(); }, Reset); _presetsHelper = new PresetsMenuHelper(); _randomGroup = new HierarchicalGroup(ToolsStrings.RaceGrid_Random); UpdateRandomModes(); Modes = new HierarchicalGroup { BuiltInGridMode.SameCar, _randomGroup, BuiltInGridMode.Custom, _presetsHelper.Create(PresetableKeyValue, p => { ImportFromPresetData(p.ReadData()); }, ControlsStrings.Common_Presets) }; NonfilteredList.CollectionChanged += OnCollectionChanged; NonfilteredList.ItemPropertyChanged += OnItemPropertyChanged; FilteredView = new BetterListCollectionView(NonfilteredList) { CustomSort = this }; // _saveable.Initialize(); FilesStorage.Instance.Watcher(ContentCategory.GridTypes).Update += OnGridTypesUpdate; }
public async Task <IList <Game.AiCar> > GenerateGameEntries(CancellationToken cancellation = default(CancellationToken)) { if (IsBusy) { await RebuildGridAsync(); if (cancellation.IsCancellationRequested) { return(null); } } var opponentsNumber = OpponentsNumberLimited; if (FilteredView.Count == 0 || opponentsNumber == 0) { return(new Game.AiCar[0]); } var skins = new Dictionary <string, GoodShuffle <CarSkinObject> >(); foreach (var car in FilteredView.OfType <RaceGridEntry>().Where(x => x.CarSkin == null).Select(x => x.Car).Distinct()) { await car.SkinsManager.EnsureLoadedAsync(); if (cancellation.IsCancellationRequested) { return(null); } skins[car.Id] = GoodShuffle.Get(car.EnabledOnlySkins); } NameNationality[] nameNationalities; if (opponentsNumber == 7 && OptionNfsPorscheNames) { nameNationalities = new[] { new NameNationality { Name = "Dylan", Nationality = "Wales" }, new NameNationality { Name = "Parise", Nationality = "Italy" }, new NameNationality { Name = "Steele", Nationality = "United States" }, new NameNationality { Name = "Wingnut", Nationality = "England" }, new NameNationality { Name = "Leadfoot", Nationality = "Australia" }, new NameNationality { Name = "Amazon", Nationality = "United States" }, new NameNationality { Name = "Backlash", Nationality = "United States" } }; } else if (DataProvider.Instance.NationalitiesAndNames.Any()) { nameNationalities = GoodShuffle.Get(DataProvider.Instance.NationalitiesAndNamesList).Take(opponentsNumber).ToArray(); } else { nameNationalities = null; } List <int> aiLevels; if (AiLevelFixed) { aiLevels = null; } else { var aiLevelsInner = from i in Enumerable.Range(0, opponentsNumber) select AiLevelMin + ((opponentsNumber < 2 ? 1d : 1d - i / (opponentsNumber - 1d)) * (AiLevel - AiLevelMin)).RoundToInt(); if (AiLevelArrangeReverse) { aiLevelsInner = aiLevelsInner.Reverse(); } if (Equals(AiLevelArrangeRandom, 1d)) { aiLevelsInner = GoodShuffle.Get(aiLevelsInner); } else if (AiLevelArrangeRandom > 0d) { aiLevelsInner = LimitedShuffle.Get(aiLevelsInner, AiLevelArrangeRandom); } aiLevels = aiLevelsInner.Take(opponentsNumber).ToList(); Logging.Debug("AI levels: " + aiLevels.Select(x => $@"{x}%").JoinToString(@", ")); } IEnumerable <RaceGridEntry> final; if (Mode.CandidatesMode) { var list = FilteredView.OfType <RaceGridEntry>().SelectMany(x => new[] { x }.Repeat(x.CandidatePriority)).ToList(); if (ShuffleCandidates) { var shuffled = GoodShuffle.Get(list); if (_playerCar != null) { var same = list.FirstOrDefault(x => x.Car == _playerCar); if (same != null) { shuffled.IgnoreOnce(same); } } final = shuffled.Take(opponentsNumber); } else { var skip = _playerCar; final = LinqExtension.RangeFrom().Select(x => list.RandomElement()).Where(x => { if (x.Car == skip) { skip = null; return(false); } return(true); }).Take(opponentsNumber); } } else { final = NonfilteredList.Where(x => !x.SpecialEntry); } if (_playerCar != null) { skins.GetValueOrDefault(_playerCar.Id)?.IgnoreOnce(_playerCar.SelectedSkin); } var takenNames = new List <string>(opponentsNumber); return(final.Take(opponentsNumber).Select((entry, i) => { var level = entry.AiLevel ?? aiLevels?[i] ?? 100; var skin = entry.CarSkin; if (skin == null) { skin = skins.GetValueOrDefault(entry.Car.Id)?.Next; } var name = entry.Name; if (string.IsNullOrWhiteSpace(name) && SettingsHolder.Drive.QuickDriveUseSkinNames) { var skinDriverNames = skin?.DriverName?.Split(',').Select(x => x.Trim()).Where(x => x.Length > 0).ToList(); if (skinDriverNames?.Count > 0) { name = GoodShuffle.Get(skinDriverNames).Take(skinDriverNames.Count).FirstOrDefault(x => !takenNames.Contains(x)) ?? name; takenNames.Add(name); } } if (string.IsNullOrWhiteSpace(name)) { name = nameNationalities?[i].Name ?? @"AI #" + i; takenNames.Add(name); } var nationality = entry.Nationality ?? nameNationalities?[i].Nationality ?? @"Italy"; var skinId = skin?.Id; return new Game.AiCar { AiLevel = level, CarId = entry.Car.Id, DriverName = AiLevelInDriverName ? $@"{name} ({level}%)" : name, Nationality = nationality, Setup = "", SkinId = skinId }; }).ToList()); }
public void InsertEntry(int index, [NotNull] RaceGridEntry entry) { var oldIndex = NonfilteredList.IndexOf(entry); var count = NonfilteredList.Count; var isNew = oldIndex == -1; var limit = isNew ? count : count - 1; if (index < 0 || index > limit) { index = limit; } if (oldIndex == index) { return; } if (Mode.CandidatesMode) { if (isNew) { Mode = BuiltInGridMode.CandidatesManual; var existed = NonfilteredList.FirstOrDefault(x => x.Same(entry)); if (existed != null) { existed.CandidatePriority++; } else { NonfilteredList.Add(entry); } return; } NonfilteredList.ReplaceEverythingBy(NonfilteredList.Sort(Compare)); NonfilteredList.Move(oldIndex, index); try { _modeKeepOrder = true; Mode = BuiltInGridMode.Custom; } finally { _modeKeepOrder = false; } } else if (isNew) { if (index == count) { NonfilteredList.Add(entry); } else { NonfilteredList.Insert(index, entry); } UpdateOpponentsNumber(); } else if (index != oldIndex) { NonfilteredList.Move(oldIndex, index); } if (StartingPosition != 0) { StartingPositionLimited = NonfilteredList.IndexOf(_playerEntry) + 1; } UpdateExceeded(); }