Options Rewrite WIP All Options Done

This commit is contained in:
Ralty
2025-07-26 20:45:40 +07:00
parent ea85c71523
commit 3dd23f0690
15 changed files with 181 additions and 116 deletions
+3
View File
@@ -147,6 +147,9 @@
<str id="devMode-name">Developer Mode</str>
<str id="devMode-desc">If checked, you will be able to access developer features like certain keybinds, editors, developer options, state reloads, console and more.</str>
<str id="allowConfigWarning-name">Allow Mod Configs Warning Popup</str>
<str id="allowConfigWarning-desc">If checked, a popup at the start of the game will appear if the current mod doesn't have a mod configuration file</str>
<str id="resetSaveData-name">Reset Save Data</str>
<str id="resetSaveData-desc">Select this option to reset save data. This will remove all of your highscores.</str>
</group>
+12 -10
View File
@@ -62,26 +62,28 @@
<str id="framerate-name">Klatki</str>
<str id="framerate-desc">Ilość Klatek na sekundę ktore gra renderuje</str>
<str id="antialiasing-name">Wygładzanie</str>
<str id="antialiasing-desc">Jeśli wyłączone, Wygładzanie nie będzie widoczne na Sprite'ach. Może poprawić wydajność na koszt ostrzejszego, pikselowatego wyglądu Sprite'ów.</str>
<str id="colorHealthBar-name">Kolorowe Zdrowie</str>
<str id="colorHealthBar-desc">Jeśli wyłączone, Pasek zdrowia będzie tylko używał czerwonego i zielonego koloru, takiego jak z oryginalnej gry.</str>
<str id="week6PixelPerfect-name">Perfekcyjne Piksele</str>
<str id="week6PixelPerfect-desc">Jeśli włączone, Tydzień 6 będzie miał efekt perfekcyjnych pikseli, ustawiający każdy piksel na ekranie.</str>
<str id="gameplayShaders-name">Shadery Rozgrywki</str>
<str id="gameplayShaders-desc">Jeśli wyłączone, Shadery Rozgrywki (efekty wizualne jak Aberacja Chromatyczna z Thorns) nie będą ładowane; może być to pomocne na słabszych urządzeniach.</str>
<str id="flashingMenu-name">Migające Menu</str>
<str id="flashingMenu-desc">Jeśli wyłączone, tło menu głównego nie będzie migać kolorów po wybraniu opcji. Inne migania będą znacznie wolniejsze.</str>
<str id="lowMemoryMode-name">Niskie zużycie pamięci</str>
<group name="AppearanceOptionsAdvanced" prefix="Advanced.">
<str id="antialiasing-name">Wygładzanie</str>
<str id="antialiasing-desc">Jeśli wyłączone, Wygładzanie nie będzie widoczne na Sprite'ach. Może poprawić wydajność na koszt ostrzejszego, pikselowatego wyglądu Sprite'ów.</str>
<str id="lowMemoryMode-name">Niskie zużycie pamięci</str>
<str id="lowMemoryMode-desc">Jeśli włączone, usunie niektóre elementy tła, co użyje mniej pamięci.</str>
<str id="gpuOnlyBitmaps-name">Sprite'y w VRAM</str>
<str id="gpuOnlyBitmaps-desc">Jeśli włączone, utrzyma obrazy tylko w GPU, uwalniając więcej pamięci (EKSPERYMENTALNE). Wyłaczenie tego użyje o wiele więcej pamięci, szczególnie przy większych duszkach. Zostaw włączone w wypadku wątpliwości.</str>
<str id="gameplayShaders-name">Shadery Rozgrywki</str>
<str id="gameplayShaders-desc">Jeśli wyłączone, Shadery Rozgrywki (efekty wizualne jak Aberacja Chromatyczna z Thorns) nie będą ładowane; może być to pomocne na słabszych urządzeniach.</str>
<str id="gpuOnlyBitmaps-name">Sprite'y w VRAM</str>
<str id="gpuOnlyBitmaps-desc">Jeśli włączone, utrzyma obrazy tylko w GPU, uwalniając więcej pamięci (EKSPERYMENTALNE). Wyłaczenie tego użyje o wiele więcej pamięci, szczególnie przy większych duszkach. Zostaw włączone w wypadku wątpliwości.</str>
</group>
</group>
<group name="GameplayOptions" prefix="GameplayOptions.">
@@ -112,7 +114,7 @@
<str id="streamedMusic-name">Strumieniowana Muzyka</str>
<str id="streamedMusic-desc">Jeśli włączone, tylko muzyka będzie strumieniować audio, uwalniając więcej pamięci, na możliwy koszt większego użycia CPU. (EKSPERYMENTALNE)</str>
If checked, only musics will have streamed audio, ALSO freeing a LOT of memory with the downside of higher cpu usage if more audio are being streamed at once (EXPERIMENTAL). Turning this off will consume a lot of memory, especially on longer songs. If you aren't sure, leave this on.
<str id="streamedVocals-name">Strumieniowane Wokale</str>
<str id="streamedVocals-desc">Jeśli włączone, tylko wokale będą strumieniować audio, uwalniając więcej pamięci, na możliwy koszt większego użycia CPU. (EKSPERYMENTALNE)</str>
</group>
+1 -1
View File
@@ -122,7 +122,7 @@ class MainState extends FlxState {
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
#end
if (Options.devMode) {
if (Options.devMode && Options.allowConfigWarning) {
var lib:ModsFolderLibrary;
for (e in Paths.assetsTree.libraries) {
@:privateAccess if (!(e is openfl.utils.AssetLibrary) || !((lib = cast cast(e, openfl.utils.AssetLibrary).__proxy) is ModsFolderLibrary)) continue;
+1
View File
@@ -45,6 +45,7 @@ class Options
public static var streamedMusic:Bool = true;
public static var streamedVocals:Bool = true;
public static var quality:Int = 1;
public static var allowConfigWarning:Bool = true;
#if MODCHARTING_FEATURES
public static var modchartingHoldSubdivisions:Int = 4;
#end
+6 -1
View File
@@ -89,6 +89,9 @@ class TreeMenu extends UIState {
if (cameraScroll && last != null) {
if (menuChangeTween != null && menuChangeTween.active) menuChangeTween.cancel();
FlxG.camera.scroll.x = last.x;
for (menu in tree) if (menu != null) menu.transitioning = false;
for (menu in previousMenus) if (menu != null) menu.transitioning = false;
}
}
@@ -203,8 +206,9 @@ class TreeMenu extends UIState {
}});
for (menu in tree) if (menu != null) menu.transitioning = true;
for (menu in previousMenus) if (menu != null) menu.transitioning = true;
}
for (menu in previousMenus) if (menu != null) menu.transitioning = true;
}
override function update(elapsed:Float) {
@@ -250,6 +254,7 @@ class TreeMenu extends UIState {
public function reloadStrings() {
for (menu in tree) if (menu != null) menu.reloadStrings();
updateLabels();
}
public function destroyPreviousMenus() {
+4 -2
View File
@@ -48,8 +48,8 @@ class TreeMenuScreen extends FlxSpriteGroup {
public var controls(get, never):Controls;
inline function get_controls():Controls return PlayerSettings.solo.controls;
var leftTurboControl:TurboControls = new TurboControls([Control.LEFT], 0.2, 1 / 30);
var rightTurboControl:TurboControls = new TurboControls([Control.RIGHT], 0.2, 1 / 30);
var leftTurboControl:TurboControls = new TurboControls([Control.LEFT], 0.2, 1 / 48);
var rightTurboControl:TurboControls = new TurboControls([Control.RIGHT], 0.2, 1 / 48);
var upTurboControl:TurboControls = new TurboControls([Control.UP]);
var downTurboControl:TurboControls = new TurboControls([Control.DOWN]);
var turboBasics:Array<TurboBasic>;
@@ -126,6 +126,8 @@ class TreeMenuScreen extends FlxSpriteGroup {
public function close() {
onClose.dispatch();
if (curOption != null) curOption.selected = false;
if (parent == null) return destroy();
else parent.removeMenu(this);
@@ -2,7 +2,7 @@ package funkin.options.categories;
class AppearanceOptions extends TreeMenuScreen {
public function new() {
super('optionsTree.appearance-name', 'optionsTree.appearance-desc', "AppearanceOptions.");
super('optionsTree.appearance-name', 'optionsTree.appearance-desc', 'AppearanceOptions.');
add(new NumOption(getNameID('framerate'), getDescID('framerate'),
30, 240, 1,
@@ -35,7 +35,7 @@ class AppearanceOptions extends TreeMenuScreen {
class AdvancedAppearanceOptions extends TreeMenuScreen {
public function new() {
super('optionsMenu.advanced', 'optionsTree.appearance.advanced-desc', "AppearanceOptions.Advanced.");
super('optionsMenu.advanced', 'optionsTree.appearance.advanced-desc', 'AppearanceOptions.Advanced.');
for (option in [
new Checkbox(getNameID('antialiasing'), getDescID('antialiasing'), 'antialiasing', __changeAntialiasing),
@@ -4,7 +4,66 @@ import flixel.util.FlxTimer;
import funkin.backend.system.Conductor;
class GameplayOptions extends TreeMenuScreen {
var __metronome = FlxG.sound.load(Paths.sound('editors/charter/metronome'));
var offsetSetting:NumOption;
public function new() {
super('optionsTree.gameplay-name', 'optionsTree.gameplay-desc', 'GameplayOptions.');
add(new Checkbox(getNameID('downscroll'), getDescID('downscroll'), 'downscroll'));
add(new Checkbox(getNameID('ghostTapping'), getDescID('ghostTapping'), 'ghostTapping'));
add(new Checkbox(getNameID('naughtyness'), getDescID('naughtyness'), 'naughtyness'));
add(new Checkbox(getNameID('camZoomOnBeat'), getDescID('camZoomOnBeat'), 'camZoomOnBeat'));
add(new Checkbox(getNameID('autoPause'), getDescID('autoPause'), 'autoPause'));
add(offsetSetting = new NumOption(getNameID('songOffset'), getDescID('songOffset'), -999, 999, 1, 'songOffset', __changeOffset));
add(new Separator());
add(new TextOption('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', ' >', () ->
parent.addMenu(new AdvancedGameplayOptions())));
}
private function __changeOffset(offset:Float) Conductor.songOffset = offset;
var __lastBeat:Int = 0;
var __lastSongBeat:Int = 0;
override function update(elapsed:Float) {
super.update(elapsed);
FlxG.camera.zoom = CoolUtil.fpsLerp(FlxG.camera.zoom, 1, 0.1);
if (offsetSetting.selected) {
if (__lastBeat != Conductor.curBeat) {
FlxG.camera.zoom += 0.03;
__lastBeat = Conductor.curBeat;
}
var beat = Math.floor(Conductor.getTimeInBeats(FlxG.sound.music.time));
if (__lastSongBeat != beat) {
__metronome.replay();
__lastSongBeat = beat;
}
}
}
override function changeSelection(change:Int, force:Bool = false) {
super.changeSelection(change, force);
if (offsetSetting.selected) FlxG.sound.music.volume = 0.5;
else FlxG.sound.music.volume = 1;
}
override function close() {
super.close();
FlxG.camera.zoom = 1;
FlxG.sound.music.volume = 1;
}
}
class AdvancedGameplayOptions extends OptionsScreen {
}
class AdvancedGameplayOptions extends TreeMenuScreen {
public function new() {
super('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', 'GameplayOptions.Advanced.');
add(new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic'));
add(new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals'));
}
}
@@ -3,17 +3,13 @@ package funkin.options.categories;
class LanguageRadio extends RadioButton {
public var langID:String;
public function new(name:String, langID:String) {
public function new(screen:TreeMenuScreen, name:String, langID:String) {
super(screen, name, "LanguageOptions.language-desc", null, langID, null, "languageSelector");
this.langID = langID;
super(name, "LanguageOptions.language-desc", null, langID, null, "languageSelector");
checked = langID == TU.curLanguage;
}
override function reloadStrings() {
super.reloadStrings();
}
override function set_rawDesc(v:String) {
rawDesc = v;
var config = TU.getConfig(langID);
@@ -23,28 +19,25 @@ class LanguageRadio extends RadioButton {
return v;
}
override dynamic function onSet(value:Dynamic) {
override function select() {
var prev = checked;
super.select();
if (prev == checked) return;
TranslationUtil.setLanguage(value);
if(FlxG.state is OptionsMenu) {
var menu:OptionsMenu = cast FlxG.state;
menu.reloadStrings();
trace("Reloading strings");
}
if (screen.parent == null) screen.reloadStrings();
else screen.parent.reloadStrings();
}
}
class LanguageOptions extends TreeMenuScreen {
public override function new(title:String, desc:String) {
super(title, desc, "LanguageOptions.");
public override function new() {
super('optionsTree.language-name', 'optionsTree.language-desc', 'LanguageOptions.');
var langArray:Array<String> = TranslationUtil.foundLanguages;
for(lang in langArray) {
for (lang in TranslationUtil.foundLanguages) {
var split = lang.split("/");
var langId = split.first();
var langName = split.last();
var radio = new LanguageRadio(langName, langId);
add(radio);
var langId = split.first(), langName = split.last();
add(new LanguageRadio(this, langName, langId));
}
}
}
}
@@ -1,4 +1,26 @@
package funkin.options.categories;
class MiscOptions extends TreeMenuScreen {
}
public function new() {
super('optionsTree.miscellaneous-name', 'optionsTree.miscellaneous-desc', 'MiscOptions.');
add(new Checkbox(getNameID('devMode'), getDescID('devMode'), 'devMode'));
add(new Checkbox(getNameID('allowConfigWarning'), getDescID('allowConfigWarning'), 'allowConfigWarning'));
#if UPDATE_CHECKING
add(new Checkbox(getNameID('betaUpdates'), getDescID('betaUpdates'), 'betaUpdates'));
add(new TextOption(getNameID('checkForUpdates'), getDescID('checkForUpdates'), () -> {
var report = funkin.backend.system.updating.UpdateUtil.checkForUpdates();
if (report.newUpdate) FlxG.switchState(new funkin.backend.system.updating.UpdateAvailableScreen(report));
else {
CoolUtil.playMenuSFX(CANCEL);
updateDescText(translate('checkForUpdates-noUpdateFound'));
}
}));
#end
add(new Separator());
add(new TextOption(getNameID('resetSaveData'), getDescID('resetSaveData'), () -> {
// TODO: SAVE DATA RESETTING
}));
}
}
+10 -11
View File
@@ -19,8 +19,8 @@ class Checkbox extends TextOption {
"checking" => FlxPoint.get(35, 29)
];
public function new(text:String, desc:String, optionName:String, ?selectCallback:Void->Void = null, ?parent:Dynamic) {
super(text, desc);
public function new(text:String, desc:String, optionName:String, ?selectCallback:Void->Void, ?parent:Dynamic) {
super(text, desc, selectCallback);
this.optionName = optionName;
this.parent = parent = parent != null ? parent : Options;
@@ -36,14 +36,13 @@ class Checkbox extends TextOption {
__text.x = 100;
var fieldValue = Reflect.field(parent, optionName);
if (optionName != null) checked = Reflect.field(parent, optionName);
else checked = false;
}
public var firstFrame:Bool = true;
public override function update(elapsed:Float) {
override function update(elapsed:Float) {
if (checkbox.animation.curAnim == null) checkbox.animation.play(checked ? "checked" : "unchecked", true);
super.update(elapsed);
@@ -64,15 +63,15 @@ class Checkbox extends TextOption {
}
function set_checked(v:Bool) {
if (checked != v) {
checked = v;
if (!firstFrame) checkbox.animation.play(checked ? "checking" : "unchecking", true);
}
if (checked == (checked = v)) return v;
if (!firstFrame) checkbox.animation.play(checked ? "checking" : "unchecking", true);
return v;
}
public override function select() {
override function select() {
if (locked) return;
checked = !checked;
if (optionName != null) Reflect.setField(parent, optionName, checked);
@@ -82,8 +81,8 @@ class Checkbox extends TextOption {
if (selectCallback != null) selectCallback();
}
public override function destroy() {
override function destroy() {
super.destroy();
for(e in offsets) e.put();
for (e in offsets) e.put();
}
}
+2
View File
@@ -12,6 +12,8 @@ class IconOption extends TextOption {
public function new(name:String, desc:String, icon:String, callback:Void->Void) {
super(name, desc, callback);
__text.x = 100;
iconSpr = new HealthIcon(icon, false);
iconSpr.setPosition(90 - iconSpr.width, (__text.height - iconSpr.height) / 2);
iconSpr.setUnstretchedGraphicSize(150, 150, true);
+1
View File
@@ -12,6 +12,7 @@ class NewOption extends TextOption {
super(name, desc, callback);
__text.color = FlxColor.LIME;
__text.x = 100;
iconSpr = new FlxSprite().loadGraphic(Paths.image("editors/new"));
iconSpr.setPosition(90 - iconSpr.width, (__text.height - iconSpr.height) / 2);
@@ -12,6 +12,8 @@ class PortraitOption extends TextOption {
public function new(name:String, desc:String, callback:Void->Void, ?graphic:FlxGraphic, size:Int = 96, usePortrait:Bool = true) {
super(name, desc, callback);
__text.x = 100;
if (graphic != null) addPortrait(graphic, size, usePortrait);
}
+38 -64
View File
@@ -1,17 +1,19 @@
package funkin.options.type;
import flixel.math.FlxPoint;
import funkin.options.TreeMenuScreen;
class RadioButton extends TextOption {
public var radio:FlxSprite;
public var checked(default, set):Bool;
public var parent:Dynamic;
public var value:Dynamic;
public var forId:String;
public var optionName:String;
public var screen:TreeMenuScreen;
public var forId:String;
public var value:Dynamic;
private var offsets:Map<String, FlxPoint> = [
"unchecked" => FlxPoint.get(0, -65),
"checked" => FlxPoint.get(0, -65),
@@ -19,26 +21,15 @@ class RadioButton extends TextOption {
"checking" => FlxPoint.get(17, -40)
];
public function new(text:String, desc:String, optionName:String, value:Dynamic, ?parent:Dynamic, ?forId:String, ?options:OptionsScreen) {
super(text, desc, null);
public function new(?screen:TreeMenuScreen, text:String, desc:String, optionName:String, value:Dynamic, ?selectCallback:Void->Void, ?parent:Dynamic, ?forId:String) {
super(text, desc, selectCallback);
this.screen = screen;
this.optionName = optionName;
this.parent = parent = parent != null ? parent : Options;
this.forId = forId = forId == null ? optionName : forId;
this.value = value;
if (parent == null)
parent = Options;
if(forId == null)
forId = optionName;
this.parent = parent;
this.forId = forId;
if(options != null) {
if(FlxG.state is OptionsMenu) {
var menu:OptionsMenu = cast FlxG.state;
options = menu.optionsTree.members.last();
}
}
radio = new FlxSprite(10, -40);
radio = new FlxSprite(10, -23);
radio.frames = Paths.getFrames('menus/options/radioCrank');
radio.animation.addByPrefix("unchecked", "Radio unselected0", 24);
radio.animation.addByPrefix("checked", "Radio Selected Static0", 24);
@@ -49,75 +40,58 @@ class RadioButton extends TextOption {
radio.updateHitbox();
add(radio);
this.value = value;
__text.x = 100;
this.optionName = optionName;
if(optionName != null) {
checked = Reflect.field(parent, optionName) == value;
} else {
checked = false;
}
if (optionName != null) checked = Reflect.field(parent, optionName) == value;
else checked = false;
}
public var firstFrame:Bool = true;
public override function update(elapsed:Float) {
if(radio.animation.curAnim == null) {
radio.animation.play(checked ? "checked" : "unchecked", true);
}
override function update(elapsed:Float) {
if (radio.animation.curAnim == null) radio.animation.play(checked ? "checked" : "unchecked", true);
super.update(elapsed);
switch(radio.animation.curAnim.name) {
case "unchecking":
if(radio.animation.curAnim.finished) {
radio.animation.play("unchecked", true);
trace("UNCHECKING finished");
}
case "checking":
if(radio.animation.curAnim.finished) {
radio.animation.play("checked", true);
trace("CHECKING finished");
}
if (radio.animation.curAnim.finished) switch(radio.animation.curAnim.name) {
case "unchecking": radio.animation.play("unchecked", true);
case "checking": radio.animation.play("checked", true);
}
firstFrame = false;
}
override function draw() {
if(radio.animation.curAnim != null) {
if (radio.animation.curAnim != null) {
var offset = offsets[radio.animation.curAnim.name];
if (offset != null)
radio.frameOffset.set(offset.x, offset.y);
if (offset != null) radio.frameOffset.set(offset.x, offset.y);
}
super.draw();
}
function set_checked(v:Bool) {
if(checked != v) {
checked = v;
if(!firstFrame) {
radio.animation.play(checked ? "checking" : "unchecking", true);
}
}
if (checked == (checked = v)) return v;
if (!firstFrame) radio.animation.play(checked ? "checking" : "unchecking", true);
return v;
}
public override function select() {
override function select() {
if (locked) return;
checked = true;
if(checked) {
onSet(value);
if (optionName != null) Reflect.setField(parent, optionName, value);
CoolUtil.playMenuSFX(CHECKED);
if (screen != null) {
for (item in screen.members) if (item != null && item != this && item is RadioButton) cast(item, RadioButton).checked = false;
}
if (selectCallback != null) selectCallback();
}
public dynamic function onSet(value:Dynamic) {
if(optionName != null) {
Reflect.setField(parent, optionName, value);
}
}
public override function destroy() {
override function destroy() {
super.destroy();
for(e in offsets) e.put();
for (e in offsets) e.put();
}
}