Etterna 0.74.4
Loading...
Searching...
No Matches
UlbuBase.h
1#pragma once
2
3#include "Agnostic/HA_PatternMods/GenericChordstream.h"
4#include "Agnostic/HA_PatternMods/CJ.h"
5
6#include "Dependent/MetaIntervalGenericHandInfo.h"
7#include "Dependent/HD_PatternMods/GenericBracketing.h"
8#include "Dependent/HD_PatternMods/GenericStream.h"
9
10#include "SequencedBaseDiffCalc.h"
11
15{
16 public:
17 Calc& _calc;
18 bool dbg = false;
19 int hand = 0;
20
21 // keeps track of occurrences of basic row based sequencing, mostly for
22 // skilset detection, contains itvinfo as well, the very basic metrics used
23 // for detection
24 metaItvInfo _mitvi;
25
26 // the generic hand stats
28
29 // meta row info keeps track of basic pattern sequencing as we scan down
30 // the notedata rows, we will recyle two pointers (we want each row to be
31 // able to "look back" at the meta info generated at the last row so the mhi
32 // generation requires the last generated mhi object as an arg
33 std::unique_ptr<metaRowInfo> _last_mri;
34 std::unique_ptr<metaRowInfo> _mri;
35
36 GStreamMod _gstream;
37 GChordStreamMod _gchordstream;
38 GBracketingMod _gbracketing;
39 CJMod _cj;
40
41 oversimplified_jacks lazy_jacks;
42
43 explicit Bazoinkazoink(Calc& calc)
44 : _calc(calc)
45 {
46 _last_mri = std::make_unique<metaRowInfo>(calc);
47 _mri = std::make_unique<metaRowInfo>(calc);
48 }
49
50 private:
51 const std::array<std::vector<int>, NUM_Skillset> pmods = { {
52 // Overall
53 {},
54
55 // Stream
56 {
57 GStream,
58 },
59
60 // Jumpstream
61 {
62 GChordStream,
63 },
64
65 // Handstream
66 {
67 GBracketing,
68 },
69
70 // Stamina
71 {},
72
73 // Jackspeed
74 {},
75
76 // Chordjack
77 {
78 CJ,
79 },
80
81 // Technical
82 {
83
84 },
85 }};
86
87 const std::array<float, NUM_Skillset> basescalers = {
88 0.F, 1.F, 1.F, 1.F, 0.93F, 1.F, 1.F, 1.F
89 };
90
91 public:
92 virtual const std::array<std::vector<int>, NUM_Skillset>& get_pmods() const
93 {
94 return pmods;
95 }
96 virtual const std::array<float, NUM_Skillset>& get_basescalers() const
97 {
98 return basescalers;
99 }
100 virtual void adj_diff_func(
101 const size_t& itv,
102 const int& hand,
103 float*& adj_diff,
104 float*& stam_base,
105 const float& adj_npsbase,
106 const int& ss,
107 std::array<float, NUM_Skillset>& pmod_product_cur_interval)
108 {
109 switch (ss) {
110 case Skill_Stream:
111 break;
112 case Skill_Jumpstream: {
113 } break;
114 case Skill_Handstream: {
115 } break;
116 case Skill_JackSpeed:
117 break;
118 case Skill_Chordjack:
119 break;
120 case Skill_Technical:
121 *adj_diff =
122 _calc.init_base_diff_vals.at(hand).at(TechBase).at(itv) *
123 pmod_product_cur_interval.at(ss) * basescalers.at(ss);
124 break;
125 default:
126 break;
127 }
128 }
129
133 {
134 for (auto& hand : both_hands) {
135 for (auto& base : {TechBase}) {
136 // to be thorough: JackBase, CJBase, NPSBase, RMABase
137 auto& v = _calc.init_base_diff_vals.at(hand)[base];
138 std::fill(v.begin(), v.end(), 0.F);
139 }
140 _calc.jack_diff.at(hand).clear();
141 }
142 }
143
145 void operator()() {
147 hand = 0;
148
149 full_hand_reset();
150 full_agnostic_reset();
151 reset_row_sequencing();
152
153 run_agnostic_pmod_loop();
154 run_dependent_pmod_loop();
155 }
156
157 virtual void full_agnostic_reset() {
158 _gchordstream.full_reset();
159 _cj.full_reset();
160
161 _mri.get()->reset();
162 _last_mri.get()->reset();
163 }
164
165 virtual void setup_agnostic_pmods() {
166
167 }
168
169 virtual void advance_agnostic_sequencing() {
170
171 }
172
173 virtual void set_agnostic_pmods(const int& itv) {
174 PatternMods::set_agnostic(
175 _gchordstream._pmod, _gchordstream(_mitvi), itv, _calc);
176 PatternMods::set_agnostic(_cj._pmod, _cj(_mitvi), itv, _calc);
177 }
178
179 virtual void run_agnostic_pmod_loop() {
180 setup_agnostic_pmods();
181
182 for (auto itv = 0; itv < _calc.numitv; ++itv) {
183 for (auto row = 0; row < _calc.itv_size.at(itv); ++row) {
184
185 const auto& ri = _calc.adj_ni.at(itv).at(row);
186 (*_mri)(
187 *_last_mri, _mitvi, ri.row_time, ri.row_count, ri.row_notes);
188
189 advance_agnostic_sequencing();
190
191 // we only need to look back 1 metanoterow object, so we can
192 // swap the one we just built into last and recycle the two
193 // pointers instead of keeping track of everything
194 swap(_mri, _last_mri);
195 }
196
197 // run pattern mod generation for hand agnostic mods
198 set_agnostic_pmods(itv);
199
200 // reset any accumulated interval info and set cur index number
201 _mitvi.handle_interval_end();
202 }
203
204 PatternMods::run_agnostic_smoothing_pass(_calc.numitv, _calc);
205
206 // copy left -> right for agnostic mods
207 PatternMods::bruh_they_the_same(_calc.numitv, _calc);
208 }
209
210
211 virtual void reset_row_sequencing() {
212 _mitvi.reset();
213 }
214
215 virtual void setup_dependent_mods() {
216
217 }
218
219 virtual void set_dependent_pmods(const int& itv) {
220 PatternMods::set_dependent(
221 hand, _gstream._pmod, _gstream(_mitvghi), itv, _calc);
222 PatternMods::set_dependent(
223 hand, _gbracketing._pmod, _gbracketing(_mitvghi), itv, _calc);
224 }
225
226 virtual void full_hand_reset() {
227 lazy_jacks.init(_calc.keycount);
228
229 _gstream.full_reset();
230 _gbracketing.full_reset();
231
232 _mitvghi.zero();
233 }
234
235 virtual void handle_dependent_interval_end(const int& itv) {
236 set_dependent_pmods(itv);
237
238 set_sequenced_base_diffs(itv);
239
240 _mitvghi.interval_end();
241 }
242
243 virtual void set_sequenced_base_diffs(const int& itv) const {
244
245 }
246
247 virtual void run_dependent_pmod_loop() {
248 setup_dependent_mods();
249
250 hand = 0;
251 for (const auto& ids : _calc.hand_col_masks) {
252 full_hand_reset();
253 nps::actual_cancer(_calc, hand);
254 Smooth(_calc.init_base_diff_vals.at(hand).at(NPSBase),
255 0.F,
256 _calc.numitv);
257
258 auto row_time = s_init;
259 auto last_row_time = s_init;
260 auto any_ms = ms_init;
261 auto row_notes = 0u;
262 for (auto itv = 0; itv < _calc.numitv; ++itv) {
263 for (auto row = 0; row < _calc.itv_size.at(itv); row++) {
264 const auto& ri = _calc.adj_ni.at(itv).at(row);
265 row_time = ri.row_time;
266 row_notes = ri.row_notes;
267 any_ms = ms_from(row_time, last_row_time);
268 auto masked_notes = row_notes & ids;
269
270 auto non_empty_cols = find_non_empty_cols(masked_notes);
271 if (non_empty_cols.empty()) {
272 continue;
273 }
274
275 for (auto& c : non_empty_cols) {
276 lazy_jacks(c, row_time);
277 }
278
279 // update counts
280 _mitvghi.handle_row(masked_notes, ids);
281
282 auto thing =
283 std::pair{ row_time,
284 ms_to_scaled_nps(
285 lazy_jacks.get_lowest_jack_ms(hand, _calc)) *
286 basescalers[Skill_JackSpeed] };
287 if (std::isnan(thing.second)) {
288 thing.second = 0.F;
289 }
290 _calc.jack_diff.at(hand).push_back(thing);
291
292 last_row_time = row_time;
293 }
294 handle_dependent_interval_end(itv);
295 }
296 PatternMods::run_dependent_smoothing_pass(_calc.numitv, _calc);
297
298 hand++;
299 }
300 }
301
302#if !defined(STANDALONE_CALC) && !defined(PHPCALC)
303
304 virtual const std::string get_calc_param_xml() const {
305 return "Save/CalcParams_generic.xml";
306 }
307
308 virtual void load_calc_params_internal(const XNode& params) const {
309 load_params_for_mod(&params, _gstream._params, _gstream.name);
310 load_params_for_mod(&params, _gchordstream._params, _gchordstream.name);
311 load_params_for_mod(&params, _gbracketing._params, _gbracketing.name);
312 load_params_for_mod(&params, _cj._params, _cj.name);
313 }
314
315 virtual XNode* make_param_node_internal(XNode* calcparams) const
316 {
317 calcparams->AppendChild(
318 make_mod_param_node(_gstream._params, _gstream.name));
319 calcparams->AppendChild(
320 make_mod_param_node(_gchordstream._params, _gchordstream.name));
321 calcparams->AppendChild(
322 make_mod_param_node(_gbracketing._params, _gbracketing.name));
323 calcparams->AppendChild(make_mod_param_node(_cj._params, _cj.name));
324
325 return calcparams;
326 }
327
329 void load_calc_params_from_disk(bool bForce = false) const {
330 const auto fn = get_calc_param_xml();
331
332 // Hold calc params program-global persistent info
333 thread_local RageFile* pFile;
334 thread_local XNode params;
335 // Only ever try to load params once per thread unless forcing
336 thread_local bool paramsLoaded = false;
337
338 // Don't keep loading params if nothing to load/no reason to
339 // Allow a force to bypass
340 if (paramsLoaded && !bForce)
341 return;
342
343 // Load if missing
344 if (pFile == nullptr || bForce || !pFile->IsOpen()) {
345 delete pFile;
346 pFile = new RageFile();
347 // Failed to load
348 if (!pFile->Open(fn, RageFile::READ))
349 return;
350 }
351
352 // If it isn't loaded or we are forcing a load, load it
353 if (params.ChildrenEmpty() || bForce) {
354 if (!XmlFileUtil::LoadFromFileShowErrors(params, *pFile)) {
355 pFile->Close();
356 return;
357 }
358 }
359
360 // ignore params from older versions
361 std::string vers;
362 params.GetAttrValue("vers", vers);
363 if (vers.empty() || stoi(vers) != GetCalcVersion()) {
364 return;
365 }
366 paramsLoaded = true;
367
368 load_calc_params_internal(params);
369 pFile->Close();
370 }
371
373 void write_params_to_disk() const {
374 const auto fn = get_calc_param_xml();
375 const std::unique_ptr<XNode> xml(make_param_node());
376
377 std::string err;
378 RageFile f;
379 if (!f.Open(fn, RageFile::WRITE)) {
380 return;
381 }
382 XmlFileUtil::SaveToFile(xml.get(), f, "", false);
383 f.Close();
384 }
385
386 static auto make_mod_param_node(
387 const std::vector<std::pair<std::string, float*>>& param_map,
388 const std::string& name) -> XNode*
389 {
390 auto* pmod = new XNode(name);
391 for (const auto& p : param_map) {
392 pmod->AppendChild(p.first, std::to_string(*p.second));
393 }
394
395 return pmod;
396 }
397
398 static void load_params_for_mod(
399 const XNode* node,
400 const std::vector<std::pair<std::string, float*>>& param_map,
401 const std::string& name)
402 {
403 auto boat = 0.F;
404 const auto* pmod = node->GetChild(name);
405 if (pmod == nullptr) {
406 return;
407 }
408 for (const auto& p : param_map) {
409 const auto* ch = pmod->GetChild(p.first);
410 if (ch == nullptr) {
411 continue;
412 }
413
414 ch->GetTextValue(boat);
415 *p.second = boat;
416 }
417 }
418
419 XNode* make_param_node() const {
420 auto* calcparams = new XNode("CalcParams");
421 calcparams->AppendAttr("vers", GetCalcVersion());
422 return make_param_node_internal(calcparams);
423 }
424#endif
425};
Main driver class for the difficulty calculator as a whole.
Definition MinaCalc.h:82
std::array< std::array< std::vector< float >, NUM_CalcDiffValue >, num_hands > init_base_diff_vals
Definition MinaCalc.h:187
int numitv
Total number of intervals for the current file/rate (one per half second)
Definition MinaCalc.h:263
std::vector< std::array< RowInfo, max_rows_for_single_interval > > adj_ni
Definition MinaCalc.h:162
unsigned keycount
Assigns the keymode specific logic.
Definition MinaCalc.h:104
std::array< std::vector< std::pair< float, float > >, num_hands > jack_diff
Definition MinaCalc.h:239
std::vector< int > itv_size
Number of rows in each interval.
Definition MinaCalc.h:165
High-level file access.
Definition RageFile.h:16
Definition XmlFile.h:95
Definition UlbuBase.h:15
void reset_base_diffs()
Definition UlbuBase.h:132
void write_params_to_disk() const
save default xml parameters
Definition UlbuBase.h:373
void load_calc_params_from_disk(bool bForce=false) const
load custom xml parameters
Definition UlbuBase.h:329
void operator()()
main driver for operations
Definition UlbuBase.h:145
Definition CJ.h:7
Definition GenericBracketing.h:7
Definition GenericChordstream.h:7
Definition GenericStream.h:8
Definition MetaIntervalGenericHandInfo.h:145
void interval_end()
handle end of interval
Definition MetaIntervalGenericHandInfo.h:160
void zero()
Definition MetaIntervalGenericHandInfo.h:173
Definition MetaIntervalInfo.h:20
static void actual_cancer(Calc &calc, const int &hand)
determine NPSBase, itv_points, CJBase for this hand
Definition SequencedBaseDiffCalc.h:68
Definition SequencedBaseDiffCalc.h:942