mirror of
https://github.com/ppy/osu.git
synced 2025-01-06 10:22:54 +08:00
Simplify skin bindable flow
Now, nothing touches the configuration apart from `OsuGame`, making everything else flow better and avoid weird cyclic set bugs. Closes https://github.com/ppy/osu/issues/20234.
This commit is contained in:
parent
cb6d02ec3a
commit
f31deaef7c
@ -56,14 +56,12 @@ using osu.Game.Screens.Menu;
|
|||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Skinning;
|
|
||||||
using osu.Game.Skinning.Editor;
|
using osu.Game.Skinning.Editor;
|
||||||
using osu.Game.Updater;
|
using osu.Game.Updater;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using Sentry;
|
using Sentry;
|
||||||
using Logger = osu.Framework.Logging.Logger;
|
|
||||||
|
|
||||||
namespace osu.Game
|
namespace osu.Game
|
||||||
{
|
{
|
||||||
@ -294,25 +292,13 @@ namespace osu.Game
|
|||||||
|
|
||||||
Ruleset.ValueChanged += r => configRuleset.Value = r.NewValue.ShortName;
|
Ruleset.ValueChanged += r => configRuleset.Value = r.NewValue.ShortName;
|
||||||
|
|
||||||
// bind config int to database SkinInfo
|
|
||||||
configSkin = LocalConfig.GetBindable<string>(OsuSetting.Skin);
|
configSkin = LocalConfig.GetBindable<string>(OsuSetting.Skin);
|
||||||
|
|
||||||
|
// Transfer skin from config to realm instance once on startup.
|
||||||
|
SkinManager.SetSkinFromConfiguration(configSkin.Value);
|
||||||
|
|
||||||
|
// Transfer any runtime changes back to configuration file.
|
||||||
SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID.ToString();
|
SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID.ToString();
|
||||||
configSkin.ValueChanged += skinId =>
|
|
||||||
{
|
|
||||||
Live<SkinInfo> skinInfo = null;
|
|
||||||
|
|
||||||
if (Guid.TryParse(skinId.NewValue, out var guid))
|
|
||||||
skinInfo = SkinManager.Query(s => s.ID == guid);
|
|
||||||
|
|
||||||
if (skinInfo == null)
|
|
||||||
{
|
|
||||||
if (guid == SkinInfo.CLASSIC_SKIN)
|
|
||||||
skinInfo = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged();
|
|
||||||
}
|
|
||||||
|
|
||||||
SkinManager.CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.CreateInfo().ToLiveUnmanaged();
|
|
||||||
};
|
|
||||||
configSkin.TriggerChange();
|
|
||||||
|
|
||||||
IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true);
|
IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true);
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
@ -36,9 +35,6 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
Icon = FontAwesome.Solid.PaintBrush
|
Icon = FontAwesome.Solid.PaintBrush
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly Bindable<Live<SkinInfo>> dropdownBindable = new Bindable<Live<SkinInfo>> { Default = DefaultSkin.CreateInfo().ToLiveUnmanaged() };
|
|
||||||
private readonly Bindable<string> configBindable = new Bindable<string>();
|
|
||||||
|
|
||||||
private static readonly Live<SkinInfo> random_skin_info = new SkinInfo
|
private static readonly Live<SkinInfo> random_skin_info = new SkinInfo
|
||||||
{
|
{
|
||||||
ID = SkinInfo.RANDOM_SKIN,
|
ID = SkinInfo.RANDOM_SKIN,
|
||||||
@ -56,13 +52,14 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
private IDisposable realmSubscription;
|
private IDisposable realmSubscription;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor)
|
private void load([CanBeNull] SkinEditorOverlay skinEditor)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
skinDropdown = new SkinSettingsDropdown
|
skinDropdown = new SkinSettingsDropdown
|
||||||
{
|
{
|
||||||
LabelText = SkinSettingsStrings.CurrentSkin,
|
LabelText = SkinSettingsStrings.CurrentSkin,
|
||||||
|
Current = skins.CurrentSkinInfo,
|
||||||
Keywords = new[] { @"skins" }
|
Keywords = new[] { @"skins" }
|
||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
@ -73,47 +70,30 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
new ExportSkinButton(),
|
new ExportSkinButton(),
|
||||||
new DeleteSkinButton(),
|
new DeleteSkinButton(),
|
||||||
};
|
};
|
||||||
|
|
||||||
config.BindWith(OsuSetting.Skin, configBindable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
skinDropdown.Current = dropdownBindable;
|
skinDropdown.Current = skins.CurrentSkinInfo;
|
||||||
|
|
||||||
realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All<SkinInfo>()
|
realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All<SkinInfo>()
|
||||||
.Where(s => !s.DeletePending)
|
.Where(s => !s.DeletePending)
|
||||||
.OrderByDescending(s => s.Protected) // protected skins should be at the top.
|
.OrderByDescending(s => s.Protected) // protected skins should be at the top.
|
||||||
.ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged);
|
.ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged);
|
||||||
|
|
||||||
configBindable.BindValueChanged(_ => Scheduler.AddOnce(updateSelectedSkinFromConfig));
|
skinDropdown.Current.BindValueChanged(skin =>
|
||||||
|
|
||||||
dropdownBindable.BindValueChanged(dropdownSelectionChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dropdownSelectionChanged(ValueChangedEvent<Live<SkinInfo>> skin)
|
|
||||||
{
|
|
||||||
// Only handle cases where it's clear the user has intent to change skins.
|
|
||||||
if (skin.OldValue == null) return;
|
|
||||||
|
|
||||||
if (skin.NewValue.Equals(random_skin_info))
|
|
||||||
{
|
{
|
||||||
var skinBefore = skins.CurrentSkinInfo.Value;
|
if (skin.NewValue == random_skin_info)
|
||||||
|
|
||||||
skins.SelectRandomSkin();
|
|
||||||
|
|
||||||
if (skinBefore == skins.CurrentSkinInfo.Value)
|
|
||||||
{
|
{
|
||||||
// the random selection didn't change the skin, so we should manually update the dropdown to match.
|
// before selecting random, set the skin back to the previous selection.
|
||||||
dropdownBindable.Value = skins.CurrentSkinInfo.Value;
|
// this is done because at this point it will be random_skin_info, and would
|
||||||
|
// cause SelectRandomSkin to be unable to skip the previous selection.
|
||||||
|
skins.CurrentSkinInfo.Value = skin.OldValue;
|
||||||
|
skins.SelectRandomSkin();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
configBindable.Value = skin.NewValue.ID.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes, Exception error)
|
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes, Exception error)
|
||||||
@ -132,25 +112,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
dropdownItems.Add(skin.ToLive(realm));
|
dropdownItems.Add(skin.ToLive(realm));
|
||||||
dropdownItems.Insert(protectedCount, random_skin_info);
|
dropdownItems.Insert(protectedCount, random_skin_info);
|
||||||
|
|
||||||
Schedule(() =>
|
Schedule(() => skinDropdown.Items = dropdownItems);
|
||||||
{
|
|
||||||
skinDropdown.Items = dropdownItems;
|
|
||||||
|
|
||||||
updateSelectedSkinFromConfig();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSelectedSkinFromConfig()
|
|
||||||
{
|
|
||||||
if (!skinDropdown.Items.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Live<SkinInfo> skin = null;
|
|
||||||
|
|
||||||
if (Guid.TryParse(configBindable.Value, out var configId))
|
|
||||||
skin = skinDropdown.Items.FirstOrDefault(s => s.ID == configId);
|
|
||||||
|
|
||||||
dropdownBindable.Value = skin ?? skinDropdown.Items.First();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -119,7 +119,9 @@ namespace osu.Game.Skinning
|
|||||||
Realm.Run(r =>
|
Realm.Run(r =>
|
||||||
{
|
{
|
||||||
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
||||||
var randomChoices = r.All<SkinInfo>().Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray();
|
var randomChoices = r.All<SkinInfo>()
|
||||||
|
.Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
if (randomChoices.Length == 0)
|
if (randomChoices.Length == 0)
|
||||||
{
|
{
|
||||||
@ -297,5 +299,21 @@ namespace osu.Game.Skinning
|
|||||||
Delete(items.ToList(), silent);
|
Delete(items.ToList(), silent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetSkinFromConfiguration(string guidString)
|
||||||
|
{
|
||||||
|
Live<SkinInfo> skinInfo = null;
|
||||||
|
|
||||||
|
if (Guid.TryParse(guidString, out var guid))
|
||||||
|
skinInfo = Query(s => s.ID == guid);
|
||||||
|
|
||||||
|
if (skinInfo == null)
|
||||||
|
{
|
||||||
|
if (guid == SkinInfo.CLASSIC_SKIN)
|
||||||
|
skinInfo = DefaultLegacySkin.SkinInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.SkinInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user