/// <summary> /// Ensure that the current skin is in a state it can accept user modifications. /// This will create a copy of any internal skin and being tracking in the database if not already. /// </summary> public void EnsureMutableSkin() { CurrentSkinInfo.Value.PerformRead(s => { if (!s.Protected) { return; } string[] existingSkinNames = realm.Run(r => r.All <SkinInfo>() .Where(skin => !skin.DeletePending) .AsEnumerable() .Select(skin => skin.Name).ToArray()); // if the user is attempting to save one of the default skin implementations, create a copy first. var skinInfo = new SkinInfo { Creator = s.Creator, InstantiationInfo = s.InstantiationInfo, Name = NamingUtils.GetNextBestName(existingSkinNames, $"{s.Name} (modified)") }; var result = skinModelManager.Import(skinInfo); if (result != null) { // save once to ensure the required json content is populated. // currently this only happens on save. result.PerformRead(skin => Save(skin.CreateInstance(this))); CurrentSkinInfo.Value = result; } }); }
public void TestEvenMoreAlreadyTaken() { string[] existingNames = Enumerable.Range(1, 30).Select(i => $"New Difficulty ({i})").Append("New Difficulty").ToArray(); string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); Assert.AreEqual("New Difficulty (31)", nextBestName); }
public void TestAlreadyTakenWithBrackets() { string[] existingNames = { "new difficulty (copy)" }; string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty (copy)"); Assert.AreEqual("New Difficulty (copy) (1)", nextBestName); }
public void TestAlreadyTakenWithDifferentCase() { string[] existingNames = { "new difficulty" }; string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); Assert.AreEqual("New Difficulty (1)", nextBestName); }
public void TestNotTakenButClose() { string[] existingNames = { "New Difficulty(1)", "New Difficulty (abcd)", "New Difficulty but not really" }; string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); Assert.AreEqual("New Difficulty", nextBestName); }
public void TestNotTaken() { string[] existingNames = { "Something", "Entirely", "Different" }; string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); Assert.AreEqual("New Difficulty", nextBestName); }
public void TestMultipleAlreadyTaken() { string[] existingNames = { "New Difficulty", "New difficulty (1)", "new Difficulty (2)", "New DIFFICULTY (3)" }; string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty"); Assert.AreEqual("New Difficulty (4)", nextBestName); }
/// <summary> /// Add a new difficulty to the provided <paramref name="targetBeatmapSet"/> based on the provided <paramref name="referenceWorkingBeatmap"/>. /// The new difficulty will be backed by a <see cref="BeatmapInfo"/> model /// and represented by the returned <see cref="WorkingBeatmap"/>. /// </summary> /// <remarks> /// Contrary to <see cref="CopyExistingDifficulty"/>, this method does not preserve hitobjects and beatmap-level settings from <paramref name="referenceWorkingBeatmap"/>. /// The created beatmap will have zero hitobjects and will have default settings (including difficulty settings), but will preserve metadata and existing timing points. /// </remarks> /// <param name="targetBeatmapSet">The <see cref="BeatmapSetInfo"/> to add the new difficulty to.</param> /// <param name="referenceWorkingBeatmap">The <see cref="WorkingBeatmap"/> to use as a baseline reference when creating the new difficulty.</param> /// <param name="rulesetInfo">The ruleset with which the new difficulty should be created.</param> public virtual WorkingBeatmap CreateNewDifficulty(BeatmapSetInfo targetBeatmapSet, WorkingBeatmap referenceWorkingBeatmap, RulesetInfo rulesetInfo) { var playableBeatmap = referenceWorkingBeatmap.GetPlayableBeatmap(rulesetInfo); var newBeatmapInfo = new BeatmapInfo(rulesetInfo, new BeatmapDifficulty(), playableBeatmap.Metadata.DeepClone()) { DifficultyName = NamingUtils.GetNextBestName(targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), "New Difficulty") }; var newBeatmap = new Beatmap { BeatmapInfo = newBeatmapInfo }; foreach (var timingPoint in playableBeatmap.ControlPointInfo.TimingPoints) { newBeatmap.ControlPointInfo.Add(timingPoint.Time, timingPoint.DeepClone()); } return(addDifficultyToSet(targetBeatmapSet, newBeatmap, referenceWorkingBeatmap.Skin)); }
/// <summary> /// Add a copy of the provided <paramref name="referenceWorkingBeatmap"/> to the provided <paramref name="targetBeatmapSet"/>. /// The new difficulty will be backed by a <see cref="BeatmapInfo"/> model /// and represented by the returned <see cref="WorkingBeatmap"/>. /// </summary> /// <remarks> /// Contrary to <see cref="CreateNewDifficulty"/>, this method creates a nearly-exact copy of <paramref name="referenceWorkingBeatmap"/> /// (with the exception of a few key properties that cannot be copied under any circumstance, like difficulty name, beatmap hash, or online status). /// </remarks> /// <param name="targetBeatmapSet">The <see cref="BeatmapSetInfo"/> to add the copy to.</param> /// <param name="referenceWorkingBeatmap">The <see cref="WorkingBeatmap"/> to be copied.</param> public virtual WorkingBeatmap CopyExistingDifficulty(BeatmapSetInfo targetBeatmapSet, WorkingBeatmap referenceWorkingBeatmap) { var newBeatmap = referenceWorkingBeatmap.GetPlayableBeatmap(referenceWorkingBeatmap.BeatmapInfo.Ruleset).Clone(); BeatmapInfo newBeatmapInfo; newBeatmap.BeatmapInfo = newBeatmapInfo = referenceWorkingBeatmap.BeatmapInfo.Clone(); // assign a new ID to the clone. newBeatmapInfo.ID = Guid.NewGuid(); // add "(copy)" suffix to difficulty name, and additionally ensure that it doesn't conflict with any other potentially pre-existing copies. newBeatmapInfo.DifficultyName = NamingUtils.GetNextBestName( targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), $"{newBeatmapInfo.DifficultyName} (copy)"); // clear the hash, as that's what is used to match .osu files with their corresponding realm beatmaps. newBeatmapInfo.Hash = string.Empty; // clear online properties. newBeatmapInfo.OnlineID = -1; newBeatmapInfo.Status = BeatmapOnlineStatus.None; return(addDifficultyToSet(targetBeatmapSet, newBeatmap, referenceWorkingBeatmap.Skin)); }
public void TestEmptySet() { string nextBestName = NamingUtils.GetNextBestName(Enumerable.Empty <string>(), "New Difficulty"); Assert.AreEqual("New Difficulty", nextBestName); }