diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 0644313bf9..1bba73bea0 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -110,13 +110,25 @@ namespace osu.Game.Tests.Database Assert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked); detachedBeatmapSet.Status = BeatmapOnlineStatus.Ranked; - beatmapSet.PerformWrite(s => detachedBeatmapSet.CopyChangesToRealm(s)); + beatmapSet.PerformWrite(s => + { + detachedBeatmapSet.CopyChangesToRealm(s); + }); beatmapSet.PerformRead(s => { + // Check above changes explicitly. Assert.AreEqual(BeatmapOnlineStatus.Ranked, s.Status); Assert.AreEqual("New Artist", s.Beatmaps.First().Metadata.Artist); Assert.AreEqual(newUser, s.Beatmaps.First().Metadata.Author); + Assert.NotZero(s.Files.Count); + + // Check nothing was lost in the copy operation. + Assert.AreEqual(s.Files.Count, detachedBeatmapSet.Files.Count); + Assert.AreEqual(s.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count()); + Assert.AreEqual(s.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); + Assert.AreEqual(s.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); + Assert.AreEqual(s.Metadata, detachedBeatmapSet.Metadata); }); } }); diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 53aba67275..1b732b3c8a 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -162,6 +162,7 @@ namespace osu.Game.Beatmaps public Guid BeatmapSetInfoID => BeatmapSet?.ID ?? Guid.Empty; [Ignored] + [IgnoreMap] public BeatmapDifficulty BaseDifficulty { get => Difficulty; diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs index a5e5962a04..188d619627 100644 --- a/osu.Game/Database/RealmObjectExtensions.cs +++ b/osu.Game/Database/RealmObjectExtensions.cs @@ -19,6 +19,50 @@ namespace osu.Game.Database { public static class RealmObjectExtensions { + private static readonly IMapper write_mapper = new MapperConfiguration(c => + { + c.ShouldMapField = fi => false; + c.ShouldMapProperty = pi => pi.SetMethod?.IsPublic == true; + + c.CreateMap() + .ForMember(s => s.Author, cc => cc.Ignore()) + .AfterMap((s, d) => + { + copyChangesToRealm(s.Author, d.Author); + }); + c.CreateMap(); + c.CreateMap(); + c.CreateMap(); + c.CreateMap(); + c.CreateMap() + .ForMember(s => s.Ruleset, cc => cc.Ignore()) + .ForMember(s => s.Metadata, cc => cc.Ignore()) + .ForMember(s => s.Difficulty, cc => cc.Ignore()) + .ForMember(s => s.BeatmapSet, cc => cc.Ignore()) + .AfterMap((s, d) => + { + d.Ruleset = d.Realm.Find(s.Ruleset.ShortName); + copyChangesToRealm(s.Difficulty, d.Difficulty); + copyChangesToRealm(s.Metadata, d.Metadata); + }); + c.CreateMap() + .ForMember(s => s.Beatmaps, cc => cc.Ignore()) + .AfterMap((s, d) => + { + foreach (var beatmap in s.Beatmaps) + { + var existing = d.Beatmaps.FirstOrDefault(b => b.ID == beatmap.ID); + + if (existing != null) + copyChangesToRealm(beatmap, existing); + else + d.Beatmaps.Add(beatmap); + } + }); + + c.AddGlobalIgnore(nameof(RealmObjectBase.ObjectSchema)); + }).CreateMapper(); + private static readonly IMapper mapper = new MapperConfiguration(c => { c.ShouldMapField = fi => false; @@ -52,6 +96,8 @@ namespace osu.Game.Database foreach (var beatmap in d.Beatmaps) beatmap.BeatmapSet = d; }); + + c.AddGlobalIgnore(nameof(RealmObjectBase.ObjectSchema)); }).CreateMapper(); /// @@ -90,10 +136,17 @@ namespace osu.Game.Database return mapper.Map(item); } - public static void CopyChangesToRealm(this T source, T destination) where T : RealmObjectBase - { - mapper.Map(source, destination); - } + /// + /// Copy changes in a detached beatmap back to realm. + /// This is a temporary method to handle existing flows only. It should not be used going forward if we can avoid it. + /// + /// The detached beatmap to copy from. + /// The live beatmap to copy to. + public static void CopyChangesToRealm(this BeatmapSetInfo source, BeatmapSetInfo destination) + => copyChangesToRealm(source, destination); + + private static void copyChangesToRealm(T source, T destination) where T : RealmObjectBase + => write_mapper.Map(source, destination); public static List> ToLiveUnmanaged(this IEnumerable realmList) where T : RealmObject, IHasGuidPrimaryKey