-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathHitObjectPlacementBlueprint.cs
More file actions
169 lines (136 loc) · 6.5 KB
/
HitObjectPlacementBlueprint.cs
File metadata and controls
169 lines (136 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// 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.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose;
using osuTK;
namespace osu.Game.Rulesets.Edit
{
/// <summary>
/// A blueprint which governs the creation of a new <see cref="HitObject"/> to actualisation.
/// </summary>
public abstract partial class HitObjectPlacementBlueprint : PlacementBlueprint
{
/// <summary>
/// Whether the sample bank should be taken from the previous hit object.
/// </summary>
public bool AutomaticBankAssignment { get; set; }
/// <summary>
/// Whether the sample addition bank should be taken from the previous hit objects.
/// </summary>
public bool AutomaticAdditionBankAssignment { get; set; }
/// <summary>
/// The <see cref="HitObject"/> that is being placed.
/// </summary>
public readonly HitObject HitObject;
[Resolved]
protected EditorClock EditorClock { get; private set; } = null!;
[Resolved]
private EditorBeatmap beatmap { get; set; } = null!;
private Bindable<double> startTimeBindable = null!;
private HitObject? getPreviousHitObject() => beatmap.HitObjects.TakeWhile(h => h.StartTime <= startTimeBindable.Value).LastOrDefault();
protected override bool IsValidForPlacement => base.IsValidForPlacement && HitObject.StartTime >= beatmap.ControlPointInfo.TimingPoints.FirstOrDefault()?.Time;
[Resolved]
private IPlacementHandler placementHandler { get; set; } = null!;
protected HitObjectPlacementBlueprint(HitObject hitObject)
{
HitObject = hitObject;
// adding the default hit sample should be the case regardless of the ruleset.
HitObject.Samples.Add(new HitSampleInfo(HitSampleInfo.HIT_NORMAL));
}
[BackgroundDependencyLoader]
private void load()
{
startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy();
startTimeBindable.BindValueChanged(_ => ApplyDefaultsToHitObject(), true);
}
private bool placementBegun;
protected override void BeginPlacement(bool commitStart = false)
{
base.BeginPlacement(commitStart);
if (State.Value == Visibility.Visible)
placementHandler.ShowPlacement(HitObject);
placementBegun = true;
}
public override void EndPlacement(bool commit)
{
base.EndPlacement(commit);
if (IsValidForPlacement && commit)
placementHandler.CommitPlacement(HitObject);
else
placementHandler.HidePlacement();
}
protected override void Update()
{
base.Update();
Colour = IsValidForPlacement ? Colour4.White : Colour4.Red;
}
/// <summary>
/// Updates the time and position of this <see cref="PlacementBlueprint"/>.
/// </summary>
public override SnapResult UpdateTimeAndPosition(Vector2 screenSpacePosition, double time)
{
if (PlacementActive == PlacementState.Waiting)
{
HitObject.StartTime = time;
if (HitObject is IHasComboInformation comboInformation)
comboInformation.UpdateComboInformation(getPreviousHitObject() as IHasComboInformation);
}
var lastHitObject = getPreviousHitObject();
var lastHitNormal = lastHitObject?.Samples?.FirstOrDefault(o => o.Name == HitSampleInfo.HIT_NORMAL);
if (lastHitNormal != null && AutomaticBankAssignment)
// Inherit the bank from the previous hit object
HitObject.Samples = HitObject.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newBank: lastHitNormal.Bank, newEditorAutoBank: true) : s).ToList();
else
HitObject.Samples = HitObject.Samples.Select(s => s.Name == HitSampleInfo.HIT_NORMAL ? s.With(newEditorAutoBank: false) : s).ToList();
if (lastHitNormal != null)
{
// Inherit the volume and sample set info from the previous hit object
HitObject.Samples = HitObject.Samples.Select(s => s.With(
newVolume: lastHitNormal.Volume,
newSuffix: lastHitNormal.Suffix,
newUseBeatmapSamples: lastHitNormal.UseBeatmapSamples)).ToList();
}
if (AutomaticAdditionBankAssignment)
{
string bank = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank ?? HitSampleInfo.BANK_SOFT;
HitObject.Samples = HitObject.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newBank: bank, newEditorAutoBank: true) : s).ToList();
}
else
HitObject.Samples = HitObject.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newEditorAutoBank: false) : s).ToList();
if (HitObject is IHasRepeats hasRepeats)
{
// Make sure all the node samples are identical to the hit object's samples
for (int i = 0; i < hasRepeats.NodeSamples.Count; i++)
hasRepeats.NodeSamples[i] = HitObject.Samples.Select(o => o.With()).ToList();
}
return new SnapResult(screenSpacePosition, time);
}
/// <summary>
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,IBeatmapDifficultyInfo,CancellationToken)"/>,
/// refreshing <see cref="Objects.HitObject.NestedHitObjects"/> and parameters for the <see cref="HitObject"/>.
/// </summary>
protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.Difficulty);
protected override void PopIn()
{
base.PopIn();
if (placementBegun)
placementHandler.ShowPlacement(HitObject);
}
protected override void PopOut()
{
base.PopOut();
placementHandler.HidePlacement();
}
}
}