|
1 | 1 | #include <maniac/common.h> |
2 | 2 | #include <maniac/maniac.h> |
3 | 3 |
|
4 | | -void maniac::randomize(std::vector<osu::Action> &actions, std::pair<int, int> range) { |
| 4 | +void maniac::randomize(std::vector<osu::HitObject> &hit_objects, std::pair<int, int> range) { |
5 | 5 | if (!range.first && !range.second) |
6 | 6 | return; |
7 | 7 |
|
8 | 8 | std::random_device rd; |
9 | 9 | std::mt19937 gen(rd()); |
| 10 | + |
10 | 11 | std::uniform_int_distribution<> distr(range.first, range.second); |
11 | 12 |
|
12 | | - for (auto &action : actions) { |
13 | | - action.time += distr(gen); |
| 13 | + for (auto &hit_object : hit_objects) { |
| 14 | + // if it's a slider we want to randomize start and end, if it's not we ignore end anyway |
| 15 | + hit_object.start_time += distr(gen); |
| 16 | + hit_object.end_time += distr(gen); |
14 | 17 | } |
15 | 18 |
|
16 | | - debug("randomized %d actions with a range of [%d, %d]", actions.size(), range.first, |
| 19 | + debug("randomized %d hit objects with a range of [%d, %d]", hit_objects.size(), range.first, |
17 | 20 | range.second); |
18 | 21 | } |
19 | 22 |
|
20 | | -static std::vector<int> actions_per_frame(const std::vector<osu::Action> &actions, |
21 | | - int time_frame = 1000) { |
22 | | - std::vector<int> frames = {}; |
23 | | - const size_t chunks_needed = (actions.back().time / time_frame) + 1; |
24 | | - |
25 | | - debug("will need %d frames", chunks_needed); |
26 | | - |
27 | | - for (size_t chunk_i = 0; chunk_i < chunks_needed; chunk_i++) { |
28 | | - frames.emplace_back(0); |
29 | | - |
30 | | - for (const auto &action : actions) { |
31 | | - const int32_t lower_bound = time_frame * chunk_i; |
32 | | - const int32_t upper_bound = lower_bound + time_frame; |
33 | | - |
34 | | - if (action.time >= lower_bound && action.time <= upper_bound) { |
35 | | - frames[chunk_i]++; |
36 | | - } |
37 | | - } |
38 | | - } |
39 | | - |
40 | | - return frames; |
41 | | -} |
42 | | - |
43 | | -void maniac::humanize(std::vector<osu::Action> &actions, int modifier) { |
44 | | - if (!modifier) |
45 | | - return; |
| 23 | +void maniac::humanize(std::vector<osu::HitObject> &hit_objects, int modifier) { |
| 24 | + if (!modifier) { |
| 25 | + return; |
| 26 | + } |
46 | 27 |
|
47 | 28 | const auto actual_modifier = static_cast<double>(modifier) / 100.0; |
48 | 29 |
|
49 | | - constexpr auto frame_range = 1000; |
50 | | - const auto frames = actions_per_frame(actions, frame_range); |
| 30 | + // count number of hits/unit of time (slice size) |
| 31 | + constexpr auto slice_size = 1000; |
51 | 32 |
|
52 | | - std::random_device rd; |
53 | | - std::mt19937 gen(rd()); |
| 33 | + const auto latest_hit = std::max_element(hit_objects.begin(), hit_objects.end(), [](auto a, auto b) { |
| 34 | + return a.end_time < b.end_time; |
| 35 | + })->end_time; |
54 | 36 |
|
55 | | - std::uniform_int_distribution<> offset_distr(-5, 5); |
| 37 | + auto slices = std::vector<int>{}; |
| 38 | + slices.resize((latest_hit / slice_size) + 1); |
56 | 39 |
|
57 | | - const auto frames_size = frames.size(); |
58 | | - for (auto &action : actions) { |
59 | | - const auto random_offset = offset_distr(gen); |
60 | | - const size_t frame_i = action.time / frame_range; |
| 40 | + for (const auto &hit_object : hit_objects) { |
| 41 | + slices.at(hit_object.start_time / slice_size)++; |
61 | 42 |
|
62 | | - if (frame_i >= frames_size) { |
63 | | - debug("ignoring invalid frame_i (%d)", frame_i); |
| 43 | + if (hit_object.is_slider) { |
| 44 | + slices.at(hit_object.end_time / slice_size)++; |
| 45 | + } |
| 46 | + } |
64 | 47 |
|
65 | | - continue; |
66 | | - } |
| 48 | + for (auto &hit_object : hit_objects) { |
| 49 | + const auto start_offset = static_cast<int>(slices.at(hit_object.start_time / slice_size) * actual_modifier); |
67 | 50 |
|
68 | | - const int offset = static_cast<int>(frames.at(frame_i) * actual_modifier) + random_offset; |
| 51 | + hit_object.start_time += start_offset; |
69 | 52 |
|
70 | | - action.time += offset; |
71 | | - } |
| 53 | + if (hit_object.is_slider) { |
| 54 | + const auto end_offset = static_cast<int>(slices.at(hit_object.end_time / slice_size) * actual_modifier); |
| 55 | + |
| 56 | + hit_object.end_time += end_offset; |
| 57 | + } |
| 58 | + } |
72 | 59 |
|
73 | | - debug("%s %d %s %d %s %dms %s %f", "humanized", actions.size(), "actions over", |
74 | | - frames_size, "time frames of", frame_range, "with a modifier of", actual_modifier); |
| 60 | + debug("humanized %d hit objects (%d slices of %dms) with modifier %d", hit_objects.size(), slices.size(), slice_size, modifier); |
75 | 61 | } |
0 commit comments