1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-12-29 00:08:11 +00:00

Resolve several bugs related to event note placement.

This commit is contained in:
EliteMasterEric 2023-10-27 01:42:05 -04:00
parent 0a4e0861cc
commit b2dd58b904
10 changed files with 112 additions and 48 deletions

View file

@ -165,7 +165,10 @@
<icon path="art/iconOG.png" /> <icon path="art/iconOG.png" />
<haxedef name="CAN_OPEN_LINKS" unless="switch" /> <haxedef name="CAN_OPEN_LINKS" unless="switch" />
<haxedef name="CAN_CHEAT" if="switch debug" /> <haxedef name="CAN_CHEAT" if="switch debug" />
<!-- I don't -->
<haxedef name="haxeui_no_mouse_reset" /> <haxedef name="haxeui_no_mouse_reset" />
<!-- Clicking outside a dialog should deselect the current focused component. -->
<haxedef name="haxeui_focus_out_on_click" />
<!-- Skip the Intro --> <!-- Skip the Intro -->
<section if="debug"> <section if="debug">
<!-- Starts the game at the specified week, at the first song --> <!-- Starts the game at the specified week, at the first song -->

2
assets

@ -1 +1 @@
Subproject commit ef79a6cf1ae3dcbd86a5b798f8117a6c692c0156 Subproject commit 6b6f2462afb099a7301a782ae521a0175fb7c71b

View file

@ -56,27 +56,45 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
Conductor.stepHit.remove(this.stepHit); Conductor.stepHit.remove(this.stepHit);
} }
override function update(elapsed:Float) function handleControls():Void
{ {
super.update(elapsed); var isHaxeUIFocused:Bool = haxe.ui.focus.FocusManager.instance?.focus != null;
// Rebindable volume keys. if (!isHaxeUIFocused)
if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted(); {
else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1); // Rebindable volume keys.
else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1); if (controls.VOLUME_MUTE) FlxG.sound.toggleMuted();
else if (controls.VOLUME_UP) FlxG.sound.changeVolume(0.1);
else if (controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
}
}
function handleFunctionControls():Void
{
// Emergency exit button. // Emergency exit button.
if (FlxG.keys.justPressed.F4) FlxG.switchState(new MainMenuState()); if (FlxG.keys.justPressed.F4) FlxG.switchState(new MainMenuState());
// This can now be used in EVERY STATE YAY! // This can now be used in EVERY STATE YAY!
if (FlxG.keys.justPressed.F5) debug_refreshModules(); if (FlxG.keys.justPressed.F5) debug_refreshModules();
}
function handleQuickWatch():Void
{
// Display Conductor info in the watch window. // Display Conductor info in the watch window.
FlxG.watch.addQuick("songPosition", Conductor.songPosition); FlxG.watch.addQuick("songPosition", Conductor.songPosition);
FlxG.watch.addQuick("bpm", Conductor.bpm); FlxG.watch.addQuick("bpm", Conductor.bpm);
FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime); FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime);
FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime); FlxG.watch.addQuick("currentBeatTime", Conductor.currentBeatTime);
FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime); FlxG.watch.addQuick("currentStepTime", Conductor.currentStepTime);
}
override function update(elapsed:Float)
{
super.update(elapsed);
handleControls();
handleFunctionControls();
handleQuickWatch();
dispatchEvent(new UpdateScriptEvent(elapsed)); dispatchEvent(new UpdateScriptEvent(elapsed));
} }

View file

@ -208,25 +208,32 @@ typedef SongEventSchemaField =
type:SongEventFieldType, type:SongEventFieldType,
/** /**
* Used for ENUM values. * Used only for ENUM values.
* The key is the display name and the value is the actual value. * The key is the display name and the value is the actual value.
*/ */
?keys:Map<String, Dynamic>, ?keys:Map<String, Dynamic>,
/** /**
* Used for INTEGER and FLOAT values. * Used for INTEGER and FLOAT values.
* The minimum value that can be entered. * The minimum value that can be entered.
* @default No minimum
*/ */
?min:Float, ?min:Float,
/** /**
* Used for INTEGER and FLOAT values. * Used for INTEGER and FLOAT values.
* The maximum value that can be entered. * The maximum value that can be entered.
* @default No maximum
*/ */
?max:Float, ?max:Float,
/** /**
* Used for INTEGER and FLOAT values. * Used for INTEGER and FLOAT values.
* The step value that will be used when incrementing/decrementing the value. * The step value that will be used when incrementing/decrementing the value.
* @default `0.1`
*/ */
?step:Float, ?step:Float,
/** /**
* An optional default value for the field. * An optional default value for the field.
*/ */

View file

@ -516,12 +516,22 @@ class SongEventData
public inline function getInt(key:String):Null<Int> public inline function getInt(key:String):Null<Int>
{ {
return value == null ? null : cast Reflect.field(value, key); if (value == null) return null;
var result = Reflect.field(value, key);
if (result == null) return null;
if (Std.isOfType(result, Int)) return result;
if (Std.isOfType(result, String)) return Std.parseInt(cast result);
return cast result;
} }
public inline function getFloat(key:String):Null<Float> public inline function getFloat(key:String):Null<Float>
{ {
return value == null ? null : cast Reflect.field(value, key); if (value == null) return null;
var result = Reflect.field(value, key);
if (result == null) return null;
if (Std.isOfType(result, Float)) return result;
if (Std.isOfType(result, String)) return Std.parseFloat(cast result);
return cast result;
} }
public inline function getString(key:String):String public inline function getString(key:String):String

View file

@ -12,6 +12,7 @@ using Lambda;
using StringTools; using StringTools;
using funkin.util.tools.ArraySortTools; using funkin.util.tools.ArraySortTools;
using funkin.util.tools.ArrayTools; using funkin.util.tools.ArrayTools;
using funkin.util.tools.DynamicTools;
using funkin.util.tools.Int64Tools; using funkin.util.tools.Int64Tools;
using funkin.util.tools.IteratorTools; using funkin.util.tools.IteratorTools;
using funkin.util.tools.MapTools; using funkin.util.tools.MapTools;

View file

@ -123,21 +123,25 @@ class ChartEditorEventSprite extends FlxSprite
function set_eventData(value:Null<SongEventData>):Null<SongEventData> function set_eventData(value:Null<SongEventData>):Null<SongEventData>
{ {
this.eventData = value; if (value == null)
if (this.eventData == null)
{ {
this.eventData = null;
// Disown parent. MAKE SURE TO REVIVE BEFORE REUSING // Disown parent. MAKE SURE TO REVIVE BEFORE REUSING
this.kill(); this.kill();
this.visible = false;
return null;
}
else
{
this.visible = true;
// Only play the animation if the event type has changed.
// if (this.eventData == null || this.eventData.event != value.event)
playAnimation(value.event);
this.eventData = value;
// Update the position to match the note data.
updateEventPosition();
return this.eventData; return this.eventData;
} }
this.visible = true;
playAnimation(this.eventData.event);
// Update the position to match the note data.
updateEventPosition();
return this.eventData;
} }
public function updateEventPosition(?origin:FlxObject) public function updateEventPosition(?origin:FlxObject)

View file

@ -71,6 +71,7 @@ import haxe.ui.core.Component;
import haxe.ui.core.Screen; import haxe.ui.core.Screen;
import haxe.ui.events.DragEvent; import haxe.ui.events.DragEvent;
import haxe.ui.events.UIEvent; import haxe.ui.events.UIEvent;
import haxe.ui.focus.FocusManager;
import haxe.ui.notifications.NotificationManager; import haxe.ui.notifications.NotificationManager;
import haxe.ui.notifications.NotificationType; import haxe.ui.notifications.NotificationType;
import openfl.Assets; import openfl.Assets;
@ -492,22 +493,14 @@ class ChartEditorState extends HaxeUIState
var hitsoundsEnabledOpponent:Bool = true; var hitsoundsEnabledOpponent:Bool = true;
/** /**
* Whether the user's mouse cursor is hovering over a SOLID component of the HaxeUI. * Whether the user is focused on an input in the Haxe UI, and inputs are being fed into it.
* If so, ignore mouse events underneath. * If the user clicks off the input, focus will leave.
*/ */
var isCursorOverHaxeUI(get, never):Bool; var isHaxeUIFocused(get, never):Bool;
function get_isCursorOverHaxeUI():Bool function get_isHaxeUIFocused():Bool
{ {
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY); return FocusManager.instance.focus != null;
}
var isCursorOverHaxeUIButton(get, never):Bool;
function get_isCursorOverHaxeUIButton():Bool
{
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Button)
|| Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY, haxe.ui.components.Link);
} }
/** /**
@ -1905,11 +1898,11 @@ class ChartEditorState extends HaxeUIState
handleHelpKeybinds(); handleHelpKeybinds();
#if debug #if debug
handleQuickWatch(); handleQuickWatches();
#end #end
} }
function handleQuickWatch():Void function handleQuickWatches():Void
{ {
FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels); FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels);
FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels); FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels);
@ -1957,8 +1950,8 @@ class ChartEditorState extends HaxeUIState
**/ **/
function handleScrollKeybinds():Void function handleScrollKeybinds():Void
{ {
// Don't scroll when the cursor is over the UI, unless a playbar button (the << >> ones) is pressed. // Don't scroll when the user is interacting with the UI, unless a playbar button (the << >> ones) is pressed.
if (isCursorOverHaxeUI && playbarButtonPressed == null) return; if (isHaxeUIFocused && playbarButtonPressed == null) return;
var scrollAmount:Float = 0; // Amount to scroll the grid. var scrollAmount:Float = 0; // Amount to scroll the grid.
var playheadAmount:Float = 0; // Amount to scroll the playhead relative to the grid. var playheadAmount:Float = 0; // Amount to scroll the playhead relative to the grid.
@ -2157,7 +2150,7 @@ class ChartEditorState extends HaxeUIState
if (FlxG.mouse.justReleased) FlxG.sound.play(Paths.sound("chartingSounds/ClickUp")); if (FlxG.mouse.justReleased) FlxG.sound.play(Paths.sound("chartingSounds/ClickUp"));
// Note: If a menu is open in HaxeUI, don't handle cursor behavior. // Note: If a menu is open in HaxeUI, don't handle cursor behavior.
var shouldHandleCursor:Bool = !isCursorOverHaxeUI || (selectionBoxStartPos != null); var shouldHandleCursor:Bool = !isHaxeUIFocused || (selectionBoxStartPos != null);
var eventColumn:Int = (STRUMLINE_SIZE * 2 + 1) - 1; var eventColumn:Int = (STRUMLINE_SIZE * 2 + 1) - 1;
if (shouldHandleCursor) if (shouldHandleCursor)
@ -2612,14 +2605,14 @@ class ChartEditorState extends HaxeUIState
{ {
// Create an event and place it in the chart. // Create an event and place it in the chart.
// TODO: Figure out configuring event data. // TODO: Figure out configuring event data.
var newEventData:SongEventData = new SongEventData(cursorSnappedMs, selectedEventKind, selectedEventData); var newEventData:SongEventData = new SongEventData(cursorSnappedMs, selectedEventKind, selectedEventData.clone());
performCommand(new AddEventsCommand([newEventData], FlxG.keys.pressed.CONTROL)); performCommand(new AddEventsCommand([newEventData], FlxG.keys.pressed.CONTROL));
} }
else else
{ {
// Create a note and place it in the chart. // Create a note and place it in the chart.
var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, selectedNoteKind); var newNoteData:SongNoteData = new SongNoteData(cursorSnappedMs, cursorColumn, 0, selectedNoteKind.clone());
performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL)); performCommand(new AddNotesCommand([newNoteData], FlxG.keys.pressed.CONTROL));
@ -3392,7 +3385,7 @@ class ChartEditorState extends HaxeUIState
*/ */
function handleTestKeybinds():Void function handleTestKeybinds():Void
{ {
if (!isHaxeUIDialogOpen && !isCursorOverHaxeUI && FlxG.keys.justPressed.ENTER) if (!isHaxeUIDialogOpen && !isHaxeUIFocused && FlxG.keys.justPressed.ENTER)
{ {
var minimal = FlxG.keys.pressed.SHIFT; var minimal = FlxG.keys.pressed.SHIFT;
ChartEditorToolboxHandler.hideAllToolboxes(this); ChartEditorToolboxHandler.hideAllToolboxes(this);
@ -3889,7 +3882,7 @@ class ChartEditorState extends HaxeUIState
} }
} }
if (FlxG.keys.justPressed.SPACE && !isHaxeUIDialogOpen) if (FlxG.keys.justPressed.SPACE && !(isHaxeUIDialogOpen || isHaxeUIFocused))
{ {
toggleAudioPlayback(); toggleAudioPlayback();
} }

View file

@ -346,6 +346,8 @@ class ChartEditorToolboxHandler
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType'); trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
state.selectedEventKind = eventType;
var schema:SongEventSchema = SongEventParser.getEventSchema(eventType); var schema:SongEventSchema = SongEventParser.getEventSchema(eventType);
if (schema == null) if (schema == null)
@ -356,6 +358,7 @@ class ChartEditorToolboxHandler
buildEventDataFormFromSchema(state, toolboxEventsDataGrid, schema); buildEventDataFormFromSchema(state, toolboxEventsDataGrid, schema);
} }
toolboxEventsEventKind.value = state.selectedEventKind;
return toolbox; return toolbox;
} }
@ -379,6 +382,7 @@ class ChartEditorToolboxHandler
// Add a label. // Add a label.
var label:Label = new Label(); var label:Label = new Label();
label.text = field.title; label.text = field.title;
label.verticalAlign = "center";
target.addComponent(label); target.addComponent(label);
var input:Component; var input:Component;
@ -396,8 +400,8 @@ class ChartEditorToolboxHandler
var numberStepper:NumberStepper = new NumberStepper(); var numberStepper:NumberStepper = new NumberStepper();
numberStepper.id = field.name; numberStepper.id = field.name;
numberStepper.step = field.step ?? 0.1; numberStepper.step = field.step ?? 0.1;
numberStepper.min = field.min ?? 0.0; if (field.min != null) numberStepper.min = field.min;
numberStepper.max = field.max ?? 1.0; if (field.max != null) numberStepper.max = field.max;
if (field.defaultValue != null) numberStepper.value = field.defaultValue; if (field.defaultValue != null) numberStepper.value = field.defaultValue;
input = numberStepper; input = numberStepper;
case BOOL: case BOOL:
@ -416,7 +420,7 @@ class ChartEditorToolboxHandler
for (optionName in field.keys.keys()) for (optionName in field.keys.keys())
{ {
var optionValue:Null<String> = field.keys.get(optionName); var optionValue:Null<Dynamic> = field.keys.get(optionName);
trace('$optionName : $optionValue'); trace('$optionName : $optionValue');
dropDown.dataSource.add({value: optionValue, text: optionName}); dropDown.dataSource.add({value: optionValue, text: optionName});
} }
@ -438,11 +442,21 @@ class ChartEditorToolboxHandler
target.addComponent(input); target.addComponent(input);
input.onChange = function(event:UIEvent) { input.onChange = function(event:UIEvent) {
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${event.target.value}'); var value = event.target.value;
if (field.type == ENUM)
{
value = event.target.value.value;
}
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
if (event.target.value == null) state.selectedEventData.remove(event.target.id); if (value == null)
{
state.selectedEventData.remove(event.target.id);
}
else else
state.selectedEventData.set(event.target.id, event.target.value); {
state.selectedEventData.set(event.target.id, value);
}
} }
} }
} }

View file

@ -0,0 +1,14 @@
package funkin.util.tools;
class DynamicTools
{
/**
* Creates a full clone of the input `Dynamic`. Only guaranteed to work on anonymous structures.
* @param input The `Dynamic` to clone.
* @return A clone of the input `Dynamic`.
*/
public static function clone(input:Dynamic):Dynamic
{
return Reflect.copy(input);
}
}