1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-07 23:23:12 +08:00

Merge branch 'master' into feature/command-handler

This commit is contained in:
Marvin Schürz 2024-10-10 15:27:09 +02:00
commit 597396d64a
18 changed files with 246 additions and 77 deletions

View File

@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2024.1007.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2024.1009.0" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.

View File

@ -24,7 +24,7 @@
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="System.IO.Packaging" Version="8.0.0" />
<PackageReference Include="System.IO.Packaging" Version="8.0.1" />
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageReference Include="Velopack" Version="0.0.630-g9c52e40" />
</ItemGroup>

View File

@ -0,0 +1,126 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
using osuTK;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
public partial class GridPlacementBlueprint : PlacementBlueprint
{
[Resolved]
private HitObjectComposer? hitObjectComposer { get; set; }
private OsuGridToolboxGroup gridToolboxGroup = null!;
private Vector2 originalOrigin;
private float originalSpacing;
private float originalRotation;
[BackgroundDependencyLoader]
private void load(OsuGridToolboxGroup gridToolboxGroup)
{
this.gridToolboxGroup = gridToolboxGroup;
originalOrigin = gridToolboxGroup.StartPosition.Value;
originalSpacing = gridToolboxGroup.Spacing.Value;
originalRotation = gridToolboxGroup.GridLinesRotation.Value;
}
public override void EndPlacement(bool commit)
{
if (!commit && PlacementActive != PlacementState.Finished)
{
gridToolboxGroup.StartPosition.Value = originalOrigin;
gridToolboxGroup.Spacing.Value = originalSpacing;
if (!gridToolboxGroup.GridLinesRotation.Disabled)
gridToolboxGroup.GridLinesRotation.Value = originalRotation;
}
base.EndPlacement(commit);
// You typically only place the grid once, so we switch back to the last tool after placement.
if (commit && hitObjectComposer is OsuHitObjectComposer osuHitObjectComposer)
osuHitObjectComposer.SetLastTool();
}
protected override bool OnClick(ClickEvent e)
{
if (e.Button == MouseButton.Left)
{
switch (PlacementActive)
{
case PlacementState.Waiting:
BeginPlacement(true);
return true;
case PlacementState.Active:
EndPlacement(true);
return true;
}
}
return base.OnClick(e);
}
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == MouseButton.Right)
{
// Reset the grid to the default values.
gridToolboxGroup.StartPosition.Value = gridToolboxGroup.StartPosition.Default;
gridToolboxGroup.Spacing.Value = gridToolboxGroup.Spacing.Default;
if (!gridToolboxGroup.GridLinesRotation.Disabled)
gridToolboxGroup.GridLinesRotation.Value = gridToolboxGroup.GridLinesRotation.Default;
EndPlacement(true);
return true;
}
return base.OnMouseDown(e);
}
protected override bool OnDragStart(DragStartEvent e)
{
if (e.Button == MouseButton.Left)
{
BeginPlacement(true);
return true;
}
return base.OnDragStart(e);
}
protected override void OnDragEnd(DragEndEvent e)
{
if (PlacementActive == PlacementState.Active)
EndPlacement(true);
base.OnDragEnd(e);
}
public override SnapType SnapType => ~SnapType.GlobalGrids;
public override void UpdateTimeAndPosition(SnapResult result)
{
var pos = ToLocalSpace(result.ScreenSpacePosition);
if (PlacementActive != PlacementState.Active)
gridToolboxGroup.StartPosition.Value = pos;
else
{
// Default to the original spacing and rotation if the distance is too small.
if (Vector2.Distance(gridToolboxGroup.StartPosition.Value, pos) < 2)
{
gridToolboxGroup.Spacing.Value = originalSpacing;
if (!gridToolboxGroup.GridLinesRotation.Disabled)
gridToolboxGroup.GridLinesRotation.Value = originalRotation;
}
else
{
gridToolboxGroup.SetGridFromPoints(gridToolboxGroup.StartPosition.Value, pos);
}
}
}
}
}

View File

@ -180,7 +180,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
private bool isSplittable(PathControlPointPiece<T> p) =>
// A hit object can only be split on control points which connect two different path segments.
p.ControlPoint.Type.HasValue && p != Pieces.FirstOrDefault() && p != Pieces.LastOrDefault();
p.ControlPoint.Type.HasValue && p.ControlPoint != controlPoints.FirstOrDefault() && p.ControlPoint != controlPoints.LastOrDefault();
private void onControlPointsChanged(object sender, NotifyCollectionChangedEventArgs e)
{

View File

@ -0,0 +1,29 @@
// 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 osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Osu.Edit.Blueprints;
namespace osu.Game.Rulesets.Osu.Edit
{
public partial class GridFromPointsTool : CompositionTool
{
public GridFromPointsTool()
: base("Grid")
{
TooltipText = """
Left click to set the origin.
Left click again to set the spacing and rotation.
Right click to reset to default.
Click and drag to set the origin, spacing and rotation.
""";
}
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.DraftingCompass };
public override PlacementBlueprint CreatePlacementBlueprint() => new GridPlacementBlueprint();
}
}

View File

@ -11,12 +11,10 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.RadioButtons;
@ -40,7 +38,6 @@ namespace osu.Game.Rulesets.Osu.Edit
{
MinValue = 0f,
MaxValue = OsuPlayfield.BASE_SIZE.X,
Precision = 1f
};
/// <summary>
@ -50,7 +47,6 @@ namespace osu.Game.Rulesets.Osu.Edit
{
MinValue = 0f,
MaxValue = OsuPlayfield.BASE_SIZE.Y,
Precision = 1f
};
/// <summary>
@ -60,7 +56,6 @@ namespace osu.Game.Rulesets.Osu.Edit
{
MinValue = 4f,
MaxValue = 128f,
Precision = 1f
};
/// <summary>
@ -70,14 +65,13 @@ namespace osu.Game.Rulesets.Osu.Edit
{
MinValue = -180f,
MaxValue = 180f,
Precision = 1f
};
/// <summary>
/// Read-only bindable representing the grid's origin.
/// Equivalent to <code>new Vector2(StartPositionX, StartPositionY)</code>
/// </summary>
public Bindable<Vector2> StartPosition { get; } = new Bindable<Vector2>();
public Bindable<Vector2> StartPosition { get; } = new Bindable<Vector2>(OsuPlayfield.BASE_SIZE / 2);
/// <summary>
/// Read-only bindable representing the grid's spacing in both the X and Y dimension.
@ -93,8 +87,6 @@ namespace osu.Game.Rulesets.Osu.Edit
private ExpandableSlider<float> gridLinesRotationSlider = null!;
private EditorRadioButtonCollection gridTypeButtons = null!;
private ExpandableButton useSelectedObjectPositionButton = null!;
public OsuGridToolboxGroup()
: base("grid")
{
@ -102,6 +94,26 @@ namespace osu.Game.Rulesets.Osu.Edit
private const float max_automatic_spacing = 64;
public void SetGridFromPoints(Vector2 point1, Vector2 point2)
{
StartPositionX.Value = point1.X;
StartPositionY.Value = point1.Y;
// Get the angle between the two points and normalize to the valid range.
if (!GridLinesRotation.Disabled)
{
float period = GridLinesRotation.MaxValue - GridLinesRotation.MinValue;
GridLinesRotation.Value = normalizeRotation(MathHelper.RadiansToDegrees(MathF.Atan2(point2.Y - point1.Y, point2.X - point1.X)), period);
}
// Divide the distance so that there is a good density of grid lines.
// This matches the maximum grid size of the grid size cycling hotkey.
float dist = Vector2.Distance(point1, point2);
while (dist >= max_automatic_spacing)
dist /= 2;
Spacing.Value = dist;
}
[BackgroundDependencyLoader]
private void load()
{
@ -117,20 +129,6 @@ namespace osu.Game.Rulesets.Osu.Edit
Current = StartPositionY,
KeyboardStep = 1,
},
useSelectedObjectPositionButton = new ExpandableButton
{
ExpandedLabelText = "Centre on selected object",
Action = () =>
{
if (editorBeatmap.SelectedHitObjects.Count != 1)
return;
var position = ((IHasPosition)editorBeatmap.SelectedHitObjects.Single()).Position;
StartPosition.Value = new Vector2(MathF.Round(position.X), MathF.Round(position.Y));
updateEnabledStates();
},
RelativeSizeAxes = Axes.X,
},
spacingSlider = new ExpandableSlider<float>
{
Current = Spacing,
@ -179,15 +177,15 @@ namespace osu.Game.Rulesets.Osu.Edit
StartPositionX.BindValueChanged(x =>
{
startPositionXSlider.ContractedLabelText = $"X: {x.NewValue:N0}";
startPositionXSlider.ExpandedLabelText = $"X Offset: {x.NewValue:N0}";
startPositionXSlider.ContractedLabelText = $"X: {x.NewValue:#,0.##}";
startPositionXSlider.ExpandedLabelText = $"X Offset: {x.NewValue:#,0.##}";
StartPosition.Value = new Vector2(x.NewValue, StartPosition.Value.Y);
}, true);
StartPositionY.BindValueChanged(y =>
{
startPositionYSlider.ContractedLabelText = $"Y: {y.NewValue:N0}";
startPositionYSlider.ExpandedLabelText = $"Y Offset: {y.NewValue:N0}";
startPositionYSlider.ContractedLabelText = $"Y: {y.NewValue:#,0.##}";
startPositionYSlider.ExpandedLabelText = $"Y Offset: {y.NewValue:#,0.##}";
StartPosition.Value = new Vector2(StartPosition.Value.X, y.NewValue);
}, true);
@ -195,13 +193,12 @@ namespace osu.Game.Rulesets.Osu.Edit
{
StartPositionX.Value = pos.NewValue.X;
StartPositionY.Value = pos.NewValue.Y;
updateEnabledStates();
});
Spacing.BindValueChanged(spacing =>
{
spacingSlider.ContractedLabelText = $"S: {spacing.NewValue:N0}";
spacingSlider.ExpandedLabelText = $"Spacing: {spacing.NewValue:N0}";
spacingSlider.ContractedLabelText = $"S: {spacing.NewValue:#,0.##}";
spacingSlider.ExpandedLabelText = $"Spacing: {spacing.NewValue:#,0.##}";
SpacingVector.Value = new Vector2(spacing.NewValue);
editorBeatmap.BeatmapInfo.GridSize = (int)spacing.NewValue;
}, true);
@ -219,34 +216,29 @@ namespace osu.Game.Rulesets.Osu.Edit
switch (v.NewValue)
{
case PositionSnapGridType.Square:
GridLinesRotation.Value = ((GridLinesRotation.Value + 405) % 90) - 45;
GridLinesRotation.Value = normalizeRotation(GridLinesRotation.Value, 90);
GridLinesRotation.MinValue = -45;
GridLinesRotation.MaxValue = 45;
break;
case PositionSnapGridType.Triangle:
GridLinesRotation.Value = ((GridLinesRotation.Value + 390) % 60) - 30;
GridLinesRotation.Value = normalizeRotation(GridLinesRotation.Value, 60);
GridLinesRotation.MinValue = -30;
GridLinesRotation.MaxValue = 30;
break;
}
}, true);
editorBeatmap.BeatmapReprocessed += updateEnabledStates;
editorBeatmap.SelectedHitObjects.BindCollectionChanged((_, _) => updateEnabledStates());
expandingContainer?.Expanded.BindValueChanged(v =>
{
gridTypeButtons.FadeTo(v.NewValue ? 1f : 0f, 500, Easing.OutQuint);
gridTypeButtons.BypassAutoSizeAxes = !v.NewValue ? Axes.Y : Axes.None;
updateEnabledStates();
}, true);
}
private void updateEnabledStates()
private float normalizeRotation(float rotation, float period)
{
useSelectedObjectPositionButton.Enabled.Value = expandingContainer?.Expanded.Value == true
&& editorBeatmap.SelectedHitObjects.Count == 1
&& !Precision.AlmostEquals(StartPosition.Value, ((IHasPosition)editorBeatmap.SelectedHitObjects.Single()).Position, 0.5f);
return ((rotation + 360 + period * 0.5f) % period) - period * 0.5f;
}
private void nextGridSize()

View File

@ -45,7 +45,8 @@ namespace osu.Game.Rulesets.Osu.Edit
{
new HitCircleCompositionTool(),
new SliderCompositionTool(),
new SpinnerCompositionTool()
new SpinnerCompositionTool(),
new GridFromPointsTool()
};
private readonly Bindable<TernaryState> rectangularGridSnapToggle = new Bindable<TernaryState>();
@ -79,13 +80,12 @@ namespace osu.Game.Rulesets.Osu.Edit
// Give a bit of breathing room around the playfield content.
PlayfieldContentContainer.Padding = new MarginPadding(10);
LayerBelowRuleset.AddRange(new Drawable[]
{
LayerBelowRuleset.Add(
distanceSnapGridContainer = new Container
{
RelativeSizeAxes = Axes.Both
}
});
);
selectedHitObjects = EditorBeatmap.SelectedHitObjects.GetBoundCopy();
selectedHitObjects.CollectionChanged += (_, _) => updateDistanceSnapGrid();

View File

@ -44,7 +44,7 @@ namespace osu.Game.Database
{
if (changes == null)
{
if (detachedBeatmapSets.Count > 0 && sender.Count == 0)
if (sender is RealmResetEmptySet<BeatmapSetInfo>)
{
// Usually we'd reset stuff here, but doing so triggers a silly flow which ends up deadlocking realm.
// Additionally, user should not be at song select when realm is blocking all operations in the first place.

View File

@ -568,7 +568,7 @@ namespace osu.Game.Database
lock (notificationsResetMap)
{
// Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing.
notificationsResetMap.Add(action, () => callback(new EmptyRealmSet<T>(), null));
notificationsResetMap.Add(action, () => callback(new RealmResetEmptySet<T>(), null));
}
return RegisterCustomSubscription(action);

View File

@ -12,7 +12,13 @@ using Realms.Schema;
namespace osu.Game.Database
{
public class EmptyRealmSet<T> : IRealmCollection<T>
/// <summary>
/// This can arrive in <see cref="RealmAccess.RegisterForNotifications{T}"/> callbacks to imply that realm access has been reset.
/// </summary>
/// <remarks>
/// Usually implies that the original database may return soon and the callback can usually be silently ignored.
///</remarks>
public class RealmResetEmptySet<T> : IRealmCollection<T>
{
private IList<T> emptySet => Array.Empty<T>();

View File

@ -541,7 +541,10 @@ namespace osu.Game
realmBlocker = realm.BlockAllOperations("migration");
success = true;
}
catch { }
catch (Exception ex)
{
Logger.Log($"Attempting to block all operations failed: {ex}", LoggingTarget.Database);
}
readyToRun.Set();
}, false);

View File

@ -72,7 +72,7 @@ namespace osu.Game.Overlays
private AudioFilter audioDuckFilter = null!;
private readonly Bindable<RandomSelectAlgorithm> randomSelectAlgorithm = new Bindable<RandomSelectAlgorithm>();
private readonly List<BeatmapSetInfo> previousRandomSets = new List<BeatmapSetInfo>();
private readonly List<Live<BeatmapSetInfo>> previousRandomSets = new List<Live<BeatmapSetInfo>>();
private int randomHistoryDirection;
[BackgroundDependencyLoader]
@ -249,19 +249,19 @@ namespace osu.Game.Overlays
queuedDirection = TrackChangeDirection.Prev;
BeatmapSetInfo? playableSet;
Live<BeatmapSetInfo>? playableSet;
if (Shuffle.Value)
playableSet = getNextRandom(-1, allowProtectedTracks);
else
{
playableSet = getBeatmapSets().AsEnumerable().TakeWhile(i => !i.Equals(current?.BeatmapSetInfo)).LastOrDefault(s => !s.Protected || allowProtectedTracks)
?? getBeatmapSets().AsEnumerable().LastOrDefault(s => !s.Protected || allowProtectedTracks);
playableSet = getBeatmapSets().TakeWhile(i => !i.Value.Equals(current?.BeatmapSetInfo)).LastOrDefault(s => !s.Value.Protected || allowProtectedTracks)
?? getBeatmapSets().LastOrDefault(s => !s.Value.Protected || allowProtectedTracks);
}
if (playableSet != null)
{
changeBeatmap(beatmaps.GetWorkingBeatmap(playableSet.Beatmaps.First()));
changeBeatmap(beatmaps.GetWorkingBeatmap(playableSet.Value.Beatmaps.First()));
restartTrack();
return PreviousTrackResult.Previous;
}
@ -345,19 +345,19 @@ namespace osu.Game.Overlays
queuedDirection = TrackChangeDirection.Next;
BeatmapSetInfo? playableSet;
Live<BeatmapSetInfo>? playableSet;
if (Shuffle.Value)
playableSet = getNextRandom(1, allowProtectedTracks);
else
{
playableSet = getBeatmapSets().AsEnumerable().SkipWhile(i => !i.Equals(current?.BeatmapSetInfo))
.Where(i => !i.Protected || allowProtectedTracks)
playableSet = getBeatmapSets().SkipWhile(i => !i.Value.Equals(current?.BeatmapSetInfo))
.Where(i => !i.Value.Protected || allowProtectedTracks)
.ElementAtOrDefault(1)
?? getBeatmapSets().AsEnumerable().FirstOrDefault(i => !i.Protected || allowProtectedTracks);
?? getBeatmapSets().FirstOrDefault(i => !i.Value.Protected || allowProtectedTracks);
}
var playableBeatmap = playableSet?.Beatmaps.FirstOrDefault();
var playableBeatmap = playableSet?.Value.Beatmaps.FirstOrDefault();
if (playableBeatmap != null)
{
@ -369,11 +369,11 @@ namespace osu.Game.Overlays
return false;
}
private BeatmapSetInfo? getNextRandom(int direction, bool allowProtectedTracks)
private Live<BeatmapSetInfo>? getNextRandom(int direction, bool allowProtectedTracks)
{
BeatmapSetInfo result;
Live<BeatmapSetInfo> result;
var possibleSets = getBeatmapSets().AsEnumerable().Where(s => !s.Protected || allowProtectedTracks).ToArray();
var possibleSets = getBeatmapSets().Where(s => !s.Value.Protected || allowProtectedTracks).ToArray();
if (possibleSets.Length == 0)
return null;
@ -432,7 +432,9 @@ namespace osu.Game.Overlays
private TrackChangeDirection? queuedDirection;
private IQueryable<BeatmapSetInfo> getBeatmapSets() => realm.Realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending);
private IEnumerable<Live<BeatmapSetInfo>> getBeatmapSets() => realm.Realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending)
.AsEnumerable()
.Select(s => new RealmLive<BeatmapSetInfo>(s, realm));
private void changeBeatmap(WorkingBeatmap newWorking)
{
@ -459,8 +461,8 @@ namespace osu.Game.Overlays
else
{
// figure out the best direction based on order in playlist.
int last = getBeatmapSets().AsEnumerable().TakeWhile(b => !b.Equals(current.BeatmapSetInfo)).Count();
int next = getBeatmapSets().AsEnumerable().TakeWhile(b => !b.Equals(newWorking.BeatmapSetInfo)).Count();
int last = getBeatmapSets().TakeWhile(b => !b.Value.Equals(current.BeatmapSetInfo)).Count();
int next = getBeatmapSets().TakeWhile(b => !b.Value.Equals(newWorking.BeatmapSetInfo)).Count();
direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next;
}

View File

@ -20,13 +20,13 @@ namespace osu.Game.Overlays.Settings
Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS };
}
public LocalisableString TooltipText { get; set; }
public IEnumerable<string> Keywords { get; set; } = Array.Empty<string>();
public BindableBool CanBeShown { get; } = new BindableBool(true);
IBindable<bool> IConditionalFilterable.CanBeShown => CanBeShown;
public LocalisableString TooltipText { get; set; }
public override IEnumerable<LocalisableString> FilterTerms
{
get

View File

@ -91,6 +91,9 @@ namespace osu.Game.Rulesets.Edit
private Bindable<bool> autoSeekOnPlacement;
private readonly Bindable<bool> composerFocusMode = new Bindable<bool>();
[CanBeNull]
private RadioButton lastTool;
protected DrawableRuleset<TObject> DrawableRuleset { get; private set; }
protected HitObjectComposer(Ruleset ruleset)
@ -214,8 +217,7 @@ namespace osu.Game.Rulesets.Edit
},
};
toolboxCollection.Items = CompositionTools
.Prepend(new SelectTool())
toolboxCollection.Items = (CompositionTools.Prepend(new SelectTool()))
.Select(t => new HitObjectCompositionToolButton(t, () => toolSelected(t)))
.ToList();
@ -232,7 +234,7 @@ namespace osu.Game.Rulesets.Edit
sampleBankTogglesCollection.AddRange(BlueprintContainer.SampleBankTernaryStates.Select(b => new DrawableTernaryButton(b)));
setSelectTool();
SetSelectTool();
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
}
@ -257,7 +259,7 @@ namespace osu.Game.Rulesets.Edit
{
// it's important this is performed before the similar code in EditorRadioButton disables the button.
if (!timing.NewValue)
setSelectTool();
SetSelectTool();
});
EditorBeatmap.HasTiming.BindValueChanged(hasTiming =>
@ -461,14 +463,18 @@ namespace osu.Game.Rulesets.Edit
if (EditorBeatmap.SelectedHitObjects.Any())
{
// ensure in selection mode if a selection is made.
setSelectTool();
SetSelectTool();
}
}
private void setSelectTool() => toolboxCollection.Items.First().Select();
public void SetSelectTool() => toolboxCollection.Items.First().Select();
public void SetLastTool() => (lastTool ?? toolboxCollection.Items.First()).Select();
private void toolSelected(CompositionTool tool)
{
lastTool = toolboxCollection.Items.OfType<HitObjectCompositionToolButton>().FirstOrDefault(i => i.Tool == BlueprintContainer.CurrentTool);
BlueprintContainer.CurrentTool = tool;
if (!(tool is SelectTool))

View File

@ -71,6 +71,11 @@ namespace osu.Game.Rulesets.Edit
PlacementActive = PlacementState.Finished;
}
/// <summary>
/// Determines which objects to snap to for the snap result in <see cref="UpdateTimeAndPosition"/>.
/// </summary>
public virtual SnapType SnapType => SnapType.All;
/// <summary>
/// Updates the time and position of this <see cref="PlacementBlueprint"/> based on the provided snap information.
/// </summary>

View File

@ -297,7 +297,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
private void updatePlacementPosition()
{
var snapResult = Composer.FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position);
var snapResult = Composer.FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position, CurrentPlacement.SnapType);
// if no time was found from positional snapping, we should still quantize to the beat.
snapResult.Time ??= Beatmap.SnapTime(EditorClock.CurrentTime, null);

View File

@ -35,7 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="11.5.0" />
<PackageReference Include="ppy.osu.Framework" Version="2024.1007.0" />
<PackageReference Include="ppy.osu.Framework" Version="2024.1009.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2024.1003.0" />
<PackageReference Include="Sentry" Version="4.3.0" />
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->

View File

@ -17,6 +17,6 @@
<MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2024.1007.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2024.1009.0" />
</ItemGroup>
</Project>