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:
parent
0a4e0861cc
commit
b2dd58b904
|
@ -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
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit ef79a6cf1ae3dcbd86a5b798f8117a6c692c0156
|
Subproject commit 6b6f2462afb099a7301a782ae521a0175fb7c71b
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
source/funkin/util/tools/DynamicTools.hx
Normal file
14
source/funkin/util/tools/DynamicTools.hx
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue