Browse Source

Allow servers to override convars via neosu.json

Clément Wolf 4 months ago
parent
commit
937a849056
78 changed files with 4143 additions and 1017 deletions
  1. 5 5
      src/App/Osu/BackgroundImageHandler.cpp
  2. 7 1
      src/App/Osu/Bancho.cpp
  3. 11 1
      src/App/Osu/BanchoNetworking.cpp
  4. 1 0
      src/App/Osu/BanchoNetworking.h
  5. 116 115
      src/App/Osu/Beatmap.cpp
  6. 1 0
      src/App/Osu/Changelog.cpp
  7. 11 11
      src/App/Osu/Circle.cpp
  8. 24 21
      src/App/Osu/Database.cpp
  9. 20 20
      src/App/Osu/DatabaseBeatmap.cpp
  10. 3 3
      src/App/Osu/DifficultyCalculator.cpp
  11. 45 43
      src/App/Osu/GameRules.cpp
  12. 183 179
      src/App/Osu/HUD.cpp
  13. 33 32
      src/App/Osu/HitObject.cpp
  14. 44 44
      src/App/Osu/KeyBindings.cpp
  15. 8 8
      src/App/Osu/MainMenu.cpp
  16. 45 45
      src/App/Osu/ModFPoSu.cpp
  17. 127 0
      src/App/Osu/NeosuSettings.cpp
  18. 4 0
      src/App/Osu/NeosuSettings.h
  19. 1 1
      src/App/Osu/NotificationOverlay.cpp
  20. 4 4
      src/App/Osu/OptionsMenu.cpp
  21. 66 72
      src/App/Osu/Osu.cpp
  22. 0 1
      src/App/Osu/Osu.h
  23. 3 3
      src/App/Osu/PauseMenu.cpp
  24. 3 3
      src/App/Osu/RankingScreen.cpp
  25. 4 4
      src/App/Osu/RichPresence.cpp
  26. 0 4
      src/App/Osu/RoomScreen.cpp
  27. 17 16
      src/App/Osu/Skin.cpp
  28. 1 1
      src/App/Osu/SkinImage.cpp
  29. 18 18
      src/App/Osu/Slider.cpp
  30. 3 3
      src/App/Osu/SliderCurves.cpp
  31. 16 16
      src/App/Osu/SliderRenderer.cpp
  32. 9 9
      src/App/Osu/SongBrowser/Button.cpp
  33. 8 8
      src/App/Osu/SongBrowser/CollectionButton.cpp
  34. 19 19
      src/App/Osu/SongBrowser/SongBrowser.cpp
  35. 3 3
      src/App/Osu/SongBrowser/SongButton.cpp
  36. 4 4
      src/App/Osu/SongBrowser/SongDifficultyButton.cpp
  37. 4 4
      src/App/Osu/SongBrowser/UserButton.cpp
  38. 1 1
      src/App/Osu/Spinner.cpp
  39. 1 1
      src/App/Osu/TooltipOverlay.cpp
  40. 1 1
      src/App/Osu/UserStatsScreen.cpp
  41. 21 21
      src/App/Osu/score.cpp
  42. 1 1
      src/Engine/AnimationHandler.cpp
  43. 125 89
      src/Engine/ConVar.cpp
  44. 25 31
      src/Engine/ConVar.h
  45. 24 24
      src/Engine/Engine.cpp
  46. 3 3
      src/Engine/Environment.cpp
  47. 2 2
      src/Engine/Font.cpp
  48. 10 10
      src/Engine/Graphics.cpp
  49. 7 7
      src/Engine/Input/Mouse.cpp
  50. 3 3
      src/Engine/Main/main_Linux.cpp
  51. 3 3
      src/Engine/Main/main_OSX_cpp.cpp
  52. 9 9
      src/Engine/Main/main_SDL.cpp
  53. 7 7
      src/Engine/Main/main_Windows.cpp
  54. 1 1
      src/Engine/NetworkHandler.cpp
  55. 2 2
      src/Engine/Platform/File.cpp
  56. 1 1
      src/Engine/Platform/Thread.cpp
  57. 1 1
      src/Engine/Platform/WinEnvironment.cpp
  58. 1 1
      src/Engine/Profiler.cpp
  59. 1 1
      src/Engine/RenderTarget.cpp
  60. 1 1
      src/Engine/Renderer/OpenGLLegacyInterface.cpp
  61. 1 1
      src/Engine/Renderer/OpenGLVertexArrayObject.cpp
  62. 5 5
      src/Engine/ResourceManager.cpp
  63. 1 1
      src/Engine/Shader.cpp
  64. 3 3
      src/Engine/Sound.cpp
  65. 14 13
      src/Engine/SoundEngine.cpp
  66. 1 1
      src/GUI/CBaseUIBoxShadow.cpp
  67. 6 6
      src/GUI/CBaseUIScrollView.cpp
  68. 2 2
      src/GUI/CBaseUITextbox.cpp
  69. 2 2
      src/GUI/CBaseUIWindow.cpp
  70. 3 19
      src/GUI/Windows/Console.cpp
  71. 0 1
      src/GUI/Windows/Console.h
  72. 6 6
      src/GUI/Windows/ConsoleBox.cpp
  73. 3 3
      src/GUI/Windows/VinylScratcher/VSControlBar.cpp
  74. 1 1
      src/GUI/Windows/VinylScratcher/VSMusicBrowser.cpp
  75. 1 1
      src/GUI/Windows/VinylScratcher/VSTitleBar.cpp
  76. 10 10
      src/GUI/Windows/VisualProfiler.cpp
  77. 2647 0
      src/Util/cJSON.cpp
  78. 315 0
      src/Util/cJSON.h

+ 5 - 5
src/App/Osu/BackgroundImageHandler.cpp

@@ -12,18 +12,18 @@
 #include "Engine.h"
 #include "ResourceManager.h"
 
-ConVar osu_load_beatmap_background_images("osu_load_beatmap_background_images", true, FCVAR_NONE);
+ConVar osu_load_beatmap_background_images("osu_load_beatmap_background_images", true, FCVAR_DEFAULT);
 
-ConVar osu_background_image_cache_size("osu_background_image_cache_size", 32, FCVAR_NONE,
+ConVar osu_background_image_cache_size("osu_background_image_cache_size", 32, FCVAR_DEFAULT,
                                        "how many images can stay loaded in parallel");
 ConVar osu_background_image_loading_delay(
-    "osu_background_image_loading_delay", 0.1f, FCVAR_NONE,
+    "osu_background_image_loading_delay", 0.1f, FCVAR_DEFAULT,
     "how many seconds to wait until loading background images for visible beatmaps starts");
 ConVar osu_background_image_eviction_delay_seconds(
-    "osu_background_image_eviction_delay_seconds", 0.05f, FCVAR_NONE,
+    "osu_background_image_eviction_delay_seconds", 0.05f, FCVAR_DEFAULT,
     "how many seconds to keep stale background images in the cache before deleting them (if seconds && frames)");
 ConVar osu_background_image_eviction_delay_frames(
-    "osu_background_image_eviction_delay_frames", 0, FCVAR_NONE,
+    "osu_background_image_eviction_delay_frames", 0, FCVAR_DEFAULT,
     "how many frames to keep stale background images in the cache before deleting them (if seconds && frames)");
 
 BackgroundImageHandler::BackgroundImageHandler() { m_bFrozen = false; }

+ 7 - 1
src/App/Osu/Bancho.cpp

@@ -197,7 +197,6 @@ void handle_packet(Packet *packet) {
             bancho.osu->m_optionsMenu->logInButton->setColor(0xffff0000);
             bancho.osu->m_optionsMenu->logInButton->is_loading = false;
             convar->getConVarByName("mp_autologin")->setValue(true);
-            ConVars::sv_cheats.setValue(!bancho.submit_scores());
             print_new_channels = true;
 
             std::stringstream ss;
@@ -228,6 +227,13 @@ void handle_packet(Packet *packet) {
 
             // If server sent a score submission policy, update options menu to hide the checkbox
             bancho.osu->m_optionsMenu->updateLayout();
+
+            APIRequest request;
+            request.type = GET_NEOSU_SETTINGS;
+            request.path = UString::format("/neosu.json?u=%s&h=%s", bancho.username.toUtf8(), bancho.pw_md5.toUtf8());
+            request.mime = NULL;
+            request.extra = NULL;
+            send_api_request(request);
         } else {
             convar->getConVarByName("mp_autologin")->setValue(false);
             bancho.osu->m_optionsMenu->logInButton->setText("Log in");

+ 11 - 1
src/App/Osu/BanchoNetworking.cpp

@@ -17,6 +17,7 @@
 #include "Engine.h"
 #include "File.h"
 #include "Lobby.h"
+#include "NeosuSettings.h"
 #include "OptionsMenu.h"
 #include "ResourceManager.h"
 #include "RoomScreen.h"
@@ -95,6 +96,11 @@ void disconnect() {
         bancho.server_icon = nullptr;
     }
 
+    std::vector<ConVar *> convars = convar->getConVarArray();
+    for(auto var : convars) {
+        var->resetDefaults();
+    }
+
     bancho.score_submission_policy = ServerPolicy::NO_PREFERENCE;
     bancho.set_fposu_flag = false;
     bancho.set_mirror_flag = false;
@@ -103,7 +109,6 @@ void disconnect() {
     bancho.osu->m_optionsMenu->logInButton->setText("Log in");
     bancho.osu->m_optionsMenu->logInButton->setColor(0xff00ff00);
     bancho.osu->m_optionsMenu->logInButton->is_loading = false;
-    ConVars::sv_cheats.setValue(true);
 
     for(auto pair : online_users) {
         delete pair.second;
@@ -387,6 +392,11 @@ static void *do_networking(void *data) {
 
 static void handle_api_response(Packet packet) {
     switch(packet.id) {
+        case GET_NEOSU_SETTINGS: {
+            process_neosu_settings(packet);
+            break;
+        }
+
         case GET_BEATMAPSET_INFO: {
             RoomScreen::process_beatmapset_info_response(packet);
             break;

+ 1 - 0
src/App/Osu/BanchoNetworking.h

@@ -23,6 +23,7 @@ enum APIRequestType {
     GET_REPLAY,
     MARK_AS_READ,
     SUBMIT_SCORE,
+    GET_NEOSU_SETTINGS,
 };
 
 struct APIRequest {

+ 116 - 115
src/App/Osu/Beatmap.cpp

@@ -54,219 +54,220 @@
 #include "SoundEngine.h"
 #include "Spinner.h"
 
-ConVar osu_pvs("osu_pvs", true, FCVAR_NONE,
+ConVar osu_pvs("osu_pvs", true, FCVAR_DEFAULT,
                "optimizes all loops over all hitobjects by clamping the range to the Potentially Visible Set");
-ConVar osu_draw_hitobjects("osu_draw_hitobjects", true, FCVAR_NONE);
-ConVar osu_draw_beatmap_background_image("osu_draw_beatmap_background_image", true, FCVAR_NONE);
+ConVar osu_draw_hitobjects("osu_draw_hitobjects", true, FCVAR_DEFAULT);
+ConVar osu_draw_beatmap_background_image("osu_draw_beatmap_background_image", true, FCVAR_DEFAULT);
 
-ConVar osu_universal_offset("osu_universal_offset", 0.0f, FCVAR_NONE);
+ConVar osu_universal_offset("osu_universal_offset", 0.0f, FCVAR_DEFAULT);
 ConVar osu_universal_offset_hardcoded_fallback_dsound("osu_universal_offset_hardcoded_fallback_dsound", -15.0f,
-                                                      FCVAR_NONE);
+                                                      FCVAR_DEFAULT);
 ConVar osu_old_beatmap_offset(
-    "osu_old_beatmap_offset", 24.0f, FCVAR_NONE,
+    "osu_old_beatmap_offset", 24.0f, FCVAR_DEFAULT,
     "offset in ms which is added to beatmap versions < 5 (default value is hardcoded 24 ms in stable)");
-ConVar osu_timingpoints_offset("osu_timingpoints_offset", 5.0f, FCVAR_NONE,
+ConVar osu_timingpoints_offset("osu_timingpoints_offset", 5.0f, FCVAR_DEFAULT,
                                "Offset in ms which is added before determining the active timingpoint for the sample "
                                "type and sample volume (hitsounds) of the current frame");
 ConVar osu_interpolate_music_pos(
-    "osu_interpolate_music_pos", true, FCVAR_NONE,
+    "osu_interpolate_music_pos", true, FCVAR_DEFAULT,
     "Interpolate song position with engine time if the audio library reports the same position more than once");
 ConVar osu_compensate_music_speed(
-    "osu_compensate_music_speed", true, FCVAR_NONE,
+    "osu_compensate_music_speed", true, FCVAR_DEFAULT,
     "compensates speeds slower than 1x a little bit, by adding an offset depending on the slowness");
-ConVar osu_combobreak_sound_combo("osu_combobreak_sound_combo", 20, FCVAR_NONE,
+ConVar osu_combobreak_sound_combo("osu_combobreak_sound_combo", 20, FCVAR_DEFAULT,
                                   "Only play the combobreak sound if the combo is higher than this");
 ConVar osu_beatmap_preview_mods_live(
-    "osu_beatmap_preview_mods_live", false, FCVAR_NONE,
+    "osu_beatmap_preview_mods_live", false, FCVAR_DEFAULT,
     "whether to immediately apply all currently selected mods while browsing beatmaps (e.g. speed/pitch)");
-ConVar osu_beatmap_preview_music_loop("osu_beatmap_preview_music_loop", true, FCVAR_NONE);
+ConVar osu_beatmap_preview_music_loop("osu_beatmap_preview_music_loop", true, FCVAR_DEFAULT);
 
-ConVar osu_ar_override("osu_ar_override", -1.0f, FCVAR_NONVANILLA,
+ConVar osu_ar_override("osu_ar_override", -1.0f, FCVAR_UNLOCKED,
                        "use this to override between AR 0 and AR 12.5+. active if value is more than or equal to 0.");
-ConVar osu_ar_overridenegative("osu_ar_overridenegative", 0.0f, FCVAR_NONVANILLA,
+ConVar osu_ar_overridenegative("osu_ar_overridenegative", 0.0f, FCVAR_UNLOCKED,
                                "use this to override below AR 0. active if value is less than 0, disabled otherwise. "
                                "this override always overrides the other override.");
-ConVar osu_cs_override("osu_cs_override", -1.0f, FCVAR_NONVANILLA,
+ConVar osu_cs_override("osu_cs_override", -1.0f, FCVAR_UNLOCKED,
                        "use this to override between CS 0 and CS 12.1429. active if value is more than or equal to 0.");
-ConVar osu_cs_overridenegative("osu_cs_overridenegative", 0.0f, FCVAR_NONVANILLA,
+ConVar osu_cs_overridenegative("osu_cs_overridenegative", 0.0f, FCVAR_UNLOCKED,
                                "use this to override below CS 0. active if value is less than 0, disabled otherwise. "
                                "this override always overrides the other override.");
-ConVar osu_cs_cap_sanity("osu_cs_cap_sanity", true, FCVAR_CHEAT);
-ConVar osu_hp_override("osu_hp_override", -1.0f, FCVAR_NONVANILLA);
-ConVar osu_od_override("osu_od_override", -1.0f, FCVAR_NONVANILLA);
-ConVar osu_ar_override_lock("osu_ar_override_lock", false, FCVAR_NONVANILLA,
+ConVar osu_cs_cap_sanity("osu_cs_cap_sanity", true, FCVAR_LOCKED);
+ConVar osu_hp_override("osu_hp_override", -1.0f, FCVAR_UNLOCKED);
+ConVar osu_od_override("osu_od_override", -1.0f, FCVAR_UNLOCKED);
+ConVar osu_ar_override_lock("osu_ar_override_lock", false, FCVAR_UNLOCKED,
                             "always force constant AR even through speed changes");
-ConVar osu_od_override_lock("osu_od_override_lock", false, FCVAR_NONVANILLA,
+ConVar osu_od_override_lock("osu_od_override_lock", false, FCVAR_UNLOCKED,
                             "always force constant OD even through speed changes");
 
-ConVar osu_background_dim("osu_background_dim", 0.9f, FCVAR_NONE);
-ConVar osu_background_fade_after_load("osu_background_fade_after_load", true, FCVAR_NONE);
-ConVar osu_background_dont_fade_during_breaks("osu_background_dont_fade_during_breaks", false, FCVAR_NONE);
-ConVar osu_background_fade_min_duration("osu_background_fade_min_duration", 1.4f, FCVAR_NONE,
+ConVar osu_background_dim("osu_background_dim", 0.9f, FCVAR_DEFAULT);
+ConVar osu_background_fade_after_load("osu_background_fade_after_load", true, FCVAR_DEFAULT);
+ConVar osu_background_dont_fade_during_breaks("osu_background_dont_fade_during_breaks", false, FCVAR_DEFAULT);
+ConVar osu_background_fade_min_duration("osu_background_fade_min_duration", 1.4f, FCVAR_DEFAULT,
                                         "Only fade if the break is longer than this (in seconds)");
-ConVar osu_background_fade_in_duration("osu_background_fade_in_duration", 0.85f, FCVAR_NONE);
-ConVar osu_background_fade_out_duration("osu_background_fade_out_duration", 0.25f, FCVAR_NONE);
-ConVar osu_background_brightness("osu_background_brightness", 0.0f, FCVAR_NONE,
+ConVar osu_background_fade_in_duration("osu_background_fade_in_duration", 0.85f, FCVAR_DEFAULT);
+ConVar osu_background_fade_out_duration("osu_background_fade_out_duration", 0.25f, FCVAR_DEFAULT);
+ConVar osu_background_brightness("osu_background_brightness", 0.0f, FCVAR_DEFAULT,
                                  "0 to 1, if this is larger than 0 then it will replace the entire beatmap background "
                                  "image with a solid color (see osu_background_color_r/g/b)");
-ConVar osu_background_color_r("osu_background_color_r", 255.0f, FCVAR_NONE,
+ConVar osu_background_color_r("osu_background_color_r", 255.0f, FCVAR_DEFAULT,
                               "0 to 255, only relevant if osu_background_brightness is larger than 0");
-ConVar osu_background_color_g("osu_background_color_g", 255.0f, FCVAR_NONE,
+ConVar osu_background_color_g("osu_background_color_g", 255.0f, FCVAR_DEFAULT,
                               "0 to 255, only relevant if osu_background_brightness is larger than 0");
-ConVar osu_background_color_b("osu_background_color_b", 255.0f, FCVAR_NONE,
+ConVar osu_background_color_b("osu_background_color_b", 255.0f, FCVAR_DEFAULT,
                               "0 to 255, only relevant if osu_background_brightness is larger than 0");
-ConVar osu_hiterrorbar_misaims("osu_hiterrorbar_misaims", true, FCVAR_NONE);
+ConVar osu_hiterrorbar_misaims("osu_hiterrorbar_misaims", true, FCVAR_DEFAULT);
 
 ConVar osu_followpoints_prevfadetime("osu_followpoints_prevfadetime", 400.0f,
-                                     FCVAR_NONE);  // TODO: this shouldn't be in this class
-
-ConVar osu_auto_and_relax_block_user_input("osu_auto_and_relax_block_user_input", true, FCVAR_NONE);
-
-ConVar osu_mod_timewarp("osu_mod_timewarp", false, FCVAR_NONVANILLA);
-ConVar osu_mod_timewarp_multiplier("osu_mod_timewarp_multiplier", 1.5f, FCVAR_NONE);
-ConVar osu_mod_minimize("osu_mod_minimize", false, FCVAR_NONVANILLA);
-ConVar osu_mod_minimize_multiplier("osu_mod_minimize_multiplier", 0.5f, FCVAR_CHEAT);
-ConVar osu_mod_jigsaw1("osu_mod_jigsaw1", false, FCVAR_NONVANILLA);
-ConVar osu_mod_artimewarp("osu_mod_artimewarp", false, FCVAR_NONVANILLA);
-ConVar osu_mod_artimewarp_multiplier("osu_mod_artimewarp_multiplier", 0.5f, FCVAR_NONE);
-ConVar osu_mod_arwobble("osu_mod_arwobble", false, FCVAR_NONVANILLA);
-ConVar osu_mod_arwobble_strength("osu_mod_arwobble_strength", 1.0f, FCVAR_CHEAT);
-ConVar osu_mod_arwobble_interval("osu_mod_arwobble_interval", 7.0f, FCVAR_CHEAT);
-ConVar osu_mod_fullalternate("osu_mod_fullalternate", false, FCVAR_NONE);
+                                     FCVAR_DEFAULT);  // TODO: this shouldn't be in this class
+
+ConVar osu_auto_and_relax_block_user_input("osu_auto_and_relax_block_user_input", true, FCVAR_DEFAULT);
+
+ConVar osu_mod_timewarp("osu_mod_timewarp", false, FCVAR_UNLOCKED);
+ConVar osu_mod_timewarp_multiplier("osu_mod_timewarp_multiplier", 1.5f, FCVAR_DEFAULT);
+ConVar osu_mod_minimize("osu_mod_minimize", false, FCVAR_UNLOCKED);
+ConVar osu_mod_minimize_multiplier("osu_mod_minimize_multiplier", 0.5f, FCVAR_LOCKED);
+ConVar osu_mod_jigsaw1("osu_mod_jigsaw1", false, FCVAR_UNLOCKED);
+ConVar osu_mod_artimewarp("osu_mod_artimewarp", false, FCVAR_UNLOCKED);
+ConVar osu_mod_artimewarp_multiplier("osu_mod_artimewarp_multiplier", 0.5f, FCVAR_DEFAULT);
+ConVar osu_mod_arwobble("osu_mod_arwobble", false, FCVAR_UNLOCKED);
+ConVar osu_mod_arwobble_strength("osu_mod_arwobble_strength", 1.0f, FCVAR_LOCKED);
+ConVar osu_mod_arwobble_interval("osu_mod_arwobble_interval", 7.0f, FCVAR_LOCKED);
+ConVar osu_mod_fullalternate("osu_mod_fullalternate", false, FCVAR_DEFAULT);
 
 ConVar osu_early_note_time(
-    "osu_early_note_time", 1500.0f, FCVAR_NONE,
+    "osu_early_note_time", 1500.0f, FCVAR_DEFAULT,
     "Timeframe in ms at the beginning of a beatmap which triggers a starting delay for easier reading");
 ConVar osu_quick_retry_time(
-    "osu_quick_retry_time", 2000.0f, FCVAR_NONE,
+    "osu_quick_retry_time", 2000.0f, FCVAR_DEFAULT,
     "Timeframe in ms subtracted from the first hitobject when quick retrying (not regular retry)");
-ConVar osu_end_delay_time("osu_end_delay_time", 750.0f, FCVAR_NONE,
+ConVar osu_end_delay_time("osu_end_delay_time", 750.0f, FCVAR_DEFAULT,
                           "Duration in ms which is added at the end of a beatmap after the last hitobject is finished "
                           "but before the ranking screen is automatically shown");
 ConVar osu_end_skip(
-    "osu_end_skip", true, FCVAR_NONE,
+    "osu_end_skip", true, FCVAR_DEFAULT,
     "whether the beatmap jumps to the ranking screen as soon as the last hitobject plus lenience has passed");
-ConVar osu_end_skip_time("osu_end_skip_time", 400.0f, FCVAR_NONE,
+ConVar osu_end_skip_time("osu_end_skip_time", 400.0f, FCVAR_DEFAULT,
                          "Duration in ms which is added to the endTime of the last hitobject, after which pausing the "
                          "game will immediately jump to the ranking screen");
-ConVar osu_skip_time("osu_skip_time", 5000.0f, FCVAR_CHEAT,
+ConVar osu_skip_time("osu_skip_time", 5000.0f, FCVAR_LOCKED,
                      "Timeframe in ms within a beatmap which allows skipping if it doesn't contain any hitobjects");
-ConVar osu_fail_time("osu_fail_time", 2.25f, FCVAR_NONE,
+ConVar osu_fail_time("osu_fail_time", 2.25f, FCVAR_DEFAULT,
                      "Timeframe in s for the slowdown effect after failing, before the pause menu is shown");
-ConVar osu_notelock_type("osu_notelock_type", 2, FCVAR_CHEAT,
+ConVar osu_notelock_type("osu_notelock_type", 2, FCVAR_LOCKED,
                          "which notelock algorithm to use (0 = None, 1 = neosu, 2 = osu!stable, 3 = osu!lazer 2020)");
-ConVar osu_notelock_stable_tolerance2b("osu_notelock_stable_tolerance2b", 3, FCVAR_CHEAT,
+ConVar osu_notelock_stable_tolerance2b("osu_notelock_stable_tolerance2b", 3, FCVAR_LOCKED,
                                        "time tolerance in milliseconds to allow hitting simultaneous objects close "
                                        "together (e.g. circle at end of slider)");
-ConVar osu_mod_suddendeath_restart("osu_mod_suddendeath_restart", false, FCVAR_NONE,
+ConVar osu_mod_suddendeath_restart("osu_mod_suddendeath_restart", false,
+                                   FCVAR_UNLOCK_SINGLEPLAYER | FCVAR_ALWAYS_SUBMIT,
                                    "osu! has this set to false (i.e. you fail after missing). if set to true, then "
                                    "behave like SS/PF, instantly restarting the map");
 
 ConVar osu_drain_type(
-    "osu_drain_type", 2, FCVAR_CHEAT,
+    "osu_drain_type", 2, FCVAR_LOCKED,
     "which hp drain algorithm to use (1 = None, 2 = osu!stable, 3 = osu!lazer 2020, 4 = osu!lazer 2018)");
-ConVar osu_drain_kill("osu_drain_kill", true, FCVAR_CHEAT, "whether to kill the player upon failing");
+ConVar osu_drain_kill("osu_drain_kill", true, FCVAR_LOCKED, "whether to kill the player upon failing");
 ConVar osu_drain_kill_notification_duration(
-    "osu_drain_kill_notification_duration", 1.0f, FCVAR_NONE,
+    "osu_drain_kill_notification_duration", 1.0f, FCVAR_DEFAULT,
     "how long to display the \"You have failed, but you can keep playing!\" notification (0 = disabled)");
 
-ConVar osu_drain_vr_duration("osu_drain_vr_duration", 0.35f, FCVAR_NONE);
+ConVar osu_drain_vr_duration("osu_drain_vr_duration", 0.35f, FCVAR_DEFAULT);
 ConVar osu_drain_stable_passive_fail(
-    "osu_drain_stable_passive_fail", false, FCVAR_NONE,
+    "osu_drain_stable_passive_fail", false, FCVAR_DEFAULT,
     "whether to fail the player instantly if health = 0, or only once a negative judgement occurs");
-ConVar osu_drain_stable_break_before("osu_drain_stable_break_before", false, FCVAR_NONE,
+ConVar osu_drain_stable_break_before("osu_drain_stable_break_before", false, FCVAR_DEFAULT,
                                      "drain after last hitobject before a break actually starts");
 ConVar osu_drain_stable_break_before_old(
-    "osu_drain_stable_break_before_old", true, FCVAR_NONE,
+    "osu_drain_stable_break_before_old", true, FCVAR_DEFAULT,
     "for beatmap versions < 8, drain after last hitobject before a break actually starts");
-ConVar osu_drain_stable_break_after("osu_drain_stable_break_after", false, FCVAR_NONE,
+ConVar osu_drain_stable_break_after("osu_drain_stable_break_after", false, FCVAR_DEFAULT,
                                     "drain after a break before the next hitobject can be clicked");
 ConVar osu_drain_lazer_passive_fail(
-    "osu_drain_lazer_passive_fail", false, FCVAR_NONE,
+    "osu_drain_lazer_passive_fail", false, FCVAR_DEFAULT,
     "whether to fail the player instantly if health = 0, or only once a negative judgement occurs");
-ConVar osu_drain_lazer_break_before("osu_drain_lazer_break_before", false, FCVAR_NONE,
+ConVar osu_drain_lazer_break_before("osu_drain_lazer_break_before", false, FCVAR_DEFAULT,
                                     "drain after last hitobject before a break actually starts");
-ConVar osu_drain_lazer_break_after("osu_drain_lazer_break_after", false, FCVAR_NONE,
+ConVar osu_drain_lazer_break_after("osu_drain_lazer_break_after", false, FCVAR_DEFAULT,
                                    "drain after a break before the next hitobject can be clicked");
-ConVar osu_drain_stable_spinner_nerf("osu_drain_stable_spinner_nerf", 0.25f, FCVAR_CHEAT,
+ConVar osu_drain_stable_spinner_nerf("osu_drain_stable_spinner_nerf", 0.25f, FCVAR_LOCKED,
                                      "drain gets multiplied with this while a spinner is active");
-ConVar osu_drain_stable_hpbar_recovery("osu_drain_stable_hpbar_recovery", 160.0f, FCVAR_CHEAT,
+ConVar osu_drain_stable_hpbar_recovery("osu_drain_stable_hpbar_recovery", 160.0f, FCVAR_LOCKED,
                                        "hp gets set to this value when failing with ez and causing a recovery");
 
-ConVar osu_play_hitsound_on_click_while_playing("osu_play_hitsound_on_click_while_playing", false, FCVAR_NONE);
+ConVar osu_play_hitsound_on_click_while_playing("osu_play_hitsound_on_click_while_playing", false, FCVAR_DEFAULT);
 
-ConVar osu_debug_draw_timingpoints("osu_debug_draw_timingpoints", false, FCVAR_CHEAT);
+ConVar osu_debug_draw_timingpoints("osu_debug_draw_timingpoints", false, FCVAR_LOCKED);
 
-ConVar osu_draw_followpoints("osu_draw_followpoints", true, FCVAR_NONE);
-ConVar osu_draw_reverse_order("osu_draw_reverse_order", false, FCVAR_NONE);
-ConVar osu_draw_playfield_border("osu_draw_playfield_border", true, FCVAR_NONE);
+ConVar osu_draw_followpoints("osu_draw_followpoints", true, FCVAR_DEFAULT);
+ConVar osu_draw_reverse_order("osu_draw_reverse_order", false, FCVAR_DEFAULT);
+ConVar osu_draw_playfield_border("osu_draw_playfield_border", true, FCVAR_DEFAULT);
 
-ConVar osu_stacking("osu_stacking", true, FCVAR_NONE, "Whether to use stacking calculations or not");
-ConVar osu_stacking_leniency_override("osu_stacking_leniency_override", -1.0f, FCVAR_NONE);
+ConVar osu_stacking("osu_stacking", true, FCVAR_DEFAULT, "Whether to use stacking calculations or not");
+ConVar osu_stacking_leniency_override("osu_stacking_leniency_override", -1.0f, FCVAR_DEFAULT);
 
-ConVar osu_auto_snapping_strength("osu_auto_snapping_strength", 1.0f, FCVAR_NONE,
+ConVar osu_auto_snapping_strength("osu_auto_snapping_strength", 1.0f, FCVAR_DEFAULT,
                                   "How many iterations of quadratic interpolation to use, more = snappier, 0 = linear");
-ConVar osu_auto_cursordance("osu_auto_cursordance", false, FCVAR_NONE);
+ConVar osu_auto_cursordance("osu_auto_cursordance", false, FCVAR_DEFAULT);
 ConVar osu_autopilot_snapping_strength(
-    "osu_autopilot_snapping_strength", 2.0f, FCVAR_NONE,
+    "osu_autopilot_snapping_strength", 2.0f, FCVAR_DEFAULT,
     "How many iterations of quadratic interpolation to use, more = snappier, 0 = linear");
-ConVar osu_autopilot_lenience("osu_autopilot_lenience", 0.75f, FCVAR_NONE);
+ConVar osu_autopilot_lenience("osu_autopilot_lenience", 0.75f, FCVAR_DEFAULT);
 
-ConVar osu_followpoints_clamp("osu_followpoints_clamp", false, FCVAR_NONE,
+ConVar osu_followpoints_clamp("osu_followpoints_clamp", false, FCVAR_DEFAULT,
                               "clamp followpoint approach time to current circle approach time (instead of using the "
                               "hardcoded default 800 ms raw)");
-ConVar osu_followpoints_anim("osu_followpoints_anim", false, FCVAR_NONE,
+ConVar osu_followpoints_anim("osu_followpoints_anim", false, FCVAR_DEFAULT,
                              "scale + move animation while fading in followpoints (osu only does this when its "
                              "internal default skin is being used)");
-ConVar osu_followpoints_connect_combos("osu_followpoints_connect_combos", false, FCVAR_NONE,
+ConVar osu_followpoints_connect_combos("osu_followpoints_connect_combos", false, FCVAR_DEFAULT,
                                        "connect followpoints even if a new combo has started");
-ConVar osu_followpoints_connect_spinners("osu_followpoints_connect_spinners", false, FCVAR_NONE,
+ConVar osu_followpoints_connect_spinners("osu_followpoints_connect_spinners", false, FCVAR_DEFAULT,
                                          "connect followpoints even through spinners");
-ConVar osu_followpoints_approachtime("osu_followpoints_approachtime", 800.0f, FCVAR_NONE);
-ConVar osu_followpoints_scale_multiplier("osu_followpoints_scale_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_followpoints_separation_multiplier("osu_followpoints_separation_multiplier", 1.0f, FCVAR_NONE);
+ConVar osu_followpoints_approachtime("osu_followpoints_approachtime", 800.0f, FCVAR_DEFAULT);
+ConVar osu_followpoints_scale_multiplier("osu_followpoints_scale_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_followpoints_separation_multiplier("osu_followpoints_separation_multiplier", 1.0f, FCVAR_DEFAULT);
 
-ConVar osu_number_scale_multiplier("osu_number_scale_multiplier", 1.0f, FCVAR_NONE);
+ConVar osu_number_scale_multiplier("osu_number_scale_multiplier", 1.0f, FCVAR_DEFAULT);
 
-ConVar osu_playfield_mirror_horizontal("osu_playfield_mirror_horizontal", false, FCVAR_NONE);
-ConVar osu_playfield_mirror_vertical("osu_playfield_mirror_vertical", false, FCVAR_NONE);
+ConVar osu_playfield_mirror_horizontal("osu_playfield_mirror_horizontal", false, FCVAR_DEFAULT);
+ConVar osu_playfield_mirror_vertical("osu_playfield_mirror_vertical", false, FCVAR_DEFAULT);
 
-ConVar osu_playfield_rotation("osu_playfield_rotation", 0.0f, FCVAR_CHEAT,
+ConVar osu_playfield_rotation("osu_playfield_rotation", 0.0f, FCVAR_LOCKED,
                               "rotates the entire playfield by this many degrees");
-ConVar osu_playfield_stretch_x("osu_playfield_stretch_x", 0.0f, FCVAR_CHEAT,
+ConVar osu_playfield_stretch_x("osu_playfield_stretch_x", 0.0f, FCVAR_LOCKED,
                                "offsets/multiplies all hitobject coordinates by it (0 = default 1x playfield size, -1 "
                                "= on a line, -0.5 = 0.5x playfield size, 0.5 = 1.5x playfield size)");
-ConVar osu_playfield_stretch_y("osu_playfield_stretch_y", 0.0f, FCVAR_CHEAT,
+ConVar osu_playfield_stretch_y("osu_playfield_stretch_y", 0.0f, FCVAR_LOCKED,
                                "offsets/multiplies all hitobject coordinates by it (0 = default 1x playfield size, -1 "
                                "= on a line, -0.5 = 0.5x playfield size, 0.5 = 1.5x playfield size)");
 ConVar osu_playfield_circular(
-    "osu_playfield_circular", false, FCVAR_CHEAT,
+    "osu_playfield_circular", false, FCVAR_LOCKED,
     "whether the playfield area should be transformed from a rectangle into a circle/disc/oval");
 
-ConVar osu_drain_lazer_health_min("osu_drain_lazer_health_min", 0.95f, FCVAR_NONE);
-ConVar osu_drain_lazer_health_mid("osu_drain_lazer_health_mid", 0.70f, FCVAR_NONE);
-ConVar osu_drain_lazer_health_max("osu_drain_lazer_health_max", 0.30f, FCVAR_NONE);
-
-ConVar osu_mod_wobble("osu_mod_wobble", false, FCVAR_NONVANILLA);
-ConVar osu_mod_wobble2("osu_mod_wobble2", false, FCVAR_NONVANILLA);
-ConVar osu_mod_wobble_strength("osu_mod_wobble_strength", 25.0f, FCVAR_NONE);
-ConVar osu_mod_wobble_frequency("osu_mod_wobble_frequency", 1.0f, FCVAR_NONE);
-ConVar osu_mod_wobble_rotation_speed("osu_mod_wobble_rotation_speed", 1.0f, FCVAR_NONE);
-ConVar osu_mod_jigsaw2("osu_mod_jigsaw2", false, FCVAR_NONVANILLA);
-ConVar osu_mod_jigsaw_followcircle_radius_factor("osu_mod_jigsaw_followcircle_radius_factor", 0.0f, FCVAR_NONE);
-ConVar osu_mod_shirone("osu_mod_shirone", false, FCVAR_NONVANILLA);
-ConVar osu_mod_shirone_combo("osu_mod_shirone_combo", 20.0f, FCVAR_NONE);
-ConVar osu_mod_mafham_render_chunksize("osu_mod_mafham_render_chunksize", 15, FCVAR_NONE,
+ConVar osu_drain_lazer_health_min("osu_drain_lazer_health_min", 0.95f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_health_mid("osu_drain_lazer_health_mid", 0.70f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_health_max("osu_drain_lazer_health_max", 0.30f, FCVAR_DEFAULT);
+
+ConVar osu_mod_wobble("osu_mod_wobble", false, FCVAR_UNLOCKED);
+ConVar osu_mod_wobble2("osu_mod_wobble2", false, FCVAR_UNLOCKED);
+ConVar osu_mod_wobble_strength("osu_mod_wobble_strength", 25.0f, FCVAR_DEFAULT);
+ConVar osu_mod_wobble_frequency("osu_mod_wobble_frequency", 1.0f, FCVAR_DEFAULT);
+ConVar osu_mod_wobble_rotation_speed("osu_mod_wobble_rotation_speed", 1.0f, FCVAR_DEFAULT);
+ConVar osu_mod_jigsaw2("osu_mod_jigsaw2", false, FCVAR_UNLOCKED);
+ConVar osu_mod_jigsaw_followcircle_radius_factor("osu_mod_jigsaw_followcircle_radius_factor", 0.0f, FCVAR_DEFAULT);
+ConVar osu_mod_shirone("osu_mod_shirone", false, FCVAR_UNLOCKED);
+ConVar osu_mod_shirone_combo("osu_mod_shirone_combo", 20.0f, FCVAR_DEFAULT);
+ConVar osu_mod_mafham_render_chunksize("osu_mod_mafham_render_chunksize", 15, FCVAR_DEFAULT,
                                        "render this many hitobjects per frame chunk into the scene buffer (spreads "
                                        "rendering across many frames to minimize lag)");
 
-ConVar osu_mandala("osu_mandala", false, FCVAR_CHEAT);
-ConVar osu_mandala_num("osu_mandala_num", 7, FCVAR_NONE);
+ConVar osu_mandala("osu_mandala", false, FCVAR_LOCKED);
+ConVar osu_mandala_num("osu_mandala_num", 7, FCVAR_DEFAULT);
 
-ConVar osu_debug_hiterrorbar_misaims("osu_debug_hiterrorbar_misaims", false, FCVAR_NONE);
+ConVar osu_debug_hiterrorbar_misaims("osu_debug_hiterrorbar_misaims", false, FCVAR_DEFAULT);
 
 ConVar osu_pp_live_timeout(
-    "osu_pp_live_timeout", 1.0f, FCVAR_NONE,
+    "osu_pp_live_timeout", 1.0f, FCVAR_DEFAULT,
     "show message that we're still calculating stars after this many seconds, on the first start of the beatmap");
 
 Beatmap::Beatmap(Osu *osu) {
@@ -1075,7 +1076,7 @@ void Beatmap::fail() {
     // Change behavior of relax mod when online
     if(bancho.is_online() && m_osu->getModRelax()) return;
 
-    if(!bancho.is_playing_a_multi_map() && osu_drain_kill.getBool()) {
+    if(osu_drain_kill.getBool()) {
         engine->getSound()->play(getSkin()->getFailsound());
 
         m_bFailed = true;
@@ -1478,7 +1479,7 @@ LiveScore::HIT Beatmap::addHitResult(HitObject *hitObject, LiveScore::HIT hit, l
         }
     } else if(m_osu->getModSD()) {
         if(hit == LiveScore::HIT::HIT_MISS) {
-            if(osu_mod_suddendeath_restart.getBool() && !bancho.is_in_a_multi_room())
+            if(osu_mod_suddendeath_restart.getBool())
                 restart();
             else
                 fail();

+ 1 - 0
src/App/Osu/Changelog.cpp

@@ -29,6 +29,7 @@ Changelog::Changelog(Osu *osu) : ScreenBackable(osu) {
     CHANGELOG latest;
     latest.title =
         UString::format("%.2f (%s, %s)", convar->getConVarByName("osu_version")->getFloat(), __DATE__, __TIME__);
+    latest.changes.push_back("- Added option for servers to override convars using neosu.json");
     latest.changes.push_back("- Hid password cvar from console command list");
     latest.changes.push_back("- Removed DirectX, Software, Vulkan renderers");
     latest.changes.push_back("- Removed OpenCL support");

+ 11 - 11
src/App/Osu/Circle.cpp

@@ -24,20 +24,20 @@
 #include "SkinImage.h"
 #include "SoundEngine.h"
 
-ConVar osu_bug_flicker_log("osu_bug_flicker_log", false, FCVAR_NONE);
+ConVar osu_bug_flicker_log("osu_bug_flicker_log", false, FCVAR_DEFAULT);
 
-ConVar osu_circle_color_saturation("osu_circle_color_saturation", 1.0f, FCVAR_NONE);
-ConVar osu_circle_rainbow("osu_circle_rainbow", false, FCVAR_NONE);
-ConVar osu_circle_number_rainbow("osu_circle_number_rainbow", false, FCVAR_NONE);
-ConVar osu_circle_shake_duration("osu_circle_shake_duration", 0.120f, FCVAR_NONE);
-ConVar osu_circle_shake_strength("osu_circle_shake_strength", 8.0f, FCVAR_NONE);
-ConVar osu_approach_circle_alpha_multiplier("osu_approach_circle_alpha_multiplier", 0.9f, FCVAR_NONE);
+ConVar osu_circle_color_saturation("osu_circle_color_saturation", 1.0f, FCVAR_DEFAULT);
+ConVar osu_circle_rainbow("osu_circle_rainbow", false, FCVAR_DEFAULT);
+ConVar osu_circle_number_rainbow("osu_circle_number_rainbow", false, FCVAR_DEFAULT);
+ConVar osu_circle_shake_duration("osu_circle_shake_duration", 0.120f, FCVAR_DEFAULT);
+ConVar osu_circle_shake_strength("osu_circle_shake_strength", 8.0f, FCVAR_DEFAULT);
+ConVar osu_approach_circle_alpha_multiplier("osu_approach_circle_alpha_multiplier", 0.9f, FCVAR_DEFAULT);
 
-ConVar osu_draw_numbers("osu_draw_numbers", true, FCVAR_NONE);
-ConVar osu_draw_circles("osu_draw_circles", true, FCVAR_NONE);
-ConVar osu_draw_approach_circles("osu_draw_approach_circles", true, FCVAR_NONE);
+ConVar osu_draw_numbers("osu_draw_numbers", true, FCVAR_DEFAULT);
+ConVar osu_draw_circles("osu_draw_circles", true, FCVAR_DEFAULT);
+ConVar osu_draw_approach_circles("osu_draw_approach_circles", true, FCVAR_DEFAULT);
 
-ConVar osu_slider_draw_endcircle("osu_slider_draw_endcircle", true, FCVAR_NONE);
+ConVar osu_slider_draw_endcircle("osu_slider_draw_endcircle", true, FCVAR_DEFAULT);
 
 int Circle::rainbowNumber = 0;
 int Circle::rainbowColorCounter = 0;

+ 24 - 21
src/App/Osu/Database.cpp

@@ -27,47 +27,50 @@
 
 #ifdef _WIN32
 
-ConVar osu_folder("osu_folder", "C:/Program Files (x86)/osu!/", FCVAR_NONE);
+ConVar osu_folder("osu_folder", "C:/Program Files (x86)/osu!/", FCVAR_DEFAULT);
 
 #elif defined __APPLE__
 
-ConVar osu_folder("osu_folder", "/osu!/", FCVAR_NONE);
+ConVar osu_folder("osu_folder", "/osu!/", FCVAR_DEFAULT);
 
 #else
 
-ConVar osu_folder("osu_folder", "", FCVAR_NONE);
+ConVar osu_folder("osu_folder", "", FCVAR_DEFAULT);
 
 #endif
 
-ConVar osu_folder_sub_songs("osu_folder_sub_songs", "Songs/", FCVAR_NONE);
-ConVar osu_folder_sub_skins("osu_folder_sub_skins", "Skins/", FCVAR_NONE);
+ConVar osu_folder_sub_songs("osu_folder_sub_songs", "Songs/", FCVAR_DEFAULT);
+ConVar osu_folder_sub_skins("osu_folder_sub_skins", "Skins/", FCVAR_DEFAULT);
 
-ConVar osu_database_enabled("osu_database_enabled", true, FCVAR_NONE);
-ConVar osu_database_version("osu_database_version", OSU_VERSION_DATEONLY, FCVAR_NONE,
+ConVar osu_database_enabled("osu_database_enabled", true, FCVAR_DEFAULT);
+ConVar osu_database_version("osu_database_version", OSU_VERSION_DATEONLY, FCVAR_DEFAULT,
                             "maximum supported osu!.db version, above this will use fallback loader");
-ConVar osu_database_ignore_version_warnings("osu_database_ignore_version_warnings", false, FCVAR_NONE);
-ConVar osu_database_ignore_version("osu_database_ignore_version", true, FCVAR_NONE,
+ConVar osu_database_ignore_version_warnings("osu_database_ignore_version_warnings", false, FCVAR_DEFAULT);
+ConVar osu_database_ignore_version("osu_database_ignore_version", true, FCVAR_DEFAULT,
                                    "ignore upper version limit and force load the db file (may crash)");
-ConVar osu_scores_enabled("osu_scores_enabled", true, FCVAR_NONE);
-ConVar osu_scores_legacy_enabled("osu_scores_legacy_enabled", true, FCVAR_NONE, "load osu!'s scores.db");
-ConVar osu_scores_custom_enabled("osu_scores_custom_enabled", true, FCVAR_NONE, "load custom scores.db");
-ConVar osu_scores_save_immediately("osu_scores_save_immediately", true, FCVAR_NONE,
+ConVar osu_scores_enabled("osu_scores_enabled", true, FCVAR_DEFAULT);
+ConVar osu_scores_legacy_enabled("osu_scores_legacy_enabled", true, FCVAR_DEFAULT, "load osu!'s scores.db");
+ConVar osu_scores_custom_enabled("osu_scores_custom_enabled", true, FCVAR_DEFAULT, "load custom scores.db");
+ConVar osu_scores_save_immediately("osu_scores_save_immediately", true, FCVAR_DEFAULT,
                                    "write scores.db as soon as a new score is added");
-ConVar osu_scores_sort_by_pp("osu_scores_sort_by_pp", true, FCVAR_NONE, "display pp in score browser instead of score");
-ConVar osu_scores_bonus_pp("osu_scores_bonus_pp", true, FCVAR_NONE,
+ConVar osu_scores_sort_by_pp("osu_scores_sort_by_pp", true, FCVAR_DEFAULT,
+                             "display pp in score browser instead of score");
+ConVar osu_scores_bonus_pp("osu_scores_bonus_pp", true, FCVAR_DEFAULT,
                            "whether to add bonus pp to total (real) pp or not");
 ConVar osu_scores_rename("osu_scores_rename");
 ConVar osu_scores_export("osu_scores_export");
-ConVar osu_collections_legacy_enabled("osu_collections_legacy_enabled", true, FCVAR_NONE, "load osu!'s collection.db");
-ConVar osu_collections_custom_enabled("osu_collections_custom_enabled", true, FCVAR_NONE, "load custom collections.db");
-ConVar osu_collections_custom_version("osu_collections_custom_version", 20220110, FCVAR_NONE,
+ConVar osu_collections_legacy_enabled("osu_collections_legacy_enabled", true, FCVAR_DEFAULT,
+                                      "load osu!'s collection.db");
+ConVar osu_collections_custom_enabled("osu_collections_custom_enabled", true, FCVAR_DEFAULT,
+                                      "load custom collections.db");
+ConVar osu_collections_custom_version("osu_collections_custom_version", 20220110, FCVAR_DEFAULT,
                                       "maximum supported custom collections.db version");
-ConVar osu_collections_save_immediately("osu_collections_save_immediately", true, FCVAR_NONE,
+ConVar osu_collections_save_immediately("osu_collections_save_immediately", true, FCVAR_DEFAULT,
                                         "write collections.db as soon as anything is changed");
 ConVar osu_user_include_relax_and_autopilot_for_stats("osu_user_include_relax_and_autopilot_for_stats", false,
-                                                      FCVAR_NONE);
+                                                      FCVAR_DEFAULT);
 ConVar osu_user_switcher_include_legacy_scores_for_names("osu_user_switcher_include_legacy_scores_for_names", true,
-                                                         FCVAR_NONE);
+                                                         FCVAR_DEFAULT);
 
 Packet load_db(std::string path) {
     Packet db;

+ 20 - 20
src/App/Osu/DatabaseBeatmap.cpp

@@ -29,51 +29,51 @@
 #include "SongBrowser/SongBrowser.h"
 #include "Spinner.h"
 
-ConVar osu_mod_random("osu_mod_random", false, FCVAR_NONVANILLA);
+ConVar osu_mod_random("osu_mod_random", false, FCVAR_UNLOCKED);
 ConVar osu_mod_random_seed(
-    "osu_mod_random_seed", 0, FCVAR_NONE,
+    "osu_mod_random_seed", 0, FCVAR_DEFAULT,
     "0 = random seed every reload, any other value will force that value to be used as the seed");
-ConVar osu_mod_random_circle_offset_x_percent("osu_mod_random_circle_offset_x_percent", 1.0f, FCVAR_NONE,
+ConVar osu_mod_random_circle_offset_x_percent("osu_mod_random_circle_offset_x_percent", 1.0f, FCVAR_DEFAULT,
                                               "how much the randomness affects things");
-ConVar osu_mod_random_circle_offset_y_percent("osu_mod_random_circle_offset_y_percent", 1.0f, FCVAR_NONE,
+ConVar osu_mod_random_circle_offset_y_percent("osu_mod_random_circle_offset_y_percent", 1.0f, FCVAR_DEFAULT,
                                               "how much the randomness affects things");
-ConVar osu_mod_random_slider_offset_x_percent("osu_mod_random_slider_offset_x_percent", 1.0f, FCVAR_NONE,
+ConVar osu_mod_random_slider_offset_x_percent("osu_mod_random_slider_offset_x_percent", 1.0f, FCVAR_DEFAULT,
                                               "how much the randomness affects things");
-ConVar osu_mod_random_slider_offset_y_percent("osu_mod_random_slider_offset_y_percent", 1.0f, FCVAR_NONE,
+ConVar osu_mod_random_slider_offset_y_percent("osu_mod_random_slider_offset_y_percent", 1.0f, FCVAR_DEFAULT,
                                               "how much the randomness affects things");
-ConVar osu_mod_random_spinner_offset_x_percent("osu_mod_random_spinner_offset_x_percent", 1.0f, FCVAR_NONE,
+ConVar osu_mod_random_spinner_offset_x_percent("osu_mod_random_spinner_offset_x_percent", 1.0f, FCVAR_DEFAULT,
                                                "how much the randomness affects things");
-ConVar osu_mod_random_spinner_offset_y_percent("osu_mod_random_spinner_offset_y_percent", 1.0f, FCVAR_NONE,
+ConVar osu_mod_random_spinner_offset_y_percent("osu_mod_random_spinner_offset_y_percent", 1.0f, FCVAR_DEFAULT,
                                                "how much the randomness affects things");
-ConVar osu_mod_reverse_sliders("osu_mod_reverse_sliders", false, FCVAR_NONVANILLA);
-ConVar osu_mod_strict_tracking("osu_mod_strict_tracking", false, FCVAR_NONVANILLA);
-ConVar osu_mod_strict_tracking_remove_slider_ticks("osu_mod_strict_tracking_remove_slider_ticks", false, FCVAR_CHEAT,
+ConVar osu_mod_reverse_sliders("osu_mod_reverse_sliders", false, FCVAR_UNLOCKED);
+ConVar osu_mod_strict_tracking("osu_mod_strict_tracking", false, FCVAR_UNLOCKED);
+ConVar osu_mod_strict_tracking_remove_slider_ticks("osu_mod_strict_tracking_remove_slider_ticks", false, FCVAR_LOCKED,
                                                    "whether the strict tracking mod should remove slider ticks or not, "
                                                    "this changed after its initial implementation in lazer");
 
 ConVar osu_show_approach_circle_on_first_hidden_object("osu_show_approach_circle_on_first_hidden_object", true,
-                                                       FCVAR_NONE);
+                                                       FCVAR_DEFAULT);
 
-ConVar osu_stars_stacking("osu_stars_stacking", true, FCVAR_NONE,
+ConVar osu_stars_stacking("osu_stars_stacking", true, FCVAR_DEFAULT,
                           "respect hitobject stacking before calculating stars/pp");
 
-ConVar osu_slider_max_repeats("osu_slider_max_repeats", 9000, FCVAR_CHEAT,
+ConVar osu_slider_max_repeats("osu_slider_max_repeats", 9000, FCVAR_LOCKED,
                               "maximum number of repeats allowed per slider (clamp range)");
-ConVar osu_slider_max_ticks("osu_slider_max_ticks", 2048, FCVAR_CHEAT,
+ConVar osu_slider_max_ticks("osu_slider_max_ticks", 2048, FCVAR_LOCKED,
                             "maximum number of ticks allowed per slider (clamp range)");
 
-ConVar osu_number_max("osu_number_max", 0, FCVAR_NONE,
+ConVar osu_number_max("osu_number_max", 0, FCVAR_DEFAULT,
                       "0 = disabled, 1/2/3/4/etc. limits visual circle numbers to this number");
-ConVar osu_ignore_beatmap_combo_numbers("osu_ignore_beatmap_combo_numbers", false, FCVAR_NONE,
+ConVar osu_ignore_beatmap_combo_numbers("osu_ignore_beatmap_combo_numbers", false, FCVAR_DEFAULT,
                                         "may be used in conjunction with osu_number_max");
 
-ConVar osu_beatmap_version("osu_beatmap_version", 128, FCVAR_NONE,
+ConVar osu_beatmap_version("osu_beatmap_version", 128, FCVAR_DEFAULT,
                            "maximum supported .osu file version, above this will simply not load (this was 14 but got "
                            "bumped to 128 due to lazer backports)");
 ConVar osu_beatmap_max_num_hitobjects(
-    "osu_beatmap_max_num_hitobjects", 40000, FCVAR_NONE,
+    "osu_beatmap_max_num_hitobjects", 40000, FCVAR_DEFAULT,
     "maximum number of total allowed hitobjects per beatmap (prevent crashing on deliberate game-breaking beatmaps)");
-ConVar osu_beatmap_max_num_slider_scoringtimes("osu_beatmap_max_num_slider_scoringtimes", 32768, FCVAR_NONE,
+ConVar osu_beatmap_max_num_slider_scoringtimes("osu_beatmap_max_num_slider_scoringtimes", 32768, FCVAR_DEFAULT,
                                                "maximum number of slider score increase events allowed per slider "
                                                "(prevent crashing on deliberate game-breaking beatmaps)");
 

+ 3 - 3
src/App/Osu/DifficultyCalculator.cpp

@@ -15,13 +15,13 @@
 #include "Replay.h"
 #include "SliderCurves.h"
 
-ConVar osu_stars_xexxar_angles_sliders("osu_stars_xexxar_angles_sliders", true, FCVAR_NONE,
+ConVar osu_stars_xexxar_angles_sliders("osu_stars_xexxar_angles_sliders", true, FCVAR_DEFAULT,
                                        "completely enables/disables the new star/pp calc algorithm");
 ConVar osu_stars_slider_curve_points_separation(
-    "osu_stars_slider_curve_points_separation", 20.0f, FCVAR_NONE,
+    "osu_stars_slider_curve_points_separation", 20.0f, FCVAR_DEFAULT,
     "massively reduce curve accuracy for star calculations to save memory/performance");
 ConVar osu_stars_and_pp_lazer_relax_autopilot_nerf_disabled(
-    "osu_stars_and_pp_lazer_relax_autopilot_nerf_disabled", true, FCVAR_NONE,
+    "osu_stars_and_pp_lazer_relax_autopilot_nerf_disabled", true, FCVAR_DEFAULT,
     "generally disables all nerfs for relax/autopilot in both star/pp algorithms. since neosu has always allowed "
     "these, the default is to not nerf them.");
 

+ 45 - 43
src/App/Osu/GameRules.cpp

@@ -7,77 +7,79 @@
 
 #include "GameRules.h"
 
-ConVar GameRules::osu_playfield_border_top_percent("osu_playfield_border_top_percent", 0.117f, FCVAR_NONE);
-ConVar GameRules::osu_playfield_border_bottom_percent("osu_playfield_border_bottom_percent", 0.0834f, FCVAR_NONE);
+ConVar GameRules::osu_playfield_border_top_percent("osu_playfield_border_top_percent", 0.117f, FCVAR_DEFAULT);
+ConVar GameRules::osu_playfield_border_bottom_percent("osu_playfield_border_bottom_percent", 0.0834f, FCVAR_DEFAULT);
 
 ConVar GameRules::osu_hitobject_hittable_dim(
-    "osu_hitobject_hittable_dim", true, FCVAR_NONE,
+    "osu_hitobject_hittable_dim", true, FCVAR_DEFAULT,
     "whether to dim objects not yet within the miss-range (when they can't even be missed yet)");
 ConVar GameRules::osu_hitobject_hittable_dim_start_percent(
-    "osu_hitobject_hittable_dim_start_percent", 0.7647f, FCVAR_NONE,
+    "osu_hitobject_hittable_dim_start_percent", 0.7647f, FCVAR_DEFAULT,
     "dimmed objects start at this brightness value before becoming fullbright (only RGB, this does not affect "
     "alpha/transparency)");
-ConVar GameRules::osu_hitobject_hittable_dim_duration("osu_hitobject_hittable_dim_duration", 100, FCVAR_NONE,
+ConVar GameRules::osu_hitobject_hittable_dim_duration("osu_hitobject_hittable_dim_duration", 100, FCVAR_DEFAULT,
                                                       "in milliseconds (!)");
 
-ConVar GameRules::osu_hitobject_fade_in_time("osu_hitobject_fade_in_time", 400, FCVAR_CHEAT, "in milliseconds (!)");
-ConVar GameRules::osu_hitobject_fade_out_time("osu_hitobject_fade_out_time", 0.293f, FCVAR_CHEAT, "in seconds (!)");
+ConVar GameRules::osu_hitobject_fade_in_time("osu_hitobject_fade_in_time", 400, FCVAR_LOCKED, "in milliseconds (!)");
+ConVar GameRules::osu_hitobject_fade_out_time("osu_hitobject_fade_out_time", 0.293f, FCVAR_LOCKED, "in seconds (!)");
 ConVar GameRules::osu_hitobject_fade_out_time_speed_multiplier_min(
-    "osu_hitobject_fade_out_time_speed_multiplier_min", 0.5f, FCVAR_CHEAT,
+    "osu_hitobject_fade_out_time_speed_multiplier_min", 0.5f, FCVAR_LOCKED,
     "The minimum multiplication factor allowed for the speed multiplier influencing the fadeout duration");
 
-ConVar GameRules::osu_circle_fade_out_scale("osu_circle_fade_out_scale", 0.4f, FCVAR_CHEAT);
+ConVar GameRules::osu_circle_fade_out_scale("osu_circle_fade_out_scale", 0.4f, FCVAR_LOCKED);
 
 ConVar GameRules::osu_slider_followcircle_fadein_fade_time("osu_slider_followcircle_fadein_fade_time", 0.06f,
-                                                           FCVAR_NONE);
+                                                           FCVAR_DEFAULT);
 ConVar GameRules::osu_slider_followcircle_fadeout_fade_time("osu_slider_followcircle_fadeout_fade_time", 0.25f,
-                                                            FCVAR_NONE);
-ConVar GameRules::osu_slider_followcircle_fadein_scale("osu_slider_followcircle_fadein_scale", 0.5f, FCVAR_NONE);
+                                                            FCVAR_DEFAULT);
+ConVar GameRules::osu_slider_followcircle_fadein_scale("osu_slider_followcircle_fadein_scale", 0.5f, FCVAR_DEFAULT);
 ConVar GameRules::osu_slider_followcircle_fadein_scale_time("osu_slider_followcircle_fadein_scale_time", 0.18f,
-                                                            FCVAR_NONE);
-ConVar GameRules::osu_slider_followcircle_fadeout_scale("osu_slider_followcircle_fadeout_scale", 0.8f, FCVAR_NONE);
+                                                            FCVAR_DEFAULT);
+ConVar GameRules::osu_slider_followcircle_fadeout_scale("osu_slider_followcircle_fadeout_scale", 0.8f, FCVAR_DEFAULT);
 ConVar GameRules::osu_slider_followcircle_fadeout_scale_time("osu_slider_followcircle_fadeout_scale_time", 0.25f,
-                                                             FCVAR_NONE);
-ConVar GameRules::osu_slider_followcircle_tick_pulse_time("osu_slider_followcircle_tick_pulse_time", 0.2f, FCVAR_NONE);
+                                                             FCVAR_DEFAULT);
+ConVar GameRules::osu_slider_followcircle_tick_pulse_time("osu_slider_followcircle_tick_pulse_time", 0.2f,
+                                                          FCVAR_DEFAULT);
 ConVar GameRules::osu_slider_followcircle_tick_pulse_scale("osu_slider_followcircle_tick_pulse_scale", 0.1f,
-                                                           FCVAR_NONE);
+                                                           FCVAR_DEFAULT);
 
-ConVar GameRules::osu_spinner_fade_out_time_multiplier("osu_spinner_fade_out_time_multiplier", 0.7f, FCVAR_CHEAT);
+ConVar GameRules::osu_spinner_fade_out_time_multiplier("osu_spinner_fade_out_time_multiplier", 0.7f, FCVAR_LOCKED);
 
-ConVar GameRules::osu_slider_followcircle_size_multiplier("osu_slider_followcircle_size_multiplier", 2.4f, FCVAR_CHEAT);
+ConVar GameRules::osu_slider_followcircle_size_multiplier("osu_slider_followcircle_size_multiplier", 2.4f,
+                                                          FCVAR_LOCKED);
 
-ConVar GameRules::osu_mod_fps("osu_mod_fps", false, FCVAR_NONVANILLA);
-ConVar GameRules::osu_mod_no50s("osu_mod_no50s", false, FCVAR_NONVANILLA);
-ConVar GameRules::osu_mod_no100s("osu_mod_no100s", false, FCVAR_NONVANILLA);
-ConVar GameRules::osu_mod_ming3012("osu_mod_ming3012", false, FCVAR_NONVANILLA);
-ConVar GameRules::osu_mod_millhioref("osu_mod_millhioref", false, FCVAR_NONVANILLA);
-ConVar GameRules::osu_mod_millhioref_multiplier("osu_mod_millhioref_multiplier", 2.0f, FCVAR_CHEAT);
-ConVar GameRules::osu_mod_mafham("osu_mod_mafham", false, FCVAR_NONVANILLA);
+ConVar GameRules::osu_mod_fps("osu_mod_fps", false, FCVAR_UNLOCKED);
+ConVar GameRules::osu_mod_no50s("osu_mod_no50s", false, FCVAR_UNLOCKED);
+ConVar GameRules::osu_mod_no100s("osu_mod_no100s", false, FCVAR_UNLOCKED);
+ConVar GameRules::osu_mod_ming3012("osu_mod_ming3012", false, FCVAR_UNLOCKED);
+ConVar GameRules::osu_mod_millhioref("osu_mod_millhioref", false, FCVAR_UNLOCKED);
+ConVar GameRules::osu_mod_millhioref_multiplier("osu_mod_millhioref_multiplier", 2.0f, FCVAR_LOCKED);
+ConVar GameRules::osu_mod_mafham("osu_mod_mafham", false, FCVAR_UNLOCKED);
 ConVar GameRules::osu_mod_mafham_render_livesize(
-    "osu_mod_mafham_render_livesize", 25, FCVAR_NONE,
+    "osu_mod_mafham_render_livesize", 25, FCVAR_DEFAULT,
     "render this many hitobjects without any scene buffering, higher = more lag but more up-to-date scene");
-ConVar GameRules::osu_stacking_ar_override("osu_stacking_ar_override", -1, FCVAR_CHEAT,
+ConVar GameRules::osu_stacking_ar_override("osu_stacking_ar_override", -1, FCVAR_LOCKED,
                                            "allows overriding the approach time used for the stacking calculations. "
                                            "behaves as if disabled if the value is less than 0.");
-ConVar GameRules::osu_mod_halfwindow("osu_mod_halfwindow", false, FCVAR_NONVANILLA);
-ConVar GameRules::osu_mod_halfwindow_allow_300s("osu_mod_halfwindow_allow_300s", true, FCVAR_NONE,
+ConVar GameRules::osu_mod_halfwindow("osu_mod_halfwindow", false, FCVAR_UNLOCKED);
+ConVar GameRules::osu_mod_halfwindow_allow_300s("osu_mod_halfwindow_allow_300s", true, FCVAR_DEFAULT,
                                                 "should positive hit deltas be allowed within 300 range");
 
 // all values here are in milliseconds
-ConVar GameRules::osu_approachtime_min("osu_approachtime_min", 1800, FCVAR_CHEAT);
-ConVar GameRules::osu_approachtime_mid("osu_approachtime_mid", 1200, FCVAR_CHEAT);
-ConVar GameRules::osu_approachtime_max("osu_approachtime_max", 450, FCVAR_CHEAT);
+ConVar GameRules::osu_approachtime_min("osu_approachtime_min", 1800, FCVAR_LOCKED);
+ConVar GameRules::osu_approachtime_mid("osu_approachtime_mid", 1200, FCVAR_LOCKED);
+ConVar GameRules::osu_approachtime_max("osu_approachtime_max", 450, FCVAR_LOCKED);
 
-ConVar GameRules::osu_hitwindow_300_min("osu_hitwindow_300_min", 80, FCVAR_CHEAT);
-ConVar GameRules::osu_hitwindow_300_mid("osu_hitwindow_300_mid", 50, FCVAR_CHEAT);
-ConVar GameRules::osu_hitwindow_300_max("osu_hitwindow_300_max", 20, FCVAR_CHEAT);
+ConVar GameRules::osu_hitwindow_300_min("osu_hitwindow_300_min", 80, FCVAR_LOCKED);
+ConVar GameRules::osu_hitwindow_300_mid("osu_hitwindow_300_mid", 50, FCVAR_LOCKED);
+ConVar GameRules::osu_hitwindow_300_max("osu_hitwindow_300_max", 20, FCVAR_LOCKED);
 
-ConVar GameRules::osu_hitwindow_100_min("osu_hitwindow_100_min", 140, FCVAR_CHEAT);
-ConVar GameRules::osu_hitwindow_100_mid("osu_hitwindow_100_mid", 100, FCVAR_CHEAT);
-ConVar GameRules::osu_hitwindow_100_max("osu_hitwindow_100_max", 60, FCVAR_CHEAT);
+ConVar GameRules::osu_hitwindow_100_min("osu_hitwindow_100_min", 140, FCVAR_LOCKED);
+ConVar GameRules::osu_hitwindow_100_mid("osu_hitwindow_100_mid", 100, FCVAR_LOCKED);
+ConVar GameRules::osu_hitwindow_100_max("osu_hitwindow_100_max", 60, FCVAR_LOCKED);
 
-ConVar GameRules::osu_hitwindow_50_min("osu_hitwindow_50_min", 200, FCVAR_CHEAT);
-ConVar GameRules::osu_hitwindow_50_mid("osu_hitwindow_50_mid", 150, FCVAR_CHEAT);
-ConVar GameRules::osu_hitwindow_50_max("osu_hitwindow_50_max", 100, FCVAR_CHEAT);
+ConVar GameRules::osu_hitwindow_50_min("osu_hitwindow_50_min", 200, FCVAR_LOCKED);
+ConVar GameRules::osu_hitwindow_50_mid("osu_hitwindow_50_mid", 150, FCVAR_LOCKED);
+ConVar GameRules::osu_hitwindow_50_max("osu_hitwindow_50_max", 100, FCVAR_LOCKED);
 
-ConVar GameRules::osu_hitwindow_miss("osu_hitwindow_miss", 400, FCVAR_CHEAT);
+ConVar GameRules::osu_hitwindow_miss("osu_hitwindow_miss", 400, FCVAR_LOCKED);

+ 183 - 179
src/App/Osu/HUD.cpp

@@ -36,215 +36,219 @@
 #include "VertexArrayObject.h"
 #include "score.h"
 
-ConVar osu_automatic_cursor_size("osu_automatic_cursor_size", false, FCVAR_NONE);
-
-ConVar osu_cursor_alpha("osu_cursor_alpha", 1.0f, FCVAR_NONE);
-ConVar osu_cursor_scale("osu_cursor_scale", 1.0f, FCVAR_NONE);
-ConVar osu_cursor_expand_scale_multiplier("osu_cursor_expand_scale_multiplier", 1.3f, FCVAR_NONE);
-ConVar osu_cursor_expand_duration("osu_cursor_expand_duration", 0.1f, FCVAR_NONE);
-ConVar osu_cursor_trail_scale("osu_cursor_trail_scale", 1.0f, FCVAR_NONE);
-ConVar osu_cursor_trail_length("osu_cursor_trail_length", 0.17f, FCVAR_NONE,
+ConVar osu_automatic_cursor_size("osu_automatic_cursor_size", false, FCVAR_DEFAULT);
+
+ConVar osu_cursor_alpha("osu_cursor_alpha", 1.0f, FCVAR_DEFAULT);
+ConVar osu_cursor_scale("osu_cursor_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_cursor_expand_scale_multiplier("osu_cursor_expand_scale_multiplier", 1.3f, FCVAR_DEFAULT);
+ConVar osu_cursor_expand_duration("osu_cursor_expand_duration", 0.1f, FCVAR_DEFAULT);
+ConVar osu_cursor_trail_scale("osu_cursor_trail_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_cursor_trail_length("osu_cursor_trail_length", 0.17f, FCVAR_DEFAULT,
                                "how long unsmooth cursortrails should be, in seconds");
 ConVar osu_cursor_trail_spacing(
-    "osu_cursor_trail_spacing", 0.015f, FCVAR_NONE,
+    "osu_cursor_trail_spacing", 0.015f, FCVAR_DEFAULT,
     "how big the gap between consecutive unsmooth cursortrail images should be, in seconds");
-ConVar osu_cursor_trail_alpha("osu_cursor_trail_alpha", 1.0f, FCVAR_NONE);
-ConVar osu_cursor_trail_smooth_force("osu_cursor_trail_smooth_force", false, FCVAR_NONE);
-ConVar osu_cursor_trail_smooth_length("osu_cursor_trail_smooth_length", 0.5f, FCVAR_NONE,
+ConVar osu_cursor_trail_alpha("osu_cursor_trail_alpha", 1.0f, FCVAR_DEFAULT);
+ConVar osu_cursor_trail_smooth_force("osu_cursor_trail_smooth_force", false, FCVAR_DEFAULT);
+ConVar osu_cursor_trail_smooth_length("osu_cursor_trail_smooth_length", 0.5f, FCVAR_DEFAULT,
                                       "how long smooth cursortrails should be, in seconds");
 ConVar osu_cursor_trail_smooth_div(
-    "osu_cursor_trail_smooth_div", 4.0f, FCVAR_NONE,
+    "osu_cursor_trail_smooth_div", 4.0f, FCVAR_DEFAULT,
     "divide the cursortrail.png image size by this much, for determining the distance to the next trail image");
-ConVar osu_cursor_trail_max_size("osu_cursor_trail_max_size", 2048, FCVAR_NONE,
+ConVar osu_cursor_trail_max_size("osu_cursor_trail_max_size", 2048, FCVAR_DEFAULT,
                                  "maximum number of rendered trail images, array size limit");
 ConVar osu_cursor_trail_expand(
-    "osu_cursor_trail_expand", true, FCVAR_NONE,
+    "osu_cursor_trail_expand", true, FCVAR_DEFAULT,
     "if \"CursorExpand: 1\" in your skin.ini, whether the trail should then also expand or not");
-ConVar osu_cursor_ripple_duration("osu_cursor_ripple_duration", 0.7f, FCVAR_NONE,
+ConVar osu_cursor_ripple_duration("osu_cursor_ripple_duration", 0.7f, FCVAR_DEFAULT,
                                   "time in seconds each cursor ripple is visible");
-ConVar osu_cursor_ripple_alpha("osu_cursor_ripple_alpha", 1.0f, FCVAR_NONE);
-ConVar osu_cursor_ripple_additive("osu_cursor_ripple_additive", true, FCVAR_NONE, "use additive blending");
-ConVar osu_cursor_ripple_anim_start_scale("osu_cursor_ripple_anim_start_scale", 0.05f, FCVAR_NONE,
+ConVar osu_cursor_ripple_alpha("osu_cursor_ripple_alpha", 1.0f, FCVAR_DEFAULT);
+ConVar osu_cursor_ripple_additive("osu_cursor_ripple_additive", true, FCVAR_DEFAULT, "use additive blending");
+ConVar osu_cursor_ripple_anim_start_scale("osu_cursor_ripple_anim_start_scale", 0.05f, FCVAR_DEFAULT,
                                           "start size multiplier");
-ConVar osu_cursor_ripple_anim_end_scale("osu_cursor_ripple_anim_end_scale", 0.5f, FCVAR_NONE, "end size multiplier");
+ConVar osu_cursor_ripple_anim_end_scale("osu_cursor_ripple_anim_end_scale", 0.5f, FCVAR_DEFAULT, "end size multiplier");
 ConVar osu_cursor_ripple_anim_start_fadeout_delay(
-    "osu_cursor_ripple_anim_start_fadeout_delay", 0.0f, FCVAR_NONE,
+    "osu_cursor_ripple_anim_start_fadeout_delay", 0.0f, FCVAR_DEFAULT,
     "delay in seconds after which to start fading out (limited by osu_cursor_ripple_duration of course)");
-ConVar osu_cursor_ripple_tint_r("osu_cursor_ripple_tint_r", 255, FCVAR_NONE, "from 0 to 255");
-ConVar osu_cursor_ripple_tint_g("osu_cursor_ripple_tint_g", 255, FCVAR_NONE, "from 0 to 255");
-ConVar osu_cursor_ripple_tint_b("osu_cursor_ripple_tint_b", 255, FCVAR_NONE, "from 0 to 255");
+ConVar osu_cursor_ripple_tint_r("osu_cursor_ripple_tint_r", 255, FCVAR_DEFAULT, "from 0 to 255");
+ConVar osu_cursor_ripple_tint_g("osu_cursor_ripple_tint_g", 255, FCVAR_DEFAULT, "from 0 to 255");
+ConVar osu_cursor_ripple_tint_b("osu_cursor_ripple_tint_b", 255, FCVAR_DEFAULT, "from 0 to 255");
 
-ConVar osu_hud_shift_tab_toggles_everything("osu_hud_shift_tab_toggles_everything", true, FCVAR_NONE);
-ConVar osu_hud_scale("osu_hud_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_alpha("osu_hud_hiterrorbar_alpha", 1.0f, FCVAR_NONE,
+ConVar osu_hud_shift_tab_toggles_everything("osu_hud_shift_tab_toggles_everything", true, FCVAR_DEFAULT);
+ConVar osu_hud_scale("osu_hud_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_alpha("osu_hud_hiterrorbar_alpha", 1.0f, FCVAR_DEFAULT,
                                  "opacity multiplier for entire hiterrorbar");
-ConVar osu_hud_hiterrorbar_bar_alpha("osu_hud_hiterrorbar_bar_alpha", 1.0f, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_bar_alpha("osu_hud_hiterrorbar_bar_alpha", 1.0f, FCVAR_DEFAULT,
                                      "opacity multiplier for background color bar");
-ConVar osu_hud_hiterrorbar_centerline_alpha("osu_hud_hiterrorbar_centerline_alpha", 1.0f, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_centerline_alpha("osu_hud_hiterrorbar_centerline_alpha", 1.0f, FCVAR_DEFAULT,
                                             "opacity multiplier for center line");
-ConVar osu_hud_hiterrorbar_entry_additive("osu_hud_hiterrorbar_entry_additive", true, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_entry_additive("osu_hud_hiterrorbar_entry_additive", true, FCVAR_DEFAULT,
                                           "whether to use additive blending for all hit error entries/lines");
-ConVar osu_hud_hiterrorbar_entry_alpha("osu_hud_hiterrorbar_entry_alpha", 0.75f, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_entry_alpha("osu_hud_hiterrorbar_entry_alpha", 0.75f, FCVAR_DEFAULT,
                                        "opacity multiplier for all hit error entries/lines");
-ConVar osu_hud_hiterrorbar_entry_300_r("osu_hud_hiterrorbar_entry_300_r", 50, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_300_g("osu_hud_hiterrorbar_entry_300_g", 188, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_300_b("osu_hud_hiterrorbar_entry_300_b", 231, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_100_r("osu_hud_hiterrorbar_entry_100_r", 87, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_100_g("osu_hud_hiterrorbar_entry_100_g", 227, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_100_b("osu_hud_hiterrorbar_entry_100_b", 19, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_50_r("osu_hud_hiterrorbar_entry_50_r", 218, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_50_g("osu_hud_hiterrorbar_entry_50_g", 174, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_50_b("osu_hud_hiterrorbar_entry_50_b", 70, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_miss_r("osu_hud_hiterrorbar_entry_miss_r", 205, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_miss_g("osu_hud_hiterrorbar_entry_miss_g", 0, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_miss_b("osu_hud_hiterrorbar_entry_miss_b", 0, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_centerline_r("osu_hud_hiterrorbar_centerline_r", 255, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_centerline_g("osu_hud_hiterrorbar_centerline_g", 255, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_centerline_b("osu_hud_hiterrorbar_centerline_b", 255, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_entry_hit_fade_time("osu_hud_hiterrorbar_entry_hit_fade_time", 6.0f, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_entry_300_r("osu_hud_hiterrorbar_entry_300_r", 50, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_300_g("osu_hud_hiterrorbar_entry_300_g", 188, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_300_b("osu_hud_hiterrorbar_entry_300_b", 231, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_100_r("osu_hud_hiterrorbar_entry_100_r", 87, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_100_g("osu_hud_hiterrorbar_entry_100_g", 227, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_100_b("osu_hud_hiterrorbar_entry_100_b", 19, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_50_r("osu_hud_hiterrorbar_entry_50_r", 218, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_50_g("osu_hud_hiterrorbar_entry_50_g", 174, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_50_b("osu_hud_hiterrorbar_entry_50_b", 70, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_miss_r("osu_hud_hiterrorbar_entry_miss_r", 205, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_miss_g("osu_hud_hiterrorbar_entry_miss_g", 0, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_miss_b("osu_hud_hiterrorbar_entry_miss_b", 0, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_centerline_r("osu_hud_hiterrorbar_centerline_r", 255, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_centerline_g("osu_hud_hiterrorbar_centerline_g", 255, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_centerline_b("osu_hud_hiterrorbar_centerline_b", 255, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_entry_hit_fade_time("osu_hud_hiterrorbar_entry_hit_fade_time", 6.0f, FCVAR_DEFAULT,
                                                "fade duration of 50/100/300 hit entries/lines in seconds");
-ConVar osu_hud_hiterrorbar_entry_miss_fade_time("osu_hud_hiterrorbar_entry_miss_fade_time", 4.0f, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_entry_miss_fade_time("osu_hud_hiterrorbar_entry_miss_fade_time", 4.0f, FCVAR_DEFAULT,
                                                 "fade duration of miss entries/lines in seconds");
-ConVar osu_hud_hiterrorbar_scale("osu_hud_hiterrorbar_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_showmisswindow("osu_hud_hiterrorbar_showmisswindow", false, FCVAR_NONE);
+ConVar osu_hud_hiterrorbar_scale("osu_hud_hiterrorbar_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_showmisswindow("osu_hud_hiterrorbar_showmisswindow", false, FCVAR_DEFAULT);
 ConVar osu_hud_hiterrorbar_width_percent_with_misswindow("osu_hud_hiterrorbar_width_percent_with_misswindow", 0.4f,
-                                                         FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_width_percent("osu_hud_hiterrorbar_width_percent", 0.15f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_height_percent("osu_hud_hiterrorbar_height_percent", 0.007f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_offset_percent("osu_hud_hiterrorbar_offset_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_offset_bottom_percent("osu_hud_hiterrorbar_offset_bottom_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_offset_top_percent("osu_hud_hiterrorbar_offset_top_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_offset_left_percent("osu_hud_hiterrorbar_offset_left_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_offset_right_percent("osu_hud_hiterrorbar_offset_right_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_bar_width_scale("osu_hud_hiterrorbar_bar_width_scale", 0.6f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_bar_height_scale("osu_hud_hiterrorbar_bar_height_scale", 3.4f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_max_entries("osu_hud_hiterrorbar_max_entries", 32, FCVAR_NONE,
+                                                         FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_width_percent("osu_hud_hiterrorbar_width_percent", 0.15f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_height_percent("osu_hud_hiterrorbar_height_percent", 0.007f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_offset_percent("osu_hud_hiterrorbar_offset_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_offset_bottom_percent("osu_hud_hiterrorbar_offset_bottom_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_offset_top_percent("osu_hud_hiterrorbar_offset_top_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_offset_left_percent("osu_hud_hiterrorbar_offset_left_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_offset_right_percent("osu_hud_hiterrorbar_offset_right_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_bar_width_scale("osu_hud_hiterrorbar_bar_width_scale", 0.6f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_bar_height_scale("osu_hud_hiterrorbar_bar_height_scale", 3.4f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_max_entries("osu_hud_hiterrorbar_max_entries", 32, FCVAR_DEFAULT,
                                        "maximum number of entries/lines");
-ConVar osu_hud_hiterrorbar_hide_during_spinner("osu_hud_hiterrorbar_hide_during_spinner", true, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_ur_scale("osu_hud_hiterrorbar_ur_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_ur_alpha("osu_hud_hiterrorbar_ur_alpha", 0.5f, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_hide_during_spinner("osu_hud_hiterrorbar_hide_during_spinner", true, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_ur_scale("osu_hud_hiterrorbar_ur_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_ur_alpha("osu_hud_hiterrorbar_ur_alpha", 0.5f, FCVAR_DEFAULT,
                                     "opacity multiplier for unstable rate text above hiterrorbar");
-ConVar osu_hud_hiterrorbar_ur_offset_x_percent("osu_hud_hiterrorbar_ur_offset_x_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_hiterrorbar_ur_offset_y_percent("osu_hud_hiterrorbar_ur_offset_y_percent", 0.0f, FCVAR_NONE);
-ConVar osu_hud_scorebar_scale("osu_hud_scorebar_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_scorebar_hide_during_breaks("osu_hud_scorebar_hide_during_breaks", true, FCVAR_NONE);
-ConVar osu_hud_scorebar_hide_anim_duration("osu_hud_scorebar_hide_anim_duration", 0.5f, FCVAR_NONE);
-ConVar osu_hud_combo_scale("osu_hud_combo_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_score_scale("osu_hud_score_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_accuracy_scale("osu_hud_accuracy_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_progressbar_scale("osu_hud_progressbar_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_playfield_border_size("osu_hud_playfield_border_size", 5.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_scale("osu_hud_statistics_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_spacing_scale("osu_hud_statistics_spacing_scale", 1.1f, FCVAR_NONE);
-ConVar osu_hud_statistics_offset_x("osu_hud_statistics_offset_x", 5.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_offset_y("osu_hud_statistics_offset_y", 50.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_pp_decimal_places("osu_hud_statistics_pp_decimal_places", 0, FCVAR_NONE,
+ConVar osu_hud_hiterrorbar_ur_offset_x_percent("osu_hud_hiterrorbar_ur_offset_x_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_hiterrorbar_ur_offset_y_percent("osu_hud_hiterrorbar_ur_offset_y_percent", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_scorebar_scale("osu_hud_scorebar_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_scorebar_hide_during_breaks("osu_hud_scorebar_hide_during_breaks", true, FCVAR_DEFAULT);
+ConVar osu_hud_scorebar_hide_anim_duration("osu_hud_scorebar_hide_anim_duration", 0.5f, FCVAR_DEFAULT);
+ConVar osu_hud_combo_scale("osu_hud_combo_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_score_scale("osu_hud_score_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_accuracy_scale("osu_hud_accuracy_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_progressbar_scale("osu_hud_progressbar_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_playfield_border_size("osu_hud_playfield_border_size", 5.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_scale("osu_hud_statistics_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_spacing_scale("osu_hud_statistics_spacing_scale", 1.1f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_offset_x("osu_hud_statistics_offset_x", 5.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_offset_y("osu_hud_statistics_offset_y", 50.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_pp_decimal_places("osu_hud_statistics_pp_decimal_places", 0, FCVAR_DEFAULT,
                                             "number of decimal places for the live pp counter (min = 0, max = 2)");
-ConVar osu_hud_statistics_pp_offset_x("osu_hud_statistics_pp_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_pp_offset_y("osu_hud_statistics_pp_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_perfectpp_offset_x("osu_hud_statistics_perfectpp_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_perfectpp_offset_y("osu_hud_statistics_perfectpp_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_misses_offset_x("osu_hud_statistics_misses_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_misses_offset_y("osu_hud_statistics_misses_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_sliderbreaks_offset_x("osu_hud_statistics_sliderbreaks_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_sliderbreaks_offset_y("osu_hud_statistics_sliderbreaks_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_maxpossiblecombo_offset_x("osu_hud_statistics_maxpossiblecombo_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_maxpossiblecombo_offset_y("osu_hud_statistics_maxpossiblecombo_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_livestars_offset_x("osu_hud_statistics_livestars_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_livestars_offset_y("osu_hud_statistics_livestars_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_totalstars_offset_x("osu_hud_statistics_totalstars_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_totalstars_offset_y("osu_hud_statistics_totalstars_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_bpm_offset_x("osu_hud_statistics_bpm_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_bpm_offset_y("osu_hud_statistics_bpm_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_ar_offset_x("osu_hud_statistics_ar_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_ar_offset_y("osu_hud_statistics_ar_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_cs_offset_x("osu_hud_statistics_cs_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_cs_offset_y("osu_hud_statistics_cs_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_od_offset_x("osu_hud_statistics_od_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_od_offset_y("osu_hud_statistics_od_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_hp_offset_x("osu_hud_statistics_hp_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_hp_offset_y("osu_hud_statistics_hp_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_hitwindow300_offset_x("osu_hud_statistics_hitwindow300_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_hitwindow300_offset_y("osu_hud_statistics_hitwindow300_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_nps_offset_x("osu_hud_statistics_nps_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_nps_offset_y("osu_hud_statistics_nps_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_nd_offset_x("osu_hud_statistics_nd_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_nd_offset_y("osu_hud_statistics_nd_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_ur_offset_x("osu_hud_statistics_ur_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_ur_offset_y("osu_hud_statistics_ur_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_hitdelta_offset_x("osu_hud_statistics_hitdelta_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_statistics_hitdelta_offset_y("osu_hud_statistics_hitdelta_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_scoreboard_scale("osu_hud_scoreboard_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_scoreboard_offset_y_percent("osu_hud_scoreboard_offset_y_percent", 0.11f, FCVAR_NONE);
-ConVar osu_hud_scoreboard_use_menubuttonbackground("osu_hud_scoreboard_use_menubuttonbackground", true, FCVAR_NONE);
-ConVar osu_hud_inputoverlay_scale("osu_hud_inputoverlay_scale", 1.0f, FCVAR_NONE);
-ConVar osu_hud_inputoverlay_offset_x("osu_hud_inputoverlay_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_hud_inputoverlay_offset_y("osu_hud_inputoverlay_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_hud_inputoverlay_anim_scale_duration("osu_hud_inputoverlay_anim_scale_duration", 0.16f, FCVAR_NONE);
-ConVar osu_hud_inputoverlay_anim_scale_multiplier("osu_hud_inputoverlay_anim_scale_multiplier", 0.8f, FCVAR_NONE);
-ConVar osu_hud_inputoverlay_anim_color_duration("osu_hud_inputoverlay_anim_color_duration", 0.1f, FCVAR_NONE);
-ConVar osu_hud_fps_smoothing("osu_hud_fps_smoothing", true, FCVAR_NONE);
+ConVar osu_hud_statistics_pp_offset_x("osu_hud_statistics_pp_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_pp_offset_y("osu_hud_statistics_pp_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_perfectpp_offset_x("osu_hud_statistics_perfectpp_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_perfectpp_offset_y("osu_hud_statistics_perfectpp_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_misses_offset_x("osu_hud_statistics_misses_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_misses_offset_y("osu_hud_statistics_misses_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_sliderbreaks_offset_x("osu_hud_statistics_sliderbreaks_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_sliderbreaks_offset_y("osu_hud_statistics_sliderbreaks_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_maxpossiblecombo_offset_x("osu_hud_statistics_maxpossiblecombo_offset_x", 0.0f,
+                                                    FCVAR_DEFAULT);
+ConVar osu_hud_statistics_maxpossiblecombo_offset_y("osu_hud_statistics_maxpossiblecombo_offset_y", 0.0f,
+                                                    FCVAR_DEFAULT);
+ConVar osu_hud_statistics_livestars_offset_x("osu_hud_statistics_livestars_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_livestars_offset_y("osu_hud_statistics_livestars_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_totalstars_offset_x("osu_hud_statistics_totalstars_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_totalstars_offset_y("osu_hud_statistics_totalstars_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_bpm_offset_x("osu_hud_statistics_bpm_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_bpm_offset_y("osu_hud_statistics_bpm_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_ar_offset_x("osu_hud_statistics_ar_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_ar_offset_y("osu_hud_statistics_ar_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_cs_offset_x("osu_hud_statistics_cs_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_cs_offset_y("osu_hud_statistics_cs_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_od_offset_x("osu_hud_statistics_od_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_od_offset_y("osu_hud_statistics_od_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_hp_offset_x("osu_hud_statistics_hp_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_hp_offset_y("osu_hud_statistics_hp_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_hitwindow300_offset_x("osu_hud_statistics_hitwindow300_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_hitwindow300_offset_y("osu_hud_statistics_hitwindow300_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_nps_offset_x("osu_hud_statistics_nps_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_nps_offset_y("osu_hud_statistics_nps_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_nd_offset_x("osu_hud_statistics_nd_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_nd_offset_y("osu_hud_statistics_nd_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_ur_offset_x("osu_hud_statistics_ur_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_ur_offset_y("osu_hud_statistics_ur_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_hitdelta_offset_x("osu_hud_statistics_hitdelta_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_statistics_hitdelta_offset_y("osu_hud_statistics_hitdelta_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_scoreboard_scale("osu_hud_scoreboard_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_scoreboard_offset_y_percent("osu_hud_scoreboard_offset_y_percent", 0.11f, FCVAR_DEFAULT);
+ConVar osu_hud_scoreboard_use_menubuttonbackground("osu_hud_scoreboard_use_menubuttonbackground", true, FCVAR_DEFAULT);
+ConVar osu_hud_inputoverlay_scale("osu_hud_inputoverlay_scale", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_inputoverlay_offset_x("osu_hud_inputoverlay_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_inputoverlay_offset_y("osu_hud_inputoverlay_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_hud_inputoverlay_anim_scale_duration("osu_hud_inputoverlay_anim_scale_duration", 0.16f, FCVAR_DEFAULT);
+ConVar osu_hud_inputoverlay_anim_scale_multiplier("osu_hud_inputoverlay_anim_scale_multiplier", 0.8f, FCVAR_DEFAULT);
+ConVar osu_hud_inputoverlay_anim_color_duration("osu_hud_inputoverlay_anim_color_duration", 0.1f, FCVAR_DEFAULT);
+ConVar osu_hud_fps_smoothing("osu_hud_fps_smoothing", true, FCVAR_DEFAULT);
 ConVar osu_hud_scrubbing_timeline_hover_tooltip_offset_multiplier(
-    "osu_hud_scrubbing_timeline_hover_tooltip_offset_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_hud_scrubbing_timeline_strains_height("osu_hud_scrubbing_timeline_strains_height", 200.0f, FCVAR_NONE);
-ConVar osu_hud_scrubbing_timeline_strains_alpha("osu_hud_scrubbing_timeline_strains_alpha", 0.4f, FCVAR_NONE);
-ConVar osu_hud_scrubbing_timeline_strains_aim_color_r("osu_hud_scrubbing_timeline_strains_aim_color_r", 0, FCVAR_NONE);
+    "osu_hud_scrubbing_timeline_hover_tooltip_offset_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_scrubbing_timeline_strains_height("osu_hud_scrubbing_timeline_strains_height", 200.0f, FCVAR_DEFAULT);
+ConVar osu_hud_scrubbing_timeline_strains_alpha("osu_hud_scrubbing_timeline_strains_alpha", 0.4f, FCVAR_DEFAULT);
+ConVar osu_hud_scrubbing_timeline_strains_aim_color_r("osu_hud_scrubbing_timeline_strains_aim_color_r", 0,
+                                                      FCVAR_DEFAULT);
 ConVar osu_hud_scrubbing_timeline_strains_aim_color_g("osu_hud_scrubbing_timeline_strains_aim_color_g", 255,
-                                                      FCVAR_NONE);
-ConVar osu_hud_scrubbing_timeline_strains_aim_color_b("osu_hud_scrubbing_timeline_strains_aim_color_b", 0, FCVAR_NONE);
+                                                      FCVAR_DEFAULT);
+ConVar osu_hud_scrubbing_timeline_strains_aim_color_b("osu_hud_scrubbing_timeline_strains_aim_color_b", 0,
+                                                      FCVAR_DEFAULT);
 ConVar osu_hud_scrubbing_timeline_strains_speed_color_r("osu_hud_scrubbing_timeline_strains_speed_color_r", 255,
-                                                        FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
 ConVar osu_hud_scrubbing_timeline_strains_speed_color_g("osu_hud_scrubbing_timeline_strains_speed_color_g", 0,
-                                                        FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
 ConVar osu_hud_scrubbing_timeline_strains_speed_color_b("osu_hud_scrubbing_timeline_strains_speed_color_b", 0,
-                                                        FCVAR_NONE);
-
-ConVar osu_draw_cursor_trail("osu_draw_cursor_trail", true, FCVAR_NONE);
-ConVar osu_draw_cursor_ripples("osu_draw_cursor_ripples", false, FCVAR_NONE);
-ConVar osu_draw_hud("osu_draw_hud", true, FCVAR_NONE);
-ConVar osu_draw_scorebar("osu_draw_scorebar", true, FCVAR_NONE);
-ConVar osu_draw_scorebarbg("osu_draw_scorebarbg", true, FCVAR_NONE);
-ConVar osu_draw_hiterrorbar("osu_draw_hiterrorbar", true, FCVAR_NONE);
-ConVar osu_draw_hiterrorbar_ur("osu_draw_hiterrorbar_ur", true, FCVAR_NONE);
-ConVar osu_draw_hiterrorbar_bottom("osu_draw_hiterrorbar_bottom", true, FCVAR_NONE);
-ConVar osu_draw_hiterrorbar_top("osu_draw_hiterrorbar_top", false, FCVAR_NONE);
-ConVar osu_draw_hiterrorbar_left("osu_draw_hiterrorbar_left", false, FCVAR_NONE);
-ConVar osu_draw_hiterrorbar_right("osu_draw_hiterrorbar_right", false, FCVAR_NONE);
-ConVar osu_draw_progressbar("osu_draw_progressbar", true, FCVAR_NONE);
-ConVar osu_draw_combo("osu_draw_combo", true, FCVAR_NONE);
-ConVar osu_draw_score("osu_draw_score", true, FCVAR_NONE);
-ConVar osu_draw_accuracy("osu_draw_accuracy", true, FCVAR_NONE);
-ConVar osu_draw_target_heatmap("osu_draw_target_heatmap", true, FCVAR_NONE);
-ConVar osu_draw_scrubbing_timeline("osu_draw_scrubbing_timeline", true, FCVAR_NONE);
-ConVar osu_draw_scrubbing_timeline_breaks("osu_draw_scrubbing_timeline_breaks", true, FCVAR_NONE);
-ConVar osu_draw_scrubbing_timeline_strain_graph("osu_draw_scrubbing_timeline_strain_graph", false, FCVAR_NONE);
-ConVar osu_draw_continue("osu_draw_continue", true, FCVAR_NONE);
-ConVar osu_draw_scoreboard("osu_draw_scoreboard", true, FCVAR_NONE);
-ConVar osu_draw_scoreboard_mp("osu_draw_scoreboard_mp", true, FCVAR_NONE);
-ConVar osu_draw_inputoverlay("osu_draw_inputoverlay", true, FCVAR_NONE);
-
-ConVar osu_draw_statistics_misses("osu_draw_statistics_misses", false, FCVAR_NONE);
-ConVar osu_draw_statistics_sliderbreaks("osu_draw_statistics_sliderbreaks", false, FCVAR_NONE);
-ConVar osu_draw_statistics_perfectpp("osu_draw_statistics_perfectpp", false, FCVAR_NONE);
-ConVar osu_draw_statistics_maxpossiblecombo("osu_draw_statistics_maxpossiblecombo", false, FCVAR_NONE);
-ConVar osu_draw_statistics_livestars("osu_draw_statistics_livestars", false, FCVAR_NONE);
-ConVar osu_draw_statistics_totalstars("osu_draw_statistics_totalstars", false, FCVAR_NONE);
-ConVar osu_draw_statistics_bpm("osu_draw_statistics_bpm", false, FCVAR_NONE);
-ConVar osu_draw_statistics_ar("osu_draw_statistics_ar", false, FCVAR_NONE);
-ConVar osu_draw_statistics_cs("osu_draw_statistics_cs", false, FCVAR_NONE);
-ConVar osu_draw_statistics_od("osu_draw_statistics_od", false, FCVAR_NONE);
-ConVar osu_draw_statistics_hp("osu_draw_statistics_hp", false, FCVAR_NONE);
-ConVar osu_draw_statistics_nps("osu_draw_statistics_nps", false, FCVAR_NONE);
-ConVar osu_draw_statistics_nd("osu_draw_statistics_nd", false, FCVAR_NONE);
-ConVar osu_draw_statistics_ur("osu_draw_statistics_ur", false, FCVAR_NONE);
-ConVar osu_draw_statistics_pp("osu_draw_statistics_pp", false, FCVAR_NONE);
-ConVar osu_draw_statistics_hitwindow300("osu_draw_statistics_hitwindow300", false, FCVAR_NONE);
-ConVar osu_draw_statistics_hitdelta("osu_draw_statistics_hitdelta", false, FCVAR_NONE);
-
-ConVar osu_combo_anim1_duration("osu_combo_anim1_duration", 0.15f, FCVAR_NONE);
-ConVar osu_combo_anim1_size("osu_combo_anim1_size", 0.15f, FCVAR_NONE);
-ConVar osu_combo_anim2_duration("osu_combo_anim2_duration", 0.4f, FCVAR_NONE);
-ConVar osu_combo_anim2_size("osu_combo_anim2_size", 0.5f, FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
+
+ConVar osu_draw_cursor_trail("osu_draw_cursor_trail", true, FCVAR_DEFAULT);
+ConVar osu_draw_cursor_ripples("osu_draw_cursor_ripples", false, FCVAR_DEFAULT);
+ConVar osu_draw_hud("osu_draw_hud", true, FCVAR_DEFAULT);
+ConVar osu_draw_scorebar("osu_draw_scorebar", true, FCVAR_DEFAULT);
+ConVar osu_draw_scorebarbg("osu_draw_scorebarbg", true, FCVAR_DEFAULT);
+ConVar osu_draw_hiterrorbar("osu_draw_hiterrorbar", true, FCVAR_DEFAULT);
+ConVar osu_draw_hiterrorbar_ur("osu_draw_hiterrorbar_ur", true, FCVAR_DEFAULT);
+ConVar osu_draw_hiterrorbar_bottom("osu_draw_hiterrorbar_bottom", true, FCVAR_DEFAULT);
+ConVar osu_draw_hiterrorbar_top("osu_draw_hiterrorbar_top", false, FCVAR_DEFAULT);
+ConVar osu_draw_hiterrorbar_left("osu_draw_hiterrorbar_left", false, FCVAR_DEFAULT);
+ConVar osu_draw_hiterrorbar_right("osu_draw_hiterrorbar_right", false, FCVAR_DEFAULT);
+ConVar osu_draw_progressbar("osu_draw_progressbar", true, FCVAR_DEFAULT);
+ConVar osu_draw_combo("osu_draw_combo", true, FCVAR_DEFAULT);
+ConVar osu_draw_score("osu_draw_score", true, FCVAR_DEFAULT);
+ConVar osu_draw_accuracy("osu_draw_accuracy", true, FCVAR_DEFAULT);
+ConVar osu_draw_target_heatmap("osu_draw_target_heatmap", true, FCVAR_DEFAULT);
+ConVar osu_draw_scrubbing_timeline("osu_draw_scrubbing_timeline", true, FCVAR_DEFAULT);
+ConVar osu_draw_scrubbing_timeline_breaks("osu_draw_scrubbing_timeline_breaks", true, FCVAR_DEFAULT);
+ConVar osu_draw_scrubbing_timeline_strain_graph("osu_draw_scrubbing_timeline_strain_graph", false, FCVAR_DEFAULT);
+ConVar osu_draw_continue("osu_draw_continue", true, FCVAR_DEFAULT);
+ConVar osu_draw_scoreboard("osu_draw_scoreboard", true, FCVAR_DEFAULT);
+ConVar osu_draw_scoreboard_mp("osu_draw_scoreboard_mp", true, FCVAR_DEFAULT);
+ConVar osu_draw_inputoverlay("osu_draw_inputoverlay", true, FCVAR_DEFAULT);
+
+ConVar osu_draw_statistics_misses("osu_draw_statistics_misses", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_sliderbreaks("osu_draw_statistics_sliderbreaks", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_perfectpp("osu_draw_statistics_perfectpp", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_maxpossiblecombo("osu_draw_statistics_maxpossiblecombo", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_livestars("osu_draw_statistics_livestars", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_totalstars("osu_draw_statistics_totalstars", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_bpm("osu_draw_statistics_bpm", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_ar("osu_draw_statistics_ar", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_cs("osu_draw_statistics_cs", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_od("osu_draw_statistics_od", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_hp("osu_draw_statistics_hp", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_nps("osu_draw_statistics_nps", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_nd("osu_draw_statistics_nd", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_ur("osu_draw_statistics_ur", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_pp("osu_draw_statistics_pp", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_hitwindow300("osu_draw_statistics_hitwindow300", false, FCVAR_DEFAULT);
+ConVar osu_draw_statistics_hitdelta("osu_draw_statistics_hitdelta", false, FCVAR_DEFAULT);
+
+ConVar osu_combo_anim1_duration("osu_combo_anim1_duration", 0.15f, FCVAR_DEFAULT);
+ConVar osu_combo_anim1_size("osu_combo_anim1_size", 0.15f, FCVAR_DEFAULT);
+ConVar osu_combo_anim2_duration("osu_combo_anim2_duration", 0.4f, FCVAR_DEFAULT);
+ConVar osu_combo_anim2_size("osu_combo_anim2_size", 0.5f, FCVAR_DEFAULT);
 
 HUD::HUD(Osu *osu) : OsuScreen(osu) {
     m_osu = osu;

+ 33 - 32
src/App/Osu/HitObject.cpp

@@ -18,76 +18,77 @@
 #include "Skin.h"
 #include "SkinImage.h"
 
-ConVar osu_hitresult_draw_300s("osu_hitresult_draw_300s", false, FCVAR_NONE);
+ConVar osu_hitresult_draw_300s("osu_hitresult_draw_300s", false, FCVAR_DEFAULT);
 
-ConVar osu_hitresult_scale("osu_hitresult_scale", 1.0f, FCVAR_NONE);
+ConVar osu_hitresult_scale("osu_hitresult_scale", 1.0f, FCVAR_DEFAULT);
 ConVar osu_hitresult_duration(
-    "osu_hitresult_duration", 1.100f, FCVAR_NONE,
+    "osu_hitresult_duration", 1.100f, FCVAR_DEFAULT,
     "max duration of the entire hitresult in seconds (this limits all other values, except for animated skins!)");
-ConVar osu_hitresult_duration_max("osu_hitresult_duration_max", 5.0f, FCVAR_NONE,
+ConVar osu_hitresult_duration_max("osu_hitresult_duration_max", 5.0f, FCVAR_DEFAULT,
                                   "absolute hard limit in seconds, even for animated skins");
 ConVar osu_hitresult_animated(
-    "osu_hitresult_animated", true, FCVAR_NONE,
+    "osu_hitresult_animated", true, FCVAR_DEFAULT,
     "whether to animate hitresult scales (depending on particle<SCORE>.png, either scale wobble or smooth scale)");
-ConVar osu_hitresult_fadein_duration("osu_hitresult_fadein_duration", 0.120f, FCVAR_NONE);
-ConVar osu_hitresult_fadeout_start_time("osu_hitresult_fadeout_start_time", 0.500f, FCVAR_NONE);
-ConVar osu_hitresult_fadeout_duration("osu_hitresult_fadeout_duration", 0.600f, FCVAR_NONE);
-ConVar osu_hitresult_miss_fadein_scale("osu_hitresult_miss_fadein_scale", 2.0f, FCVAR_NONE);
-ConVar osu_hitresult_delta_colorize("osu_hitresult_delta_colorize", false, FCVAR_NONE,
+ConVar osu_hitresult_fadein_duration("osu_hitresult_fadein_duration", 0.120f, FCVAR_DEFAULT);
+ConVar osu_hitresult_fadeout_start_time("osu_hitresult_fadeout_start_time", 0.500f, FCVAR_DEFAULT);
+ConVar osu_hitresult_fadeout_duration("osu_hitresult_fadeout_duration", 0.600f, FCVAR_DEFAULT);
+ConVar osu_hitresult_miss_fadein_scale("osu_hitresult_miss_fadein_scale", 2.0f, FCVAR_DEFAULT);
+ConVar osu_hitresult_delta_colorize("osu_hitresult_delta_colorize", false, FCVAR_DEFAULT,
                                     "whether to colorize hitresults depending on how early/late the hit (delta) was");
-ConVar osu_hitresult_delta_colorize_interpolate("osu_hitresult_delta_colorize_interpolate", true, FCVAR_NONE,
+ConVar osu_hitresult_delta_colorize_interpolate("osu_hitresult_delta_colorize_interpolate", true, FCVAR_DEFAULT,
                                                 "whether colorized hitresults should smoothly interpolate between "
                                                 "early/late colors depending on the hit delta amount");
 ConVar osu_hitresult_delta_colorize_multiplier(
-    "osu_hitresult_delta_colorize_multiplier", 2.0f, FCVAR_NONE,
+    "osu_hitresult_delta_colorize_multiplier", 2.0f, FCVAR_DEFAULT,
     "early/late colors are multiplied by this (assuming interpolation is enabled, increasing this will make early/late "
     "colors appear fully earlier)");
-ConVar osu_hitresult_delta_colorize_early_r("osu_hitresult_delta_colorize_early_r", 255, FCVAR_NONE, "from 0 to 255");
-ConVar osu_hitresult_delta_colorize_early_g("osu_hitresult_delta_colorize_early_g", 0, FCVAR_NONE, "from 0 to 255");
-ConVar osu_hitresult_delta_colorize_early_b("osu_hitresult_delta_colorize_early_b", 0, FCVAR_NONE, "from 0 to 255");
-ConVar osu_hitresult_delta_colorize_late_r("osu_hitresult_delta_colorize_late_r", 0, FCVAR_NONE, "from 0 to 255");
-ConVar osu_hitresult_delta_colorize_late_g("osu_hitresult_delta_colorize_late_g", 0, FCVAR_NONE, "from 0 to 255");
-ConVar osu_hitresult_delta_colorize_late_b("osu_hitresult_delta_colorize_late_b", 255, FCVAR_NONE, "from 0 to 255");
+ConVar osu_hitresult_delta_colorize_early_r("osu_hitresult_delta_colorize_early_r", 255, FCVAR_DEFAULT,
+                                            "from 0 to 255");
+ConVar osu_hitresult_delta_colorize_early_g("osu_hitresult_delta_colorize_early_g", 0, FCVAR_DEFAULT, "from 0 to 255");
+ConVar osu_hitresult_delta_colorize_early_b("osu_hitresult_delta_colorize_early_b", 0, FCVAR_DEFAULT, "from 0 to 255");
+ConVar osu_hitresult_delta_colorize_late_r("osu_hitresult_delta_colorize_late_r", 0, FCVAR_DEFAULT, "from 0 to 255");
+ConVar osu_hitresult_delta_colorize_late_g("osu_hitresult_delta_colorize_late_g", 0, FCVAR_DEFAULT, "from 0 to 255");
+ConVar osu_hitresult_delta_colorize_late_b("osu_hitresult_delta_colorize_late_b", 255, FCVAR_DEFAULT, "from 0 to 255");
 
-ConVar osu_approach_scale_multiplier("osu_approach_scale_multiplier", 3.0f, FCVAR_NONE);
+ConVar osu_approach_scale_multiplier("osu_approach_scale_multiplier", 3.0f, FCVAR_DEFAULT);
 
-ConVar osu_timingpoints_force("osu_timingpoints_force", true, FCVAR_NONE,
+ConVar osu_timingpoints_force("osu_timingpoints_force", true, FCVAR_DEFAULT,
                               "Forces the correct sample type and volume to be used, by getting the active timingpoint "
                               "through iteration EVERY TIME a hitsound is played (performance!)");
 
 ConVar osu_mod_hd_circle_fadein_start_percent(
-    "osu_mod_hd_circle_fadein_start_percent", 1.0f, FCVAR_CHEAT,
+    "osu_mod_hd_circle_fadein_start_percent", 1.0f, FCVAR_LOCKED,
     "hiddenFadeInStartTime = circleTime - approachTime * osu_mod_hd_circle_fadein_start_percent");
 ConVar osu_mod_hd_circle_fadein_end_percent(
-    "osu_mod_hd_circle_fadein_end_percent", 0.6f, FCVAR_CHEAT,
+    "osu_mod_hd_circle_fadein_end_percent", 0.6f, FCVAR_LOCKED,
     "hiddenFadeInEndTime = circleTime - approachTime * osu_mod_hd_circle_fadein_end_percent");
 ConVar osu_mod_hd_circle_fadeout_start_percent(
-    "osu_mod_hd_circle_fadeout_start_percent", 0.6f, FCVAR_CHEAT,
+    "osu_mod_hd_circle_fadeout_start_percent", 0.6f, FCVAR_LOCKED,
     "hiddenFadeOutStartTime = circleTime - approachTime * osu_mod_hd_circle_fadeout_start_percent");
 ConVar osu_mod_hd_circle_fadeout_end_percent(
-    "osu_mod_hd_circle_fadeout_end_percent", 0.3f, FCVAR_CHEAT,
+    "osu_mod_hd_circle_fadeout_end_percent", 0.3f, FCVAR_LOCKED,
     "hiddenFadeOutEndTime = circleTime - approachTime * osu_mod_hd_circle_fadeout_end_percent");
 
-ConVar osu_mod_target_300_percent("osu_mod_target_300_percent", 0.5f, FCVAR_CHEAT);
-ConVar osu_mod_target_100_percent("osu_mod_target_100_percent", 0.7f, FCVAR_CHEAT);
-ConVar osu_mod_target_50_percent("osu_mod_target_50_percent", 0.95f, FCVAR_CHEAT);
+ConVar osu_mod_target_300_percent("osu_mod_target_300_percent", 0.5f, FCVAR_LOCKED);
+ConVar osu_mod_target_100_percent("osu_mod_target_100_percent", 0.7f, FCVAR_LOCKED);
+ConVar osu_mod_target_50_percent("osu_mod_target_50_percent", 0.95f, FCVAR_LOCKED);
 
-ConVar osu_mod_mafham_ignore_hittable_dim("osu_mod_mafham_ignore_hittable_dim", true, FCVAR_NONE,
+ConVar osu_mod_mafham_ignore_hittable_dim("osu_mod_mafham_ignore_hittable_dim", true, FCVAR_DEFAULT,
                                           "having hittable dim enabled makes it possible to \"read\" the beatmap by "
                                           "looking at the un-dim animations (thus making it a lot easier)");
 
-ConVar osu_mod_approach_different("osu_mod_approach_different", false, FCVAR_NONVANILLA,
+ConVar osu_mod_approach_different("osu_mod_approach_different", false, FCVAR_UNLOCKED,
                                   "replicates osu!lazer's \"Approach Different\" mod");
 ConVar osu_mod_approach_different_initial_size(
-    "osu_mod_approach_different_initial_size", 4.0f, FCVAR_NONE,
+    "osu_mod_approach_different_initial_size", 4.0f, FCVAR_DEFAULT,
     "initial size of the approach circles, relative to hit circles (as a multiplier)");
 ConVar osu_mod_approach_different_style(
-    "osu_mod_approach_different_style", 1, FCVAR_NONE,
+    "osu_mod_approach_different_style", 1, FCVAR_DEFAULT,
     "0 = linear, 1 = gravity, 2 = InOut1, 3 = InOut2, 4 = Accelerate1, 5 = Accelerate2, 6 = Accelerate3, 7 = "
     "Decelerate1, 8 = Decelerate2, 9 = Decelerate3");
 
 ConVar osu_relax_offset(
-    "osu_relax_offset", 0, FCVAR_NONE,
+    "osu_relax_offset", 0, FCVAR_DEFAULT,
     "osu!relax always hits -12 ms too early, so set this to -12 (note the negative) if you want it to be the same");
 
 ConVar *HitObject::m_osu_approach_scale_multiplier_ref = &osu_approach_scale_multiplier;

+ 44 - 44
src/App/Osu/KeyBindings.cpp

@@ -9,50 +9,50 @@
 
 #include "Keyboard.h"
 
-ConVar KeyBindings::LEFT_CLICK("osu_key_left_click", (int)KEY_Z, FCVAR_NONE);
-ConVar KeyBindings::RIGHT_CLICK("osu_key_right_click", (int)KEY_X, FCVAR_NONE);
-ConVar KeyBindings::LEFT_CLICK_2("osu_key_left_click_2", 0, FCVAR_NONE);
-ConVar KeyBindings::RIGHT_CLICK_2("osu_key_right_click_2", 0, FCVAR_NONE);
-
-ConVar KeyBindings::FPOSU_ZOOM("osu_key_fposu_zoom", 0, FCVAR_NONE);
-
-ConVar KeyBindings::INCREASE_VOLUME("osu_key_increase_volume", (int)KEY_UP, FCVAR_NONE);
-ConVar KeyBindings::DECREASE_VOLUME("osu_key_decrease_volume", (int)KEY_DOWN, FCVAR_NONE);
-
-ConVar KeyBindings::INCREASE_LOCAL_OFFSET("osu_key_increase_local_offset", (int)KEY_ADD, FCVAR_NONE);
-ConVar KeyBindings::DECREASE_LOCAL_OFFSET("osu_key_decrease_local_offset", (int)KEY_SUBTRACT, FCVAR_NONE);
-
-ConVar KeyBindings::GAME_PAUSE("osu_key_game_pause", (int)KEY_ESCAPE, FCVAR_NONE);
-ConVar KeyBindings::SKIP_CUTSCENE("osu_key_skip_cutscene", (int)KEY_SPACE, FCVAR_NONE);
-ConVar KeyBindings::TOGGLE_SCOREBOARD("osu_key_toggle_scoreboard", (int)KEY_TAB, FCVAR_NONE);
-ConVar KeyBindings::SEEK_TIME("osu_key_seek_time", (int)KEY_SHIFT, FCVAR_NONE);
-ConVar KeyBindings::SEEK_TIME_BACKWARD("osu_key_seek_time_backward", (int)KEY_LEFT, FCVAR_NONE);
-ConVar KeyBindings::SEEK_TIME_FORWARD("osu_key_seek_time_forward", (int)KEY_RIGHT, FCVAR_NONE);
-ConVar KeyBindings::QUICK_RETRY("osu_key_quick_retry", (int)KEY_BACKSPACE, FCVAR_NONE);
-ConVar KeyBindings::QUICK_SAVE("osu_key_quick_save", (int)KEY_F6, FCVAR_NONE);
-ConVar KeyBindings::QUICK_LOAD("osu_key_quick_load", (int)KEY_F7, FCVAR_NONE);
-ConVar KeyBindings::INSTANT_REPLAY("osu_key_instant_replay", (int)KEY_F2, FCVAR_NONE);
-ConVar KeyBindings::TOGGLE_CHAT("osu_key_toggle_chat", (int)KEY_F8, FCVAR_NONE);
-ConVar KeyBindings::SAVE_SCREENSHOT("osu_key_save_screenshot", (int)KEY_F12, FCVAR_NONE);
-ConVar KeyBindings::DISABLE_MOUSE_BUTTONS("osu_key_disable_mouse_buttons", (int)KEY_F10, FCVAR_NONE);
-ConVar KeyBindings::BOSS_KEY("osu_key_boss", (int)KEY_INSERT, FCVAR_NONE);
-
-ConVar KeyBindings::TOGGLE_MODSELECT("osu_key_toggle_modselect", (int)KEY_F1, FCVAR_NONE);
-ConVar KeyBindings::RANDOM_BEATMAP("osu_key_random_beatmap", (int)KEY_F2, FCVAR_NONE);
-
-ConVar KeyBindings::MOD_EASY("osu_key_mod_easy", (int)KEY_Q, FCVAR_NONE);
-ConVar KeyBindings::MOD_NOFAIL("osu_key_mod_nofail", (int)KEY_W, FCVAR_NONE);
-ConVar KeyBindings::MOD_HALFTIME("osu_key_mod_halftime", (int)KEY_E, FCVAR_NONE);
-ConVar KeyBindings::MOD_HARDROCK("osu_key_mod_hardrock", (int)KEY_A, FCVAR_NONE);
-ConVar KeyBindings::MOD_SUDDENDEATH("osu_key_mod_suddendeath", (int)KEY_S, FCVAR_NONE);
-ConVar KeyBindings::MOD_DOUBLETIME("osu_key_mod_doubletime", (int)KEY_D, FCVAR_NONE);
-ConVar KeyBindings::MOD_HIDDEN("osu_key_mod_hidden", (int)KEY_F, FCVAR_NONE);
-ConVar KeyBindings::MOD_FLASHLIGHT("osu_key_mod_flashlight", (int)KEY_G, FCVAR_NONE);
-ConVar KeyBindings::MOD_RELAX("osu_key_mod_relax", (int)KEY_Z, FCVAR_NONE);
-ConVar KeyBindings::MOD_AUTOPILOT("osu_key_mod_autopilot", (int)KEY_X, FCVAR_NONE);
-ConVar KeyBindings::MOD_SPUNOUT("osu_key_mod_spunout", (int)KEY_C, FCVAR_NONE);
-ConVar KeyBindings::MOD_AUTO("osu_key_mod_auto", (int)KEY_V, FCVAR_NONE);
-ConVar KeyBindings::MOD_SCOREV2("osu_key_mod_scorev2", (int)KEY_B, FCVAR_NONE);
+ConVar KeyBindings::LEFT_CLICK("osu_key_left_click", (int)KEY_Z, FCVAR_DEFAULT);
+ConVar KeyBindings::RIGHT_CLICK("osu_key_right_click", (int)KEY_X, FCVAR_DEFAULT);
+ConVar KeyBindings::LEFT_CLICK_2("osu_key_left_click_2", 0, FCVAR_DEFAULT);
+ConVar KeyBindings::RIGHT_CLICK_2("osu_key_right_click_2", 0, FCVAR_DEFAULT);
+
+ConVar KeyBindings::FPOSU_ZOOM("osu_key_fposu_zoom", 0, FCVAR_DEFAULT);
+
+ConVar KeyBindings::INCREASE_VOLUME("osu_key_increase_volume", (int)KEY_UP, FCVAR_DEFAULT);
+ConVar KeyBindings::DECREASE_VOLUME("osu_key_decrease_volume", (int)KEY_DOWN, FCVAR_DEFAULT);
+
+ConVar KeyBindings::INCREASE_LOCAL_OFFSET("osu_key_increase_local_offset", (int)KEY_ADD, FCVAR_DEFAULT);
+ConVar KeyBindings::DECREASE_LOCAL_OFFSET("osu_key_decrease_local_offset", (int)KEY_SUBTRACT, FCVAR_DEFAULT);
+
+ConVar KeyBindings::GAME_PAUSE("osu_key_game_pause", (int)KEY_ESCAPE, FCVAR_DEFAULT);
+ConVar KeyBindings::SKIP_CUTSCENE("osu_key_skip_cutscene", (int)KEY_SPACE, FCVAR_DEFAULT);
+ConVar KeyBindings::TOGGLE_SCOREBOARD("osu_key_toggle_scoreboard", (int)KEY_TAB, FCVAR_DEFAULT);
+ConVar KeyBindings::SEEK_TIME("osu_key_seek_time", (int)KEY_SHIFT, FCVAR_DEFAULT);
+ConVar KeyBindings::SEEK_TIME_BACKWARD("osu_key_seek_time_backward", (int)KEY_LEFT, FCVAR_DEFAULT);
+ConVar KeyBindings::SEEK_TIME_FORWARD("osu_key_seek_time_forward", (int)KEY_RIGHT, FCVAR_DEFAULT);
+ConVar KeyBindings::QUICK_RETRY("osu_key_quick_retry", (int)KEY_BACKSPACE, FCVAR_DEFAULT);
+ConVar KeyBindings::QUICK_SAVE("osu_key_quick_save", (int)KEY_F6, FCVAR_DEFAULT);
+ConVar KeyBindings::QUICK_LOAD("osu_key_quick_load", (int)KEY_F7, FCVAR_DEFAULT);
+ConVar KeyBindings::INSTANT_REPLAY("osu_key_instant_replay", (int)KEY_F2, FCVAR_DEFAULT);
+ConVar KeyBindings::TOGGLE_CHAT("osu_key_toggle_chat", (int)KEY_F8, FCVAR_DEFAULT);
+ConVar KeyBindings::SAVE_SCREENSHOT("osu_key_save_screenshot", (int)KEY_F12, FCVAR_DEFAULT);
+ConVar KeyBindings::DISABLE_MOUSE_BUTTONS("osu_key_disable_mouse_buttons", (int)KEY_F10, FCVAR_DEFAULT);
+ConVar KeyBindings::BOSS_KEY("osu_key_boss", (int)KEY_INSERT, FCVAR_DEFAULT);
+
+ConVar KeyBindings::TOGGLE_MODSELECT("osu_key_toggle_modselect", (int)KEY_F1, FCVAR_DEFAULT);
+ConVar KeyBindings::RANDOM_BEATMAP("osu_key_random_beatmap", (int)KEY_F2, FCVAR_DEFAULT);
+
+ConVar KeyBindings::MOD_EASY("osu_key_mod_easy", (int)KEY_Q, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_NOFAIL("osu_key_mod_nofail", (int)KEY_W, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_HALFTIME("osu_key_mod_halftime", (int)KEY_E, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_HARDROCK("osu_key_mod_hardrock", (int)KEY_A, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_SUDDENDEATH("osu_key_mod_suddendeath", (int)KEY_S, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_DOUBLETIME("osu_key_mod_doubletime", (int)KEY_D, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_HIDDEN("osu_key_mod_hidden", (int)KEY_F, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_FLASHLIGHT("osu_key_mod_flashlight", (int)KEY_G, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_RELAX("osu_key_mod_relax", (int)KEY_Z, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_AUTOPILOT("osu_key_mod_autopilot", (int)KEY_X, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_SPUNOUT("osu_key_mod_spunout", (int)KEY_C, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_AUTO("osu_key_mod_auto", (int)KEY_V, FCVAR_DEFAULT);
+ConVar KeyBindings::MOD_SCOREV2("osu_key_mod_scorev2", (int)KEY_B, FCVAR_DEFAULT);
 
 std::vector<ConVar*> KeyBindings::ALL = {&KeyBindings::LEFT_CLICK,
                                          &KeyBindings::RIGHT_CLICK,

+ 8 - 8
src/App/Osu/MainMenu.cpp

@@ -132,18 +132,18 @@ void MainMenuPauseButton::draw(Graphics *g) {
 
 ConVar osu_toggle_preview_music("osu_toggle_preview_music");
 
-ConVar osu_draw_menu_background("osu_draw_menu_background", false, FCVAR_NONE);
-ConVar osu_main_menu_startup_anim_duration("osu_main_menu_startup_anim_duration", 0.25f, FCVAR_NONE);
-ConVar osu_main_menu_alpha("osu_main_menu_alpha", 0.8f, FCVAR_NONE);
-ConVar osu_main_menu_friend("osu_main_menu_friend", true, FCVAR_NONE);
+ConVar osu_draw_menu_background("osu_draw_menu_background", false, FCVAR_DEFAULT);
+ConVar osu_main_menu_startup_anim_duration("osu_main_menu_startup_anim_duration", 0.25f, FCVAR_DEFAULT);
+ConVar osu_main_menu_alpha("osu_main_menu_alpha", 0.8f, FCVAR_DEFAULT);
+ConVar osu_main_menu_friend("osu_main_menu_friend", true, FCVAR_DEFAULT);
 
-ConVar osu_main_menu_banner_always_text("osu_main_menu_banner_always_text", "", FCVAR_NONE);
+ConVar osu_main_menu_banner_always_text("osu_main_menu_banner_always_text", "", FCVAR_DEFAULT);
 ConVar osu_main_menu_banner_ifupdatedfromoldversion_text("osu_main_menu_banner_ifupdatedfromoldversion_text", "",
-                                                         FCVAR_NONE);
+                                                         FCVAR_DEFAULT);
 ConVar osu_main_menu_banner_ifupdatedfromoldversion_le3300_text(
-    "osu_main_menu_banner_ifupdatedfromoldversion_le3300_text", "", FCVAR_NONE);
+    "osu_main_menu_banner_ifupdatedfromoldversion_le3300_text", "", FCVAR_DEFAULT);
 ConVar osu_main_menu_banner_ifupdatedfromoldversion_le3303_text(
-    "osu_main_menu_banner_ifupdatedfromoldversion_le3303_text", "", FCVAR_NONE);
+    "osu_main_menu_banner_ifupdatedfromoldversion_le3303_text", "", FCVAR_DEFAULT);
 
 ConVar *MainMenu::m_osu_universal_offset_ref = NULL;
 ConVar *MainMenu::m_osu_universal_offset_hardcoded_ref = NULL;

+ 45 - 45
src/App/Osu/ModFPoSu.cpp

@@ -29,56 +29,56 @@
 #include "ResourceManager.h"
 #include "Skin.h"
 
-ConVar osu_mod_fposu("osu_mod_fposu", false, FCVAR_NONE);
-
-ConVar fposu_mouse_dpi("fposu_mouse_dpi", 400, FCVAR_NONE);
-ConVar fposu_mouse_cm_360("fposu_mouse_cm_360", 30.0f, FCVAR_NONE);
-ConVar fposu_absolute_mode("fposu_absolute_mode", false, FCVAR_NONE);
-
-ConVar fposu_distance("fposu_distance", 0.5f, FCVAR_NONE);
-ConVar fposu_playfield_position_x("fposu_playfield_position_x", 0.0f, FCVAR_NONE);
-ConVar fposu_playfield_position_y("fposu_playfield_position_y", 0.0f, FCVAR_NONE);
-ConVar fposu_playfield_position_z("fposu_playfield_position_z", 0.0f, FCVAR_NONE);
-ConVar fposu_playfield_rotation_x("fposu_playfield_rotation_x", 0.0f, FCVAR_NONE);
-ConVar fposu_playfield_rotation_y("fposu_playfield_rotation_y", 0.0f, FCVAR_NONE);
-ConVar fposu_playfield_rotation_z("fposu_playfield_rotation_z", 0.0f, FCVAR_NONE);
-ConVar fposu_fov("fposu_fov", 103.0f, FCVAR_NONE);
-ConVar fposu_zoom_fov("fposu_zoom_fov", 45.0f, FCVAR_NONE);
-ConVar fposu_zoom_sensitivity_ratio("fposu_zoom_sensitivity_ratio", 1.0f, FCVAR_NONE,
+ConVar osu_mod_fposu("osu_mod_fposu", false, FCVAR_DEFAULT);
+
+ConVar fposu_mouse_dpi("fposu_mouse_dpi", 400, FCVAR_DEFAULT);
+ConVar fposu_mouse_cm_360("fposu_mouse_cm_360", 30.0f, FCVAR_DEFAULT);
+ConVar fposu_absolute_mode("fposu_absolute_mode", false, FCVAR_DEFAULT);
+
+ConVar fposu_distance("fposu_distance", 0.5f, FCVAR_DEFAULT);
+ConVar fposu_playfield_position_x("fposu_playfield_position_x", 0.0f, FCVAR_DEFAULT);
+ConVar fposu_playfield_position_y("fposu_playfield_position_y", 0.0f, FCVAR_DEFAULT);
+ConVar fposu_playfield_position_z("fposu_playfield_position_z", 0.0f, FCVAR_DEFAULT);
+ConVar fposu_playfield_rotation_x("fposu_playfield_rotation_x", 0.0f, FCVAR_DEFAULT);
+ConVar fposu_playfield_rotation_y("fposu_playfield_rotation_y", 0.0f, FCVAR_DEFAULT);
+ConVar fposu_playfield_rotation_z("fposu_playfield_rotation_z", 0.0f, FCVAR_DEFAULT);
+ConVar fposu_fov("fposu_fov", 103.0f, FCVAR_DEFAULT);
+ConVar fposu_zoom_fov("fposu_zoom_fov", 45.0f, FCVAR_DEFAULT);
+ConVar fposu_zoom_sensitivity_ratio("fposu_zoom_sensitivity_ratio", 1.0f, FCVAR_DEFAULT,
                                     "replicates zoom_sensitivity_ratio behavior on css/csgo/tf2/etc.");
-ConVar fposu_zoom_anim_duration("fposu_zoom_anim_duration", 0.065f, FCVAR_NONE,
+ConVar fposu_zoom_anim_duration("fposu_zoom_anim_duration", 0.065f, FCVAR_DEFAULT,
                                 "time in seconds for the zoom/unzoom animation");
-ConVar fposu_zoom_toggle("fposu_zoom_toggle", false, FCVAR_NONE, "whether the zoom key acts as a toggle");
-ConVar fposu_vertical_fov("fposu_vertical_fov", false, FCVAR_NONE);
-ConVar fposu_curved("fposu_curved", true, FCVAR_NONE);
-ConVar fposu_skybox("fposu_skybox", true, FCVAR_NONE);
-ConVar fposu_cube("fposu_cube", true, FCVAR_NONE);
-ConVar fposu_cube_size("fposu_cube_size", 500.0f, FCVAR_NONE);
-ConVar fposu_cube_tint_r("fposu_cube_tint_r", 255, FCVAR_NONE, "from 0 to 255");
-ConVar fposu_cube_tint_g("fposu_cube_tint_g", 255, FCVAR_NONE, "from 0 to 255");
-ConVar fposu_cube_tint_b("fposu_cube_tint_b", 255, FCVAR_NONE, "from 0 to 255");
-ConVar fposu_invert_vertical("fposu_invert_vertical", false, FCVAR_NONE);
-ConVar fposu_invert_horizontal("fposu_invert_horizontal", false, FCVAR_NONE);
-
-ConVar fposu_noclip("fposu_noclip", true, FCVAR_NONE);
-ConVar fposu_noclipspeed("fposu_noclipspeed", 2.0f, FCVAR_NONE);
-ConVar fposu_noclipaccelerate("fposu_noclipaccelerate", 20.0f, FCVAR_NONE);
-ConVar fposu_noclipfriction("fposu_noclipfriction", 10.0f, FCVAR_NONE);
-
-ConVar fposu_draw_cursor_trail("fposu_draw_cursor_trail", true, FCVAR_NONE);
-ConVar fposu_draw_scorebarbg_on_top("fposu_draw_scorebarbg_on_top", false, FCVAR_NONE);
-ConVar fposu_transparent_playfield("fposu_transparent_playfield", false, FCVAR_NONE,
+ConVar fposu_zoom_toggle("fposu_zoom_toggle", false, FCVAR_DEFAULT, "whether the zoom key acts as a toggle");
+ConVar fposu_vertical_fov("fposu_vertical_fov", false, FCVAR_DEFAULT);
+ConVar fposu_curved("fposu_curved", true, FCVAR_DEFAULT);
+ConVar fposu_skybox("fposu_skybox", true, FCVAR_DEFAULT);
+ConVar fposu_cube("fposu_cube", true, FCVAR_DEFAULT);
+ConVar fposu_cube_size("fposu_cube_size", 500.0f, FCVAR_DEFAULT);
+ConVar fposu_cube_tint_r("fposu_cube_tint_r", 255, FCVAR_DEFAULT, "from 0 to 255");
+ConVar fposu_cube_tint_g("fposu_cube_tint_g", 255, FCVAR_DEFAULT, "from 0 to 255");
+ConVar fposu_cube_tint_b("fposu_cube_tint_b", 255, FCVAR_DEFAULT, "from 0 to 255");
+ConVar fposu_invert_vertical("fposu_invert_vertical", false, FCVAR_DEFAULT);
+ConVar fposu_invert_horizontal("fposu_invert_horizontal", false, FCVAR_DEFAULT);
+
+ConVar fposu_noclip("fposu_noclip", true, FCVAR_DEFAULT);
+ConVar fposu_noclipspeed("fposu_noclipspeed", 2.0f, FCVAR_DEFAULT);
+ConVar fposu_noclipaccelerate("fposu_noclipaccelerate", 20.0f, FCVAR_DEFAULT);
+ConVar fposu_noclipfriction("fposu_noclipfriction", 10.0f, FCVAR_DEFAULT);
+
+ConVar fposu_draw_cursor_trail("fposu_draw_cursor_trail", true, FCVAR_DEFAULT);
+ConVar fposu_draw_scorebarbg_on_top("fposu_draw_scorebarbg_on_top", false, FCVAR_DEFAULT);
+ConVar fposu_transparent_playfield("fposu_transparent_playfield", false, FCVAR_DEFAULT,
                                    "only works if background dim is 100% and background brightness is 0%");
 
-ConVar fposu_mod_strafing("fposu_mod_strafing", false, FCVAR_NONVANILLA);
-ConVar fposu_mod_strafing_strength_x("fposu_mod_strafing_strength_x", 0.3f, FCVAR_NONE);
-ConVar fposu_mod_strafing_frequency_x("fposu_mod_strafing_frequency_x", 0.1f, FCVAR_NONE);
-ConVar fposu_mod_strafing_strength_y("fposu_mod_strafing_strength_y", 0.1f, FCVAR_NONE);
-ConVar fposu_mod_strafing_frequency_y("fposu_mod_strafing_frequency_y", 0.2f, FCVAR_NONE);
-ConVar fposu_mod_strafing_strength_z("fposu_mod_strafing_strength_z", 0.15f, FCVAR_NONE);
-ConVar fposu_mod_strafing_frequency_z("fposu_mod_strafing_frequency_z", 0.15f, FCVAR_NONE);
+ConVar fposu_mod_strafing("fposu_mod_strafing", false, FCVAR_UNLOCKED);
+ConVar fposu_mod_strafing_strength_x("fposu_mod_strafing_strength_x", 0.3f, FCVAR_DEFAULT);
+ConVar fposu_mod_strafing_frequency_x("fposu_mod_strafing_frequency_x", 0.1f, FCVAR_DEFAULT);
+ConVar fposu_mod_strafing_strength_y("fposu_mod_strafing_strength_y", 0.1f, FCVAR_DEFAULT);
+ConVar fposu_mod_strafing_frequency_y("fposu_mod_strafing_frequency_y", 0.2f, FCVAR_DEFAULT);
+ConVar fposu_mod_strafing_strength_z("fposu_mod_strafing_strength_z", 0.15f, FCVAR_DEFAULT);
+ConVar fposu_mod_strafing_frequency_z("fposu_mod_strafing_frequency_z", 0.15f, FCVAR_DEFAULT);
 
-ConVar fposu_mod_3d_depthwobble("fposu_mod_3d_depthwobble", false, FCVAR_NONVANILLA);
+ConVar fposu_mod_3d_depthwobble("fposu_mod_3d_depthwobble", false, FCVAR_UNLOCKED);
 
 constexpr const float ModFPoSu::SIZEDIV3D;
 constexpr const int ModFPoSu::SUBDIVISIONS;

+ 127 - 0
src/App/Osu/NeosuSettings.cpp

@@ -0,0 +1,127 @@
+#include "NeosuSettings.h"
+
+#include "ConVar.h"
+#include "Engine.h"
+#include "cJSON.h"
+
+void process_neosu_settings(Packet packet) {
+    if(packet.size == 0) {
+        debugLog("Failed to get neosu.json! Server probably doesn't support it.\n");
+        return;
+    }
+
+    cJSON *json = cJSON_ParseWithLength((char *)packet.memory, packet.size);
+    if(json == NULL) {
+        debugLog("Failed to parse neosu.json! (received %d bytes)\n", packet.size);
+        return;
+    }
+
+    int nb_overrides = 0;
+    int nb_errors = 0;
+
+    cJSON *object = NULL;
+    cJSON_ArrayForEach(object, json) {
+        cJSON *default_value = NULL;
+        cJSON *unlock_singleplayer = NULL;
+        cJSON *unlock_multiplayer = NULL;
+        cJSON *always_submit = NULL;
+
+        if(object->string == NULL) continue;
+
+        auto cvar = convar->getConVarByName(object->string);
+        if(cvar->getName() == UString("emptyDummyConVar")) {
+            debugLog("Unknown convar \"%s\", cannot override.\n", object->string);
+            continue;
+        }
+
+        cvar->resetDefaults();
+        int flags = cvar->getFlags();
+        if(flags & (FCVAR_HIDDEN | FCVAR_PRIVATE)) {
+            debugLog("Server tried to override private convar \"%s\"!\n", object->string);
+            goto cvar_err;
+        }
+
+        default_value = cJSON_GetObjectItemCaseSensitive(object, "default");
+        if(default_value != NULL) {
+            if(cvar->getType() == ConVar::CONVAR_TYPE::CONVAR_TYPE_STRING) {
+                char *new_default = cJSON_GetStringValue(default_value);
+                if(new_default) {
+                    cvar->setDefaultString(new_default);
+                } else {
+                    debugLog("Invalid type for \"%s\" in neosu.json! \"default\" should be a string.\n",
+                             object->string);
+                    goto cvar_err;
+                }
+            } else if(cvar->getType() == ConVar::CONVAR_TYPE::CONVAR_TYPE_BOOL) {
+                if(!cJSON_IsBool(default_value)) {
+                    debugLog("Invalid type for \"%s\" in neosu.json! \"default\" should be a boolean.\n",
+                             object->string);
+                    goto cvar_err;
+                } else {
+                    cvar->setDefaultFloat(cJSON_IsTrue(default_value) ? 1.f : 0.f);
+                }
+            } else {
+                if(!cJSON_IsNumber(default_value)) {
+                    debugLog("Invalid type for \"%s\" in neosu.json! \"default\" should be a number.\n",
+                             object->string);
+                    goto cvar_err;
+                } else {
+                    cvar->setDefaultFloat(cJSON_GetNumberValue(default_value));
+                }
+            }
+        }
+
+        unlock_singleplayer = cJSON_GetObjectItemCaseSensitive(object, "unlock_singleplayer");
+        if(unlock_singleplayer) {
+            if(!cJSON_IsBool(unlock_singleplayer)) {
+                debugLog("Invalid type for \"%s\" in neosu.json! \"unlock_singleplayer\" should be a boolean.\n",
+                         object->string);
+                goto cvar_err;
+            }
+
+            flags &= ~(FCVAR_UNLOCK_SINGLEPLAYER);
+            if(cJSON_IsTrue(unlock_singleplayer)) {
+                flags |= FCVAR_UNLOCK_SINGLEPLAYER;
+            }
+        }
+
+        unlock_multiplayer = cJSON_GetObjectItemCaseSensitive(object, "unlock_multiplayer");
+        if(unlock_multiplayer) {
+            if(!cJSON_IsBool(unlock_multiplayer)) {
+                debugLog("Invalid type for \"%s\" in neosu.json! \"unlock_multiplayer\" should be a boolean.\n",
+                         object->string);
+                goto cvar_err;
+            }
+
+            flags &= ~(FCVAR_UNLOCK_MULTIPLAYER);
+            if(cJSON_IsTrue(unlock_multiplayer)) {
+                flags |= FCVAR_UNLOCK_MULTIPLAYER;
+            }
+        }
+
+        always_submit = cJSON_GetObjectItemCaseSensitive(object, "always_submit");
+        if(always_submit) {
+            if(!cJSON_IsBool(always_submit)) {
+                debugLog("Invalid type for \"%s\" in neosu.json! \"always_submit\" should be a boolean.\n",
+                         object->string);
+                goto cvar_err;
+            }
+
+            flags &= ~(FCVAR_ALWAYS_SUBMIT);
+            if(cJSON_IsTrue(always_submit)) {
+                flags |= FCVAR_ALWAYS_SUBMIT;
+            }
+        }
+
+        cvar->setFlags(flags);
+        nb_overrides++;
+        continue;
+
+    cvar_err:
+        cvar->resetDefaults();
+        nb_errors++;
+    }
+
+    debugLog("Finished applying neosu.json configuration (%d overrides, %d errors)\n", nb_overrides, nb_errors);
+    cJSON_Delete(json);
+}

+ 4 - 0
src/App/Osu/NeosuSettings.h

@@ -0,0 +1,4 @@
+#pragma once
+#include "BanchoProtocol.h"
+
+void process_neosu_settings(Packet packet);

+ 1 - 1
src/App/Osu/NotificationOverlay.cpp

@@ -14,7 +14,7 @@
 #include "Osu.h"
 #include "ResourceManager.h"
 
-ConVar osu_notification_duration("osu_notification_duration", 1.25f, FCVAR_NONE);
+ConVar osu_notification_duration("osu_notification_duration", 1.25f, FCVAR_DEFAULT);
 
 NotificationOverlay::NotificationOverlay(Osu *osu) : OsuScreen(osu) {
     m_bWaitForKey = false;

+ 4 - 4
src/App/Osu/OptionsMenu.cpp

@@ -47,10 +47,10 @@
 #include "UISearchOverlay.h"
 #include "UISlider.h"
 
-ConVar osu_options_save_on_back("osu_options_save_on_back", true, FCVAR_NONE);
-ConVar osu_options_high_quality_sliders("osu_options_high_quality_sliders", false, FCVAR_NONE);
+ConVar osu_options_save_on_back("osu_options_save_on_back", true, FCVAR_DEFAULT);
+ConVar osu_options_high_quality_sliders("osu_options_high_quality_sliders", false, FCVAR_DEFAULT);
 ConVar osu_options_slider_preview_use_legacy_renderer(
-    "osu_options_slider_preview_use_legacy_renderer", false, FCVAR_NONE,
+    "osu_options_slider_preview_use_legacy_renderer", false, FCVAR_DEFAULT,
     "apparently newer AMD drivers with old gpus are crashing here with the legacy renderer? was just me being lazy "
     "anyway, so now there is a vao render path as it should be");
 
@@ -58,7 +58,7 @@ void _osuOptionsSliderQualityWrapper(UString oldValue, UString newValue) {
     float value = lerp<float>(1.0f, 2.5f, 1.0f - newValue.toFloat());
     convar->getConVarByName("osu_slider_curve_points_separation")->setValue(value);
 };
-ConVar osu_options_slider_quality("osu_options_slider_quality", 0.0f, FCVAR_NONE, _osuOptionsSliderQualityWrapper);
+ConVar osu_options_slider_quality("osu_options_slider_quality", 0.0f, FCVAR_DEFAULT, _osuOptionsSliderQualityWrapper);
 
 const char *OptionsMenu::OSU_CONFIG_FILE_NAME = "";  // set dynamically below in the constructor
 

+ 66 - 72
src/App/Osu/Osu.cpp

@@ -63,92 +63,96 @@
 #include "score.h"
 
 // release configuration
-ConVar auto_update("auto_update", true, FCVAR_NONE);
-ConVar osu_version("osu_version", 35.01f, FCVAR_NONE);
+ConVar auto_update("auto_update", true, FCVAR_DEFAULT);
+ConVar osu_version("osu_version", 35.01f, FCVAR_DEFAULT | FCVAR_HIDDEN);
 
 #ifdef _DEBUG
-ConVar osu_debug("osu_debug", true, FCVAR_NONE);
+ConVar osu_debug("osu_debug", true, FCVAR_DEFAULT);
 #else
-ConVar osu_debug("osu_debug", false, FCVAR_NONE);
+ConVar osu_debug("osu_debug", false, FCVAR_DEFAULT);
 #endif
 
-ConVar osu_disable_mousebuttons("osu_disable_mousebuttons", false, FCVAR_NONE);
-ConVar osu_disable_mousewheel("osu_disable_mousewheel", false, FCVAR_NONE);
-ConVar osu_confine_cursor_windowed("osu_confine_cursor_windowed", false, FCVAR_NONE);
-ConVar osu_confine_cursor_fullscreen("osu_confine_cursor_fullscreen", true, FCVAR_NONE);
+ConVar osu_disable_mousebuttons("osu_disable_mousebuttons", false, FCVAR_DEFAULT);
+ConVar osu_disable_mousewheel("osu_disable_mousewheel", false, FCVAR_DEFAULT);
+ConVar osu_confine_cursor_windowed("osu_confine_cursor_windowed", false, FCVAR_DEFAULT);
+ConVar osu_confine_cursor_fullscreen("osu_confine_cursor_fullscreen", true, FCVAR_DEFAULT);
 
-ConVar osu_skin("osu_skin", "default", FCVAR_NONE);
+ConVar osu_skin("osu_skin", "default", FCVAR_DEFAULT);
 ConVar osu_skin_reload("osu_skin_reload");
 
-ConVar osu_volume_master("osu_volume_master", 1.0f, FCVAR_NONE);
-ConVar osu_volume_master_inactive("osu_volume_master_inactive", 0.25f, FCVAR_NONE);
-ConVar osu_volume_effects("osu_volume_effects", 1.0f, FCVAR_NONE);
-ConVar osu_volume_music("osu_volume_music", 0.4f, FCVAR_NONE);
-ConVar osu_volume_change_interval("osu_volume_change_interval", 0.05f, FCVAR_NONE);
-ConVar osu_hud_volume_duration("osu_hud_volume_duration", 1.0f, FCVAR_NONE);
-ConVar osu_hud_volume_size_multiplier("osu_hud_volume_size_multiplier", 1.5f, FCVAR_NONE);
-
-ConVar osu_speed_override("osu_speed_override", -1.0f, FCVAR_NONVANILLA);
-ConVar osu_animation_speed_override("osu_animation_speed_override", -1.0f, FCVAR_CHEAT);
-
-ConVar osu_pause_on_focus_loss("osu_pause_on_focus_loss", true, FCVAR_NONE);
-ConVar osu_quick_retry_delay("osu_quick_retry_delay", 0.27f, FCVAR_NONE);
-ConVar osu_scrubbing_smooth("osu_scrubbing_smooth", true, FCVAR_NONE);
-ConVar osu_skip_intro_enabled("osu_skip_intro_enabled", true, FCVAR_NONE,
+ConVar osu_volume_master("osu_volume_master", 1.0f, FCVAR_DEFAULT);
+ConVar osu_volume_master_inactive("osu_volume_master_inactive", 0.25f, FCVAR_DEFAULT);
+ConVar osu_volume_effects("osu_volume_effects", 1.0f, FCVAR_DEFAULT);
+ConVar osu_volume_music("osu_volume_music", 0.4f, FCVAR_DEFAULT);
+ConVar osu_volume_change_interval("osu_volume_change_interval", 0.05f, FCVAR_DEFAULT);
+ConVar osu_hud_volume_duration("osu_hud_volume_duration", 1.0f, FCVAR_DEFAULT);
+ConVar osu_hud_volume_size_multiplier("osu_hud_volume_size_multiplier", 1.5f, FCVAR_DEFAULT);
+
+ConVar osu_speed_override("osu_speed_override", -1.0f, FCVAR_UNLOCKED);
+ConVar osu_animation_speed_override("osu_animation_speed_override", -1.0f, FCVAR_LOCKED);
+
+ConVar osu_pause_on_focus_loss("osu_pause_on_focus_loss", true, FCVAR_DEFAULT);
+ConVar osu_quick_retry_delay("osu_quick_retry_delay", 0.27f, FCVAR_DEFAULT);
+ConVar osu_scrubbing_smooth("osu_scrubbing_smooth", true, FCVAR_DEFAULT);
+ConVar osu_skip_intro_enabled("osu_skip_intro_enabled", true, FCVAR_DEFAULT,
                               "enables/disables skip button for intro until first hitobject");
-ConVar osu_skip_breaks_enabled("osu_skip_breaks_enabled", true, FCVAR_NONE,
+ConVar osu_skip_breaks_enabled("osu_skip_breaks_enabled", true, FCVAR_DEFAULT,
                                "enables/disables skip button for breaks in the middle of beatmaps");
-ConVar osu_seek_delta("osu_seek_delta", 5, FCVAR_NONE, "how many seconds to skip backward/forward when quick seeking");
+ConVar osu_seek_delta("osu_seek_delta", 5, FCVAR_DEFAULT,
+                      "how many seconds to skip backward/forward when quick seeking");
 
-ConVar osu_mods("osu_mods", "", FCVAR_NONE);
-ConVar osu_mod_touchdevice("osu_mod_touchdevice", false, FCVAR_NONE, "used for force applying touch pp nerf always");
-ConVar osu_mod_fadingcursor("osu_mod_fadingcursor", false, FCVAR_NONVANILLA);
-ConVar osu_mod_fadingcursor_combo("osu_mod_fadingcursor_combo", 50.0f, FCVAR_NONE);
-ConVar osu_mod_endless("osu_mod_endless", false, FCVAR_CHEAT);
+ConVar osu_mods("osu_mods", "", FCVAR_DEFAULT);
+ConVar osu_mod_touchdevice("osu_mod_touchdevice", false, FCVAR_DEFAULT, "used for force applying touch pp nerf always");
+ConVar osu_mod_fadingcursor("osu_mod_fadingcursor", false, FCVAR_UNLOCKED);
+ConVar osu_mod_fadingcursor_combo("osu_mod_fadingcursor_combo", 50.0f, FCVAR_DEFAULT);
+ConVar osu_mod_endless("osu_mod_endless", false, FCVAR_LOCKED);
 
 ConVar osu_notification("osu_notification");
-ConVar osu_notification_color_r("osu_notification_color_r", 255, FCVAR_NONE);
-ConVar osu_notification_color_g("osu_notification_color_g", 255, FCVAR_NONE);
-ConVar osu_notification_color_b("osu_notification_color_b", 255, FCVAR_NONE);
+ConVar osu_notification_color_r("osu_notification_color_r", 255, FCVAR_DEFAULT);
+ConVar osu_notification_color_g("osu_notification_color_g", 255, FCVAR_DEFAULT);
+ConVar osu_notification_color_b("osu_notification_color_b", 255, FCVAR_DEFAULT);
 
-ConVar osu_ui_scale("osu_ui_scale", 1.0f, FCVAR_NONE, "multiplier");
-ConVar osu_ui_scale_to_dpi("osu_ui_scale_to_dpi", true, FCVAR_NONE,
+ConVar osu_ui_scale("osu_ui_scale", 1.0f, FCVAR_DEFAULT, "multiplier");
+ConVar osu_ui_scale_to_dpi("osu_ui_scale_to_dpi", true, FCVAR_DEFAULT,
                            "whether the game should scale its UI based on the DPI reported by your operating system");
 ConVar osu_ui_scale_to_dpi_minimum_width(
-    "osu_ui_scale_to_dpi_minimum_width", 2200, FCVAR_NONE,
+    "osu_ui_scale_to_dpi_minimum_width", 2200, FCVAR_DEFAULT,
     "any in-game resolutions below this will have osu_ui_scale_to_dpi force disabled");
 ConVar osu_ui_scale_to_dpi_minimum_height(
-    "osu_ui_scale_to_dpi_minimum_height", 1300, FCVAR_NONE,
+    "osu_ui_scale_to_dpi_minimum_height", 1300, FCVAR_DEFAULT,
     "any in-game resolutions below this will have osu_ui_scale_to_dpi force disabled");
-ConVar osu_letterboxing("osu_letterboxing", true, FCVAR_NONE);
-ConVar osu_letterboxing_offset_x("osu_letterboxing_offset_x", 0.0f, FCVAR_NONE);
-ConVar osu_letterboxing_offset_y("osu_letterboxing_offset_y", 0.0f, FCVAR_NONE);
-ConVar osu_resolution("osu_resolution", "1280x720", FCVAR_NONE);
-ConVar osu_resolution_enabled("osu_resolution_enabled", false, FCVAR_NONE);
-ConVar osu_resolution_keep_aspect_ratio("osu_resolution_keep_aspect_ratio", false, FCVAR_NONE);
-ConVar osu_force_legacy_slider_renderer("osu_force_legacy_slider_renderer", false, FCVAR_NONE,
+ConVar osu_letterboxing("osu_letterboxing", true, FCVAR_DEFAULT);
+ConVar osu_letterboxing_offset_x("osu_letterboxing_offset_x", 0.0f, FCVAR_DEFAULT);
+ConVar osu_letterboxing_offset_y("osu_letterboxing_offset_y", 0.0f, FCVAR_DEFAULT);
+ConVar osu_resolution("osu_resolution", "1280x720", FCVAR_DEFAULT);
+ConVar osu_resolution_enabled("osu_resolution_enabled", false, FCVAR_DEFAULT);
+ConVar osu_resolution_keep_aspect_ratio("osu_resolution_keep_aspect_ratio", false, FCVAR_DEFAULT);
+ConVar osu_force_legacy_slider_renderer("osu_force_legacy_slider_renderer", false, FCVAR_DEFAULT,
                                         "on some older machines, this may be faster than vertexbuffers");
 
-ConVar osu_draw_fps("osu_draw_fps", true, FCVAR_NONE);
+ConVar osu_draw_fps("osu_draw_fps", true, FCVAR_DEFAULT);
 
-ConVar osu_alt_f4_quits_even_while_playing("osu_alt_f4_quits_even_while_playing", true, FCVAR_NONE);
-ConVar osu_win_disable_windows_key_while_playing("osu_win_disable_windows_key_while_playing", true, FCVAR_NONE);
+ConVar osu_alt_f4_quits_even_while_playing("osu_alt_f4_quits_even_while_playing", true, FCVAR_DEFAULT);
+ConVar osu_win_disable_windows_key_while_playing("osu_win_disable_windows_key_while_playing", true, FCVAR_DEFAULT);
 
-ConVar avoid_flashes("avoid_flashes", false, FCVAR_NONE, "disable flashing elements (like FL dimming on sliders)");
-ConVar flashlight_radius("flashlight_radius", 100.f, FCVAR_CHEAT);
-ConVar flashlight_follow_delay("flashlight_follow_delay", 0.120f, FCVAR_CHEAT);
-ConVar flashlight_always_hard("flashlight_always_hard", false, FCVAR_NONE, "always use 200+ combo flashlight radius");
+ConVar avoid_flashes("avoid_flashes", false, FCVAR_DEFAULT, "disable flashing elements (like FL dimming on sliders)");
+ConVar flashlight_radius("flashlight_radius", 100.f, FCVAR_LOCKED);
+ConVar flashlight_follow_delay("flashlight_follow_delay", 0.120f, FCVAR_LOCKED);
+ConVar flashlight_always_hard("flashlight_always_hard", false, FCVAR_DEFAULT,
+                              "always use 200+ combo flashlight radius");
 
-ConVar start_first_main_menu_song_at_preview_point("start_first_main_menu_song_at_preview_point", false, FCVAR_NONE);
-ConVar nightcore_enjoyer("nightcore_enjoyer", false, FCVAR_NONE, "automatically select nightcore when speed modifying");
-ConVar scoreboard_animations("scoreboard_animations", true, FCVAR_NONE, "animate in-game scoreboard");
-ConVar instant_replay_duration("instant_replay_duration", 15.f, FCVAR_NONE, "instant replay (F2) duration, in seconds");
-ConVar normalize_loudness("normalize_loudness", false, FCVAR_NONE, "normalize loudness across songs");
+ConVar start_first_main_menu_song_at_preview_point("start_first_main_menu_song_at_preview_point", false, FCVAR_DEFAULT);
+ConVar nightcore_enjoyer("nightcore_enjoyer", false, FCVAR_DEFAULT,
+                         "automatically select nightcore when speed modifying");
+ConVar scoreboard_animations("scoreboard_animations", true, FCVAR_DEFAULT, "animate in-game scoreboard");
+ConVar instant_replay_duration("instant_replay_duration", 15.f, FCVAR_DEFAULT,
+                               "instant replay (F2) duration, in seconds");
+ConVar normalize_loudness("normalize_loudness", false, FCVAR_DEFAULT, "normalize loudness across songs");
 
-ConVar mp_server("mp_server", "ez-pp.farm", FCVAR_NONE);
-ConVar mp_password("mp_password", "", FCVAR_HIDDEN);
-ConVar mp_autologin("mp_autologin", false, FCVAR_NONE);
-ConVar submit_scores("submit_scores", false, FCVAR_NONE);
+ConVar mp_server("mp_server", "ez-pp.farm", FCVAR_DEFAULT);
+ConVar mp_password("mp_password", "", FCVAR_DEFAULT | FCVAR_HIDDEN);
+ConVar mp_autologin("mp_autologin", false, FCVAR_DEFAULT);
+ConVar submit_scores("submit_scores", false, FCVAR_DEFAULT);
 
 // If catboy.best doesn't work for you, here are some alternatives:
 // - https://api.osu.direct/d/
@@ -156,7 +160,7 @@ ConVar submit_scores("submit_scores", false, FCVAR_NONE);
 // - https://api.nerinyan.moe/d/
 // - https://osu.gatari.pw/d/
 // - https://osu.sayobot.cn/osu.php?s=
-ConVar beatmap_mirror("beatmap_mirror", "https://catboy.best/s/", FCVAR_NONE,
+ConVar beatmap_mirror("beatmap_mirror", "https://catboy.best/s/", FCVAR_DEFAULT,
                       "mirror from which beatmapsets will be downloaded");
 
 ConVar *Osu::version = &osu_version;
@@ -253,8 +257,6 @@ Osu::Osu(int instanceID) {
     }
 
     // convar callbacks
-    ConVars::sv_cheats.setCallback(fastdelegate::MakeDelegate(this, &Osu::onCheatsChange));
-
     osu_speed_override.setCallback(fastdelegate::MakeDelegate(this, &Osu::onSpeedChange));
     osu_animation_speed_override.setCallback(fastdelegate::MakeDelegate(this, &Osu::onAnimationSpeedChange));
 
@@ -1986,14 +1988,6 @@ void Osu::updateWindowsKeyDisable() {
 
 void Osu::fireResolutionChanged() { onResolutionChanged(g_vInternalResolution); }
 
-void Osu::onCheatsChange(UString oldValue, UString newValue) {
-    (void)oldValue;
-    (void)newValue;
-    if(bancho.is_online() && (bancho.submit_scores() || bancho.is_in_a_multi_room()) && ConVars::sv_cheats.getBool()) {
-        ConVars::sv_cheats.setValue(false);
-    }
-}
-
 void Osu::onInternalResolutionChanged(UString oldValue, UString args) {
     if(args.length() < 7) return;
 

+ 0 - 1
src/App/Osu/Osu.h

@@ -199,7 +199,6 @@ class Osu : public App, public MouseListener {
     void fireResolutionChanged();
 
     // callbacks
-    void onCheatsChange(UString oldValue, UString newValue);
     void onInternalResolutionChanged(UString oldValue, UString args);
 
     void onSkinReload();

+ 3 - 3
src/App/Osu/PauseMenu.cpp

@@ -27,9 +27,9 @@
 #include "SoundEngine.h"
 #include "UIPauseMenuButton.h"
 
-ConVar osu_pause_dim_background("osu_pause_dim_background", true, FCVAR_NONE);
-ConVar osu_pause_dim_alpha("osu_pause_dim_alpha", 0.58f, FCVAR_NONE);
-ConVar osu_pause_anim_duration("osu_pause_anim_duration", 0.15f, FCVAR_NONE);
+ConVar osu_pause_dim_background("osu_pause_dim_background", true, FCVAR_DEFAULT);
+ConVar osu_pause_dim_alpha("osu_pause_dim_alpha", 0.58f, FCVAR_DEFAULT);
+ConVar osu_pause_anim_duration("osu_pause_anim_duration", 0.15f, FCVAR_DEFAULT);
 
 PauseMenu::PauseMenu(Osu *osu) : OsuScreen(osu) {
     m_bScheduledVisibility = false;

+ 3 - 3
src/App/Osu/RankingScreen.cpp

@@ -37,9 +37,9 @@
 #include "UIRankingScreenRankingPanel.h"
 #include "score.h"
 
-ConVar osu_rankingscreen_topbar_height_percent("osu_rankingscreen_topbar_height_percent", 0.785f, FCVAR_NONE);
-ConVar osu_rankingscreen_pp("osu_rankingscreen_pp", true, FCVAR_NONE);
-ConVar osu_draw_rankingscreen_background_image("osu_draw_rankingscreen_background_image", true, FCVAR_NONE);
+ConVar osu_rankingscreen_topbar_height_percent("osu_rankingscreen_topbar_height_percent", 0.785f, FCVAR_DEFAULT);
+ConVar osu_rankingscreen_pp("osu_rankingscreen_pp", true, FCVAR_DEFAULT);
+ConVar osu_draw_rankingscreen_background_image("osu_draw_rankingscreen_background_image", true, FCVAR_DEFAULT);
 
 class RankingScreenIndexLabel : public CBaseUILabel {
    public:

+ 4 - 4
src/App/Osu/RichPresence.cpp

@@ -22,12 +22,12 @@
 #include "SongBrowser/SongBrowser.h"
 #include "score.h"
 
-ConVar osu_rich_presence("osu_rich_presence", true, FCVAR_NONE, RichPresence::onRichPresenceChange);
+ConVar osu_rich_presence("osu_rich_presence", true, FCVAR_DEFAULT, RichPresence::onRichPresenceChange);
 ConVar osu_rich_presence_dynamic_windowtitle(
-    "osu_rich_presence_dynamic_windowtitle", true, FCVAR_NONE,
+    "osu_rich_presence_dynamic_windowtitle", true, FCVAR_DEFAULT,
     "should the window title show the currently playing beatmap Artist - Title and [Difficulty] name");
-ConVar osu_rich_presence_show_recentplaystats("osu_rich_presence_show_recentplaystats", true, FCVAR_NONE);
-ConVar osu_rich_presence_discord_show_totalpp("osu_rich_presence_discord_show_totalpp", true, FCVAR_NONE);
+ConVar osu_rich_presence_show_recentplaystats("osu_rich_presence_show_recentplaystats", true, FCVAR_DEFAULT);
+ConVar osu_rich_presence_discord_show_totalpp("osu_rich_presence_discord_show_totalpp", true, FCVAR_DEFAULT);
 
 ConVar *RichPresence::m_name_ref = NULL;
 

+ 0 - 4
src/App/Osu/RoomScreen.cpp

@@ -516,8 +516,6 @@ void RoomScreen::ragequit() {
     m_osu->m_mainMenu->setVisible(true);
     m_osu->m_chat->removeChannel("#multiplayer");
     m_osu->m_chat->updateVisibility();
-
-    ConVars::sv_cheats.setValue(!bancho.submit_scores());
 }
 
 void RoomScreen::process_beatmapset_info_response(Packet packet) {
@@ -638,8 +636,6 @@ void RoomScreen::on_map_change(bool download) {
 }
 
 void RoomScreen::on_room_joined(Room room) {
-    ConVars::sv_cheats.setValue(false);
-
     bancho.room = room;
     debugLog("Joined room #%d\nPlayers:\n", room.id);
     for(int i = 0; i < 16; i++) {

+ 17 - 16
src/App/Osu/Skin.cpp

@@ -26,35 +26,36 @@
 #define OSU_BITMASK_HITFINISH 0x4
 #define OSU_BITMASK_HITCLAP 0x8
 
-ConVar osu2_sound_source_id("osu2_sound_source_id", 1, FCVAR_NONE,
+ConVar osu2_sound_source_id("osu2_sound_source_id", 1, FCVAR_DEFAULT,
                             "which instance/player/client should play hitsounds (e.g. master top left is always 1)");
 
-ConVar osu_skin_async("osu_skin_async", true, FCVAR_NONE, "load in background without blocking");
-ConVar osu_skin_hd("osu_skin_hd", true, FCVAR_NONE, "load and use @2x versions of skin images, if available");
+ConVar osu_skin_async("osu_skin_async", true, FCVAR_DEFAULT, "load in background without blocking");
+ConVar osu_skin_hd("osu_skin_hd", true, FCVAR_DEFAULT, "load and use @2x versions of skin images, if available");
 ConVar osu_skin_mipmaps(
-    "osu_skin_mipmaps", false, FCVAR_NONE,
+    "osu_skin_mipmaps", false, FCVAR_DEFAULT,
     "generate mipmaps for every skin image (only useful on lower game resolutions, requires more vram)");
-ConVar osu_skin_color_index_add("osu_skin_color_index_add", 0, FCVAR_NONE);
-ConVar osu_skin_animation_force("osu_skin_animation_force", false, FCVAR_NONE);
+ConVar osu_skin_color_index_add("osu_skin_color_index_add", 0, FCVAR_DEFAULT);
+ConVar osu_skin_animation_force("osu_skin_animation_force", false, FCVAR_DEFAULT);
 ConVar osu_skin_use_skin_hitsounds(
-    "osu_skin_use_skin_hitsounds", true, FCVAR_NONE,
+    "osu_skin_use_skin_hitsounds", true, FCVAR_DEFAULT,
     "If enabled: Use skin's sound samples. If disabled: Use default skin's sound samples. For hitsounds only.");
-ConVar osu_skin_force_hitsound_sample_set("osu_skin_force_hitsound_sample_set", 0, FCVAR_NONE,
+ConVar osu_skin_force_hitsound_sample_set("osu_skin_force_hitsound_sample_set", 0, FCVAR_DEFAULT,
                                           "force a specific hitsound sample set to always be used regardless of what "
                                           "the beatmap says. 0 = disabled, 1 = normal, 2 = soft, 3 = drum.");
-ConVar osu_skin_random("osu_skin_random", false, FCVAR_NONE, "select random skin from list on every skin load/reload");
-ConVar osu_skin_random_elements("osu_skin_random_elements", false, FCVAR_NONE,
+ConVar osu_skin_random("osu_skin_random", false, FCVAR_DEFAULT,
+                       "select random skin from list on every skin load/reload");
+ConVar osu_skin_random_elements("osu_skin_random_elements", false, FCVAR_DEFAULT,
                                 "sElECt RanDOM sKIn eLemENTs FRoM ranDom SkINs");
-ConVar osu_mod_fposu_sound_panning("osu_mod_fposu_sound_panning", false, FCVAR_NONE, "see osu_sound_panning");
-ConVar osu_mod_fps_sound_panning("osu_mod_fps_sound_panning", false, FCVAR_NONE, "see osu_sound_panning");
-ConVar osu_sound_panning("osu_sound_panning", true, FCVAR_NONE,
+ConVar osu_mod_fposu_sound_panning("osu_mod_fposu_sound_panning", false, FCVAR_DEFAULT, "see osu_sound_panning");
+ConVar osu_mod_fps_sound_panning("osu_mod_fps_sound_panning", false, FCVAR_DEFAULT, "see osu_sound_panning");
+ConVar osu_sound_panning("osu_sound_panning", true, FCVAR_DEFAULT,
                          "positional hitsound audio depending on the playfield position");
-ConVar osu_sound_panning_multiplier("osu_sound_panning_multiplier", 1.0f, FCVAR_NONE,
+ConVar osu_sound_panning_multiplier("osu_sound_panning_multiplier", 1.0f, FCVAR_DEFAULT,
                                     "the final panning value is multiplied with this, e.g. if you want to reduce or "
                                     "increase the effect strength by a percentage");
 
-ConVar osu_ignore_beatmap_combo_colors("osu_ignore_beatmap_combo_colors", false, FCVAR_NONE);
-ConVar osu_ignore_beatmap_sample_volume("osu_ignore_beatmap_sample_volume", false, FCVAR_NONE);
+ConVar osu_ignore_beatmap_combo_colors("osu_ignore_beatmap_combo_colors", false, FCVAR_DEFAULT);
+ConVar osu_ignore_beatmap_sample_volume("osu_ignore_beatmap_sample_volume", false, FCVAR_DEFAULT);
 
 const char *Skin::OSUSKIN_DEFAULT_SKIN_PATH = "";  // set dynamically below in the constructor
 Image *Skin::m_missingTexture = NULL;

+ 1 - 1
src/App/Osu/SkinImage.cpp

@@ -14,7 +14,7 @@
 #include "ResourceManager.h"
 #include "Skin.h"
 
-ConVar osu_skin_animation_fps_override("osu_skin_animation_fps_override", -1.0f, FCVAR_NONE);
+ConVar osu_skin_animation_fps_override("osu_skin_animation_fps_override", -1.0f, FCVAR_DEFAULT);
 
 ConVar *SkinImage::m_osu_skin_mipmaps_ref = NULL;
 

+ 18 - 18
src/App/Osu/Slider.cpp

@@ -27,41 +27,41 @@
 #include "SoundEngine.h"
 #include "VertexArrayObject.h"
 
-ConVar osu_slider_ball_tint_combo_color("osu_slider_ball_tint_combo_color", true, FCVAR_NONE);
+ConVar osu_slider_ball_tint_combo_color("osu_slider_ball_tint_combo_color", true, FCVAR_DEFAULT);
 
-ConVar osu_snaking_sliders("osu_snaking_sliders", true, FCVAR_NONE);
-ConVar osu_mod_hd_slider_fade_percent("osu_mod_hd_slider_fade_percent", 1.0f, FCVAR_CHEAT);
-ConVar osu_mod_hd_slider_fast_fade("osu_mod_hd_slider_fast_fade", false, FCVAR_NONE);
+ConVar osu_snaking_sliders("osu_snaking_sliders", true, FCVAR_DEFAULT);
+ConVar osu_mod_hd_slider_fade_percent("osu_mod_hd_slider_fade_percent", 1.0f, FCVAR_LOCKED);
+ConVar osu_mod_hd_slider_fast_fade("osu_mod_hd_slider_fast_fade", false, FCVAR_DEFAULT);
 
-ConVar osu_slider_end_inside_check_offset("osu_slider_end_inside_check_offset", 36, FCVAR_CHEAT,
+ConVar osu_slider_end_inside_check_offset("osu_slider_end_inside_check_offset", 36, FCVAR_LOCKED,
                                           "offset in milliseconds going backwards from the end point, at which \"being "
                                           "inside the slider\" is checked. (osu bullshit behavior)");
-ConVar osu_slider_end_miss_breaks_combo("osu_slider_end_miss_breaks_combo", false, FCVAR_NONE,
+ConVar osu_slider_end_miss_breaks_combo("osu_slider_end_miss_breaks_combo", false, FCVAR_DEFAULT,
                                         "should a missed sliderend break combo (aka cause a regular sliderbreak)");
-ConVar osu_slider_break_epilepsy("osu_slider_break_epilepsy", false, FCVAR_NONE);
-ConVar osu_slider_scorev2("osu_slider_scorev2", false, FCVAR_CHEAT);
+ConVar osu_slider_break_epilepsy("osu_slider_break_epilepsy", false, FCVAR_DEFAULT);
+ConVar osu_slider_scorev2("osu_slider_scorev2", false, FCVAR_LOCKED);
 
-ConVar osu_slider_draw_body("osu_slider_draw_body", true, FCVAR_NONE);
-ConVar osu_slider_shrink("osu_slider_shrink", false, FCVAR_NONE);
-ConVar osu_slider_snake_duration_multiplier("osu_slider_snake_duration_multiplier", 1.0f, FCVAR_NONE,
+ConVar osu_slider_draw_body("osu_slider_draw_body", true, FCVAR_DEFAULT);
+ConVar osu_slider_shrink("osu_slider_shrink", false, FCVAR_DEFAULT);
+ConVar osu_slider_snake_duration_multiplier("osu_slider_snake_duration_multiplier", 1.0f, FCVAR_DEFAULT,
                                             "the default snaking duration is multiplied with this (max sensible value "
                                             "is 3, anything above that will take longer than the approachtime)");
 ConVar osu_slider_reverse_arrow_black_threshold(
-    "osu_slider_reverse_arrow_black_threshold", 1.0f, FCVAR_NONE,
+    "osu_slider_reverse_arrow_black_threshold", 1.0f, FCVAR_DEFAULT,
     "Blacken reverse arrows if the average color brightness percentage is above this value");  // looks too shitty atm
-ConVar osu_slider_reverse_arrow_fadein_duration("osu_slider_reverse_arrow_fadein_duration", 150, FCVAR_NONE,
+ConVar osu_slider_reverse_arrow_fadein_duration("osu_slider_reverse_arrow_fadein_duration", 150, FCVAR_DEFAULT,
                                                 "duration in ms of the reverse arrow fadein animation after it starts");
 ConVar osu_slider_body_smoothsnake(
-    "osu_slider_body_smoothsnake", true, FCVAR_NONE,
+    "osu_slider_body_smoothsnake", true, FCVAR_DEFAULT,
     "draw 1 extra interpolated circle mesh at the start & end of every slider for extra smooth snaking/shrinking");
-ConVar osu_slider_body_lazer_fadeout_style("osu_slider_body_lazer_fadeout_style", true, FCVAR_NONE,
+ConVar osu_slider_body_lazer_fadeout_style("osu_slider_body_lazer_fadeout_style", true, FCVAR_DEFAULT,
                                            "if snaking out sliders are enabled (aka shrinking sliders), smoothly fade "
                                            "out the last remaining part of the body (instead of vanishing instantly)");
-ConVar osu_slider_body_fade_out_time_multiplier("osu_slider_body_fade_out_time_multiplier", 1.0f, FCVAR_NONE,
+ConVar osu_slider_body_fade_out_time_multiplier("osu_slider_body_fade_out_time_multiplier", 1.0f, FCVAR_DEFAULT,
                                                 "multiplies osu_hitobject_fade_out_time");
-ConVar osu_slider_reverse_arrow_animated("osu_slider_reverse_arrow_animated", true, FCVAR_NONE,
+ConVar osu_slider_reverse_arrow_animated("osu_slider_reverse_arrow_animated", true, FCVAR_DEFAULT,
                                          "pulse animation on reverse arrows");
-ConVar osu_slider_reverse_arrow_alpha_multiplier("osu_slider_reverse_arrow_alpha_multiplier", 1.0f, FCVAR_NONE);
+ConVar osu_slider_reverse_arrow_alpha_multiplier("osu_slider_reverse_arrow_alpha_multiplier", 1.0f, FCVAR_DEFAULT);
 
 ConVar *Slider::m_osu_playfield_mirror_horizontal_ref = NULL;
 ConVar *Slider::m_osu_playfield_mirror_vertical_ref = NULL;

+ 3 - 3
src/App/Osu/SliderCurves.cpp

@@ -12,12 +12,12 @@
 #include "Engine.h"
 
 ConVar osu_slider_curve_points_separation(
-    "osu_slider_curve_points_separation", 2.5f, FCVAR_CHEAT,
+    "osu_slider_curve_points_separation", 2.5f, FCVAR_LOCKED,
     "slider body curve approximation step width in osu!pixels, don't set this lower than around 1.5");
-ConVar osu_slider_curve_max_points("osu_slider_curve_max_points", 9999.0f, FCVAR_CHEAT,
+ConVar osu_slider_curve_max_points("osu_slider_curve_max_points", 9999.0f, FCVAR_LOCKED,
                                    "maximum number of allowed interpolated curve points. quality will be forced to go "
                                    "down if a slider has more steps than this");
-ConVar osu_slider_curve_max_length("osu_slider_curve_max_length", 65536 / 2, FCVAR_CHEAT,
+ConVar osu_slider_curve_max_length("osu_slider_curve_max_length", 65536 / 2, FCVAR_LOCKED,
                                    "maximum slider length in osu!pixels (i.e. pixelLength). also used to clamp all "
                                    "(control-)point coordinates to sane values.");
 

+ 16 - 16
src/App/Osu/SliderRenderer.cpp

@@ -38,27 +38,27 @@ float SliderRenderer::m_fBoundingBoxMaxX = 0.0f;
 float SliderRenderer::m_fBoundingBoxMinY = std::numeric_limits<float>::max();
 float SliderRenderer::m_fBoundingBoxMaxY = 0.0f;
 
-ConVar osu_slider_debug_draw("osu_slider_debug_draw", false, FCVAR_NONE,
+ConVar osu_slider_debug_draw("osu_slider_debug_draw", false, FCVAR_DEFAULT,
                              "draw hitcircle at every curve point and nothing else (no vao, no rt, no shader, nothing) "
                              "(requires enabling legacy slider renderer)");
 ConVar osu_slider_debug_draw_square_vao(
-    "osu_slider_debug_draw_square_vao", false, FCVAR_NONE,
+    "osu_slider_debug_draw_square_vao", false, FCVAR_DEFAULT,
     "generate square vaos and nothing else (no rt, no shader) (requires disabling legacy slider renderer)");
-ConVar osu_slider_debug_wireframe("osu_slider_debug_wireframe", false, FCVAR_NONE, "unused");
-
-ConVar osu_slider_alpha_multiplier("osu_slider_alpha_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_slider_body_alpha_multiplier("osu_slider_body_alpha_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_slider_body_color_saturation("osu_slider_body_color_saturation", 1.0f, FCVAR_NONE);
-ConVar osu_slider_border_feather("osu_slider_border_feather", 0.0f, FCVAR_NONE);
-ConVar osu_slider_border_size_multiplier("osu_slider_border_size_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_slider_border_tint_combo_color("osu_slider_border_tint_combo_color", false, FCVAR_NONE);
-ConVar osu_slider_osu_next_style("osu_slider_osu_next_style", false, FCVAR_NONE);
-ConVar osu_slider_rainbow("osu_slider_rainbow", false, FCVAR_NONE);
-ConVar osu_slider_use_gradient_image("osu_slider_use_gradient_image", false, FCVAR_NONE);
-
-ConVar osu_slider_body_unit_circle_subdivisions("osu_slider_body_unit_circle_subdivisions", 42, FCVAR_NONE);
+ConVar osu_slider_debug_wireframe("osu_slider_debug_wireframe", false, FCVAR_DEFAULT, "unused");
+
+ConVar osu_slider_alpha_multiplier("osu_slider_alpha_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_slider_body_alpha_multiplier("osu_slider_body_alpha_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_slider_body_color_saturation("osu_slider_body_color_saturation", 1.0f, FCVAR_DEFAULT);
+ConVar osu_slider_border_feather("osu_slider_border_feather", 0.0f, FCVAR_DEFAULT);
+ConVar osu_slider_border_size_multiplier("osu_slider_border_size_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_slider_border_tint_combo_color("osu_slider_border_tint_combo_color", false, FCVAR_DEFAULT);
+ConVar osu_slider_osu_next_style("osu_slider_osu_next_style", false, FCVAR_DEFAULT);
+ConVar osu_slider_rainbow("osu_slider_rainbow", false, FCVAR_DEFAULT);
+ConVar osu_slider_use_gradient_image("osu_slider_use_gradient_image", false, FCVAR_DEFAULT);
+
+ConVar osu_slider_body_unit_circle_subdivisions("osu_slider_body_unit_circle_subdivisions", 42, FCVAR_DEFAULT);
 ConVar osu_slider_legacy_use_baked_vao(
-    "osu_slider_legacy_use_baked_vao", false, FCVAR_NONE,
+    "osu_slider_legacy_use_baked_vao", false, FCVAR_DEFAULT,
     "use baked cone mesh instead of raw mesh for legacy slider renderer (disabled by default because usually slower on "
     "very old gpus even though it should not be)");
 

+ 9 - 9
src/App/Osu/SongBrowser/Button.cpp

@@ -14,15 +14,15 @@
 #include "Skin.h"
 #include "SoundEngine.h"
 
-ConVar osu_songbrowser_button_active_color_a("osu_songbrowser_button_active_color_a", 220 + 10, FCVAR_NONE);
-ConVar osu_songbrowser_button_active_color_r("osu_songbrowser_button_active_color_r", 255, FCVAR_NONE);
-ConVar osu_songbrowser_button_active_color_g("osu_songbrowser_button_active_color_g", 255, FCVAR_NONE);
-ConVar osu_songbrowser_button_active_color_b("osu_songbrowser_button_active_color_b", 255, FCVAR_NONE);
-
-ConVar osu_songbrowser_button_inactive_color_a("osu_songbrowser_button_inactive_color_a", 240, FCVAR_NONE);
-ConVar osu_songbrowser_button_inactive_color_r("osu_songbrowser_button_inactive_color_r", 235, FCVAR_NONE);
-ConVar osu_songbrowser_button_inactive_color_g("osu_songbrowser_button_inactive_color_g", 73, FCVAR_NONE);
-ConVar osu_songbrowser_button_inactive_color_b("osu_songbrowser_button_inactive_color_b", 153, FCVAR_NONE);
+ConVar osu_songbrowser_button_active_color_a("osu_songbrowser_button_active_color_a", 220 + 10, FCVAR_DEFAULT);
+ConVar osu_songbrowser_button_active_color_r("osu_songbrowser_button_active_color_r", 255, FCVAR_DEFAULT);
+ConVar osu_songbrowser_button_active_color_g("osu_songbrowser_button_active_color_g", 255, FCVAR_DEFAULT);
+ConVar osu_songbrowser_button_active_color_b("osu_songbrowser_button_active_color_b", 255, FCVAR_DEFAULT);
+
+ConVar osu_songbrowser_button_inactive_color_a("osu_songbrowser_button_inactive_color_a", 240, FCVAR_DEFAULT);
+ConVar osu_songbrowser_button_inactive_color_r("osu_songbrowser_button_inactive_color_r", 235, FCVAR_DEFAULT);
+ConVar osu_songbrowser_button_inactive_color_g("osu_songbrowser_button_inactive_color_g", 73, FCVAR_DEFAULT);
+ConVar osu_songbrowser_button_inactive_color_b("osu_songbrowser_button_inactive_color_b", 153, FCVAR_DEFAULT);
 
 int Button::marginPixelsX = 9;
 int Button::marginPixelsY = 9;

+ 8 - 8
src/App/Osu/SongBrowser/CollectionButton.cpp

@@ -16,22 +16,22 @@
 #include "UIContextMenu.h"
 
 ConVar osu_songbrowser_button_collection_active_color_a("osu_songbrowser_button_collection_active_color_a", 255,
-                                                        FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_collection_active_color_r("osu_songbrowser_button_collection_active_color_r", 163,
-                                                        FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_collection_active_color_g("osu_songbrowser_button_collection_active_color_g", 240,
-                                                        FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_collection_active_color_b("osu_songbrowser_button_collection_active_color_b", 44,
-                                                        FCVAR_NONE);
+                                                        FCVAR_DEFAULT);
 
 ConVar osu_songbrowser_button_collection_inactive_color_a("osu_songbrowser_button_collection_inactive_color_a", 255,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_collection_inactive_color_r("osu_songbrowser_button_collection_inactive_color_r", 35,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_collection_inactive_color_g("osu_songbrowser_button_collection_inactive_color_g", 50,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_collection_inactive_color_b("osu_songbrowser_button_collection_inactive_color_b", 143,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 
 CollectionButton::CollectionButton(Osu *osu, SongBrowser *songBrowser, CBaseUIScrollView *view,
                                    UIContextMenu *contextMenu, float xPos, float yPos, float xSize, float ySize,

+ 19 - 19
src/App/Osu/SongBrowser/SongBrowser.cpp

@@ -56,38 +56,38 @@
 #include "UserButton.h"
 #include "VertexArrayObject.h"
 
-ConVar osu_gamemode("osu_gamemode", "std", FCVAR_NONE);
+ConVar osu_gamemode("osu_gamemode", "std", FCVAR_DEFAULT);
 
-ConVar osu_songbrowser_sortingtype("osu_songbrowser_sortingtype", "By Date Added", FCVAR_NONE);
-ConVar osu_songbrowser_scores_sortingtype("osu_songbrowser_scores_sortingtype", "Sort By Score", FCVAR_NONE);
+ConVar osu_songbrowser_sortingtype("osu_songbrowser_sortingtype", "By Date Added", FCVAR_DEFAULT);
+ConVar osu_songbrowser_scores_sortingtype("osu_songbrowser_scores_sortingtype", "Sort By Score", FCVAR_DEFAULT);
 
-ConVar osu_songbrowser_topbar_left_percent("osu_songbrowser_topbar_left_percent", 0.93f, FCVAR_NONE);
-ConVar osu_songbrowser_topbar_left_width_percent("osu_songbrowser_topbar_left_width_percent", 0.265f, FCVAR_NONE);
-ConVar osu_songbrowser_topbar_middle_width_percent("osu_songbrowser_topbar_middle_width_percent", 0.15f, FCVAR_NONE);
-ConVar osu_songbrowser_topbar_right_height_percent("osu_songbrowser_topbar_right_height_percent", 0.5f, FCVAR_NONE);
-ConVar osu_songbrowser_topbar_right_percent("osu_songbrowser_topbar_right_percent", 0.378f, FCVAR_NONE);
-ConVar osu_songbrowser_bottombar_percent("osu_songbrowser_bottombar_percent", 0.116f, FCVAR_NONE);
+ConVar osu_songbrowser_topbar_left_percent("osu_songbrowser_topbar_left_percent", 0.93f, FCVAR_DEFAULT);
+ConVar osu_songbrowser_topbar_left_width_percent("osu_songbrowser_topbar_left_width_percent", 0.265f, FCVAR_DEFAULT);
+ConVar osu_songbrowser_topbar_middle_width_percent("osu_songbrowser_topbar_middle_width_percent", 0.15f, FCVAR_DEFAULT);
+ConVar osu_songbrowser_topbar_right_height_percent("osu_songbrowser_topbar_right_height_percent", 0.5f, FCVAR_DEFAULT);
+ConVar osu_songbrowser_topbar_right_percent("osu_songbrowser_topbar_right_percent", 0.378f, FCVAR_DEFAULT);
+ConVar osu_songbrowser_bottombar_percent("osu_songbrowser_bottombar_percent", 0.116f, FCVAR_DEFAULT);
 
-ConVar osu_draw_songbrowser_background_image("osu_draw_songbrowser_background_image", true, FCVAR_NONE);
-ConVar osu_draw_songbrowser_menu_background_image("osu_draw_songbrowser_menu_background_image", true, FCVAR_NONE);
-ConVar osu_draw_songbrowser_strain_graph("osu_draw_songbrowser_strain_graph", false, FCVAR_NONE);
-ConVar osu_songbrowser_scorebrowser_enabled("osu_songbrowser_scorebrowser_enabled", true, FCVAR_NONE);
-ConVar osu_songbrowser_background_fade_in_duration("osu_songbrowser_background_fade_in_duration", 0.1f, FCVAR_NONE);
+ConVar osu_draw_songbrowser_background_image("osu_draw_songbrowser_background_image", true, FCVAR_DEFAULT);
+ConVar osu_draw_songbrowser_menu_background_image("osu_draw_songbrowser_menu_background_image", true, FCVAR_DEFAULT);
+ConVar osu_draw_songbrowser_strain_graph("osu_draw_songbrowser_strain_graph", false, FCVAR_DEFAULT);
+ConVar osu_songbrowser_scorebrowser_enabled("osu_songbrowser_scorebrowser_enabled", true, FCVAR_DEFAULT);
+ConVar osu_songbrowser_background_fade_in_duration("osu_songbrowser_background_fade_in_duration", 0.1f, FCVAR_DEFAULT);
 
-ConVar osu_songbrowser_search_delay("osu_songbrowser_search_delay", 0.5f, FCVAR_NONE,
+ConVar osu_songbrowser_search_delay("osu_songbrowser_search_delay", 0.5f, FCVAR_DEFAULT,
                                     "delay until search update when entering text");
 void _osu_songbrowser_search_hardcoded_filter(UString oldValue, UString newValue);
-ConVar osu_songbrowser_search_hardcoded_filter("osu_songbrowser_search_hardcoded_filter", "", FCVAR_NONE,
+ConVar osu_songbrowser_search_hardcoded_filter("osu_songbrowser_search_hardcoded_filter", "", FCVAR_DEFAULT,
                                                "allows forcing the specified search filter to be active all the time",
                                                _osu_songbrowser_search_hardcoded_filter);
-ConVar osu_songbrowser_background_star_calculation("osu_songbrowser_background_star_calculation", true, FCVAR_NONE,
+ConVar osu_songbrowser_background_star_calculation("osu_songbrowser_background_star_calculation", true, FCVAR_DEFAULT,
                                                    "precalculate stars for all loaded beatmaps while in songbrowser");
 ConVar osu_songbrowser_dynamic_star_recalc(
-    "osu_songbrowser_dynamic_star_recalc", true, FCVAR_NONE,
+    "osu_songbrowser_dynamic_star_recalc", true, FCVAR_DEFAULT,
     "dynamically recalculate displayed star value of currently selected beatmap in songbrowser");
 
 ConVar osu_debug_background_star_calc(
-    "osu_debug_background_star_calc", false, FCVAR_NONE,
+    "osu_debug_background_star_calc", false, FCVAR_DEFAULT,
     "prints the name of the beatmap about to get its stars calculated (cmd/terminal window only, no in-game log!)");
 
 void _osu_songbrowser_search_hardcoded_filter(UString oldValue, UString newValue) {

+ 3 - 3
src/App/Osu/SongBrowser/SongButton.cpp

@@ -19,9 +19,9 @@
 #include "SkinImage.h"
 #include "UIContextMenu.h"
 
-ConVar osu_draw_songbrowser_thumbnails("osu_draw_songbrowser_thumbnails", true, FCVAR_NONE);
-ConVar osu_songbrowser_thumbnail_delay("osu_songbrowser_thumbnail_delay", 0.1f, FCVAR_NONE);
-ConVar osu_songbrowser_thumbnail_fade_in_duration("osu_songbrowser_thumbnail_fade_in_duration", 0.1f, FCVAR_NONE);
+ConVar osu_draw_songbrowser_thumbnails("osu_draw_songbrowser_thumbnails", true, FCVAR_DEFAULT);
+ConVar osu_songbrowser_thumbnail_delay("osu_songbrowser_thumbnail_delay", 0.1f, FCVAR_DEFAULT);
+ConVar osu_songbrowser_thumbnail_fade_in_duration("osu_songbrowser_thumbnail_fade_in_duration", 0.1f, FCVAR_DEFAULT);
 
 float SongButton::thumbnailYRatio = 1.333333f;
 

+ 4 - 4
src/App/Osu/SongBrowser/SongDifficultyButton.cpp

@@ -16,13 +16,13 @@
 #include "Skin.h"
 
 ConVar osu_songbrowser_button_difficulty_inactive_color_a("osu_songbrowser_button_difficulty_inactive_color_a", 255,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_difficulty_inactive_color_r("osu_songbrowser_button_difficulty_inactive_color_r", 0,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_difficulty_inactive_color_g("osu_songbrowser_button_difficulty_inactive_color_g", 150,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 ConVar osu_songbrowser_button_difficulty_inactive_color_b("osu_songbrowser_button_difficulty_inactive_color_b", 236,
-                                                          FCVAR_NONE);
+                                                          FCVAR_DEFAULT);
 
 ConVar *SongDifficultyButton::m_osu_scores_enabled = NULL;
 ConVar *SongDifficultyButton::m_osu_songbrowser_dynamic_star_recalc_ref = NULL;

+ 4 - 4
src/App/Osu/SongBrowser/UserButton.cpp

@@ -19,10 +19,10 @@
 
 // NOTE: selected username is stored in m_sText
 
-ConVar osu_user_draw_pp("osu_user_draw_pp", true, FCVAR_NONE);
-ConVar osu_user_draw_accuracy("osu_user_draw_accuracy", true, FCVAR_NONE);
-ConVar osu_user_draw_level("osu_user_draw_level", true, FCVAR_NONE);
-ConVar osu_user_draw_level_bar("osu_user_draw_level_bar", true, FCVAR_NONE);
+ConVar osu_user_draw_pp("osu_user_draw_pp", true, FCVAR_DEFAULT);
+ConVar osu_user_draw_accuracy("osu_user_draw_accuracy", true, FCVAR_DEFAULT);
+ConVar osu_user_draw_level("osu_user_draw_level", true, FCVAR_DEFAULT);
+ConVar osu_user_draw_level_bar("osu_user_draw_level_bar", true, FCVAR_DEFAULT);
 
 UserButton::UserButton(Osu *osu) : CBaseUIButton() {
     m_osu = osu;

+ 1 - 1
src/App/Osu/Spinner.cpp

@@ -19,7 +19,7 @@
 #include "SoundEngine.h"
 
 ConVar osu_spinner_use_ar_fadein(
-    "osu_spinner_use_ar_fadein", false, FCVAR_NONE,
+    "osu_spinner_use_ar_fadein", false, FCVAR_DEFAULT,
     "whether spinners should fade in with AR (same as circles), or with hardcoded 400 ms fadein time (osu!default)");
 
 Spinner::Spinner(int x, int y, long time, int sampleType, bool isEndOfCombo, long endTime, Beatmap *beatmap)

+ 1 - 1
src/App/Osu/TooltipOverlay.cpp

@@ -14,7 +14,7 @@
 #include "Osu.h"
 #include "ResourceManager.h"
 
-ConVar osu_tooltip_anim_duration("osu_tooltip_anim_duration", 0.4f, FCVAR_NONE);
+ConVar osu_tooltip_anim_duration("osu_tooltip_anim_duration", 0.4f, FCVAR_DEFAULT);
 
 TooltipOverlay::TooltipOverlay(Osu *osu) : OsuScreen(osu) {
     m_fAnim = 0.0f;

+ 1 - 1
src/App/Osu/UserStatsScreen.cpp

@@ -32,7 +32,7 @@
 #include "UIContextMenu.h"
 #include "UIUserStatsScreenLabel.h"
 
-ConVar osu_ui_top_ranks_max("osu_ui_top_ranks_max", 200, FCVAR_NONE,
+ConVar osu_ui_top_ranks_max("osu_ui_top_ranks_max", 200, FCVAR_DEFAULT,
                             "maximum number of displayed scores, to keep the ui/scrollbar manageable");
 
 class UserStatsScreenMenuButton : public CBaseUIButton {

+ 21 - 21
src/App/Osu/score.cpp

@@ -14,33 +14,33 @@
 #include "Replay.h"
 #include "RoomScreen.h"
 
-ConVar osu_hiterrorbar_misses("osu_hiterrorbar_misses", true, FCVAR_NONE);
-ConVar osu_debug_pp("osu_debug_pp", false, FCVAR_NONE);
+ConVar osu_hiterrorbar_misses("osu_hiterrorbar_misses", true, FCVAR_DEFAULT);
+ConVar osu_debug_pp("osu_debug_pp", false, FCVAR_DEFAULT);
 
-ConVar osu_hud_statistics_hitdelta_chunksize("osu_hud_statistics_hitdelta_chunksize", 30, FCVAR_NONE,
+ConVar osu_hud_statistics_hitdelta_chunksize("osu_hud_statistics_hitdelta_chunksize", 30, FCVAR_DEFAULT,
                                              "how many recent hit deltas to average (-1 = all)");
 
-ConVar osu_drain_vr_multiplier("osu_drain_vr_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_drain_vr_300("osu_drain_vr_300", 0.035f, FCVAR_NONE);
-ConVar osu_drain_vr_100("osu_drain_vr_100", -0.10f, FCVAR_NONE);
-ConVar osu_drain_vr_50("osu_drain_vr_50", -0.125f, FCVAR_NONE);
-ConVar osu_drain_vr_miss("osu_drain_vr_miss", -0.15f, FCVAR_NONE);
-ConVar osu_drain_vr_sliderbreak("osu_drain_vr_sliderbreak", -0.10f, FCVAR_NONE);
+ConVar osu_drain_vr_multiplier("osu_drain_vr_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_drain_vr_300("osu_drain_vr_300", 0.035f, FCVAR_DEFAULT);
+ConVar osu_drain_vr_100("osu_drain_vr_100", -0.10f, FCVAR_DEFAULT);
+ConVar osu_drain_vr_50("osu_drain_vr_50", -0.125f, FCVAR_DEFAULT);
+ConVar osu_drain_vr_miss("osu_drain_vr_miss", -0.15f, FCVAR_DEFAULT);
+ConVar osu_drain_vr_sliderbreak("osu_drain_vr_sliderbreak", -0.10f, FCVAR_DEFAULT);
 
-ConVar osu_drain_stable_hpbar_maximum("osu_drain_stable_hpbar_maximum", 200.0f, FCVAR_CHEAT);
+ConVar osu_drain_stable_hpbar_maximum("osu_drain_stable_hpbar_maximum", 200.0f, FCVAR_LOCKED);
 
-ConVar osu_drain_lazer_multiplier("osu_drain_lazer_multiplier", 0.05f, FCVAR_NONE,
+ConVar osu_drain_lazer_multiplier("osu_drain_lazer_multiplier", 0.05f, FCVAR_DEFAULT,
                                   "DEFAULT_MAX_HEALTH_INCREASE, expressed as a percentage of full health");
-ConVar osu_drain_lazer_300("osu_drain_lazer_300", 1.0f, FCVAR_NONE);
-ConVar osu_drain_lazer_100("osu_drain_lazer_100", 0.5f, FCVAR_NONE);
-ConVar osu_drain_lazer_50("osu_drain_lazer_50", -0.05f, FCVAR_NONE);
-ConVar osu_drain_lazer_miss("osu_drain_lazer_miss", -1.0f, FCVAR_NONE);
-
-ConVar osu_drain_lazer_2018_multiplier("osu_drain_lazer_2018_multiplier", 1.0f, FCVAR_NONE);
-ConVar osu_drain_lazer_2018_300("osu_drain_lazer_2018_300", 0.01f, FCVAR_NONE);
-ConVar osu_drain_lazer_2018_100("osu_drain_lazer_2018_100", 0.01f, FCVAR_NONE);
-ConVar osu_drain_lazer_2018_50("osu_drain_lazer_2018_50", 0.01f, FCVAR_NONE);
-ConVar osu_drain_lazer_2018_miss("osu_drain_lazer_2018_miss", -0.02f, FCVAR_NONE);
+ConVar osu_drain_lazer_300("osu_drain_lazer_300", 1.0f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_100("osu_drain_lazer_100", 0.5f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_50("osu_drain_lazer_50", -0.05f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_miss("osu_drain_lazer_miss", -1.0f, FCVAR_DEFAULT);
+
+ConVar osu_drain_lazer_2018_multiplier("osu_drain_lazer_2018_multiplier", 1.0f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_2018_300("osu_drain_lazer_2018_300", 0.01f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_2018_100("osu_drain_lazer_2018_100", 0.01f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_2018_50("osu_drain_lazer_2018_50", 0.01f, FCVAR_DEFAULT);
+ConVar osu_drain_lazer_2018_miss("osu_drain_lazer_2018_miss", -0.02f, FCVAR_DEFAULT);
 
 ConVar *LiveScore::m_osu_draw_statistics_pp_ref = NULL;
 ConVar *LiveScore::m_osu_drain_type_ref = NULL;

+ 1 - 1
src/Engine/AnimationHandler.cpp

@@ -10,7 +10,7 @@
 #include "ConVar.h"
 #include "Engine.h"
 
-ConVar debug_anim("debug_anim", false, FCVAR_NONE);
+ConVar debug_anim("debug_anim", false, FCVAR_DEFAULT);
 
 AnimationHandler *anim = NULL;
 

+ 125 - 89
src/Engine/ConVar.cpp

@@ -14,31 +14,22 @@
 #include "ModSelector.h"
 #include "Osu.h"
 
-// #define ALLOW_DEVELOPMENT_CONVARS // NOTE: comment this out on release
+bool ConVar::isUnlocked() const {
+    if(isFlagSet(FCVAR_PRIVATE)) return true;
+    if(!bancho.is_online()) return true;
 
-ConVar ConVars::sv_cheats("sv_cheats", true, FCVAR_NONE);
-
-bool ConVar::getBool() const {
-    if(isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return m_fDefaultValue.load() > 0;
-    if(isFlagSet(FCVAR_NONVANILLA) && bancho.is_in_a_multi_room()) return m_fDefaultValue.load() > 0;
-    return m_fValue.load() > 0;
-}
-float ConVar::getFloat() const {
-    if(isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return m_fDefaultValue.load();
-    if(isFlagSet(FCVAR_NONVANILLA) && bancho.is_in_a_multi_room()) return m_fDefaultValue.load();
-    return m_fValue.load();
-}
-int ConVar::getInt() {
-    if(isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return m_fDefaultValue.load();
-    if(isFlagSet(FCVAR_NONVANILLA) && bancho.is_in_a_multi_room()) return m_fDefaultValue.load();
-    return m_fValue.load();
-}
-const UString &ConVar::getString() {
-    if(isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return m_sDefaultValue;
-    if(isFlagSet(FCVAR_NONVANILLA) && bancho.is_in_a_multi_room()) return m_sDefaultValue;
-    return m_sValue;
+    if(bancho.is_in_a_multi_room()) {
+        return isFlagSet(FCVAR_UNLOCK_MULTIPLAYER);
+    } else {
+        return isFlagSet(FCVAR_UNLOCK_SINGLEPLAYER);
+    }
 }
 
+bool ConVar::getBool() const { return getFloat() > 0; }
+int ConVar::getInt() { return (int)getFloat(); }
+float ConVar::getFloat() const { return isUnlocked() ? m_fValue.load() : m_fDefaultValue.load(); }
+const UString &ConVar::getString() { return isUnlocked() ? m_sValue : m_sDefaultValue; }
+
 static std::vector<ConVar *> &_getGlobalConVarArray() {
     static std::vector<ConVar *> g_vConVars;  // (singleton)
     return g_vConVars;
@@ -50,8 +41,6 @@ static std::unordered_map<std::string, ConVar *> &_getGlobalConVarMap() {
 }
 
 static void _addConVar(ConVar *c) {
-    if(c->isFlagSet(FCVAR_UNREGISTERED)) return;
-
     if(_getGlobalConVarArray().size() < 1) _getGlobalConVarArray().reserve(1024);
 
     auto cname = c->getName();
@@ -74,6 +63,23 @@ static ConVar *_getConVar(const UString &name) {
         return NULL;
 }
 
+std::string ConVar::getFancyDefaultValue() {
+    switch(getType()) {
+        case ConVar::CONVAR_TYPE::CONVAR_TYPE_BOOL:
+            return m_fDefaultDefaultValue == 0 ? "false" : "true";
+        case ConVar::CONVAR_TYPE::CONVAR_TYPE_INT:
+            return std::to_string((int)m_fDefaultDefaultValue);
+        case ConVar::CONVAR_TYPE::CONVAR_TYPE_FLOAT:
+            return std::to_string(m_fDefaultDefaultValue);
+        case ConVar::CONVAR_TYPE::CONVAR_TYPE_STRING: {
+            std::string out = "\"";
+            out.append(m_sDefaultDefaultValue.toUtf8());
+            out.append("\"");
+            return out;
+        }
+    }
+}
+
 UString ConVar::typeToString(CONVAR_TYPE type) {
     switch(type) {
         case ConVar::CONVAR_TYPE::CONVAR_TYPE_BOOL:
@@ -95,25 +101,21 @@ void ConVar::init(int flags) {
     m_changecallback = NULL;
 
     m_fValue = 0.0f;
+    m_fDefaultDefaultValue = 0.0f;
     m_fDefaultValue = 0.0f;
+    m_sDefaultDefaultValue = "";
+    m_sDefaultValue = "";
 
-    m_bHasValue = true;
+    m_bHasValue = false;
     m_type = CONVAR_TYPE::CONVAR_TYPE_FLOAT;
+    m_iDefaultFlags = flags;
     m_iFlags = flags;
-
-#ifdef ALLOW_DEVELOPMENT_CONVARS
-
-    m_iFlags &= ~FCVAR_DEVELOPMENTONLY;
-
-#endif
 }
 
 void ConVar::init(UString &name, int flags) {
     init(flags);
 
     m_sName = name;
-
-    m_bHasValue = false;
     m_type = CONVAR_TYPE::CONVAR_TYPE_STRING;
 }
 
@@ -122,8 +124,6 @@ void ConVar::init(UString &name, int flags, ConVarCallback callback) {
 
     m_sName = name;
     m_callbackfunc = callback;
-
-    m_bHasValue = false;
     m_type = CONVAR_TYPE::CONVAR_TYPE_STRING;
 }
 
@@ -138,8 +138,6 @@ void ConVar::init(UString &name, int flags, ConVarCallbackArgs callbackARGS) {
 
     m_sName = name;
     m_callbackfuncargs = callbackARGS;
-
-    m_bHasValue = false;
     m_type = CONVAR_TYPE::CONVAR_TYPE_STRING;
 }
 
@@ -154,8 +152,11 @@ void ConVar::init(UString &name, float defaultValue, int flags, UString helpStri
 
     m_type = CONVAR_TYPE::CONVAR_TYPE_FLOAT;
     m_sName = name;
-    setDefaultFloatInt(defaultValue);
-    { setValueInt(defaultValue); }
+    m_fDefaultValue = defaultValue;
+    m_fDefaultDefaultValue = defaultValue;
+    m_sDefaultValue = UString::format("%g", defaultValue);
+    m_sDefaultDefaultValue = m_sDefaultValue;
+    setValue(defaultValue);
     m_sHelpString = helpString;
     m_changecallback = callback;
 }
@@ -165,14 +166,15 @@ void ConVar::init(UString &name, UString defaultValue, int flags, UString helpSt
 
     m_type = CONVAR_TYPE::CONVAR_TYPE_STRING;
     m_sName = name;
-    setDefaultStringInt(defaultValue);
-    { setValueInt(defaultValue); }
+    m_sDefaultValue = defaultValue;
+    m_sDefaultDefaultValue = defaultValue;
+    setValue(defaultValue);
     m_sHelpString = helpString;
     m_changecallback = callback;
 }
 
 ConVar::ConVar(UString name) {
-    init(name, FCVAR_NONE);
+    init(name, FCVAR_DEFAULT);
     _addConVar(this);
 }
 
@@ -218,49 +220,49 @@ ConVar::ConVar(UString name, float fDefaultValue, int flags, const char *helpStr
 
 ConVar::ConVar(UString name, int iDefaultValue, int flags) {
     init(name, (float)iDefaultValue, flags, "", NULL);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_INT; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_INT;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, int iDefaultValue, int flags, ConVarChangeCallback callback) {
     init(name, (float)iDefaultValue, flags, "", callback);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_INT; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_INT;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, int iDefaultValue, int flags, const char *helpString) {
     init(name, (float)iDefaultValue, flags, UString(helpString), NULL);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_INT; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_INT;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, int iDefaultValue, int flags, const char *helpString, ConVarChangeCallback callback) {
     init(name, (float)iDefaultValue, flags, UString(helpString), callback);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_INT; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_INT;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, bool bDefaultValue, int flags) {
     init(name, bDefaultValue ? 1.0f : 0.0f, flags, "", NULL);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, bool bDefaultValue, int flags, ConVarChangeCallback callback) {
     init(name, bDefaultValue ? 1.0f : 0.0f, flags, "", callback);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, bool bDefaultValue, int flags, const char *helpString) {
     init(name, bDefaultValue ? 1.0f : 0.0f, flags, UString(helpString), NULL);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL;
     _addConVar(this);
 }
 
 ConVar::ConVar(UString name, bool bDefaultValue, int flags, const char *helpString, ConVarChangeCallback callback) {
     init(name, bDefaultValue ? 1.0f : 0.0f, flags, UString(helpString), callback);
-    { m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL; }
+    m_type = CONVAR_TYPE::CONVAR_TYPE_BOOL;
     _addConVar(this);
 }
 
@@ -286,7 +288,7 @@ ConVar::ConVar(UString name, const char *sDefaultValue, int flags, const char *h
 }
 
 void ConVar::exec() {
-    if(isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return;
+    if(!isUnlocked()) return;
 
     if(bancho.osu != nullptr) {
         auto is_vanilla = convar->isVanilla();
@@ -306,37 +308,32 @@ void ConVar::exec() {
 }
 
 void ConVar::execArgs(UString args) {
-    if(isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return;
+    if(!isUnlocked()) return;
 
     if(m_callbackfuncargs != NULL) m_callbackfuncargs(args);
 }
 
-void ConVar::setDefaultFloat(float defaultValue) {
-    if(isFlagSet(FCVAR_HARDCODED)) return;
-
-    setDefaultFloatInt(defaultValue);
+// Reset default values to the actual defaults (before neosu.json overrides)
+void ConVar::resetDefaults() {
+    m_iFlags = m_iDefaultFlags;
+    m_fDefaultValue = m_fDefaultDefaultValue;
+    m_sDefaultValue = m_sDefaultDefaultValue;
 }
 
-void ConVar::setDefaultFloatInt(float defaultValue) {
+void ConVar::setDefaultFloat(float defaultValue) {
+    if(isFlagSet(FCVAR_PRIVATE)) return;
     m_fDefaultValue = defaultValue;
     m_sDefaultValue = UString::format("%g", defaultValue);
 }
 
 void ConVar::setDefaultString(UString defaultValue) {
-    if(isFlagSet(FCVAR_HARDCODED)) return;
-
-    setDefaultStringInt(defaultValue);
+    if(isFlagSet(FCVAR_PRIVATE)) return;
+    m_sDefaultValue = defaultValue;
 }
 
-void ConVar::setDefaultStringInt(UString defaultValue) { m_sDefaultValue = defaultValue; }
-
 void ConVar::setValue(float value) {
-    if(isFlagSet(FCVAR_HARDCODED) || (isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool())) return;
+    if(!isUnlocked()) return;
 
-    setValueInt(value);
-}
-
-void ConVar::setValueInt(float value) {
     // TODO: make this less unsafe in multithreaded environments (for float convars at least)
 
     // backup previous value
@@ -347,6 +344,7 @@ void ConVar::setValueInt(float value) {
     {
         m_fValue = value;
         m_sValue = newStringValue;
+        m_bHasValue = true;
     }
 
     // handle callbacks
@@ -363,18 +361,15 @@ void ConVar::setValueInt(float value) {
 }
 
 void ConVar::setValue(UString sValue) {
-    if(isFlagSet(FCVAR_HARDCODED) || (isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool())) return;
+    if(!isUnlocked()) return;
 
-    setValueInt(sValue);
-}
-
-void ConVar::setValueInt(UString sValue) {
     // backup previous value
     const UString oldValue = m_sValue;
 
     // then set the new value
     {
         m_sValue = sValue;
+        m_bHasValue = true;
 
         if(sValue.length() > 0) m_fValue = sValue.toFloat();
     }
@@ -405,7 +400,7 @@ void ConVar::setHelpString(UString helpString) { m_sHelpString = helpString; }
 //********************************//
 
 ConVar _emptyDummyConVar(
-    "emptyDummyConVar", 42.0f, FCVAR_NONE,
+    "emptyDummyConVar", 42.0f, FCVAR_DEFAULT,
     "this placeholder convar is returned by convar->getConVarByName() if no matching convar is found");
 
 ConVarHandler *convar = new ConVarHandler();
@@ -446,7 +441,7 @@ std::vector<ConVar *> ConVarHandler::getConVarByLetter(UString letters) const {
 
         // first try matching exactly
         for(size_t i = 0; i < convars.size(); i++) {
-            if(convars[i]->isFlagSet(FCVAR_HIDDEN) || convars[i]->isFlagSet(FCVAR_DEVELOPMENTONLY)) continue;
+            if(convars[i]->isFlagSet(FCVAR_HIDDEN)) continue;
 
             if(convars[i]->getName().find(letters, 0, letters.length()) == 0) {
                 if(letters.length() > 1)
@@ -460,7 +455,7 @@ std::vector<ConVar *> ConVarHandler::getConVarByLetter(UString letters) const {
         // then try matching substrings
         if(letters.length() > 1) {
             for(size_t i = 0; i < convars.size(); i++) {
-                if(convars[i]->isFlagSet(FCVAR_HIDDEN) || convars[i]->isFlagSet(FCVAR_DEVELOPMENTONLY)) continue;
+                if(convars[i]->isFlagSet(FCVAR_HIDDEN)) continue;
 
                 if(convars[i]->getName().find(letters) != -1) {
                     std::string stdName(convars[i]->getName().toUtf8(), convars[i]->getName().lengthUtf8());
@@ -480,16 +475,13 @@ std::vector<ConVar *> ConVarHandler::getConVarByLetter(UString letters) const {
 UString ConVarHandler::flagsToString(int flags) {
     UString string;
     {
-        if(flags == FCVAR_NONE)
+        if(flags == 0) {
             string.append("no flags");
-        else {
-            if(flags & FCVAR_UNREGISTERED) string.append(string.length() > 0 ? " unregistered" : "unregistered");
-            if(flags & FCVAR_DEVELOPMENTONLY)
-                string.append(string.length() > 0 ? " developmentonly" : "developmentonly");
-            if(flags & FCVAR_HARDCODED) string.append(string.length() > 0 ? " hardcoded" : "hardcoded");
+        } else {
             if(flags & FCVAR_HIDDEN) string.append(string.length() > 0 ? " hidden" : "hidden");
-            if(flags & FCVAR_CHEAT) string.append(string.length() > 0 ? " cheat" : "cheat");
-            if(flags & FCVAR_NONVANILLA) string.append(string.length() > 0 ? " nonvanilla" : "nonvanilla");
+            if(flags & FCVAR_UNLOCK_SINGLEPLAYER) string.append(string.length() > 0 ? " unlock_solo" : "unlock_solo");
+            if(flags & FCVAR_UNLOCK_MULTIPLAYER) string.append(string.length() > 0 ? " unlock_multi" : "unlock_multi");
+            if(flags & FCVAR_ALWAYS_SUBMIT) string.append(string.length() > 0 ? " always_submit" : "always_submit");
         }
     }
     return string;
@@ -497,7 +489,7 @@ UString ConVarHandler::flagsToString(int flags) {
 
 bool ConVarHandler::isVanilla() {
     for(auto cv : _getGlobalConVarArray()) {
-        if(!cv->isFlagSet(FCVAR_NONVANILLA)) continue;
+        if(cv->isFlagSet(FCVAR_ALWAYS_SUBMIT)) continue;
         if(cv->getString() != cv->getDefaultString()) {
             return false;
         }
@@ -529,7 +521,7 @@ static void _find(UString args) {
 
     std::vector<ConVar *> matchingConVars;
     for(size_t i = 0; i < convars.size(); i++) {
-        if(convars[i]->isFlagSet(FCVAR_HIDDEN) || convars[i]->isFlagSet(FCVAR_DEVELOPMENTONLY)) continue;
+        if(convars[i]->isFlagSet(FCVAR_HIDDEN)) continue;
 
         const UString name = convars[i]->getName();
         if(name.find(args, 0, name.length()) != -1) matchingConVars.push_back(convars[i]);
@@ -630,7 +622,7 @@ static void _listcommands(void) {
         std::sort(convars.begin(), convars.end(), CONVAR_SORT_COMPARATOR());
 
         for(size_t i = 0; i < convars.size(); i++) {
-            if(convars[i]->isFlagSet(FCVAR_HIDDEN) || convars[i]->isFlagSet(FCVAR_DEVELOPMENTONLY)) continue;
+            if(convars[i]->isFlagSet(FCVAR_HIDDEN)) continue;
 
             ConVar *var = convars[i];
 
@@ -659,6 +651,50 @@ static void _listcommands(void) {
     debugLog("----------------------------------------------\n");
 }
 
-ConVar _find_("find", FCVAR_NONE, _find);
-ConVar _help_("help", FCVAR_NONE, _help);
-ConVar _listcommands_("listcommands", FCVAR_NONE, _listcommands);
+static void _dumpcommands(void) {
+    std::vector<ConVar *> convars = convar->getConVarArray();
+    struct CONVAR_SORT_COMPARATOR {
+        bool operator()(ConVar const *var1, ConVar const *var2) { return (var1->getName() < var2->getName()); }
+    };
+    std::sort(convars.begin(), convars.end(), CONVAR_SORT_COMPARATOR());
+
+    FILE *file = fopen("commands.htm", "w");
+    if(file == NULL) {
+        debugLog("Failed to open commands.htm for writing\n");
+        return;
+    }
+
+    for(size_t i = 0; i < convars.size(); i++) {
+        ConVar *var = convars[i];
+        if(!var->hasValue()) continue;
+        if(var->isFlagSet(FCVAR_HIDDEN)) continue;
+        if(var->isFlagSet(FCVAR_PRIVATE)) continue;
+
+        std::string cmd = "<h4>";
+        cmd.append(var->getName());
+        cmd.append("</h4>\n");
+        cmd.append(var->getHelpstring().toUtf8());
+        cmd.append("<pre>{");
+        cmd.append("\n    \"default\": ");
+        cmd.append(var->getFancyDefaultValue());
+        cmd.append("\n    \"unlock_singleplayer\": ");
+        cmd.append(var->isFlagSet(FCVAR_UNLOCK_SINGLEPLAYER) ? "true" : "false");
+        cmd.append("\n    \"unlock_multiplayer\": ");
+        cmd.append(var->isFlagSet(FCVAR_UNLOCK_MULTIPLAYER) ? "true" : "false");
+        cmd.append("\n    \"always_submit\": ");
+        cmd.append(var->isFlagSet(FCVAR_ALWAYS_SUBMIT) ? "true" : "false");
+        cmd.append("\n}</pre>\n");
+
+        fwrite(cmd.c_str(), cmd.size(), 1, file);
+    }
+
+    fflush(file);
+    fclose(file);
+
+    debugLog("Commands dumped to commands.htm\n");
+}
+
+ConVar _find_("find", FCVAR_DEFAULT, _find);
+ConVar _help_("help", FCVAR_DEFAULT, _help);
+ConVar _listcommands_("listcommands", FCVAR_DEFAULT, _listcommands);
+ConVar _dumpcommands_("dumpcommands", FCVAR_HIDDEN, _dumpcommands);

+ 25 - 31
src/Engine/ConVar.h

@@ -4,29 +4,25 @@
 #include "FastDelegate.h"
 #include "UString.h"
 
-// the default, no flags at all
-#define FCVAR_NONE 0
+enum FCVAR_FLAGS {
+    // not visible in find/listcommands results etc., but is settable/gettable via console/help
+    FCVAR_HIDDEN = (1 << 0),
 
-// not added to g_vConVars list (not settable/gettable via console/help), not visible in find/listcommands
-// results etc.
-#define FCVAR_UNREGISTERED (1 << 0)
+    // if flag is not set, value will be forced to default when online
+    FCVAR_UNLOCK_SINGLEPLAYER = (1 << 1),
+    FCVAR_UNLOCK_MULTIPLAYER = (1 << 2),
+    FCVAR_UNLOCKED = (FCVAR_UNLOCK_SINGLEPLAYER | FCVAR_UNLOCK_MULTIPLAYER),
 
-// hidden in released products (like FCVAR_HIDDEN, but flag gets compiled out if ALLOW_DEVELOPMENT_CONVARS
-// is defined)
-#define FCVAR_DEVELOPMENTONLY (1 << 1)
+    // if flag is not set, score will not submit when value is not default
+    FCVAR_ALWAYS_SUBMIT = (1 << 3),
 
-// if this is set then the value can't and shouldn't ever be changed
-#define FCVAR_HARDCODED (1 << 2)
+    // don't allow server to modify this cvar
+    FCVAR_PRIVATE = (1 << 4),
 
-// not visible in find/listcommands results etc., but is settable/gettable via console/help
-#define FCVAR_HIDDEN (1 << 3)
-
-// always return default value and ignore callbacks unless sv_cheats is enabled (default value is
-// changeable via setDefault*())
-#define FCVAR_CHEAT (1 << 4)
-
-// disables score submission on servers that don't support weird mods
-#define FCVAR_NONVANILLA (1 << 5)
+    // legacy definitions
+    FCVAR_LOCKED = 0,
+    FCVAR_DEFAULT = FCVAR_UNLOCKED | FCVAR_ALWAYS_SUBMIT,
+};
 
 class ConVar {
    public:
@@ -80,6 +76,9 @@ class ConVar {
     void execArgs(UString args);
 
     // set
+    void resetDefaults();
+    void setDefaultBool(bool defaultValue) { setDefaultFloat(defaultValue ? 1.f : 0.f); }
+    void setDefaultInt(int defaultValue) { setDefaultFloat((float)defaultValue); }
     void setDefaultFloat(float defaultValue);
     void setDefaultString(UString defaultValue);
 
@@ -96,6 +95,9 @@ class ConVar {
     inline float getDefaultFloat() const { return m_fDefaultValue.load(); }
     inline const UString &getDefaultString() const { return m_sDefaultValue; }
 
+    bool isUnlocked() const;
+    std::string getFancyDefaultValue();
+
     bool getBool() const;
     float getFloat() const;
     int getInt();
@@ -105,6 +107,7 @@ class ConVar {
     inline const UString &getName() const { return m_sName; }
     inline CONVAR_TYPE getType() const { return m_type; }
     inline int getFlags() const { return m_iFlags; }
+    inline void setFlags(int new_flags) { m_iFlags = new_flags; }
 
     inline bool hasValue() const { return m_bHasValue; }
     inline bool hasCallbackArgs() const { return (m_callbackfuncargs || m_changecallback); }
@@ -120,15 +123,10 @@ class ConVar {
     void init(UString &name, float defaultValue, int flags, UString helpString, ConVarChangeCallback callback);
     void init(UString &name, UString defaultValue, int flags, UString helpString, ConVarChangeCallback callback);
 
-    void setDefaultFloatInt(float defaultValue);
-    void setDefaultStringInt(UString defaultValue);
-
-    void setValueInt(float value);
-    void setValueInt(UString sValue);
-
    private:
     bool m_bHasValue;
     CONVAR_TYPE m_type;
+    int m_iDefaultFlags;
     int m_iFlags;
 
     UString m_sName;
@@ -136,21 +134,17 @@ class ConVar {
 
     std::atomic<float> m_fValue;
     std::atomic<float> m_fDefaultValue;
+    float m_fDefaultDefaultValue;
 
     UString m_sValue;
     UString m_sDefaultValue;
+    UString m_sDefaultDefaultValue;
 
     NativeConVarCallback m_callbackfunc;
     NativeConVarCallbackArgs m_callbackfuncargs;
     NativeConVarChangeCallback m_changecallback;
 };
 
-class ConVars {
-   public:
-    // shared engine-wide cross-game convars for convenience access (for convars which don't fit anywhere else)
-    static ConVar sv_cheats;
-};
-
 //*******************//
 //  Searching/Lists  //
 //*******************//

+ 24 - 24
src/Engine/Engine.cpp

@@ -73,7 +73,7 @@ class EngineLoadingScreenApp : public App {
 };
 
 void _host_timescale_(UString oldValue, UString newValue);
-ConVar host_timescale("host_timescale", 1.0f, FCVAR_CHEAT,
+ConVar host_timescale("host_timescale", 1.0f, FCVAR_LOCKED,
                       "Scale by which the engine measures elapsed time, affects engine->getTime()", _host_timescale_);
 void _host_timescale_(UString oldValue, UString newValue) {
     if(newValue.toFloat() < 0.01f) {
@@ -81,17 +81,17 @@ void _host_timescale_(UString oldValue, UString newValue) {
         host_timescale.setValue(1.0f);
     }
 }
-ConVar epilepsy("epilepsy", false, FCVAR_NONE);
-ConVar debug_engine("debug_engine", false, FCVAR_NONE);
-ConVar minimize_on_focus_lost_if_fullscreen("minimize_on_focus_lost_if_fullscreen", true, FCVAR_NONE);
+ConVar epilepsy("epilepsy", false, FCVAR_DEFAULT);
+ConVar debug_engine("debug_engine", false, FCVAR_DEFAULT);
+ConVar minimize_on_focus_lost_if_fullscreen("minimize_on_focus_lost_if_fullscreen", true, FCVAR_DEFAULT);
 ConVar minimize_on_focus_lost_if_borderless_windowed_fullscreen(
-    "minimize_on_focus_lost_if_borderless_windowed_fullscreen", false, FCVAR_NONE);
-ConVar _win_realtimestylus("win_realtimestylus", false, FCVAR_NONE,
+    "minimize_on_focus_lost_if_borderless_windowed_fullscreen", false, FCVAR_DEFAULT);
+ConVar _win_realtimestylus("win_realtimestylus", false, FCVAR_DEFAULT,
                            "if compiled on Windows, enables native RealTimeStylus support for tablet clicks");
-ConVar _win_processpriority("win_processpriority", 1, FCVAR_NONE,
+ConVar _win_processpriority("win_processpriority", 1, FCVAR_DEFAULT,
                             "if compiled on Windows, sets the main process priority (0 = normal, 1 = high)");
 ConVar _win_disable_windows_key(
-    "win_disable_windows_key", false, FCVAR_NONE,
+    "win_disable_windows_key", false, FCVAR_DEFAULT,
     "if compiled on Windows, set to 0/1 to disable/enable all windows keys via low level keyboard hook");
 
 ConVar *win_realtimestylus = &_win_realtimestylus;  // extern
@@ -846,19 +846,19 @@ void _crash(void) {
 
 void _dpiinfo(void) { debugLog("env->getDPI() = %i, env->getDPIScale() = %f\n", env->getDPI(), env->getDPIScale()); }
 
-ConVar _exit_("exit", FCVAR_NONE, _exit);
-ConVar _shutdown_("shutdown", FCVAR_NONE, _exit);
-ConVar _restart_("restart", FCVAR_NONE, _restart);
-ConVar _printsize_("printsize", FCVAR_NONE, _printsize);
-ConVar _fullscreen_("fullscreen", FCVAR_NONE, _fullscreen);
-ConVar _borderless_("borderless", FCVAR_NONE, _borderless);
-ConVar _windowed_("windowed", FCVAR_NONE, _windowed);
-ConVar _minimize_("minimize", FCVAR_NONE, _minimize);
-ConVar _maximize_("maximize", FCVAR_NONE, _maximize);
-ConVar _resizable_toggle_("resizable_toggle", FCVAR_NONE, _toggleresizable);
-ConVar _focus_("focus", FCVAR_NONE, _focus);
-ConVar _center_("center", FCVAR_NONE, _center);
-ConVar _corporeal_("debug_ghost", FCVAR_NONE, false, _debugCorporeal);
-ConVar _errortest_("errortest", FCVAR_NONE, _errortest);
-ConVar _crash_("crash", FCVAR_NONE, _crash);
-ConVar _dpiinfo_("dpiinfo", FCVAR_NONE, _dpiinfo);
+ConVar _exit_("exit", FCVAR_DEFAULT, _exit);
+ConVar _shutdown_("shutdown", FCVAR_DEFAULT, _exit);
+ConVar _restart_("restart", FCVAR_DEFAULT, _restart);
+ConVar _printsize_("printsize", FCVAR_DEFAULT, _printsize);
+ConVar _fullscreen_("fullscreen", FCVAR_DEFAULT, _fullscreen);
+ConVar _borderless_("borderless", FCVAR_DEFAULT, _borderless);
+ConVar _windowed_("windowed", FCVAR_DEFAULT, _windowed);
+ConVar _minimize_("minimize", FCVAR_DEFAULT, _minimize);
+ConVar _maximize_("maximize", FCVAR_DEFAULT, _maximize);
+ConVar _resizable_toggle_("resizable_toggle", FCVAR_DEFAULT, _toggleresizable);
+ConVar _focus_("focus", FCVAR_DEFAULT, _focus);
+ConVar _center_("center", FCVAR_DEFAULT, _center);
+ConVar _corporeal_("debug_ghost", FCVAR_DEFAULT, false, _debugCorporeal);
+ConVar _errortest_("errortest", FCVAR_DEFAULT, _errortest);
+ConVar _crash_("crash", FCVAR_DEFAULT, _crash);
+ConVar _dpiinfo_("dpiinfo", FCVAR_DEFAULT, _dpiinfo);

+ 3 - 3
src/Engine/Environment.cpp

@@ -9,7 +9,7 @@
 
 #include "ConVar.h"
 
-ConVar _debug_env("debug_env", false, FCVAR_NONE);
+ConVar _debug_env("debug_env", false, FCVAR_DEFAULT);
 ConVar *Environment::debug_env = &_debug_env;
 
 Environment::Environment() { m_bFullscreenWindowedBorderless = false; }
@@ -33,6 +33,6 @@ void _fullscreen_windowed_borderless(UString oldValue, UString newValue) {
 
 void _monitor(UString oldValue, UString newValue) { env->setMonitor(newValue.toInt()); }
 
-ConVar _fullscreen_windowed_borderless_("fullscreen_windowed_borderless", false, FCVAR_NONE,
+ConVar _fullscreen_windowed_borderless_("fullscreen_windowed_borderless", false, FCVAR_DEFAULT,
                                         _fullscreen_windowed_borderless);
-ConVar _monitor_("monitor", 0, FCVAR_NONE, "monitor/display device to switch to, 0 = primary monitor", _monitor);
+ConVar _monitor_("monitor", 0, FCVAR_DEFAULT, "monitor/display device to switch to, 0 = primary monitor", _monitor);

+ 2 - 2
src/Engine/Font.cpp

@@ -12,9 +12,9 @@
 #include "ResourceManager.h"
 #include "VertexArrayObject.h"
 
-ConVar r_drawstring_max_string_length("r_drawstring_max_string_length", 65536, FCVAR_CHEAT,
+ConVar r_drawstring_max_string_length("r_drawstring_max_string_length", 65536, FCVAR_LOCKED,
                                       "maximum number of characters per call, sanity/memory buffer limit");
-ConVar r_debug_drawstring_unbind("r_debug_drawstring_unbind", false, FCVAR_NONE);
+ConVar r_debug_drawstring_unbind("r_debug_drawstring_unbind", false, FCVAR_DEFAULT);
 
 static unsigned char *unpackMonoBitmap(FT_Bitmap bitmap);
 

+ 10 - 10
src/Engine/Graphics.cpp

@@ -11,15 +11,15 @@
 #include "ConVar.h"
 #include "Engine.h"
 
-ConVar r_3dscene_zn("r_3dscene_zn", 5.0f, FCVAR_CHEAT);
-ConVar r_3dscene_zf("r_3dscene_zf", 5000.0f, FCVAR_CHEAT);
+ConVar r_3dscene_zn("r_3dscene_zn", 5.0f, FCVAR_LOCKED);
+ConVar r_3dscene_zf("r_3dscene_zf", 5000.0f, FCVAR_LOCKED);
 
-ConVar _r_globaloffset_x("r_globaloffset_x", 0.0f, FCVAR_CHEAT);
-ConVar _r_globaloffset_y("r_globaloffset_y", 0.0f, FCVAR_CHEAT);
-ConVar _r_debug_disable_cliprect("r_debug_disable_cliprect", false, FCVAR_CHEAT);
-ConVar _r_debug_disable_3dscene("r_debug_disable_3dscene", false, FCVAR_CHEAT);
-ConVar _r_debug_flush_drawstring("r_debug_flush_drawstring", false, FCVAR_NONE);
-ConVar _r_debug_drawimage("r_debug_drawimage", false, FCVAR_CHEAT);
+ConVar _r_globaloffset_x("r_globaloffset_x", 0.0f, FCVAR_LOCKED);
+ConVar _r_globaloffset_y("r_globaloffset_y", 0.0f, FCVAR_LOCKED);
+ConVar _r_debug_disable_cliprect("r_debug_disable_cliprect", false, FCVAR_LOCKED);
+ConVar _r_debug_disable_3dscene("r_debug_disable_3dscene", false, FCVAR_LOCKED);
+ConVar _r_debug_flush_drawstring("r_debug_flush_drawstring", false, FCVAR_DEFAULT);
+ConVar _r_debug_drawimage("r_debug_drawimage", false, FCVAR_LOCKED);
 
 ConVar *Graphics::r_globaloffset_x = &_r_globaloffset_x;
 ConVar *Graphics::r_globaloffset_y = &_r_globaloffset_y;
@@ -255,5 +255,5 @@ void _mat_wireframe(UString oldValue, UString newValue) {
     engine->getGraphics()->setWireframe(newValue.toFloat() > 0.0f);
 }
 
-ConVar _mat_wireframe_("mat_wireframe", false, FCVAR_CHEAT, _mat_wireframe);
-ConVar _vsync_("vsync", false, FCVAR_NONE, _vsync);
+ConVar _mat_wireframe_("mat_wireframe", false, FCVAR_LOCKED, _mat_wireframe);
+ConVar _vsync_("vsync", false, FCVAR_DEFAULT, _vsync);

+ 7 - 7
src/Engine/Input/Mouse.cpp

@@ -12,17 +12,17 @@
 #include "Environment.h"
 #include "ResourceManager.h"
 
-ConVar debug_mouse("debug_mouse", false, FCVAR_CHEAT);
+ConVar debug_mouse("debug_mouse", false, FCVAR_LOCKED);
 
-ConVar mouse_sensitivity("mouse_sensitivity", 1.0f, FCVAR_NONE);
-ConVar mouse_raw_input("mouse_raw_input", false, FCVAR_NONE);
-ConVar mouse_raw_input_absolute_to_window("mouse_raw_input_absolute_to_window", false, FCVAR_NONE);
-ConVar mouse_fakelag("mouse_fakelag", 0.000f, FCVAR_NONE,
+ConVar mouse_sensitivity("mouse_sensitivity", 1.0f, FCVAR_DEFAULT);
+ConVar mouse_raw_input("mouse_raw_input", false, FCVAR_DEFAULT);
+ConVar mouse_raw_input_absolute_to_window("mouse_raw_input_absolute_to_window", false, FCVAR_DEFAULT);
+ConVar mouse_fakelag("mouse_fakelag", 0.000f, FCVAR_DEFAULT,
                      "delay all mouse movement by this many seconds (e.g. 0.1 = 100 ms delay)");
 
-ConVar tablet_sensitivity_ignore("tablet_sensitivity_ignore", false, FCVAR_NONE);
+ConVar tablet_sensitivity_ignore("tablet_sensitivity_ignore", false, FCVAR_DEFAULT);
 
-ConVar win_ink_workaround("win_ink_workaround", false, FCVAR_NONE);
+ConVar win_ink_workaround("win_ink_workaround", false, FCVAR_DEFAULT);
 
 Mouse::Mouse() : InputDevice() {
     m_bMouseLeftDown = false;

+ 3 - 3
src/Engine/Main/main_Linux.cpp

@@ -46,9 +46,9 @@ bool g_bDraw = true;
 
 bool g_bHasFocus = false;  // for fps_max_background
 
-ConVar fps_max("fps_max", 60, FCVAR_NONE);
-ConVar fps_max_background("fps_max_background", 30, FCVAR_NONE);
-ConVar fps_unlimited("fps_unlimited", false, FCVAR_NONE);
+ConVar fps_max("fps_max", 60, FCVAR_DEFAULT);
+ConVar fps_max_background("fps_max_background", 30, FCVAR_DEFAULT);
+ConVar fps_unlimited("fps_unlimited", false, FCVAR_DEFAULT);
 
 Display *dpy;
 Window root;

+ 3 - 3
src/Engine/Main/main_OSX_cpp.cpp

@@ -27,9 +27,9 @@ bool g_bDraw = true;
 bool g_bMinimized = false;  // for fps_max_background
 bool g_bHasFocus = true;    // for fps_max_background // TODO: focus handling!
 
-ConVar fps_max("fps_max", 60.0f, FCVAR_NONE);
-ConVar fps_max_background("fps_max_background", 30.0f, FCVAR_NONE);
-ConVar fps_unlimited("fps_unlimited", false, FCVAR_NONE);
+ConVar fps_max("fps_max", 60.0f, FCVAR_DEFAULT);
+ConVar fps_max_background("fps_max_background", 30.0f, FCVAR_DEFAULT);
+ConVar fps_unlimited("fps_unlimited", false, FCVAR_DEFAULT);
 
 MacOSWrapper::MacOSWrapper() {
     // create timers

+ 9 - 9
src/Engine/Main/main_SDL.cpp

@@ -45,19 +45,19 @@ bool g_bHasFocus = true;    // for fps_max_background
 
 SDL_Window *g_window = NULL;
 
-ConVar fps_max("fps_max", 60.0f, FCVAR_NONE, "framerate limiter, foreground");
-ConVar fps_max_yield("fps_max_yield", true, FCVAR_NONE,
+ConVar fps_max("fps_max", 60.0f, FCVAR_DEFAULT, "framerate limiter, foreground");
+ConVar fps_max_yield("fps_max_yield", true, FCVAR_DEFAULT,
                      "always release rest of timeslice once per frame (call scheduler via sleep(0))");
-ConVar fps_max_background("fps_max_background", 30.0f, FCVAR_NONE, "framerate limiter, background");
-ConVar fps_unlimited("fps_unlimited", false, FCVAR_NONE);
+ConVar fps_max_background("fps_max_background", 30.0f, FCVAR_DEFAULT, "framerate limiter, background");
+ConVar fps_unlimited("fps_unlimited", false, FCVAR_DEFAULT);
 ConVar fps_unlimited_yield(
-    "fps_unlimited_yield", true, FCVAR_NONE,
+    "fps_unlimited_yield", true, FCVAR_DEFAULT,
     "always release rest of timeslice once per frame (call scheduler via sleep(0)), even if unlimited fps are enabled");
 
-ConVar sdl_joystick_mouse_sensitivity("sdl_joystick_mouse_sensitivity", 1.0f, FCVAR_NONE);
-ConVar sdl_joystick0_deadzone("sdl_joystick0_deadzone", 0.3f, FCVAR_NONE);
-ConVar sdl_joystick_zl_threshold("sdl_joystick_zl_threshold", -0.5f, FCVAR_NONE);
-ConVar sdl_joystick_zr_threshold("sdl_joystick_zr_threshold", -0.5f, FCVAR_NONE);
+ConVar sdl_joystick_mouse_sensitivity("sdl_joystick_mouse_sensitivity", 1.0f, FCVAR_DEFAULT);
+ConVar sdl_joystick0_deadzone("sdl_joystick0_deadzone", 0.3f, FCVAR_DEFAULT);
+ConVar sdl_joystick_zl_threshold("sdl_joystick_zl_threshold", -0.5f, FCVAR_DEFAULT);
+ConVar sdl_joystick_zr_threshold("sdl_joystick_zr_threshold", -0.5f, FCVAR_DEFAULT);
 
 int mainSDL(int argc, char *argv[], SDLEnvironment *customSDLEnvironment) {
     SDLEnvironment *environment = customSDLEnvironment;

+ 7 - 7
src/Engine/Main/main_Windows.cpp

@@ -145,18 +145,18 @@ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance =
     0x00000001;  // https://community.amd.com/thread/169965
 }
 
-ConVar fps_max("fps_max", 60.0f, FCVAR_NONE, "framerate limiter, foreground");
-ConVar fps_max_yield("fps_max_yield", false, FCVAR_NONE,
+ConVar fps_max("fps_max", 60.0f, FCVAR_DEFAULT, "framerate limiter, foreground");
+ConVar fps_max_yield("fps_max_yield", false, FCVAR_DEFAULT,
                      "always release rest of timeslice once per frame (call scheduler via sleep(0))");
-ConVar fps_max_background("fps_max_background", 30.0f, FCVAR_NONE, "framerate limiter, background");
-ConVar fps_max_background_interleaved("fps_max_background_interleaved", 1, FCVAR_NONE,
+ConVar fps_max_background("fps_max_background", 30.0f, FCVAR_DEFAULT, "framerate limiter, background");
+ConVar fps_max_background_interleaved("fps_max_background_interleaved", 1, FCVAR_DEFAULT,
                                       "experimental, update normally but only draw every n-th frame");
-ConVar fps_unlimited("fps_unlimited", false, FCVAR_NONE);
+ConVar fps_unlimited("fps_unlimited", false, FCVAR_DEFAULT);
 ConVar fps_unlimited_yield(
-    "fps_unlimited_yield", false, FCVAR_NONE,
+    "fps_unlimited_yield", false, FCVAR_DEFAULT,
     "always release rest of timeslice once per frame (call scheduler via sleep(0)), even if unlimited fps are enabled");
 
-ConVar win_mouse_raw_input_buffer("win_mouse_raw_input_buffer", false, FCVAR_NONE,
+ConVar win_mouse_raw_input_buffer("win_mouse_raw_input_buffer", false, FCVAR_DEFAULT,
                                   "use GetRawInputBuffer() to reduce wndproc event queue overflow stalls on insane "
                                   "mouse usb polling rates above 1000 Hz");
 

+ 1 - 1
src/Engine/NetworkHandler.cpp

@@ -17,7 +17,7 @@
 #define MC_PROTOCOL_VERSION 1
 #define MC_PROTOCOL_TIMEOUT 10000
 
-ConVar _name_("name", "Guest", FCVAR_NONE);
+ConVar _name_("name", "Guest", FCVAR_DEFAULT);
 
 NetworkHandler::NetworkHandler() {}
 

+ 2 - 2
src/Engine/Platform/File.cpp

@@ -10,8 +10,8 @@
 #include "ConVar.h"
 #include "Engine.h"
 
-ConVar debug_file("debug_file", false, FCVAR_NONE);
-ConVar file_size_max("file_size_max", 1024, FCVAR_NONE,
+ConVar debug_file("debug_file", false, FCVAR_DEFAULT);
+ConVar file_size_max("file_size_max", 1024, FCVAR_DEFAULT,
                      "maximum filesize sanity limit in MB, all files bigger than this are not allowed to load");
 
 ConVar *File::debug = &debug_file;

+ 1 - 1
src/Engine/Platform/Thread.cpp

@@ -42,7 +42,7 @@ class PosixThread : public BaseThread {
     bool m_bReady;
 };
 
-ConVar debug_thread("debug_thread", false, FCVAR_NONE);
+ConVar debug_thread("debug_thread", false, FCVAR_DEFAULT);
 
 ConVar *McThread::debug = &debug_thread;
 

+ 1 - 1
src/Engine/Platform/WinEnvironment.cpp

@@ -995,6 +995,6 @@ void WinEnvironment::bluescreen() {
         pNtRaiseHardError(STATUS_FLOAT_MULTIPLE_FAULTS, 0, 0, 0, 6, &uResp);
     }
 }
-ConVar _bluescreen_("bluescreen", FCVAR_NONE, WinEnvironment::bluescreen);
+ConVar _bluescreen_("bluescreen", FCVAR_DEFAULT, WinEnvironment::bluescreen);
 
 #endif

+ 1 - 1
src/Engine/Profiler.cpp

@@ -158,4 +158,4 @@ void _vprof(UString oldValue, UString newValue) {
     }
 }
 
-ConVar _vprof_("vprof", false, FCVAR_NONE, "enables/disables the visual profiler", _vprof);
+ConVar _vprof_("vprof", false, FCVAR_DEFAULT, "enables/disables the visual profiler", _vprof);

+ 1 - 1
src/Engine/RenderTarget.cpp

@@ -11,7 +11,7 @@
 #include "Engine.h"
 #include "VertexArrayObject.h"
 
-ConVar _debug_rt("debug_rt", false, FCVAR_CHEAT, "draws all rendertargets with a translucent green background");
+ConVar _debug_rt("debug_rt", false, FCVAR_LOCKED, "draws all rendertargets with a translucent green background");
 
 ConVar *RenderTarget::debug_rt = &_debug_rt;
 

+ 1 - 1
src/Engine/Renderer/OpenGLLegacyInterface.cpp

@@ -29,7 +29,7 @@
 #define TEXTURE_FREE_MEMORY_ATI 0x87FC
 #define RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
 
-ConVar r_image_unbind_after_drawimage("r_image_unbind_after_drawimage", true, FCVAR_NONE);
+ConVar r_image_unbind_after_drawimage("r_image_unbind_after_drawimage", true, FCVAR_DEFAULT);
 
 OpenGLLegacyInterface::OpenGLLegacyInterface() : Graphics() {
     // renderer

+ 1 - 1
src/Engine/Renderer/OpenGLVertexArrayObject.cpp

@@ -14,7 +14,7 @@
 #include "OpenGLHeaders.h"
 
 ConVar r_opengl_legacy_vao_use_vertex_array(
-    "r_opengl_legacy_vao_use_vertex_array", false, FCVAR_CHEAT,
+    "r_opengl_legacy_vao_use_vertex_array", false, FCVAR_LOCKED,
     "dramatically reduces per-vao draw calls, but completely breaks legacy ffp draw calls (vertices work, but "
     "texcoords/normals/etc. are NOT in gl_MultiTexCoord0 -> requiring a shader with attributes)");
 

+ 5 - 5
src/Engine/ResourceManager.cpp

@@ -36,12 +36,12 @@ class ResourceManagerLoaderThread {
 };
 
 ConVar rm_numthreads(
-    "rm_numthreads", 3, FCVAR_NONE,
+    "rm_numthreads", 3, FCVAR_DEFAULT,
     "how many parallel resource loader threads are spawned once on startup (!), and subsequently used during runtime");
-ConVar rm_warnings("rm_warnings", false, FCVAR_NONE);
-ConVar rm_debug_async_delay("rm_debug_async_delay", 0.0f, FCVAR_CHEAT);
-ConVar rm_interrupt_on_destroy("rm_interrupt_on_destroy", true, FCVAR_CHEAT);
-ConVar debug_rm_("debug_rm", false, FCVAR_NONE);
+ConVar rm_warnings("rm_warnings", false, FCVAR_DEFAULT);
+ConVar rm_debug_async_delay("rm_debug_async_delay", 0.0f, FCVAR_LOCKED);
+ConVar rm_interrupt_on_destroy("rm_interrupt_on_destroy", true, FCVAR_LOCKED);
+ConVar debug_rm_("debug_rm", false, FCVAR_DEFAULT);
 
 ConVar *ResourceManager::debug_rm = &debug_rm_;
 

+ 1 - 1
src/Engine/Shader.cpp

@@ -9,6 +9,6 @@
 
 #include "ConVar.h"
 
-ConVar _debug_shaders("debug_shaders", false, FCVAR_NONE);
+ConVar _debug_shaders("debug_shaders", false, FCVAR_DEFAULT);
 
 ConVar *Shader::debug_shaders = &_debug_shaders;

+ 3 - 3
src/Engine/Sound.cpp

@@ -11,13 +11,13 @@
 #include "SoundEngine.h"
 
 ConVar snd_play_interp_duration(
-    "snd_play_interp_duration", 0.75f, FCVAR_NONE,
+    "snd_play_interp_duration", 0.75f, FCVAR_DEFAULT,
     "smooth over freshly started channel position jitter with engine time over this duration in seconds");
-ConVar snd_play_interp_ratio("snd_play_interp_ratio", 0.50f, FCVAR_NONE,
+ConVar snd_play_interp_ratio("snd_play_interp_ratio", 0.50f, FCVAR_DEFAULT,
                              "percentage of snd_play_interp_duration to use 100% engine time over audio time (some "
                              "devices report 0 for very long)");
 
-ConVar snd_wav_file_min_size("snd_wav_file_min_size", 51, FCVAR_NONE,
+ConVar snd_wav_file_min_size("snd_wav_file_min_size", 51, FCVAR_DEFAULT,
                              "minimum file size in bytes for WAV files to be considered valid (everything below will "
                              "fail to load), this is a workaround for BASS crashes");
 

+ 14 - 13
src/Engine/SoundEngine.cpp

@@ -35,34 +35,34 @@ void _volume(UString oldValue, UString newValue) {
     engine->getSound()->setVolume(newValue.toFloat());
 }
 
-ConVar _volume_("volume", 1.0f, FCVAR_NONE, _volume);
+ConVar _volume_("volume", 1.0f, FCVAR_DEFAULT, _volume);
 
-ConVar snd_output_device("snd_output_device", "Default", FCVAR_NONE);
+ConVar snd_output_device("snd_output_device", "Default", FCVAR_DEFAULT);
 ConVar snd_restart("snd_restart");
 
-ConVar snd_freq("snd_freq", 44100, FCVAR_NONE, "output sampling rate in Hz");
-ConVar snd_updateperiod("snd_updateperiod", 10, FCVAR_NONE, "BASS_CONFIG_UPDATEPERIOD length in milliseconds");
-ConVar snd_dev_period("snd_dev_period", 10, FCVAR_NONE,
+ConVar snd_freq("snd_freq", 44100, FCVAR_DEFAULT, "output sampling rate in Hz");
+ConVar snd_updateperiod("snd_updateperiod", 10, FCVAR_DEFAULT, "BASS_CONFIG_UPDATEPERIOD length in milliseconds");
+ConVar snd_dev_period("snd_dev_period", 10, FCVAR_DEFAULT,
                       "BASS_CONFIG_DEV_PERIOD length in milliseconds, or if negative then in samples");
-ConVar snd_dev_buffer("snd_dev_buffer", 30, FCVAR_NONE, "BASS_CONFIG_DEV_BUFFER length in milliseconds");
+ConVar snd_dev_buffer("snd_dev_buffer", 30, FCVAR_DEFAULT, "BASS_CONFIG_DEV_BUFFER length in milliseconds");
 
 ConVar snd_restrict_play_frame(
-    "snd_restrict_play_frame", true, FCVAR_NONE,
+    "snd_restrict_play_frame", true, FCVAR_DEFAULT,
     "only allow one new channel per frame for overlayable sounds (prevents lag and earrape)");
-ConVar snd_change_check_interval("snd_change_check_interval", 0.0f, FCVAR_NONE,
+ConVar snd_change_check_interval("snd_change_check_interval", 0.0f, FCVAR_DEFAULT,
                                  "check for output device changes every this many seconds. 0 = disabled (default)");
 
 ConVar win_snd_wasapi_buffer_size(
-    "win_snd_wasapi_buffer_size", 0.011f, FCVAR_NONE,
+    "win_snd_wasapi_buffer_size", 0.011f, FCVAR_DEFAULT,
     "buffer size/length in seconds (e.g. 0.011 = 11 ms), directly responsible for audio delay and crackling");
 ConVar win_snd_wasapi_period_size(
-    "win_snd_wasapi_period_size", 0.0f, FCVAR_NONE,
+    "win_snd_wasapi_period_size", 0.0f, FCVAR_DEFAULT,
     "interval between OutputWasapiProc calls in seconds (e.g. 0.016 = 16 ms) (0 = use default)");
 
-ConVar asio_buffer_size("asio_buffer_size", -1, FCVAR_NONE,
+ConVar asio_buffer_size("asio_buffer_size", -1, FCVAR_DEFAULT,
                         "buffer size in samples (usually 44100 samples per second)");
 
-ConVar osu_universal_offset_hardcoded("osu_universal_offset_hardcoded", 0.0f, FCVAR_NONE);
+ConVar osu_universal_offset_hardcoded("osu_universal_offset_hardcoded", 0.0f, FCVAR_DEFAULT);
 
 void _RESTART_SOUND_ENGINE_ON_CHANGE(UString oldValue, UString newValue) {
     const int oldValueMS = std::round(oldValue.toFloat() * 1000.0f);
@@ -454,7 +454,8 @@ bool SoundEngine::initializeOutputDevice(OUTPUT_DEVICE device) {
         // BASS_WASAPI_EXCLUSIVE makes neosu have exclusive output to the sound card
         auto flags = BASS_WASAPI_RAW | BASS_MIXER_NONSTOP | BASS_WASAPI_EXCLUSIVE;
 
-        if(!BASS_WASAPI_Init(device.id, 0, 0, flags, bufferSize, updatePeriod, WASAPIPROC_BASS, (void*)g_bassOutputMixer)) {
+        if(!BASS_WASAPI_Init(device.id, 0, 0, flags, bufferSize, updatePeriod, WASAPIPROC_BASS,
+                             (void *)g_bassOutputMixer)) {
             const int errorCode = BASS_ErrorGetCode();
             if(errorCode == BASS_ERROR_WASAPI_BUFFER) {
                 debugLog("Sound Error: BASS_WASAPI_Init() failed with BASS_ERROR_WASAPI_BUFFER!");

+ 1 - 1
src/GUI/CBaseUIBoxShadow.cpp

@@ -21,7 +21,7 @@
 #include "OpenGLHeaders.h"
 */
 
-ConVar debug_box_shadows("debug_box_shadows", false, FCVAR_NONE);
+ConVar debug_box_shadows("debug_box_shadows", false, FCVAR_DEFAULT);
 
 CBaseUIBoxShadow::CBaseUIBoxShadow(Color color, float radius, float xPos, float yPos, float xSize, float ySize,
                                    UString name)

+ 6 - 6
src/GUI/CBaseUIScrollView.cpp

@@ -17,15 +17,15 @@
 #include "Mouse.h"
 #include "ResourceManager.h"
 
-ConVar ui_scrollview_resistance("ui_scrollview_resistance", 5.0f, FCVAR_NONE,
+ConVar ui_scrollview_resistance("ui_scrollview_resistance", 5.0f, FCVAR_DEFAULT,
                                 "how many pixels you have to pull before you start scrolling");
-ConVar ui_scrollview_scrollbarwidth("ui_scrollview_scrollbarwidth", 15.0f, FCVAR_NONE);
-ConVar ui_scrollview_kinetic_energy_multiplier("ui_scrollview_kinetic_energy_multiplier", 24.0f, FCVAR_NONE,
+ConVar ui_scrollview_scrollbarwidth("ui_scrollview_scrollbarwidth", 15.0f, FCVAR_DEFAULT);
+ConVar ui_scrollview_kinetic_energy_multiplier("ui_scrollview_kinetic_energy_multiplier", 24.0f, FCVAR_DEFAULT,
                                                "afterscroll delta multiplier");
-ConVar ui_scrollview_kinetic_approach_time("ui_scrollview_kinetic_approach_time", 0.075f, FCVAR_NONE,
+ConVar ui_scrollview_kinetic_approach_time("ui_scrollview_kinetic_approach_time", 0.075f, FCVAR_DEFAULT,
                                            "approach target afterscroll delta over this duration");
-ConVar ui_scrollview_mousewheel_multiplier("ui_scrollview_mousewheel_multiplier", 3.5f, FCVAR_NONE);
-ConVar ui_scrollview_mousewheel_overscrollbounce("ui_scrollview_mousewheel_overscrollbounce", true, FCVAR_NONE);
+ConVar ui_scrollview_mousewheel_multiplier("ui_scrollview_mousewheel_multiplier", 3.5f, FCVAR_DEFAULT);
+ConVar ui_scrollview_mousewheel_overscrollbounce("ui_scrollview_mousewheel_overscrollbounce", true, FCVAR_DEFAULT);
 
 CBaseUIScrollView::CBaseUIScrollView(float xPos, float yPos, float xSize, float ySize, UString name)
     : CBaseUIElement(xPos, yPos, xSize, ySize, name) {

+ 2 - 2
src/GUI/CBaseUITextbox.cpp

@@ -21,8 +21,8 @@
 #include "Mouse.h"
 #include "ResourceManager.h"
 
-ConVar ui_textbox_caret_blink_time("ui_textbox_caret_blink_time", 0.5f, FCVAR_NONE);
-ConVar ui_textbox_text_offset_x("ui_textbox_text_offset_x", 3, FCVAR_NONE);
+ConVar ui_textbox_caret_blink_time("ui_textbox_caret_blink_time", 0.5f, FCVAR_DEFAULT);
+ConVar ui_textbox_text_offset_x("ui_textbox_text_offset_x", 3, FCVAR_DEFAULT);
 
 CBaseUITextbox::CBaseUITextbox(float xPos, float yPos, float xSize, float ySize, UString name)
     : CBaseUIElement(xPos, yPos, xSize, ySize, name) {

+ 2 - 2
src/GUI/CBaseUIWindow.cpp

@@ -19,8 +19,8 @@
 #include "RenderTarget.h"
 #include "ResourceManager.h"
 
-ConVar ui_window_animspeed("ui_window_animspeed", 0.29f, FCVAR_NONE);
-ConVar ui_window_shadow_radius("ui_window_shadow_radius", 13.0f, FCVAR_NONE);
+ConVar ui_window_animspeed("ui_window_animspeed", 0.29f, FCVAR_DEFAULT);
+ConVar ui_window_shadow_radius("ui_window_shadow_radius", 13.0f, FCVAR_DEFAULT);
 
 CBaseUIWindow::CBaseUIWindow(float xPos, float yPos, float xSize, float ySize, UString name)
     : CBaseUIElement(xPos, yPos, xSize, ySize, name) {

+ 3 - 19
src/GUI/Windows/Console.cpp

@@ -24,7 +24,7 @@
 
 #define CONSOLE_BORDER 6
 
-ConVar _console_logging("console_logging", true, FCVAR_NONE);
+ConVar _console_logging("console_logging", true, FCVAR_DEFAULT);
 ConVar _clear("clear");
 
 std::vector<UString> Console::g_commandQueue;
@@ -138,8 +138,6 @@ void Console::processCommand(UString command) {
         return;
     }
 
-    if(var->isFlagSet(FCVAR_CHEAT) && !ConVars::sv_cheats.getBool()) return;
-
     // set new value (this handles all callbacks internally)
     if(commandValue.length() > 0)
         var->setValue(commandValue);
@@ -292,19 +290,5 @@ void _echo(UString args) {
     }
 }
 
-void _fizzbuzz(void) {
-    for(int i = 1; i < 101; i++) {
-        if(i % 3 == 0 && i % 5 == 0)
-            debugLog("%i fizzbuzz\n", i);
-        else if(i % 3 == 0)
-            debugLog("%i fizz\n", i);
-        else if(i % 5 == 0)
-            debugLog("%i buzz\n", i);
-        else
-            debugLog("%i\n", i);
-    }
-}
-
-ConVar _exec_("exec", FCVAR_NONE, _exec);
-ConVar _echo_("echo", FCVAR_NONE, _echo);
-ConVar _fizzbuzz_("fizzbuzz", FCVAR_NONE, _fizzbuzz);
+ConVar _exec_("exec", FCVAR_DEFAULT, _exec);
+ConVar _echo_("echo", FCVAR_DEFAULT, _echo);

+ 0 - 1
src/GUI/Windows/Console.h

@@ -36,7 +36,6 @@ class Console : public CBaseUIWindow {
     static std::vector<UString> g_commandQueue;
 
    private:
-    CBaseUITextField *m_newLog;
     CBaseUIScrollView *m_log;
     CBaseUITextbox *m_textbox;
 

+ 6 - 6
src/GUI/Windows/ConsoleBox.cpp

@@ -23,16 +23,16 @@
 
 ConVar showconsolebox("showconsolebox");
 
-ConVar consolebox_animspeed("consolebox_animspeed", 12.0f, FCVAR_NONE);
-ConVar consolebox_draw_preview("consolebox_draw_preview", true, FCVAR_NONE,
+ConVar consolebox_animspeed("consolebox_animspeed", 12.0f, FCVAR_DEFAULT);
+ConVar consolebox_draw_preview("consolebox_draw_preview", true, FCVAR_DEFAULT,
                                "whether the textbox shows the topmost suggestion while typing");
-ConVar consolebox_draw_helptext("consolebox_draw_helptext", true, FCVAR_NONE,
+ConVar consolebox_draw_helptext("consolebox_draw_helptext", true, FCVAR_DEFAULT,
                                 "whether convar suggestions also draw their helptext");
 
-ConVar console_overlay("console_overlay", false, FCVAR_NONE,
+ConVar console_overlay("console_overlay", false, FCVAR_DEFAULT,
                        "should the log overlay always be visible (or only if the console is out)");
-ConVar console_overlay_lines("console_overlay_lines", 6, FCVAR_NONE, "max number of lines of text");
-ConVar console_overlay_scale("console_overlay_scale", 1.0f, FCVAR_NONE, "log text size multiplier");
+ConVar console_overlay_lines("console_overlay_lines", 6, FCVAR_DEFAULT, "max number of lines of text");
+ConVar console_overlay_scale("console_overlay_scale", 1.0f, FCVAR_DEFAULT, "log text size multiplier");
 
 class ConsoleBoxTextbox : public CBaseUITextbox {
    public:

+ 3 - 3
src/GUI/Windows/VinylScratcher/VSControlBar.cpp

@@ -16,9 +16,9 @@
 #include "Keyboard.h"
 #include "ResourceManager.h"
 
-ConVar vs_repeat("vs_repeat", false, FCVAR_NONE);
-ConVar vs_shuffle("vs_shuffle", false, FCVAR_NONE);
-ConVar vs_volume("vs_volume", 1.0f, FCVAR_NONE);
+ConVar vs_repeat("vs_repeat", false, FCVAR_DEFAULT);
+ConVar vs_shuffle("vs_shuffle", false, FCVAR_DEFAULT);
+ConVar vs_volume("vs_volume", 1.0f, FCVAR_DEFAULT);
 
 class VSControlBarButton : public CBaseUIButton {
    public:

+ 1 - 1
src/GUI/Windows/VinylScratcher/VSMusicBrowser.cpp

@@ -17,7 +17,7 @@
 #include "ResourceManager.h"
 #include "VinylScratcher.h"
 
-ConVar vs_browser_animspeed("vs_browser_animspeed", 0.15f, FCVAR_NONE);
+ConVar vs_browser_animspeed("vs_browser_animspeed", 0.15f, FCVAR_DEFAULT);
 
 struct VSMusicBrowserNaturalSortStringComparator {
     // heavily modified version of https://github.com/scopeInfinity/NaturalSort

+ 1 - 1
src/GUI/Windows/VinylScratcher/VSTitleBar.cpp

@@ -15,7 +15,7 @@
 #include "Mouse.h"
 #include "ResourceManager.h"
 
-ConVar vs_percent("vs_percent", 0.0f, FCVAR_NONE);
+ConVar vs_percent("vs_percent", 0.0f, FCVAR_DEFAULT);
 
 class VSTitleBarButton : public CBaseUIButton {
    public:

+ 10 - 10
src/GUI/Windows/VisualProfiler.cpp

@@ -19,24 +19,24 @@
 #include "ResourceManager.h"
 #include "SoundEngine.h"
 
-ConVar vprof_graph("vprof_graph", true, FCVAR_NONE, "whether to draw the graph when the overlay is enabled");
-ConVar vprof_graph_height("vprof_graph_height", 250.0f, FCVAR_NONE);
-ConVar vprof_graph_width("vprof_graph_width", 800.0f, FCVAR_NONE);
-ConVar vprof_graph_margin("vprof_graph_margin", 40.0f, FCVAR_NONE);
-ConVar vprof_graph_range_max("vprof_graph_range_max", 16.666666f, FCVAR_NONE,
+ConVar vprof_graph("vprof_graph", true, FCVAR_DEFAULT, "whether to draw the graph when the overlay is enabled");
+ConVar vprof_graph_height("vprof_graph_height", 250.0f, FCVAR_DEFAULT);
+ConVar vprof_graph_width("vprof_graph_width", 800.0f, FCVAR_DEFAULT);
+ConVar vprof_graph_margin("vprof_graph_margin", 40.0f, FCVAR_DEFAULT);
+ConVar vprof_graph_range_max("vprof_graph_range_max", 16.666666f, FCVAR_DEFAULT,
                              "max value of the y-axis in milliseconds");
-ConVar vprof_graph_alpha("vprof_graph_alpha", 1.0f, FCVAR_NONE, "line opacity");
-ConVar vprof_graph_draw_overhead("vprof_graph_draw_overhead", false, FCVAR_NONE,
+ConVar vprof_graph_alpha("vprof_graph_alpha", 1.0f, FCVAR_DEFAULT, "line opacity");
+ConVar vprof_graph_draw_overhead("vprof_graph_draw_overhead", false, FCVAR_DEFAULT,
                                  "whether to draw the profiling overhead time in white (usually negligible)");
 
-ConVar vprof_spike("vprof_spike", 0, FCVAR_NONE,
+ConVar vprof_spike("vprof_spike", 0, FCVAR_DEFAULT,
                    "measure and display largest spike details (1 = small info, 2 = extended info)");
 
-ConVar vprof_display_mode("vprof_display_mode", 0, FCVAR_NONE,
+ConVar vprof_display_mode("vprof_display_mode", 0, FCVAR_DEFAULT,
                           "which info blade to show on the top right (gpu/engine/app/etc. info), use CTRL + TAB to "
                           "cycle through, 0 = disabled");
 
-ConVar debug_vprof("debug_vprof", false, FCVAR_NONE);
+ConVar debug_vprof("debug_vprof", false, FCVAR_DEFAULT);
 
 ConVar *VisualProfiler::m_vprof_ref = NULL;
 

+ 2647 - 0
src/Util/cJSON.cpp

@@ -0,0 +1,2647 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning(push)
+/* disable warning about single line comments in system headers */
+#pragma warning(disable : 4001)
+#endif
+
+#include <ctype.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include "cJSON.h"
+
+/* define our own boolean type */
+#ifdef true
+#undef true
+#endif
+#define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
+#define false ((cJSON_bool)0)
+
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#ifdef _WIN32
+#define NAN sqrt(-1.0)
+#else
+#define NAN 0.0 / 0.0
+#endif
+#endif
+
+typedef struct {
+    const unsigned char *json;
+    size_t position;
+} error;
+static error global_error = {NULL, 0};
+
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) { return (const char *)(global_error.json + global_error.position); }
+
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item) {
+    if(!cJSON_IsString(item)) {
+        return NULL;
+    }
+
+    return item->valuestring;
+}
+
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item) {
+    if(!cJSON_IsNumber(item)) {
+        return (double)NAN;
+    }
+
+    return item->valuedouble;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if(CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
+#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char *) cJSON_Version(void) {
+    static char version[15];
+    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+    return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) {
+    if((string1 == NULL) || (string2 == NULL)) {
+        return 1;
+    }
+
+    if(string1 == string2) {
+        return 0;
+    }
+
+    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) {
+        if(*string1 == '\0') {
+            return 0;
+        }
+    }
+
+    return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks {
+    void *(CJSON_CDECL *allocate)(size_t size);
+    void(CJSON_CDECL *deallocate)(void *pointer);
+    void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
+static void *CJSON_CDECL internal_malloc(size_t size) { return malloc(size); }
+static void CJSON_CDECL internal_free(void *pointer) { free(pointer); }
+static void *CJSON_CDECL internal_realloc(void *pointer, size_t size) { return realloc(pointer, size); }
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = {internal_malloc, internal_free, internal_realloc};
+
+static unsigned char *cJSON_strdup(const unsigned char *string, const internal_hooks *const hooks) {
+    size_t length = 0;
+    unsigned char *copy = NULL;
+
+    if(string == NULL) {
+        return NULL;
+    }
+
+    length = strlen((const char *)string) + sizeof("");
+    copy = (unsigned char *)hooks->allocate(length);
+    if(copy == NULL) {
+        return NULL;
+    }
+    memcpy(copy, string, length);
+
+    return copy;
+}
+
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks) {
+    if(hooks == NULL) {
+        /* Reset hooks */
+        global_hooks.allocate = malloc;
+        global_hooks.deallocate = free;
+        global_hooks.reallocate = realloc;
+        return;
+    }
+
+    global_hooks.allocate = malloc;
+    if(hooks->malloc_fn != NULL) {
+        global_hooks.allocate = hooks->malloc_fn;
+    }
+
+    global_hooks.deallocate = free;
+    if(hooks->free_fn != NULL) {
+        global_hooks.deallocate = hooks->free_fn;
+    }
+
+    /* use realloc only if both free and malloc are used */
+    global_hooks.reallocate = NULL;
+    if((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) {
+        global_hooks.reallocate = realloc;
+    }
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(const internal_hooks *const hooks) {
+    cJSON *node = (cJSON *)hooks->allocate(sizeof(cJSON));
+    if(node) {
+        memset(node, '\0', sizeof(cJSON));
+    }
+
+    return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) {
+    cJSON *next = NULL;
+    while(item != NULL) {
+        next = item->next;
+        if(!(item->type & cJSON_IsReference) && (item->child != NULL)) {
+            cJSON_Delete(item->child);
+        }
+        if(!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
+            global_hooks.deallocate(item->valuestring);
+            item->valuestring = NULL;
+        }
+        if(!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
+            global_hooks.deallocate(item->string);
+            item->string = NULL;
+        }
+        global_hooks.deallocate(item);
+        item = next;
+    }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void) {
+#ifdef ENABLE_LOCALES
+    struct lconv *lconv = localeconv();
+    return (unsigned char)lconv->decimal_point[0];
+#else
+    return '.';
+#endif
+}
+
+typedef struct {
+    const unsigned char *content;
+    size_t length;
+    size_t offset;
+    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+    internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON *const item, parse_buffer *const input_buffer) {
+    double number = 0;
+    unsigned char *after_end = NULL;
+    unsigned char number_c_string[64];
+    unsigned char decimal_point = get_decimal_point();
+    size_t i = 0;
+
+    if((input_buffer == NULL) || (input_buffer->content == NULL)) {
+        return false;
+    }
+
+    /* copy the number into a temporary buffer and replace '.' with the decimal point
+     * of the current locale (for strtod)
+     * This also takes care of '\0' not necessarily being available for marking the end of the input */
+    for(i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) {
+        switch(buffer_at_offset(input_buffer)[i]) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case '+':
+            case '-':
+            case 'e':
+            case 'E':
+                number_c_string[i] = buffer_at_offset(input_buffer)[i];
+                break;
+
+            case '.':
+                number_c_string[i] = decimal_point;
+                break;
+
+            default:
+                goto loop_end;
+        }
+    }
+loop_end:
+    number_c_string[i] = '\0';
+
+    number = strtod((const char *)number_c_string, (char **)&after_end);
+    if(number_c_string == after_end) {
+        return false; /* parse_error */
+    }
+
+    item->valuedouble = number;
+
+    /* use saturation in case of overflow */
+    if(number >= INT_MAX) {
+        item->valueint = INT_MAX;
+    } else if(number <= (double)INT_MIN) {
+        item->valueint = INT_MIN;
+    } else {
+        item->valueint = (int)number;
+    }
+
+    item->type = cJSON_Number;
+
+    input_buffer->offset += (size_t)(after_end - number_c_string);
+    return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) {
+    if(number >= INT_MAX) {
+        object->valueint = INT_MAX;
+    } else if(number <= (double)INT_MIN) {
+        object->valueint = INT_MIN;
+    } else {
+        object->valueint = (int)number;
+    }
+
+    return object->valuedouble = number;
+}
+
+/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
+CJSON_PUBLIC(char *) cJSON_SetValuestring(cJSON *object, const char *valuestring) {
+    char *copy = NULL;
+    /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
+    if((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference)) {
+        return NULL;
+    }
+    /* return NULL if the object is corrupted or valuestring is NULL */
+    if(object->valuestring == NULL || valuestring == NULL) {
+        return NULL;
+    }
+    if(strlen(valuestring) <= strlen(object->valuestring)) {
+        strcpy(object->valuestring, valuestring);
+        return object->valuestring;
+    }
+    copy = (char *)cJSON_strdup((const unsigned char *)valuestring, &global_hooks);
+    if(copy == NULL) {
+        return NULL;
+    }
+    if(object->valuestring != NULL) {
+        cJSON_free(object->valuestring);
+    }
+    object->valuestring = copy;
+
+    return copy;
+}
+
+typedef struct {
+    unsigned char *buffer;
+    size_t length;
+    size_t offset;
+    size_t depth; /* current nesting depth (for formatted printing) */
+    cJSON_bool noalloc;
+    cJSON_bool format; /* is this print a formatted print */
+    internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char *ensure(printbuffer *const p, size_t needed) {
+    unsigned char *newbuffer = NULL;
+    size_t newsize = 0;
+
+    if((p == NULL) || (p->buffer == NULL)) {
+        return NULL;
+    }
+
+    if((p->length > 0) && (p->offset >= p->length)) {
+        /* make sure that offset is valid */
+        return NULL;
+    }
+
+    if(needed > INT_MAX) {
+        /* sizes bigger than INT_MAX are currently not supported */
+        return NULL;
+    }
+
+    needed += p->offset + 1;
+    if(needed <= p->length) {
+        return p->buffer + p->offset;
+    }
+
+    if(p->noalloc) {
+        return NULL;
+    }
+
+    /* calculate new buffer size */
+    if(needed > (INT_MAX / 2)) {
+        /* overflow of int, use INT_MAX if possible */
+        if(needed <= INT_MAX) {
+            newsize = INT_MAX;
+        } else {
+            return NULL;
+        }
+    } else {
+        newsize = needed * 2;
+    }
+
+    if(p->hooks.reallocate != NULL) {
+        /* reallocate with realloc if available */
+        newbuffer = (unsigned char *)p->hooks.reallocate(p->buffer, newsize);
+        if(newbuffer == NULL) {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+    } else {
+        /* otherwise reallocate manually */
+        newbuffer = (unsigned char *)p->hooks.allocate(newsize);
+        if(!newbuffer) {
+            p->hooks.deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+
+        memcpy(newbuffer, p->buffer, p->offset + 1);
+        p->hooks.deallocate(p->buffer);
+    }
+    p->length = newsize;
+    p->buffer = newbuffer;
+
+    return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer *const buffer) {
+    const unsigned char *buffer_pointer = NULL;
+    if((buffer == NULL) || (buffer->buffer == NULL)) {
+        return;
+    }
+    buffer_pointer = buffer->buffer + buffer->offset;
+
+    buffer->offset += strlen((const char *)buffer_pointer);
+}
+
+/* securely comparison of floating-point variables */
+static cJSON_bool compare_double(double a, double b) {
+    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+    return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer) {
+    unsigned char *output_pointer = NULL;
+    double d = item->valuedouble;
+    int length = 0;
+    size_t i = 0;
+    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
+    unsigned char decimal_point = get_decimal_point();
+    double test = 0.0;
+
+    if(output_buffer == NULL) {
+        return false;
+    }
+
+    /* This checks for NaN and Infinity */
+    if(isnan(d) || isinf(d)) {
+        length = sprintf((char *)number_buffer, "null");
+    } else if(d == (double)item->valueint) {
+        length = sprintf((char *)number_buffer, "%d", item->valueint);
+    } else {
+        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+        length = sprintf((char *)number_buffer, "%1.15g", d);
+
+        /* Check whether the original double can be recovered */
+        if((sscanf((char *)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) {
+            /* If not, print with 17 decimal places of precision */
+            length = sprintf((char *)number_buffer, "%1.17g", d);
+        }
+    }
+
+    /* sprintf failed or buffer overrun occurred */
+    if((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
+        return false;
+    }
+
+    /* reserve appropriate space in the output */
+    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+    if(output_pointer == NULL) {
+        return false;
+    }
+
+    /* copy the printed number to the output and replace locale
+     * dependent decimal point with '.' */
+    for(i = 0; i < ((size_t)length); i++) {
+        if(number_buffer[i] == decimal_point) {
+            output_pointer[i] = '.';
+            continue;
+        }
+
+        output_pointer[i] = number_buffer[i];
+    }
+    output_pointer[i] = '\0';
+
+    output_buffer->offset += (size_t)length;
+
+    return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char *const input) {
+    unsigned int h = 0;
+    size_t i = 0;
+
+    for(i = 0; i < 4; i++) {
+        /* parse digit */
+        if((input[i] >= '0') && (input[i] <= '9')) {
+            h += (unsigned int)input[i] - '0';
+        } else if((input[i] >= 'A') && (input[i] <= 'F')) {
+            h += (unsigned int)10 + input[i] - 'A';
+        } else if((input[i] >= 'a') && (input[i] <= 'f')) {
+            h += (unsigned int)10 + input[i] - 'a';
+        } else /* invalid */
+        {
+            return 0;
+        }
+
+        if(i < 3) {
+            /* shift left to make place for the next nibble */
+            h = h << 4;
+        }
+    }
+
+    return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char *const input_pointer,
+                                           const unsigned char *const input_end, unsigned char **output_pointer) {
+    long unsigned int codepoint = 0;
+    unsigned int first_code = 0;
+    const unsigned char *first_sequence = input_pointer;
+    unsigned char utf8_length = 0;
+    unsigned char utf8_position = 0;
+    unsigned char sequence_length = 0;
+    unsigned char first_byte_mark = 0;
+
+    if((input_end - first_sequence) < 6) {
+        /* input ends unexpectedly */
+        goto fail;
+    }
+
+    /* get the first utf16 sequence */
+    first_code = parse_hex4(first_sequence + 2);
+
+    /* check that the code is valid */
+    if(((first_code >= 0xDC00) && (first_code <= 0xDFFF))) {
+        goto fail;
+    }
+
+    /* UTF16 surrogate pair */
+    if((first_code >= 0xD800) && (first_code <= 0xDBFF)) {
+        const unsigned char *second_sequence = first_sequence + 6;
+        unsigned int second_code = 0;
+        sequence_length = 12; /* \uXXXX\uXXXX */
+
+        if((input_end - second_sequence) < 6) {
+            /* input ends unexpectedly */
+            goto fail;
+        }
+
+        if((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) {
+            /* missing second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* get the second utf16 sequence */
+        second_code = parse_hex4(second_sequence + 2);
+        /* check that the code is valid */
+        if((second_code < 0xDC00) || (second_code > 0xDFFF)) {
+            /* invalid second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* calculate the unicode codepoint from the surrogate pair */
+        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+    } else {
+        sequence_length = 6; /* \uXXXX */
+        codepoint = first_code;
+    }
+
+    /* encode as UTF-8
+     * takes at maximum 4 bytes to encode:
+     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+    if(codepoint < 0x80) {
+        /* normal ascii, encoding 0xxxxxxx */
+        utf8_length = 1;
+    } else if(codepoint < 0x800) {
+        /* two bytes, encoding 110xxxxx 10xxxxxx */
+        utf8_length = 2;
+        first_byte_mark = 0xC0; /* 11000000 */
+    } else if(codepoint < 0x10000) {
+        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 3;
+        first_byte_mark = 0xE0; /* 11100000 */
+    } else if(codepoint <= 0x10FFFF) {
+        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 4;
+        first_byte_mark = 0xF0; /* 11110000 */
+    } else {
+        /* invalid unicode codepoint */
+        goto fail;
+    }
+
+    /* encode as utf8 */
+    for(utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) {
+        /* 10xxxxxx */
+        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+        codepoint >>= 6;
+    }
+    /* encode first byte */
+    if(utf8_length > 1) {
+        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+    } else {
+        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+    }
+
+    *output_pointer += utf8_length;
+
+    return sequence_length;
+
+fail:
+    return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON *const item, parse_buffer *const input_buffer) {
+    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+    unsigned char *output_pointer = NULL;
+    unsigned char *output = NULL;
+
+    /* not a string */
+    if(buffer_at_offset(input_buffer)[0] != '\"') {
+        goto fail;
+    }
+
+    {
+        /* calculate approximate size of the output (overestimate) */
+        size_t allocation_length = 0;
+        size_t skipped_bytes = 0;
+        while(((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) {
+            /* is escape sequence */
+            if(input_end[0] == '\\') {
+                if((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) {
+                    /* prevent buffer overflow when last input character is a backslash */
+                    goto fail;
+                }
+                skipped_bytes++;
+                input_end++;
+            }
+            input_end++;
+        }
+        if(((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) {
+            goto fail; /* string ended unexpectedly */
+        }
+
+        /* This is at most how much we need for the output */
+        allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+        output = (unsigned char *)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+        if(output == NULL) {
+            goto fail; /* allocation failure */
+        }
+    }
+
+    output_pointer = output;
+    /* loop through the string literal */
+    while(input_pointer < input_end) {
+        if(*input_pointer != '\\') {
+            *output_pointer++ = *input_pointer++;
+        }
+        /* escape sequence */
+        else {
+            unsigned char sequence_length = 2;
+            if((input_end - input_pointer) < 1) {
+                goto fail;
+            }
+
+            switch(input_pointer[1]) {
+                case 'b':
+                    *output_pointer++ = '\b';
+                    break;
+                case 'f':
+                    *output_pointer++ = '\f';
+                    break;
+                case 'n':
+                    *output_pointer++ = '\n';
+                    break;
+                case 'r':
+                    *output_pointer++ = '\r';
+                    break;
+                case 't':
+                    *output_pointer++ = '\t';
+                    break;
+                case '\"':
+                case '\\':
+                case '/':
+                    *output_pointer++ = input_pointer[1];
+                    break;
+
+                /* UTF-16 literal */
+                case 'u':
+                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+                    if(sequence_length == 0) {
+                        /* failed to convert UTF16-literal to UTF-8 */
+                        goto fail;
+                    }
+                    break;
+
+                default:
+                    goto fail;
+            }
+            input_pointer += sequence_length;
+        }
+    }
+
+    /* zero terminate the output */
+    *output_pointer = '\0';
+
+    item->type = cJSON_String;
+    item->valuestring = (char *)output;
+
+    input_buffer->offset = (size_t)(input_end - input_buffer->content);
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if(output != NULL) {
+        input_buffer->hooks.deallocate(output);
+        output = NULL;
+    }
+
+    if(input_pointer != NULL) {
+        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+    }
+
+    return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char *const input, printbuffer *const output_buffer) {
+    const unsigned char *input_pointer = NULL;
+    unsigned char *output = NULL;
+    unsigned char *output_pointer = NULL;
+    size_t output_length = 0;
+    /* numbers of additional characters needed for escaping */
+    size_t escape_characters = 0;
+
+    if(output_buffer == NULL) {
+        return false;
+    }
+
+    /* empty string */
+    if(input == NULL) {
+        output = ensure(output_buffer, sizeof("\"\""));
+        if(output == NULL) {
+            return false;
+        }
+        strcpy((char *)output, "\"\"");
+
+        return true;
+    }
+
+    /* set "flag" to 1 if something needs to be escaped */
+    for(input_pointer = input; *input_pointer; input_pointer++) {
+        switch(*input_pointer) {
+            case '\"':
+            case '\\':
+            case '\b':
+            case '\f':
+            case '\n':
+            case '\r':
+            case '\t':
+                /* one character escape sequence */
+                escape_characters++;
+                break;
+            default:
+                if(*input_pointer < 32) {
+                    /* UTF-16 escape sequence uXXXX */
+                    escape_characters += 5;
+                }
+                break;
+        }
+    }
+    output_length = (size_t)(input_pointer - input) + escape_characters;
+
+    output = ensure(output_buffer, output_length + sizeof("\"\""));
+    if(output == NULL) {
+        return false;
+    }
+
+    /* no characters have to be escaped */
+    if(escape_characters == 0) {
+        output[0] = '\"';
+        memcpy(output + 1, input, output_length);
+        output[output_length + 1] = '\"';
+        output[output_length + 2] = '\0';
+
+        return true;
+    }
+
+    output[0] = '\"';
+    output_pointer = output + 1;
+    /* copy the string */
+    for(input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) {
+        if((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) {
+            /* normal character, copy */
+            *output_pointer = *input_pointer;
+        } else {
+            /* character needs to be escaped */
+            *output_pointer++ = '\\';
+            switch(*input_pointer) {
+                case '\\':
+                    *output_pointer = '\\';
+                    break;
+                case '\"':
+                    *output_pointer = '\"';
+                    break;
+                case '\b':
+                    *output_pointer = 'b';
+                    break;
+                case '\f':
+                    *output_pointer = 'f';
+                    break;
+                case '\n':
+                    *output_pointer = 'n';
+                    break;
+                case '\r':
+                    *output_pointer = 'r';
+                    break;
+                case '\t':
+                    *output_pointer = 't';
+                    break;
+                default:
+                    /* escape and print as unicode codepoint */
+                    sprintf((char *)output_pointer, "u%04x", *input_pointer);
+                    output_pointer += 4;
+                    break;
+            }
+        }
+    }
+    output[output_length + 1] = '\"';
+    output[output_length + 2] = '\0';
+
+    return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON *const item, printbuffer *const p) {
+    return print_string_ptr((unsigned char *)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer);
+static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer);
+static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer);
+static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer);
+static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer);
+static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer) {
+    if((buffer == NULL) || (buffer->content == NULL)) {
+        return NULL;
+    }
+
+    if(cannot_access_at_index(buffer, 0)) {
+        return buffer;
+    }
+
+    while(can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) {
+        buffer->offset++;
+    }
+
+    if(buffer->offset == buffer->length) {
+        buffer->offset--;
+    }
+
+    return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer *const buffer) {
+    if((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) {
+        return NULL;
+    }
+
+    if(can_access_at_index(buffer, 4) && (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) {
+        buffer->offset += 3;
+    }
+
+    return buffer;
+}
+
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) {
+    size_t buffer_length;
+
+    if(NULL == value) {
+        return NULL;
+    }
+
+    /* Adding null character size due to require_null_terminated. */
+    buffer_length = strlen(value) + sizeof("");
+
+    return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end,
+                          cJSON_bool require_null_terminated) {
+    parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};
+    cJSON *item = NULL;
+
+    /* reset error position */
+    global_error.json = NULL;
+    global_error.position = 0;
+
+    if(value == NULL || 0 == buffer_length) {
+        goto fail;
+    }
+
+    buffer.content = (const unsigned char *)value;
+    buffer.length = buffer_length;
+    buffer.offset = 0;
+    buffer.hooks = global_hooks;
+
+    item = cJSON_New_Item(&global_hooks);
+    if(item == NULL) /* memory fail */
+    {
+        goto fail;
+    }
+
+    if(!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) {
+        /* parse failure. ep is set. */
+        goto fail;
+    }
+
+    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+    if(require_null_terminated) {
+        buffer_skip_whitespace(&buffer);
+        if((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') {
+            goto fail;
+        }
+    }
+    if(return_parse_end) {
+        *return_parse_end = (const char *)buffer_at_offset(&buffer);
+    }
+
+    return item;
+
+fail:
+    if(item != NULL) {
+        cJSON_Delete(item);
+    }
+
+    if(value != NULL) {
+        error local_error;
+        local_error.json = (const unsigned char *)value;
+        local_error.position = 0;
+
+        if(buffer.offset < buffer.length) {
+            local_error.position = buffer.offset;
+        } else if(buffer.length > 0) {
+            local_error.position = buffer.length - 1;
+        }
+
+        if(return_parse_end != NULL) {
+            *return_parse_end = (const char *)local_error.json + local_error.position;
+        }
+
+        global_error = local_error;
+    }
+
+    return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) { return cJSON_ParseWithOpts(value, 0, 0); }
+
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) {
+    return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
+
+static unsigned char *print(const cJSON *const item, cJSON_bool format, const internal_hooks *const hooks) {
+    static const size_t default_buffer_size = 256;
+    printbuffer buffer[1];
+    unsigned char *printed = NULL;
+
+    memset(buffer, 0, sizeof(buffer));
+
+    /* create buffer */
+    buffer->buffer = (unsigned char *)hooks->allocate(default_buffer_size);
+    buffer->length = default_buffer_size;
+    buffer->format = format;
+    buffer->hooks = *hooks;
+    if(buffer->buffer == NULL) {
+        goto fail;
+    }
+
+    /* print the value */
+    if(!print_value(item, buffer)) {
+        goto fail;
+    }
+    update_offset(buffer);
+
+    /* check if reallocate is available */
+    if(hooks->reallocate != NULL) {
+        printed = (unsigned char *)hooks->reallocate(buffer->buffer, buffer->offset + 1);
+        if(printed == NULL) {
+            goto fail;
+        }
+        buffer->buffer = NULL;
+    } else /* otherwise copy the JSON over to a new buffer */
+    {
+        printed = (unsigned char *)hooks->allocate(buffer->offset + 1);
+        if(printed == NULL) {
+            goto fail;
+        }
+        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+        printed[buffer->offset] = '\0'; /* just to be sure */
+
+        /* free the buffer */
+        hooks->deallocate(buffer->buffer);
+        buffer->buffer = NULL;
+    }
+
+    return printed;
+
+fail:
+    if(buffer->buffer != NULL) {
+        hooks->deallocate(buffer->buffer);
+        buffer->buffer = NULL;
+    }
+
+    if(printed != NULL) {
+        hooks->deallocate(printed);
+        printed = NULL;
+    }
+
+    return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { return (char *)print(item, true, &global_hooks); }
+
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { return (char *)print(item, false, &global_hooks); }
+
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) {
+    printbuffer p = {0, 0, 0, 0, 0, 0, {0, 0, 0}};
+
+    if(prebuffer < 0) {
+        return NULL;
+    }
+
+    p.buffer = (unsigned char *)global_hooks.allocate((size_t)prebuffer);
+    if(!p.buffer) {
+        return NULL;
+    }
+
+    p.length = (size_t)prebuffer;
+    p.offset = 0;
+    p.noalloc = false;
+    p.format = fmt;
+    p.hooks = global_hooks;
+
+    if(!print_value(item, &p)) {
+        global_hooks.deallocate(p.buffer);
+        p.buffer = NULL;
+        return NULL;
+    }
+
+    return (char *)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) {
+    printbuffer p = {0, 0, 0, 0, 0, 0, {0, 0, 0}};
+
+    if((length < 0) || (buffer == NULL)) {
+        return false;
+    }
+
+    p.buffer = (unsigned char *)buffer;
+    p.length = (size_t)length;
+    p.offset = 0;
+    p.noalloc = true;
+    p.format = format;
+    p.hooks = global_hooks;
+
+    return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer) {
+    if((input_buffer == NULL) || (input_buffer->content == NULL)) {
+        return false; /* no input */
+    }
+
+    /* parse the different types of values */
+    /* null */
+    if(can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)) {
+        item->type = cJSON_NULL;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* false */
+    if(can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)) {
+        item->type = cJSON_False;
+        input_buffer->offset += 5;
+        return true;
+    }
+    /* true */
+    if(can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)) {
+        item->type = cJSON_True;
+        item->valueint = 1;
+        input_buffer->offset += 4;
+        return true;
+    }
+    /* string */
+    if(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) {
+        return parse_string(item, input_buffer);
+    }
+    /* number */
+    if(can_access_at_index(input_buffer, 0) &&
+       ((buffer_at_offset(input_buffer)[0] == '-') ||
+        ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) {
+        return parse_number(item, input_buffer);
+    }
+    /* array */
+    if(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) {
+        return parse_array(item, input_buffer);
+    }
+    /* object */
+    if(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) {
+        return parse_object(item, input_buffer);
+    }
+
+    return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer) {
+    unsigned char *output = NULL;
+
+    if((item == NULL) || (output_buffer == NULL)) {
+        return false;
+    }
+
+    switch((item->type) & 0xFF) {
+        case cJSON_NULL:
+            output = ensure(output_buffer, 5);
+            if(output == NULL) {
+                return false;
+            }
+            strcpy((char *)output, "null");
+            return true;
+
+        case cJSON_False:
+            output = ensure(output_buffer, 6);
+            if(output == NULL) {
+                return false;
+            }
+            strcpy((char *)output, "false");
+            return true;
+
+        case cJSON_True:
+            output = ensure(output_buffer, 5);
+            if(output == NULL) {
+                return false;
+            }
+            strcpy((char *)output, "true");
+            return true;
+
+        case cJSON_Number:
+            return print_number(item, output_buffer);
+
+        case cJSON_Raw: {
+            size_t raw_length = 0;
+            if(item->valuestring == NULL) {
+                return false;
+            }
+
+            raw_length = strlen(item->valuestring) + sizeof("");
+            output = ensure(output_buffer, raw_length);
+            if(output == NULL) {
+                return false;
+            }
+            memcpy(output, item->valuestring, raw_length);
+            return true;
+        }
+
+        case cJSON_String:
+            return print_string(item, output_buffer);
+
+        case cJSON_Array:
+            return print_array(item, output_buffer);
+
+        case cJSON_Object:
+            return print_object(item, output_buffer);
+
+        default:
+            return false;
+    }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON *const item, parse_buffer *const input_buffer) {
+    cJSON *head = NULL; /* head of the linked list */
+    cJSON *current_item = NULL;
+
+    if(input_buffer->depth >= CJSON_NESTING_LIMIT) {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if(buffer_at_offset(input_buffer)[0] != '[') {
+        /* not an array */
+        goto fail;
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) {
+        /* empty array */
+        goto success;
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if(cannot_access_at_index(input_buffer, 0)) {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do {
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if(new_item == NULL) {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if(head == NULL) {
+            /* start the linked list */
+            current_item = head = new_item;
+        } else {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse next value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if(!parse_value(current_item, input_buffer)) {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    } while(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if(cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') {
+        goto fail; /* expected end of array */
+    }
+
+success:
+    input_buffer->depth--;
+
+    if(head != NULL) {
+        head->prev = current_item;
+    }
+
+    item->type = cJSON_Array;
+    item->child = head;
+
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if(head != NULL) {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer) {
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_element = item->child;
+
+    if(output_buffer == NULL) {
+        return false;
+    }
+
+    /* Compose the output array. */
+    /* opening square bracket */
+    output_pointer = ensure(output_buffer, 1);
+    if(output_pointer == NULL) {
+        return false;
+    }
+
+    *output_pointer = '[';
+    output_buffer->offset++;
+    output_buffer->depth++;
+
+    while(current_element != NULL) {
+        if(!print_value(current_element, output_buffer)) {
+            return false;
+        }
+        update_offset(output_buffer);
+        if(current_element->next) {
+            length = (size_t)(output_buffer->format ? 2 : 1);
+            output_pointer = ensure(output_buffer, length + 1);
+            if(output_pointer == NULL) {
+                return false;
+            }
+            *output_pointer++ = ',';
+            if(output_buffer->format) {
+                *output_pointer++ = ' ';
+            }
+            *output_pointer = '\0';
+            output_buffer->offset += length;
+        }
+        current_element = current_element->next;
+    }
+
+    output_pointer = ensure(output_buffer, 2);
+    if(output_pointer == NULL) {
+        return false;
+    }
+    *output_pointer++ = ']';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON *const item, parse_buffer *const input_buffer) {
+    cJSON *head = NULL; /* linked list head */
+    cJSON *current_item = NULL;
+
+    if(input_buffer->depth >= CJSON_NESTING_LIMIT) {
+        return false; /* to deeply nested */
+    }
+    input_buffer->depth++;
+
+    if(cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) {
+        goto fail; /* not an object */
+    }
+
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) {
+        goto success; /* empty object */
+    }
+
+    /* check if we skipped to the end of the buffer */
+    if(cannot_access_at_index(input_buffer, 0)) {
+        input_buffer->offset--;
+        goto fail;
+    }
+
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do {
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+        if(new_item == NULL) {
+            goto fail; /* allocation failure */
+        }
+
+        /* attach next item to list */
+        if(head == NULL) {
+            /* start the linked list */
+            current_item = head = new_item;
+        } else {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        if(cannot_access_at_index(input_buffer, 1)) {
+            goto fail; /* nothing comes after the comma */
+        }
+
+        /* parse the name of the child */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if(!parse_string(current_item, input_buffer)) {
+            goto fail; /* failed to parse name */
+        }
+        buffer_skip_whitespace(input_buffer);
+
+        /* swap valuestring and string, because we parsed the name */
+        current_item->string = current_item->valuestring;
+        current_item->valuestring = NULL;
+
+        if(cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) {
+            goto fail; /* invalid object */
+        }
+
+        /* parse the value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if(!parse_value(current_item, input_buffer)) {
+            goto fail; /* failed to parse value */
+        }
+        buffer_skip_whitespace(input_buffer);
+    } while(can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+    if(cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) {
+        goto fail; /* expected end of object */
+    }
+
+success:
+    input_buffer->depth--;
+
+    if(head != NULL) {
+        head->prev = current_item;
+    }
+
+    item->type = cJSON_Object;
+    item->child = head;
+
+    input_buffer->offset++;
+    return true;
+
+fail:
+    if(head != NULL) {
+        cJSON_Delete(head);
+    }
+
+    return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer) {
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_item = item->child;
+
+    if(output_buffer == NULL) {
+        return false;
+    }
+
+    /* Compose the output: */
+    length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
+    output_pointer = ensure(output_buffer, length + 1);
+    if(output_pointer == NULL) {
+        return false;
+    }
+
+    *output_pointer++ = '{';
+    output_buffer->depth++;
+    if(output_buffer->format) {
+        *output_pointer++ = '\n';
+    }
+    output_buffer->offset += length;
+
+    while(current_item) {
+        if(output_buffer->format) {
+            size_t i;
+            output_pointer = ensure(output_buffer, output_buffer->depth);
+            if(output_pointer == NULL) {
+                return false;
+            }
+            for(i = 0; i < output_buffer->depth; i++) {
+                *output_pointer++ = '\t';
+            }
+            output_buffer->offset += output_buffer->depth;
+        }
+
+        /* print key */
+        if(!print_string_ptr((unsigned char *)current_item->string, output_buffer)) {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        length = (size_t)(output_buffer->format ? 2 : 1);
+        output_pointer = ensure(output_buffer, length);
+        if(output_pointer == NULL) {
+            return false;
+        }
+        *output_pointer++ = ':';
+        if(output_buffer->format) {
+            *output_pointer++ = '\t';
+        }
+        output_buffer->offset += length;
+
+        /* print value */
+        if(!print_value(current_item, output_buffer)) {
+            return false;
+        }
+        update_offset(output_buffer);
+
+        /* print comma if not last */
+        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
+        output_pointer = ensure(output_buffer, length + 1);
+        if(output_pointer == NULL) {
+            return false;
+        }
+        if(current_item->next) {
+            *output_pointer++ = ',';
+        }
+
+        if(output_buffer->format) {
+            *output_pointer++ = '\n';
+        }
+        *output_pointer = '\0';
+        output_buffer->offset += length;
+
+        current_item = current_item->next;
+    }
+
+    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+    if(output_pointer == NULL) {
+        return false;
+    }
+    if(output_buffer->format) {
+        size_t i;
+        for(i = 0; i < (output_buffer->depth - 1); i++) {
+            *output_pointer++ = '\t';
+        }
+    }
+    *output_pointer++ = '}';
+    *output_pointer = '\0';
+    output_buffer->depth--;
+
+    return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) {
+    cJSON *child = NULL;
+    size_t size = 0;
+
+    if(array == NULL) {
+        return 0;
+    }
+
+    child = array->child;
+
+    while(child != NULL) {
+        size++;
+        child = child->next;
+    }
+
+    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+    return (int)size;
+}
+
+static cJSON *get_array_item(const cJSON *array, size_t index) {
+    cJSON *current_child = NULL;
+
+    if(array == NULL) {
+        return NULL;
+    }
+
+    current_child = array->child;
+    while((current_child != NULL) && (index > 0)) {
+        index--;
+        current_child = current_child->next;
+    }
+
+    return current_child;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) {
+    if(index < 0) {
+        return NULL;
+    }
+
+    return get_array_item(array, (size_t)index);
+}
+
+static cJSON *get_object_item(const cJSON *const object, const char *const name, const cJSON_bool case_sensitive) {
+    cJSON *current_element = NULL;
+
+    if((object == NULL) || (name == NULL)) {
+        return NULL;
+    }
+
+    current_element = object->child;
+    if(case_sensitive) {
+        while((current_element != NULL) && (current_element->string != NULL) &&
+              (strcmp(name, current_element->string) != 0)) {
+            current_element = current_element->next;
+        }
+    } else {
+        while((current_element != NULL) &&
+              (case_insensitive_strcmp((const unsigned char *)name, (const unsigned char *)(current_element->string)) !=
+               0)) {
+            current_element = current_element->next;
+        }
+    }
+
+    if((current_element == NULL) || (current_element->string == NULL)) {
+        return NULL;
+    }
+
+    return current_element;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *const object, const char *const string) {
+    return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string) {
+    return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) {
+    return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item) {
+    prev->next = item;
+    item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item, const internal_hooks *const hooks) {
+    cJSON *reference = NULL;
+    if(item == NULL) {
+        return NULL;
+    }
+
+    reference = cJSON_New_Item(hooks);
+    if(reference == NULL) {
+        return NULL;
+    }
+
+    memcpy(reference, item, sizeof(cJSON));
+    reference->string = NULL;
+    reference->type |= cJSON_IsReference;
+    reference->next = reference->prev = NULL;
+    return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) {
+    cJSON *child = NULL;
+
+    if((item == NULL) || (array == NULL) || (array == item)) {
+        return false;
+    }
+
+    child = array->child;
+    /*
+     * To find the last item in array quickly, we use prev in array
+     */
+    if(child == NULL) {
+        /* list is empty, start new one */
+        array->child = item;
+        item->prev = item;
+        item->next = NULL;
+    } else {
+        /* append to the end */
+        if(child->prev) {
+            suffix_object(child->prev, item);
+            array->child->prev = item;
+        }
+    }
+
+    return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) { return add_item_to_array(array, item); }
+
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void *cast_away_const(const void *string) { return (void *)string; }
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic pop
+#endif
+
+static cJSON_bool add_item_to_object(cJSON *const object, const char *const string, cJSON *const item,
+                                     const internal_hooks *const hooks, const cJSON_bool constant_key) {
+    char *new_key = NULL;
+    int new_type = cJSON_Invalid;
+
+    if((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) {
+        return false;
+    }
+
+    if(constant_key) {
+        new_key = (char *)cast_away_const(string);
+        new_type = item->type | cJSON_StringIsConst;
+    } else {
+        new_key = (char *)cJSON_strdup((const unsigned char *)string, hooks);
+        if(new_key == NULL) {
+            return false;
+        }
+
+        new_type = item->type & ~cJSON_StringIsConst;
+    }
+
+    if(!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
+        hooks->deallocate(item->string);
+    }
+
+    item->string = new_key;
+    item->type = new_type;
+
+    return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) {
+    return add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) {
+    return add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {
+    if(array == NULL) {
+        return false;
+    }
+
+    return add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) {
+    if((object == NULL) || (string == NULL)) {
+        return false;
+    }
+
+    return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddNullToObject(cJSON *const object, const char *const name) {
+    cJSON *null = cJSON_CreateNull();
+    if(add_item_to_object(object, name, null, &global_hooks, false)) {
+        return null;
+    }
+
+    cJSON_Delete(null);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddTrueToObject(cJSON *const object, const char *const name) {
+    cJSON *true_item = cJSON_CreateTrue();
+    if(add_item_to_object(object, name, true_item, &global_hooks, false)) {
+        return true_item;
+    }
+
+    cJSON_Delete(true_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddFalseToObject(cJSON *const object, const char *const name) {
+    cJSON *false_item = cJSON_CreateFalse();
+    if(add_item_to_object(object, name, false_item, &global_hooks, false)) {
+        return false_item;
+    }
+
+    cJSON_Delete(false_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddBoolToObject(cJSON *const object, const char *const name, const cJSON_bool boolean) {
+    cJSON *bool_item = cJSON_CreateBool(boolean);
+    if(add_item_to_object(object, name, bool_item, &global_hooks, false)) {
+        return bool_item;
+    }
+
+    cJSON_Delete(bool_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddNumberToObject(cJSON *const object, const char *const name, const double number) {
+    cJSON *number_item = cJSON_CreateNumber(number);
+    if(add_item_to_object(object, name, number_item, &global_hooks, false)) {
+        return number_item;
+    }
+
+    cJSON_Delete(number_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddStringToObject(cJSON *const object, const char *const name, const char *const string) {
+    cJSON *string_item = cJSON_CreateString(string);
+    if(add_item_to_object(object, name, string_item, &global_hooks, false)) {
+        return string_item;
+    }
+
+    cJSON_Delete(string_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddRawToObject(cJSON *const object, const char *const name, const char *const raw) {
+    cJSON *raw_item = cJSON_CreateRaw(raw);
+    if(add_item_to_object(object, name, raw_item, &global_hooks, false)) {
+        return raw_item;
+    }
+
+    cJSON_Delete(raw_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddObjectToObject(cJSON *const object, const char *const name) {
+    cJSON *object_item = cJSON_CreateObject();
+    if(add_item_to_object(object, name, object_item, &global_hooks, false)) {
+        return object_item;
+    }
+
+    cJSON_Delete(object_item);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_AddArrayToObject(cJSON *const object, const char *const name) {
+    cJSON *array = cJSON_CreateArray();
+    if(add_item_to_object(object, name, array, &global_hooks, false)) {
+        return array;
+    }
+
+    cJSON_Delete(array);
+    return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item) {
+    if((parent == NULL) || (item == NULL)) {
+        return NULL;
+    }
+
+    if(item != parent->child) {
+        /* not the first element */
+        item->prev->next = item->next;
+    }
+    if(item->next != NULL) {
+        /* not the last element */
+        item->next->prev = item->prev;
+    }
+
+    if(item == parent->child) {
+        /* first element */
+        parent->child = item->next;
+    } else if(item->next == NULL) {
+        /* last element */
+        parent->child->prev = item->prev;
+    }
+
+    /* make sure the detached item doesn't point anywhere anymore */
+    item->prev = NULL;
+    item->next = NULL;
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) {
+    if(which < 0) {
+        return NULL;
+    }
+
+    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) {
+    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) {
+    cJSON *to_detach = cJSON_GetObjectItem(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) {
+    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) {
+    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) {
+    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) {
+    cJSON *after_inserted = NULL;
+
+    if(which < 0 || newitem == NULL) {
+        return false;
+    }
+
+    after_inserted = get_array_item(array, (size_t)which);
+    if(after_inserted == NULL) {
+        return add_item_to_array(array, newitem);
+    }
+
+    if(after_inserted != array->child && after_inserted->prev == NULL) {
+        /* return false if after_inserted is a corrupted array item */
+        return false;
+    }
+
+    newitem->next = after_inserted;
+    newitem->prev = after_inserted->prev;
+    after_inserted->prev = newitem;
+    if(after_inserted == array->child) {
+        array->child = newitem;
+    } else {
+        newitem->prev->next = newitem;
+    }
+    return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement) {
+    if((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL)) {
+        return false;
+    }
+
+    if(replacement == item) {
+        return true;
+    }
+
+    replacement->next = item->next;
+    replacement->prev = item->prev;
+
+    if(replacement->next != NULL) {
+        replacement->next->prev = replacement;
+    }
+    if(parent->child == item) {
+        if(parent->child->prev == parent->child) {
+            replacement->prev = replacement;
+        }
+        parent->child = replacement;
+    } else { /*
+              * To find the last item in array quickly, we use prev in array.
+              * We can't modify the last item's next pointer where this item was the parent's child
+              */
+        if(replacement->prev != NULL) {
+            replacement->prev->next = replacement;
+        }
+        if(replacement->next == NULL) {
+            parent->child->prev = replacement;
+        }
+    }
+
+    item->next = NULL;
+    item->prev = NULL;
+    cJSON_Delete(item);
+
+    return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) {
+    if(which < 0) {
+        return false;
+    }
+
+    return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement,
+                                         cJSON_bool case_sensitive) {
+    if((replacement == NULL) || (string == NULL)) {
+        return false;
+    }
+
+    /* replace the name in the replacement */
+    if(!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) {
+        cJSON_free(replacement->string);
+    }
+    replacement->string = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
+    if(replacement->string == NULL) {
+        return false;
+    }
+
+    replacement->type &= ~cJSON_StringIsConst;
+
+    return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) {
+    return replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) {
+    return replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_NULL;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_True;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = boolean ? cJSON_True : cJSON_False;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_Number;
+        item->valuedouble = num;
+
+        /* use saturation in case of overflow */
+        if(num >= INT_MAX) {
+            item->valueint = INT_MAX;
+        } else if(num <= (double)INT_MIN) {
+            item->valueint = INT_MIN;
+        } else {
+            item->valueint = (int)num;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_String;
+        item->valuestring = (char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
+        if(!item->valuestring) {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item != NULL) {
+        item->type = cJSON_String | cJSON_IsReference;
+        item->valuestring = (char *)cast_away_const(string);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item != NULL) {
+        item->type = cJSON_Object | cJSON_IsReference;
+        item->child = (cJSON *)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item != NULL) {
+        item->type = cJSON_Array | cJSON_IsReference;
+        item->child = (cJSON *)cast_away_const(child);
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_Raw;
+        item->valuestring = (char *)cJSON_strdup((const unsigned char *)raw, &global_hooks);
+        if(!item->valuestring) {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_Array;
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) {
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item) {
+        item->type = cJSON_Object;
+    }
+
+    return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) {
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if((count < 0) || (numbers == NULL)) {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0; a && (i < (size_t)count); i++) {
+        n = cJSON_CreateNumber(numbers[i]);
+        if(!n) {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i) {
+            a->child = n;
+        } else {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if(a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) {
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if((count < 0) || (numbers == NULL)) {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0; a && (i < (size_t)count); i++) {
+        n = cJSON_CreateNumber((double)numbers[i]);
+        if(!n) {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i) {
+            a->child = n;
+        } else {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if(a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) {
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if((count < 0) || (numbers == NULL)) {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0; a && (i < (size_t)count); i++) {
+        n = cJSON_CreateNumber(numbers[i]);
+        if(!n) {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i) {
+            a->child = n;
+        } else {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if(a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) {
+    size_t i = 0;
+    cJSON *n = NULL;
+    cJSON *p = NULL;
+    cJSON *a = NULL;
+
+    if((count < 0) || (strings == NULL)) {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0; a && (i < (size_t)count); i++) {
+        n = cJSON_CreateString(strings[i]);
+        if(!n) {
+            cJSON_Delete(a);
+            return NULL;
+        }
+        if(!i) {
+            a->child = n;
+        } else {
+            suffix_object(p, n);
+        }
+        p = n;
+    }
+
+    if(a && a->child) {
+        a->child->prev = n;
+    }
+
+    return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) {
+    cJSON *newitem = NULL;
+    cJSON *child = NULL;
+    cJSON *next = NULL;
+    cJSON *newchild = NULL;
+
+    /* Bail on bad ptr */
+    if(!item) {
+        goto fail;
+    }
+    /* Create new item */
+    newitem = cJSON_New_Item(&global_hooks);
+    if(!newitem) {
+        goto fail;
+    }
+    /* Copy over all vars */
+    newitem->type = item->type & (~cJSON_IsReference);
+    newitem->valueint = item->valueint;
+    newitem->valuedouble = item->valuedouble;
+    if(item->valuestring) {
+        newitem->valuestring = (char *)cJSON_strdup((unsigned char *)item->valuestring, &global_hooks);
+        if(!newitem->valuestring) {
+            goto fail;
+        }
+    }
+    if(item->string) {
+        newitem->string = (item->type & cJSON_StringIsConst)
+                              ? item->string
+                              : (char *)cJSON_strdup((unsigned char *)item->string, &global_hooks);
+        if(!newitem->string) {
+            goto fail;
+        }
+    }
+    /* If non-recursive, then we're done! */
+    if(!recurse) {
+        return newitem;
+    }
+    /* Walk the ->next chain for the child. */
+    child = item->child;
+    while(child != NULL) {
+        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+        if(!newchild) {
+            goto fail;
+        }
+        if(next != NULL) {
+            /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+            next->next = newchild;
+            newchild->prev = next;
+            next = newchild;
+        } else {
+            /* Set newitem->child and move to it */
+            newitem->child = newchild;
+            next = newchild;
+        }
+        child = child->next;
+    }
+    if(newitem && newitem->child) {
+        newitem->child->prev = newchild;
+    }
+
+    return newitem;
+
+fail:
+    if(newitem != NULL) {
+        cJSON_Delete(newitem);
+    }
+
+    return NULL;
+}
+
+static void skip_oneline_comment(char **input) {
+    *input += static_strlen("//");
+
+    for(; (*input)[0] != '\0'; ++(*input)) {
+        if((*input)[0] == '\n') {
+            *input += static_strlen("\n");
+            return;
+        }
+    }
+}
+
+static void skip_multiline_comment(char **input) {
+    *input += static_strlen("/*");
+
+    for(; (*input)[0] != '\0'; ++(*input)) {
+        if(((*input)[0] == '*') && ((*input)[1] == '/')) {
+            *input += static_strlen("*/");
+            return;
+        }
+    }
+}
+
+static void minify_string(char **input, char **output) {
+    (*output)[0] = (*input)[0];
+    *input += static_strlen("\"");
+    *output += static_strlen("\"");
+
+    for(; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+        (*output)[0] = (*input)[0];
+
+        if((*input)[0] == '\"') {
+            (*output)[0] = '\"';
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+            return;
+        } else if(((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+            (*output)[1] = (*input)[1];
+            *input += static_strlen("\"");
+            *output += static_strlen("\"");
+        }
+    }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json) {
+    char *into = json;
+
+    if(json == NULL) {
+        return;
+    }
+
+    while(json[0] != '\0') {
+        switch(json[0]) {
+            case ' ':
+            case '\t':
+            case '\r':
+            case '\n':
+                json++;
+                break;
+
+            case '/':
+                if(json[1] == '/') {
+                    skip_oneline_comment(&json);
+                } else if(json[1] == '*') {
+                    skip_multiline_comment(&json);
+                } else {
+                    json++;
+                }
+                break;
+
+            case '\"':
+                minify_string(&json, (char **)&into);
+                break;
+
+            default:
+                into[0] = json[0];
+                json++;
+                into++;
+        }
+    }
+
+    /* and null-terminate. */
+    *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xff) == cJSON_True;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON *const item) {
+    if(item == NULL) {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive) {
+    if((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) {
+        return false;
+    }
+
+    /* check if type is valid */
+    switch(a->type & 0xFF) {
+        case cJSON_False:
+        case cJSON_True:
+        case cJSON_NULL:
+        case cJSON_Number:
+        case cJSON_String:
+        case cJSON_Raw:
+        case cJSON_Array:
+        case cJSON_Object:
+            break;
+
+        default:
+            return false;
+    }
+
+    /* identical objects are equal */
+    if(a == b) {
+        return true;
+    }
+
+    switch(a->type & 0xFF) {
+        /* in these cases and equal type is enough */
+        case cJSON_False:
+        case cJSON_True:
+        case cJSON_NULL:
+            return true;
+
+        case cJSON_Number:
+            if(compare_double(a->valuedouble, b->valuedouble)) {
+                return true;
+            }
+            return false;
+
+        case cJSON_String:
+        case cJSON_Raw:
+            if((a->valuestring == NULL) || (b->valuestring == NULL)) {
+                return false;
+            }
+            if(strcmp(a->valuestring, b->valuestring) == 0) {
+                return true;
+            }
+
+            return false;
+
+        case cJSON_Array: {
+            cJSON *a_element = a->child;
+            cJSON *b_element = b->child;
+
+            for(; (a_element != NULL) && (b_element != NULL);) {
+                if(!cJSON_Compare(a_element, b_element, case_sensitive)) {
+                    return false;
+                }
+
+                a_element = a_element->next;
+                b_element = b_element->next;
+            }
+
+            /* one of the arrays is longer than the other */
+            if(a_element != b_element) {
+                return false;
+            }
+
+            return true;
+        }
+
+        case cJSON_Object: {
+            cJSON *a_element = NULL;
+            cJSON *b_element = NULL;
+            cJSON_ArrayForEach(a_element, a) {
+                /* TODO This has O(n^2) runtime, which is horrible! */
+                b_element = get_object_item(b, a_element->string, case_sensitive);
+                if(b_element == NULL) {
+                    return false;
+                }
+
+                if(!cJSON_Compare(a_element, b_element, case_sensitive)) {
+                    return false;
+                }
+            }
+
+            /* doing this twice, once on a and b to prevent true comparison if a subset of b
+             * TODO: Do this the proper way, this is just a fix for now */
+            cJSON_ArrayForEach(b_element, b) {
+                a_element = get_object_item(a, b_element->string, case_sensitive);
+                if(a_element == NULL) {
+                    return false;
+                }
+
+                if(!cJSON_Compare(b_element, a_element, case_sensitive)) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        default:
+            return false;
+    }
+}
+
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { return global_hooks.allocate(size); }
+
+CJSON_PUBLIC(void) cJSON_free(void *object) {
+    global_hooks.deallocate(object);
+    object = NULL;
+}

+ 315 - 0
src/Util/cJSON.h

@@ -0,0 +1,315 @@
+/*
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a
+project with a different default calling convention.  For windows you have 3 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
+CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
+
+For *nix builds that support visibility attribute, you can define similar behavior by
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+*/
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+/* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type) type CJSON_STDCALL
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
+#elif defined(CJSON_IMPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if(defined(__GNUC__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+/* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 18
+
+#include <stddef.h>
+
+/* cJSON Types: */
+#define cJSON_Invalid (0)
+#define cJSON_False (1 << 0)
+#define cJSON_True (1 << 1)
+#define cJSON_NULL (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array (1 << 5)
+#define cJSON_Object (1 << 6)
+#define cJSON_Raw (1 << 7) /* raw json */
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+    struct cJSON *next;
+    struct cJSON *prev;
+    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+    struct cJSON *child;
+
+    /* The type of the item, as above. */
+    int type;
+
+    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
+    char *valuestring;
+    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
+    int valueint;
+    /* The item's number, if type==cJSON_Number */
+    double valuedouble;
+
+    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+    char *string;
+} cJSON;
+
+typedef struct cJSON_Hooks {
+    /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the
+     * hooks allow passing those functions directly. */
+    void *(CJSON_CDECL *malloc_fn)(size_t sz);
+    void(CJSON_CDECL *free_fn)(void *ptr);
+} cJSON_Hooks;
+
+typedef int cJSON_bool;
+
+/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
+ * This is to prevent stack overflows. */
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
+/* returns the version of cJSON as a string */
+CJSON_PUBLIC(const char *) cJSON_Version(void);
+
+/* Supply malloc, realloc and free functions to cJSON */
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks);
+
+/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with
+ * cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is
+ * cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the
+ * final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error
+ * so will match cJSON_GetErrorPtr(). */
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
+CJSON_PUBLIC(cJSON *)
+cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end,
+                          cJSON_bool require_null_terminated);
+
+/* Render a cJSON entity to text for transfer/storage. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. */
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well
+ * reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
+/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and
+ * 0 on failure. */
+/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes
+ * more than you actually need */
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
+/* Delete a cJSON entity and all subentities. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
+
+/* Returns the number of items in an array (or object). */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
+/* Get item "string" from object. Case insensitive. */
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *const object, const char *const string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string);
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back
+ * to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
+
+/* Check item type and return its value */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item);
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item);
+
+/* These functions check the type of an item */
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON *const item);
+
+/* These calls create a cJSON item of the appropriate type. */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
+/* raw json */
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
+
+/* Create a string where valuestring references a string so
+ * it will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
+/* Create an object/array that only references it's elements so
+ * they will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
+
+/* These utilities create an Array of count items.
+ * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be
+ * out of bounds.*/
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
+
+/* Append item to the specified array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON
+ * object. WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is
+ * zero before writing to `item->string` */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new
+ * cJSON, but don't want to corrupt your existing cJSON. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detach items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
+
+/* Update array items. */
+CJSON_PUBLIC(cJSON_bool)
+cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem);
+
+/* Duplicate a cJSON item */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+ * need to be released. With recurse!=0, it will duplicate any children connected to the item.
+ * The item->next and ->prev pointers are always zero on return from Duplicate. */
+/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered
+ * unequal. case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive);
+
+/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
+ * The input pointer json cannot point to a read-only address area, such as a string constant,
+ * but should point to a readable and writable address area. */
+CJSON_PUBLIC(void) cJSON_Minify(char *json);
+
+/* Helper functions for creating and adding items to an object at the same time.
+ * They return the added item or NULL on failure. */
+CJSON_PUBLIC(cJSON *) cJSON_AddNullToObject(cJSON *const object, const char *const name);
+CJSON_PUBLIC(cJSON *) cJSON_AddTrueToObject(cJSON *const object, const char *const name);
+CJSON_PUBLIC(cJSON *) cJSON_AddFalseToObject(cJSON *const object, const char *const name);
+CJSON_PUBLIC(cJSON *) cJSON_AddBoolToObject(cJSON *const object, const char *const name, const cJSON_bool boolean);
+CJSON_PUBLIC(cJSON *) cJSON_AddNumberToObject(cJSON *const object, const char *const name, const double number);
+CJSON_PUBLIC(cJSON *) cJSON_AddStringToObject(cJSON *const object, const char *const name, const char *const string);
+CJSON_PUBLIC(cJSON *) cJSON_AddRawToObject(cJSON *const object, const char *const name, const char *const raw);
+CJSON_PUBLIC(cJSON *) cJSON_AddObjectToObject(cJSON *const object, const char *const name);
+CJSON_PUBLIC(cJSON *) cJSON_AddArrayToObject(cJSON *const object, const char *const name);
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
+/* helper for the cJSON_SetNumberValue macro */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
+#define cJSON_SetNumberValue(object, number) \
+    ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
+/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
+CJSON_PUBLIC(char *) cJSON_SetValuestring(cJSON *object, const char *valuestring);
+
+/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
+#define cJSON_SetBoolValue(object, boolValue)                                                              \
+    ((object != NULL && ((object)->type & (cJSON_False | cJSON_True)))                                     \
+         ? (object)->type =                                                                                \
+               ((object)->type & (~(cJSON_False | cJSON_True))) | ((boolValue) ? cJSON_True : cJSON_False) \
+         : cJSON_Invalid)
+
+/* Macro for iterating over an array or object */
+#define cJSON_ArrayForEach(element, array) \
+    for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
+
+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
+CJSON_PUBLIC(void) cJSON_free(void *object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif