Merge branch 'master' into inheritable-allow-track-adjust
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.9 KiB |
@ -1,18 +1,18 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
||||||
{
|
{
|
||||||
protected override Texture GetTexture(ISkinSource skin)
|
protected override Drawable GetAnimation(ISkinSource skin)
|
||||||
{
|
{
|
||||||
// TODO: Should fallback to the head from default legacy skin instead of note.
|
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||||
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -18,12 +18,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
: new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Up, ScrollingDirection.Up));
|
: new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Up, ScrollingDirection.Up));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Texture GetTexture(ISkinSource skin)
|
protected override Drawable GetAnimation(ISkinSource skin)
|
||||||
{
|
{
|
||||||
// TODO: Should fallback to the head from default legacy skin instead of note.
|
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||||
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage)
|
return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage)
|
||||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
@ -19,7 +21,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
private Container directionContainer;
|
private Container directionContainer;
|
||||||
private Sprite noteSprite;
|
|
||||||
|
[CanBeNull]
|
||||||
|
private Drawable noteAnimation;
|
||||||
|
|
||||||
private float? minimumColumnWidth;
|
private float? minimumColumnWidth;
|
||||||
|
|
||||||
@ -39,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = noteSprite = new Sprite { Texture = GetTexture(skin) }
|
Child = noteAnimation = GetAnimation(skin) ?? Empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
@ -50,12 +54,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (noteSprite.Texture != null)
|
Texture texture = null;
|
||||||
|
|
||||||
|
if (noteAnimation is Sprite sprite)
|
||||||
|
texture = sprite.Texture;
|
||||||
|
else if (noteAnimation is TextureAnimation textureAnimation && textureAnimation.FrameCount > 0)
|
||||||
|
texture = textureAnimation.CurrentFrame;
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
{
|
{
|
||||||
// The height is scaled to the minimum column width, if provided.
|
// The height is scaled to the minimum column width, if provided.
|
||||||
float minimumWidth = minimumColumnWidth ?? DrawWidth;
|
float minimumWidth = minimumColumnWidth ?? DrawWidth;
|
||||||
|
noteAnimation.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), texture.DisplayWidth);
|
||||||
noteSprite.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), noteSprite.Texture.DisplayWidth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,9 +83,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Texture GetTexture(ISkinSource skin) => GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
[CanBeNull]
|
||||||
|
protected virtual Drawable GetAnimation(ISkinSource skin) => GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
|
|
||||||
protected Texture GetTextureFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup)
|
[CanBeNull]
|
||||||
|
protected Drawable GetAnimationFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup)
|
||||||
{
|
{
|
||||||
string suffix = string.Empty;
|
string suffix = string.Empty;
|
||||||
|
|
||||||
@ -93,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
string noteImage = GetColumnSkinConfig<string>(skin, lookup)?.Value
|
string noteImage = GetColumnSkinConfig<string>(skin, lookup)?.Value
|
||||||
?? $"mania-note{FallbackColumnIndex}{suffix}";
|
?? $"mania-note{FallbackColumnIndex}{suffix}";
|
||||||
|
|
||||||
return skin.GetTexture(noteImage, WrapMode.ClampToEdge, WrapMode.ClampToEdge);
|
return skin.GetAnimation(noteImage, WrapMode.ClampToEdge, WrapMode.ClampToEdge, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,6 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
typeof(FileStore),
|
typeof(FileStore),
|
||||||
typeof(ScoreManager),
|
typeof(ScoreManager),
|
||||||
typeof(BeatmapManager),
|
typeof(BeatmapManager),
|
||||||
typeof(SettingsStore),
|
|
||||||
typeof(RulesetConfigCache),
|
typeof(RulesetConfigCache),
|
||||||
typeof(OsuColour),
|
typeof(OsuColour),
|
||||||
typeof(IBindable<WorkingBeatmap>),
|
typeof(IBindable<WorkingBeatmap>),
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Game.Rulesets;
|
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
|
||||||
{
|
|
||||||
public abstract class DatabasedConfigManager<TLookup> : ConfigManager<TLookup>
|
|
||||||
where TLookup : struct, Enum
|
|
||||||
{
|
|
||||||
private readonly SettingsStore settings;
|
|
||||||
|
|
||||||
private readonly int? variant;
|
|
||||||
|
|
||||||
private List<DatabasedSetting> databasedSettings;
|
|
||||||
|
|
||||||
private readonly RulesetInfo ruleset;
|
|
||||||
|
|
||||||
private bool legacySettingsExist;
|
|
||||||
|
|
||||||
protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int? variant = null)
|
|
||||||
{
|
|
||||||
this.settings = settings;
|
|
||||||
this.ruleset = ruleset;
|
|
||||||
this.variant = variant;
|
|
||||||
|
|
||||||
Load();
|
|
||||||
|
|
||||||
InitialiseDefaults();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PerformLoad()
|
|
||||||
{
|
|
||||||
databasedSettings = settings.Query(ruleset?.ID, variant);
|
|
||||||
legacySettingsExist = databasedSettings.Any(s => int.TryParse(s.Key, out _));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool PerformSave()
|
|
||||||
{
|
|
||||||
lock (dirtySettings)
|
|
||||||
{
|
|
||||||
foreach (var setting in dirtySettings)
|
|
||||||
settings.Update(setting);
|
|
||||||
dirtySettings.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly List<DatabasedSetting> dirtySettings = new List<DatabasedSetting>();
|
|
||||||
|
|
||||||
protected override void AddBindable<TBindable>(TLookup lookup, Bindable<TBindable> bindable)
|
|
||||||
{
|
|
||||||
base.AddBindable(lookup, bindable);
|
|
||||||
|
|
||||||
if (legacySettingsExist)
|
|
||||||
{
|
|
||||||
var legacySetting = databasedSettings.Find(s => s.Key == ((int)(object)lookup).ToString());
|
|
||||||
|
|
||||||
if (legacySetting != null)
|
|
||||||
{
|
|
||||||
bindable.Parse(legacySetting.Value);
|
|
||||||
settings.Delete(legacySetting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var setting = databasedSettings.Find(s => s.Key == lookup.ToString());
|
|
||||||
|
|
||||||
if (setting != null)
|
|
||||||
{
|
|
||||||
bindable.Parse(setting.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
settings.Update(setting = new DatabasedSetting
|
|
||||||
{
|
|
||||||
Key = lookup.ToString(),
|
|
||||||
Value = bindable.Value,
|
|
||||||
RulesetID = ruleset?.ID,
|
|
||||||
Variant = variant,
|
|
||||||
});
|
|
||||||
|
|
||||||
databasedSettings.Add(setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
bindable.ValueChanged += b =>
|
|
||||||
{
|
|
||||||
setting.Value = b.NewValue;
|
|
||||||
|
|
||||||
lock (dirtySettings)
|
|
||||||
{
|
|
||||||
if (!dirtySettings.Contains(setting))
|
|
||||||
dirtySettings.Add(setting);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ using osu.Game.Database;
|
|||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
[Table("Settings")]
|
[Table("Settings")]
|
||||||
public class DatabasedSetting : IHasPrimaryKey
|
public class DatabasedSetting : IHasPrimaryKey // can be removed 20220315.
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
32
osu.Game/Configuration/RealmRulesetSetting.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using Realms;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Configuration
|
||||||
|
{
|
||||||
|
[MapTo(@"RulesetSetting")]
|
||||||
|
public class RealmRulesetSetting : RealmObject, IHasGuidPrimaryKey
|
||||||
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
public Guid ID { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
[Indexed]
|
||||||
|
public int RulesetID { get; set; }
|
||||||
|
|
||||||
|
[Indexed]
|
||||||
|
public int Variant { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Key { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Value { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public override string ToString() => $"{Key} => {Value}";
|
||||||
|
}
|
||||||
|
}
|
@ -1,46 +1,20 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public class SettingsStore : DatabaseBackedStore
|
public class SettingsStore
|
||||||
{
|
{
|
||||||
public event Action SettingChanged;
|
// this class mostly exists as a wrapper to avoid breaking the ruleset API (see usage in RulesetConfigManager).
|
||||||
|
// it may cease to exist going forward, depending on how the structure of the config data layer changes.
|
||||||
|
|
||||||
public SettingsStore(DatabaseContextFactory contextFactory)
|
public readonly RealmContextFactory Realm;
|
||||||
: base(contextFactory)
|
|
||||||
|
public SettingsStore(RealmContextFactory realmFactory)
|
||||||
{
|
{
|
||||||
}
|
Realm = realmFactory;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve <see cref="DatabasedSetting"/>s for a specified ruleset/variant content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rulesetId">The ruleset's internal ID.</param>
|
|
||||||
/// <param name="variant">An optional variant.</param>
|
|
||||||
public List<DatabasedSetting> Query(int? rulesetId = null, int? variant = null) =>
|
|
||||||
ContextFactory.Get().DatabasedSetting.Where(b => b.RulesetID == rulesetId && b.Variant == variant).ToList();
|
|
||||||
|
|
||||||
public void Update(DatabasedSetting setting)
|
|
||||||
{
|
|
||||||
using (ContextFactory.GetForWrite())
|
|
||||||
{
|
|
||||||
var newValue = setting.Value;
|
|
||||||
Refresh(ref setting);
|
|
||||||
setting.Value = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingChanged?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete(DatabasedSetting setting)
|
|
||||||
{
|
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
|
||||||
usage.Context.Remove(setting);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using DatabasedKeyBinding = osu.Game.Input.Bindings.DatabasedKeyBinding;
|
|
||||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -24,14 +23,13 @@ namespace osu.Game.Database
|
|||||||
public DbSet<BeatmapDifficulty> BeatmapDifficulty { get; set; }
|
public DbSet<BeatmapDifficulty> BeatmapDifficulty { get; set; }
|
||||||
public DbSet<BeatmapMetadata> BeatmapMetadata { get; set; }
|
public DbSet<BeatmapMetadata> BeatmapMetadata { get; set; }
|
||||||
public DbSet<BeatmapSetInfo> BeatmapSetInfo { get; set; }
|
public DbSet<BeatmapSetInfo> BeatmapSetInfo { get; set; }
|
||||||
public DbSet<DatabasedSetting> DatabasedSetting { get; set; }
|
|
||||||
public DbSet<FileInfo> FileInfo { get; set; }
|
public DbSet<FileInfo> FileInfo { get; set; }
|
||||||
public DbSet<RulesetInfo> RulesetInfo { get; set; }
|
public DbSet<RulesetInfo> RulesetInfo { get; set; }
|
||||||
public DbSet<SkinInfo> SkinInfo { get; set; }
|
public DbSet<SkinInfo> SkinInfo { get; set; }
|
||||||
public DbSet<ScoreInfo> ScoreInfo { get; set; }
|
public DbSet<ScoreInfo> ScoreInfo { get; set; }
|
||||||
|
|
||||||
// migrated to realm
|
// migrated to realm
|
||||||
public DbSet<DatabasedKeyBinding> DatabasedKeyBinding { get; set; }
|
public DbSet<DatabasedSetting> DatabasedSetting { get; set; }
|
||||||
|
|
||||||
private readonly string connectionString;
|
private readonly string connectionString;
|
||||||
|
|
||||||
@ -138,11 +136,6 @@ namespace osu.Game.Database
|
|||||||
modelBuilder.Entity<SkinInfo>().HasIndex(b => b.Hash).IsUnique();
|
modelBuilder.Entity<SkinInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||||
modelBuilder.Entity<SkinInfo>().HasIndex(b => b.DeletePending);
|
modelBuilder.Entity<SkinInfo>().HasIndex(b => b.DeletePending);
|
||||||
|
|
||||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => new { b.RulesetID, b.Variant });
|
|
||||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.IntAction);
|
|
||||||
modelBuilder.Entity<DatabasedKeyBinding>().Ignore(b => b.KeyCombination);
|
|
||||||
modelBuilder.Entity<DatabasedKeyBinding>().Ignore(b => b.Action);
|
|
||||||
|
|
||||||
modelBuilder.Entity<DatabasedSetting>().HasIndex(b => new { b.RulesetID, b.Variant });
|
modelBuilder.Entity<DatabasedSetting>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||||
|
|
||||||
modelBuilder.Entity<FileInfo>().HasIndex(b => b.Hash).IsUnique();
|
modelBuilder.Entity<FileInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Input.Bindings
|
|
||||||
{
|
|
||||||
[Table("KeyBinding")]
|
|
||||||
public class DatabasedKeyBinding : IKeyBinding, IHasPrimaryKey
|
|
||||||
{
|
|
||||||
public int ID { get; set; }
|
|
||||||
|
|
||||||
public int? RulesetID { get; set; }
|
|
||||||
|
|
||||||
public int? Variant { get; set; }
|
|
||||||
|
|
||||||
[Column("Keys")]
|
|
||||||
public string KeysString { get; set; }
|
|
||||||
|
|
||||||
[Column("Action")]
|
|
||||||
public int IntAction { get; set; }
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
public KeyCombination KeyCombination
|
|
||||||
{
|
|
||||||
get => KeysString;
|
|
||||||
set => KeysString = value.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
public object Action
|
|
||||||
{
|
|
||||||
get => IntAction;
|
|
||||||
set => IntAction = (int)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -140,8 +140,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
private FileStore fileStore;
|
private FileStore fileStore;
|
||||||
|
|
||||||
private SettingsStore settingsStore;
|
|
||||||
|
|
||||||
private RulesetConfigCache rulesetConfigCache;
|
private RulesetConfigCache rulesetConfigCache;
|
||||||
|
|
||||||
private SpectatorClient spectatorClient;
|
private SpectatorClient spectatorClient;
|
||||||
@ -279,8 +277,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
migrateDataToRealm();
|
migrateDataToRealm();
|
||||||
|
|
||||||
dependencies.Cache(settingsStore = new SettingsStore(contextFactory));
|
dependencies.Cache(rulesetConfigCache = new RulesetConfigCache(realmFactory, RulesetStore));
|
||||||
dependencies.Cache(rulesetConfigCache = new RulesetConfigCache(settingsStore));
|
|
||||||
|
|
||||||
var powerStatus = CreateBatteryInfo();
|
var powerStatus = CreateBatteryInfo();
|
||||||
if (powerStatus != null)
|
if (powerStatus != null)
|
||||||
@ -453,24 +450,27 @@ namespace osu.Game
|
|||||||
using (var db = contextFactory.GetForWrite())
|
using (var db = contextFactory.GetForWrite())
|
||||||
using (var usage = realmFactory.GetForWrite())
|
using (var usage = realmFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
var existingBindings = db.Context.DatabasedKeyBinding;
|
// migrate ruleset settings. can be removed 20220315.
|
||||||
|
var existingSettings = db.Context.DatabasedSetting;
|
||||||
|
|
||||||
// only migrate data if the realm database is empty.
|
// only migrate data if the realm database is empty.
|
||||||
if (!usage.Realm.All<RealmKeyBinding>().Any())
|
if (!usage.Realm.All<RealmRulesetSetting>().Any())
|
||||||
{
|
{
|
||||||
foreach (var dkb in existingBindings)
|
foreach (var dkb in existingSettings)
|
||||||
{
|
{
|
||||||
usage.Realm.Add(new RealmKeyBinding
|
if (dkb.RulesetID == null) continue;
|
||||||
|
|
||||||
|
usage.Realm.Add(new RealmRulesetSetting
|
||||||
{
|
{
|
||||||
KeyCombinationString = dkb.KeyCombination.ToString(),
|
Key = dkb.Key,
|
||||||
ActionInt = (int)dkb.Action,
|
Value = dkb.StringValue,
|
||||||
RulesetID = dkb.RulesetID,
|
RulesetID = dkb.RulesetID.Value,
|
||||||
Variant = dkb.Variant
|
Variant = dkb.Variant ?? 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Context.RemoveRange(existingBindings);
|
db.Context.RemoveRange(existingSettings);
|
||||||
|
|
||||||
usage.Commit();
|
usage.Commit();
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,86 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Configuration
|
namespace osu.Game.Rulesets.Configuration
|
||||||
{
|
{
|
||||||
public abstract class RulesetConfigManager<TLookup> : DatabasedConfigManager<TLookup>, IRulesetConfigManager
|
public abstract class RulesetConfigManager<TLookup> : ConfigManager<TLookup>, IRulesetConfigManager
|
||||||
where TLookup : struct, Enum
|
where TLookup : struct, Enum
|
||||||
{
|
{
|
||||||
protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
|
private readonly RealmContextFactory realmFactory;
|
||||||
: base(settings, ruleset, variant)
|
|
||||||
|
private readonly int variant;
|
||||||
|
|
||||||
|
private List<RealmRulesetSetting> databasedSettings = new List<RealmRulesetSetting>();
|
||||||
|
|
||||||
|
private readonly int rulesetId;
|
||||||
|
|
||||||
|
protected RulesetConfigManager(SettingsStore store, RulesetInfo ruleset, int? variant = null)
|
||||||
{
|
{
|
||||||
|
realmFactory = store?.Realm;
|
||||||
|
|
||||||
|
if (realmFactory != null && !ruleset.ID.HasValue)
|
||||||
|
throw new InvalidOperationException("Attempted to add databased settings for a non-databased ruleset");
|
||||||
|
|
||||||
|
rulesetId = ruleset.ID ?? -1;
|
||||||
|
|
||||||
|
this.variant = variant ?? 0;
|
||||||
|
|
||||||
|
Load();
|
||||||
|
|
||||||
|
InitialiseDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PerformLoad()
|
||||||
|
{
|
||||||
|
if (realmFactory != null)
|
||||||
|
{
|
||||||
|
// As long as RulesetConfigCache exists, there is no need to subscribe to realm events.
|
||||||
|
databasedSettings = realmFactory.Context.All<RealmRulesetSetting>().Where(b => b.RulesetID == rulesetId && b.Variant == variant).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool PerformSave()
|
||||||
|
{
|
||||||
|
// do nothing, realm saves immediately
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddBindable<TBindable>(TLookup lookup, Bindable<TBindable> bindable)
|
||||||
|
{
|
||||||
|
base.AddBindable(lookup, bindable);
|
||||||
|
|
||||||
|
var setting = databasedSettings.Find(s => s.Key == lookup.ToString());
|
||||||
|
|
||||||
|
if (setting != null)
|
||||||
|
{
|
||||||
|
bindable.Parse(setting.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setting = new RealmRulesetSetting
|
||||||
|
{
|
||||||
|
Key = lookup.ToString(),
|
||||||
|
Value = bindable.Value.ToString(),
|
||||||
|
RulesetID = rulesetId,
|
||||||
|
Variant = variant,
|
||||||
|
};
|
||||||
|
|
||||||
|
realmFactory?.Context.Write(() => realmFactory.Context.Add(setting));
|
||||||
|
|
||||||
|
databasedSettings.Add(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindable.ValueChanged += b =>
|
||||||
|
{
|
||||||
|
realmFactory?.Context.Write(() => setting.Value = b.NewValue.ToString());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Configuration;
|
using osu.Game.Rulesets.Configuration;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets
|
namespace osu.Game.Rulesets
|
||||||
@ -15,12 +16,31 @@ namespace osu.Game.Rulesets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RulesetConfigCache : Component
|
public class RulesetConfigCache : Component
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<int, IRulesetConfigManager> configCache = new ConcurrentDictionary<int, IRulesetConfigManager>();
|
private readonly RealmContextFactory realmFactory;
|
||||||
private readonly SettingsStore settingsStore;
|
private readonly RulesetStore rulesets;
|
||||||
|
|
||||||
public RulesetConfigCache(SettingsStore settingsStore)
|
private readonly Dictionary<int, IRulesetConfigManager> configCache = new Dictionary<int, IRulesetConfigManager>();
|
||||||
|
|
||||||
|
public RulesetConfigCache(RealmContextFactory realmFactory, RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.settingsStore = settingsStore;
|
this.realmFactory = realmFactory;
|
||||||
|
this.rulesets = rulesets;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var settingsStore = new SettingsStore(realmFactory);
|
||||||
|
|
||||||
|
// let's keep things simple for now and just retrieve all the required configs at startup..
|
||||||
|
foreach (var ruleset in rulesets.AvailableRulesets)
|
||||||
|
{
|
||||||
|
if (ruleset.ID == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
configCache[ruleset.ID.Value] = ruleset.CreateInstance().CreateConfig(settingsStore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -34,7 +54,12 @@ namespace osu.Game.Rulesets
|
|||||||
if (ruleset.RulesetInfo.ID == null)
|
if (ruleset.RulesetInfo.ID == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return configCache.GetOrAdd(ruleset.RulesetInfo.ID.Value, _ => ruleset.CreateConfig(settingsStore));
|
if (!configCache.TryGetValue(ruleset.RulesetInfo.ID.Value, out var config))
|
||||||
|
// any ruleset request which wasn't initialised on startup should not be stored to realm.
|
||||||
|
// this should only be used by tests.
|
||||||
|
return ruleset.CreateConfig(null);
|
||||||
|
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -17,10 +18,12 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
public static class LegacySkinExtensions
|
public static class LegacySkinExtensions
|
||||||
{
|
{
|
||||||
|
[CanBeNull]
|
||||||
public static Drawable GetAnimation(this ISkin source, string componentName, bool animatable, bool looping, bool applyConfigFrameRate = false, string animationSeparator = "-",
|
public static Drawable GetAnimation(this ISkin source, string componentName, bool animatable, bool looping, bool applyConfigFrameRate = false, string animationSeparator = "-",
|
||||||
bool startAtCurrentTime = true, double? frameLength = null)
|
bool startAtCurrentTime = true, double? frameLength = null)
|
||||||
=> source.GetAnimation(componentName, default, default, animatable, looping, applyConfigFrameRate, animationSeparator, startAtCurrentTime, frameLength);
|
=> source.GetAnimation(componentName, default, default, animatable, looping, applyConfigFrameRate, animationSeparator, startAtCurrentTime, frameLength);
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
public static Drawable GetAnimation(this ISkin source, string componentName, WrapMode wrapModeS, WrapMode wrapModeT, bool animatable, bool looping, bool applyConfigFrameRate = false,
|
public static Drawable GetAnimation(this ISkin source, string componentName, WrapMode wrapModeS, WrapMode wrapModeT, bool animatable, bool looping, bool applyConfigFrameRate = false,
|
||||||
string animationSeparator = "-",
|
string animationSeparator = "-",
|
||||||
bool startAtCurrentTime = true, double? frameLength = null)
|
bool startAtCurrentTime = true, double? frameLength = null)
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
@ -39,8 +38,6 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public List<SkinFileInfo> Files { get; set; } = new List<SkinFileInfo>();
|
public List<SkinFileInfo> Files { get; set; } = new List<SkinFileInfo>();
|
||||||
|
|
||||||
public List<DatabasedSetting> Settings { get; set; }
|
|
||||||
|
|
||||||
public bool DeletePending { get; set; }
|
public bool DeletePending { get; set; }
|
||||||
|
|
||||||
public static SkinInfo Default { get; } = new SkinInfo
|
public static SkinInfo Default { get; } = new SkinInfo
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
|
||||||
@ -14,9 +12,5 @@ namespace osu.Game.Skinning
|
|||||||
: base(contextFactory, storage)
|
: base(contextFactory, storage)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IQueryable<SkinInfo> AddIncludesForDeletion(IQueryable<SkinInfo> query) =>
|
|
||||||
base.AddIncludesForDeletion(query)
|
|
||||||
.Include(s => s.Settings); // don't include FileInfo. these are handled by the FileStore itself.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.3.0" />
|
<PackageReference Include="Realm" Version="10.5.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.907.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.907.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.913.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.913.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.9.0" />
|
<PackageReference Include="Sentry" Version="3.9.0" />
|
||||||
|