Skip to content

Commit a563a4a

Browse files
committed
fix mod select icons inconsistently animating
this was due to an accidental change in behavior in AnimationHandler::addAnimation, where only a single animation was replaced when overrideExisting was passed (instead of all of the old animations for the float being removed) there's still a weird unrelated issue where the score multiplier text updating is delayed, not sure why
1 parent 2d529be commit a563a4a

File tree

7 files changed

+165
-168
lines changed

7 files changed

+165
-168
lines changed

src/App/Osu/Database.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <atomic>
1212
#include <set>
13+
#include <unordered_map>
1314

1415
namespace Timing {
1516
class Timer;

src/App/Osu/LegacyReplay.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#pragma once
22
// Copyright (c) 2016, PG, All rights reserved.
33
#include "ModFlags.h"
4-
#include "cbase.h"
4+
#include "UString.h"
55

66
struct FinishedScore;
77

src/App/Osu/OsuConVars/OsuConVarDefs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,10 +559,10 @@ CONVAR(background_image_eviction_delay_frames, 60, CLIENT,
559559
"how many vsync frames to keep stale background images in the cache before deleting them");
560560
CONVAR(background_image_loading_delay, 0.075f, CLIENT,
561561
"how many seconds to wait until loading background images for visible beatmaps starts");
562+
CONVAR(slider_curve_points_separation, 2.5f, CLIENT, // NOTE: adjusted by options_slider_quality
563+
"slider body curve approximation step width in osu!pixels, don't set this lower than around 1.5");
562564

563565
// Sanity checks/limits
564-
CONVAR(slider_curve_points_separation, 2.5f, CLIENT | GAMEPLAY, // NOTE: adjusted by options_slider_quality
565-
"slider body curve approximation step width in osu!pixels, don't set this lower than around 1.5");
566566
CONVAR(
567567
beatmap_max_num_hitobjects, 40000, CLIENT | PROTECTED | GAMEPLAY,
568568
"maximum number of total allowed hitobjects per beatmap (prevent crashing on deliberate game-breaking beatmaps)");

src/App/Osu/UIModSelectorModButton.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@ class UIModSelectorModButton final : public CBaseUIButton {
2525
[[nodiscard]] inline int getState() const { return this->iState; }
2626
[[nodiscard]] inline bool isOn() const { return this->bOn; }
2727
void setOn(bool on, bool silent = false);
28-
29-
private:
3028
void onFocusStolen() override;
3129

30+
private:
3231
ModSelector *osuModSelector;
3332

3433
bool bOn;

src/Engine/AnimationHandler.cpp

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ void AnimationHandler::addAnimation(float *base, float target, float duration, f
162162
AnimationHandler::ANIMATION_TYPE type, float smoothFactor) {
163163
if(base == nullptr) return;
164164

165-
Animation newAnim{
165+
if(overrideExisting) this->deleteExistingAnimation(base);
166+
167+
this->vAnimations.push_back({
166168
.fBase = base,
167169
.fTarget = target,
168170
.fDuration = duration,
@@ -172,18 +174,7 @@ void AnimationHandler::addAnimation(float *base, float target, float duration, f
172174
.fFactor = smoothFactor,
173175
.animType = type,
174176
.bStarted = (delay == 0.0f),
175-
};
176-
177-
if(overrideExisting) {
178-
if(const auto &existing =
179-
std::ranges::find(this->vAnimations, base, [](const auto &a) -> float * { return a.fBase; });
180-
existing != this->vAnimations.end()) {
181-
*existing = newAnim;
182-
return;
183-
}
184-
}
185-
186-
this->vAnimations.push_back(newAnim);
177+
});
187178
}
188179

189180
void AnimationHandler::deleteExistingAnimation(float *base) {

src/Util/FixedSizeArray.h

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright (c) 2025, WH, All rights reserved.
2+
#pragma once
3+
4+
#include <algorithm>
5+
#include <memory>
6+
#include <vector>
7+
#include <cassert>
8+
#include <cstddef>
9+
10+
// "fixed-size std::vector", but 2*sizeof(size_t) bytes instead of 3*sizeof(size_t)
11+
template <typename T>
12+
struct FixedSizeArray {
13+
struct zero_init_t {};
14+
static inline constexpr zero_init_t zero_init{};
15+
16+
FixedSizeArray() = default;
17+
~FixedSizeArray() = default;
18+
19+
explicit FixedSizeArray(size_t size) : data_(std::make_unique_for_overwrite<T[]>(size)), size_(size) {}
20+
FixedSizeArray(size_t size, zero_init_t /**/) : data_(std::make_unique<T[]>(size)), size_(size) {}
21+
22+
FixedSizeArray(const FixedSizeArray &other)
23+
: data_(other.size_ ? std::make_unique_for_overwrite<T[]>(other.size_) : nullptr), size_(other.size_) {
24+
if constexpr(std::is_trivially_copyable_v<T>) {
25+
if(size_) memcpy(data_.get(), other.data_.get(), size_ * sizeof(T));
26+
} else {
27+
std::copy_n(other.data_.get(), size_, data_.get());
28+
}
29+
}
30+
31+
FixedSizeArray &operator=(const FixedSizeArray &other) {
32+
if(this != &other) {
33+
size_ = other.size_;
34+
data_ = other.size_ ? std::make_unique_for_overwrite<T[]>(other.size_) : nullptr;
35+
if constexpr(std::is_trivially_copyable_v<T>) {
36+
if(size_) memcpy(data_.get(), other.data_.get(), size_ * sizeof(T));
37+
} else {
38+
std::copy_n(other.data_.get(), size_, data_.get());
39+
}
40+
}
41+
return *this;
42+
}
43+
44+
FixedSizeArray(FixedSizeArray &&other) noexcept : data_(std::move(other.data_)), size_(other.size_) {
45+
other.size_ = 0;
46+
}
47+
48+
FixedSizeArray &operator=(FixedSizeArray &&other) noexcept {
49+
if(this != &other) {
50+
data_ = std::move(other.data_);
51+
size_ = other.size_;
52+
other.size_ = 0;
53+
}
54+
return *this;
55+
}
56+
57+
// constructors/assignment operators from a std::vector
58+
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
59+
explicit FixedSizeArray(std::vector<T> &&vec) noexcept
60+
: data_(vec.size() ? std::make_unique_for_overwrite<T[]>(vec.size()) : nullptr), size_(vec.size()) {
61+
if constexpr(std::is_trivially_copyable_v<T>) {
62+
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
63+
} else {
64+
std::ranges::move(vec, data_.get());
65+
}
66+
}
67+
68+
explicit FixedSizeArray(const std::vector<T> &vec) noexcept
69+
: data_(vec.size() ? std::make_unique_for_overwrite<T[]>(vec.size()) : nullptr), size_(vec.size()) {
70+
if constexpr(std::is_trivially_copyable_v<T>) {
71+
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
72+
} else {
73+
std::ranges::copy(vec, data_.get());
74+
}
75+
}
76+
77+
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
78+
FixedSizeArray &operator=(std::vector<T> &&vec) noexcept {
79+
size_ = vec.size();
80+
data_ = size_ ? std::make_unique_for_overwrite<T[]>(size_) : nullptr;
81+
if constexpr(std::is_trivially_copyable_v<T>) {
82+
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
83+
} else {
84+
std::ranges::move(vec, data_.get());
85+
}
86+
return *this;
87+
}
88+
89+
FixedSizeArray &operator=(const std::vector<T> &vec) noexcept {
90+
size_ = vec.size();
91+
data_ = size_ ? std::make_unique_for_overwrite<T[]>(size_) : nullptr;
92+
if constexpr(std::is_trivially_copyable_v<T>) {
93+
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
94+
} else {
95+
std::ranges::copy(vec, data_.get());
96+
}
97+
return *this;
98+
}
99+
100+
[[nodiscard]] constexpr inline T *data() noexcept { return data_.get(); }
101+
[[nodiscard]] constexpr inline const T *data() const noexcept { return data_.get(); }
102+
103+
[[nodiscard]] constexpr inline T &operator[](size_t i) noexcept {
104+
assert(!!data_ && "T &operator[](size_t i): !data_");
105+
assert(i >= 0 && "T &operator[](size_t i): i < 0");
106+
assert(i < size_ && "T &operator[](size_t i): i >= size_");
107+
return data_[i];
108+
}
109+
[[nodiscard]] constexpr inline const T &operator[](size_t i) const noexcept {
110+
assert(!!data_ && "const T &operator[](size_t i) const: !data_");
111+
assert(i >= 0 && "const T &operator[](size_t i) const: i < 0");
112+
assert(i < size_ && "const T &operator[](size_t i) const: i >= size_");
113+
return data_[i];
114+
}
115+
116+
[[nodiscard]] constexpr inline T &front() noexcept {
117+
assert(!empty());
118+
return operator[](0);
119+
}
120+
121+
[[nodiscard]] constexpr inline T &back() noexcept {
122+
assert(!empty());
123+
return operator[](size_ - 1);
124+
}
125+
126+
[[nodiscard]] inline constexpr const T &front() const noexcept {
127+
assert(!empty());
128+
return operator[](0);
129+
}
130+
131+
[[nodiscard]] inline constexpr const T &back() const noexcept {
132+
assert(!empty());
133+
return operator[](size_ - 1);
134+
}
135+
136+
[[nodiscard]] constexpr inline size_t size() const noexcept { return size_; }
137+
[[nodiscard]] constexpr inline bool empty() const noexcept { return size_ == 0; }
138+
139+
[[nodiscard]] constexpr inline T *begin() noexcept { return data_.get(); }
140+
[[nodiscard]] constexpr inline T *end() noexcept { return data_.get() + size_; }
141+
[[nodiscard]] constexpr inline const T *begin() const noexcept { return data_.get(); }
142+
[[nodiscard]] constexpr inline const T *end() const noexcept { return data_.get() + size_; }
143+
144+
[[nodiscard]] constexpr inline const T *cbegin() const noexcept { return data_.get(); }
145+
[[nodiscard]] constexpr inline const T *cend() const noexcept { return data_.get() + size_; }
146+
147+
void clear() noexcept {
148+
size_ = 0;
149+
data_.reset();
150+
}
151+
152+
private:
153+
std::unique_ptr<T[]> data_{nullptr};
154+
size_t size_{0};
155+
};

src/Util/templates.h

Lines changed: 1 addition & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
#include "noinclude.h"
55

66
// miscellaneous templates
7-
#include <algorithm>
8-
#include <memory>
7+
98
#include <cstdlib>
109
#include <string>
1110
#include <string_view>
1211
#include <unordered_map>
1312
#include <cassert>
14-
#include <vector>
1513

1614
// zero-initialized dynamic array, similar to std::vector but way faster when you don't need constructors
1715
// obviously don't use it on complex types :)
@@ -105,153 +103,6 @@ struct zarray {
105103
T *memory = NULL;
106104
};
107105

108-
// "fixed-size std::vector", but 2*sizeof(size_t) bytes instead of 3*sizeof(size_t)
109-
template <typename T>
110-
struct FixedSizeArray {
111-
struct zero_init_t {};
112-
static inline constexpr zero_init_t zero_init{};
113-
114-
FixedSizeArray() = default;
115-
~FixedSizeArray() = default;
116-
117-
explicit FixedSizeArray(size_t size) : data_(std::make_unique_for_overwrite<T[]>(size)), size_(size) {}
118-
FixedSizeArray(size_t size, zero_init_t /**/) : data_(std::make_unique<T[]>(size)), size_(size) {}
119-
120-
FixedSizeArray(const FixedSizeArray &other)
121-
: data_(other.size_ ? std::make_unique_for_overwrite<T[]>(other.size_) : nullptr), size_(other.size_) {
122-
if constexpr(std::is_trivially_copyable_v<T>) {
123-
if(size_) memcpy(data_.get(), other.data_.get(), size_ * sizeof(T));
124-
} else {
125-
std::copy_n(other.data_.get(), size_, data_.get());
126-
}
127-
}
128-
129-
FixedSizeArray &operator=(const FixedSizeArray &other) {
130-
if(this != &other) {
131-
size_ = other.size_;
132-
data_ = other.size_ ? std::make_unique_for_overwrite<T[]>(other.size_) : nullptr;
133-
if constexpr(std::is_trivially_copyable_v<T>) {
134-
if(size_) memcpy(data_.get(), other.data_.get(), size_ * sizeof(T));
135-
} else {
136-
std::copy_n(other.data_.get(), size_, data_.get());
137-
}
138-
}
139-
return *this;
140-
}
141-
142-
FixedSizeArray(FixedSizeArray &&other) noexcept : data_(std::move(other.data_)), size_(other.size_) {
143-
other.size_ = 0;
144-
}
145-
146-
FixedSizeArray &operator=(FixedSizeArray &&other) noexcept {
147-
if(this != &other) {
148-
data_ = std::move(other.data_);
149-
size_ = other.size_;
150-
other.size_ = 0;
151-
}
152-
return *this;
153-
}
154-
155-
// constructors/assignment operators from a std::vector
156-
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
157-
explicit FixedSizeArray(std::vector<T> &&vec) noexcept
158-
: data_(vec.size() ? std::make_unique_for_overwrite<T[]>(vec.size()) : nullptr), size_(vec.size()) {
159-
if constexpr(std::is_trivially_copyable_v<T>) {
160-
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
161-
} else {
162-
std::ranges::move(vec, data_.get());
163-
}
164-
}
165-
166-
explicit FixedSizeArray(const std::vector<T> &vec) noexcept
167-
: data_(vec.size() ? std::make_unique_for_overwrite<T[]>(vec.size()) : nullptr), size_(vec.size()) {
168-
if constexpr(std::is_trivially_copyable_v<T>) {
169-
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
170-
} else {
171-
std::ranges::copy(vec, data_.get());
172-
}
173-
}
174-
175-
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
176-
FixedSizeArray &operator=(std::vector<T> &&vec) noexcept {
177-
size_ = vec.size();
178-
data_ = size_ ? std::make_unique_for_overwrite<T[]>(size_) : nullptr;
179-
if constexpr(std::is_trivially_copyable_v<T>) {
180-
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
181-
} else {
182-
std::ranges::move(vec, data_.get());
183-
}
184-
return *this;
185-
}
186-
187-
FixedSizeArray &operator=(const std::vector<T> &vec) noexcept {
188-
size_ = vec.size();
189-
data_ = size_ ? std::make_unique_for_overwrite<T[]>(size_) : nullptr;
190-
if constexpr(std::is_trivially_copyable_v<T>) {
191-
if(size_) memcpy(data_.get(), vec.data(), size_ * sizeof(T));
192-
} else {
193-
std::ranges::copy(vec, data_.get());
194-
}
195-
return *this;
196-
}
197-
198-
[[nodiscard]] constexpr inline T *data() noexcept { return data_.get(); }
199-
[[nodiscard]] constexpr inline const T *data() const noexcept { return data_.get(); }
200-
201-
[[nodiscard]] constexpr inline T &operator[](size_t i) noexcept {
202-
assert(!!data_ && "T &operator[](size_t i): !data_");
203-
assert(i >= 0 && "T &operator[](size_t i): i < 0");
204-
assert(i < size_ && "T &operator[](size_t i): i >= size_");
205-
return data_[i];
206-
}
207-
[[nodiscard]] constexpr inline const T &operator[](size_t i) const noexcept {
208-
assert(!!data_ && "const T &operator[](size_t i) const: !data_");
209-
assert(i >= 0 && "const T &operator[](size_t i) const: i < 0");
210-
assert(i < size_ && "const T &operator[](size_t i) const: i >= size_");
211-
return data_[i];
212-
}
213-
214-
[[nodiscard]] constexpr inline T &front() noexcept {
215-
assert(!empty());
216-
return operator[](0);
217-
}
218-
219-
[[nodiscard]] constexpr inline T &back() noexcept {
220-
assert(!empty());
221-
return operator[](size_ - 1);
222-
}
223-
224-
[[nodiscard]] inline constexpr const T &front() const noexcept {
225-
assert(!empty());
226-
return operator[](0);
227-
}
228-
229-
[[nodiscard]] inline constexpr const T &back() const noexcept {
230-
assert(!empty());
231-
return operator[](size_ - 1);
232-
}
233-
234-
[[nodiscard]] constexpr inline size_t size() const noexcept { return size_; }
235-
[[nodiscard]] constexpr inline bool empty() const noexcept { return size_ == 0; }
236-
237-
[[nodiscard]] constexpr inline T *begin() noexcept { return data_.get(); }
238-
[[nodiscard]] constexpr inline T *end() noexcept { return data_.get() + size_; }
239-
[[nodiscard]] constexpr inline const T *begin() const noexcept { return data_.get(); }
240-
[[nodiscard]] constexpr inline const T *end() const noexcept { return data_.get() + size_; }
241-
242-
[[nodiscard]] constexpr inline const T *cbegin() const noexcept { return data_.get(); }
243-
[[nodiscard]] constexpr inline const T *cend() const noexcept { return data_.get() + size_; }
244-
245-
void clear() noexcept {
246-
size_ = 0;
247-
data_.reset();
248-
}
249-
250-
private:
251-
std::unique_ptr<T[]> data_{nullptr};
252-
size_t size_{0};
253-
};
254-
255106
// transparent hash and equality for heterogeneous lookup
256107
struct StringHash {
257108
using is_transparent = void;

0 commit comments

Comments
 (0)