1 hour, 39 minutes: Convertation method for old charts with old events. No, im not gonna kill myself

I think it should be removed in one of 0.8.x patches or in 0.9
Also some verbose code as this commit is a bit big
This commit is contained in:
PurSnake
2025-10-09 04:41:34 +08:00
committed by Hundrec
parent d1d77dd85c
commit e67643e0b1
@@ -15,6 +15,7 @@ import haxe.ui.containers.Frame;
import haxe.ui.events.UIEvent;
import haxe.ui.data.ArrayDataSource;
import haxe.ui.containers.Grid;
import funkin.play.event.SongEvent;
/**
* The toolbox which allows modifying information like Song Title, Scroll Speed, Characters/Stages, and starting BPM.
@@ -170,13 +171,51 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
function buildEventDataFormFromSchema(target:Box, schema:SongEventSchema, eventKind:String):Void
{
trace('Building event data form from schema for event kind: ${eventKind}');
// trace(schema);
lastEventKind = eventKind ?? 'unknown';
// Clear the frame.
target.removeAllComponents();
// Check if we have both ease and easeDir fields in the schema
var hasEaseField = false;
var hasEaseDirField = false;
for (field in schema)
{
if (field != null)
{
if (field.name == 'ease') hasEaseField = true;
if (field.name == 'easeDir') hasEaseDirField = true;
}
}
// Convert ease data for ALL events (both new and existing)
if (hasEaseField && hasEaseDirField)
{
final originalData:Map<String, Dynamic> = new Map<String, Dynamic>();
for (key in chartEditorState.eventDataToPlace.keys())
originalData.set(key, chartEditorState.eventDataToPlace.get(key));
final converted:Bool = convertEaseData(chartEditorState.eventDataToPlace);
for (key => value in originalData)
{
if (key != 'ease' && key != 'easeDir') chartEditorState.eventDataToPlace.set(key, value);
}
if (converted && !_initializing && chartEditorState.currentEventSelection.length > 0)
{
for (songEvent in chartEditorState.currentEventSelection)
{
songEvent.eventKind = chartEditorState.eventKindToPlace;
songEvent.value = Reflect.copy(chartEditorState.eventDataToPlace);
}
chartEditorState.saveDataDirty = true;
chartEditorState.noteDisplayDirty = true;
chartEditorState.notePreviewDirty = true;
chartEditorState.noteTooltipsDirty = true;
}
}
for (field in schema)
{
if (field == null) continue;
@@ -189,6 +228,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
// Add an input field for the data field.
var input:Component;
final fieldValue = chartEditorState.eventDataToPlace.get(field.name);
switch (field.type)
{
case INTEGER:
@@ -197,7 +237,8 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
numberStepper.step = field.step ?? 1.0;
if (field.min != null) numberStepper.min = field.min;
if (field.max != null) numberStepper.max = field.max;
if (field.defaultValue != null) numberStepper.value = field.defaultValue;
if (fieldValue != null) numberStepper.value = fieldValue;
else if (field.defaultValue != null) numberStepper.value = field.defaultValue;
input = numberStepper;
case FLOAT:
var numberStepper:NumberStepper = new NumberStepper();
@@ -205,12 +246,14 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
numberStepper.step = field.step ?? 0.1;
if (field.min != null) numberStepper.min = field.min;
if (field.max != null) numberStepper.max = field.max;
if (field.defaultValue != null) numberStepper.value = field.defaultValue;
if (fieldValue != null) numberStepper.value = fieldValue;
else if (field.defaultValue != null) numberStepper.value = field.defaultValue;
input = numberStepper;
case BOOL:
var checkBox:CheckBox = new CheckBox();
checkBox.id = field.name;
if (field.defaultValue != null) checkBox.selected = field.defaultValue;
if (fieldValue != null) checkBox.selected = fieldValue;
else if (field.defaultValue != null) checkBox.selected = field.defaultValue;
input = checkBox;
case ENUM:
var dropDown:DropDown = new DropDown();
@@ -224,15 +267,13 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
if (field.keys == null) throw 'Field "${field.name}" is of Enum type but has no keys.';
// Add entries to the dropdown.
for (optionName in field.keys.keys())
{
var optionValue:Null<Dynamic> = field.keys.get(optionName);
// trace('$optionName : $optionValue');
dropDown.dataSource.add({value: optionValue, text: optionName});
}
dropDown.value = field.defaultValue;
dropDown.value = fieldValue ?? field.defaultValue;
// TODO: Add an option to customize sort.
dropDown.dataSource.sort('text', ASCENDING);
@@ -241,7 +282,8 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
case STRING:
input = new TextField();
input.id = field.name;
if (field.defaultValue != null) input.text = field.defaultValue;
if (fieldValue != null) input.text = fieldValue;
else if (field.defaultValue != null) input.text = field.defaultValue;
default:
// Unknown type. Display a label that proclaims the type so we can debug it.
input = new Label();
@@ -264,49 +306,204 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
target.addComponent(inputBox);
// Update the value of the event data.
input.onChange = function(event:UIEvent) {
var value = event.target.value;
if (field.type == ENUM)
{
var drp:DropDown = cast event.target;
value = drp.selectedItem?.value ?? field.defaultValue;
}
else if (field.type == BOOL)
{
var chk:CheckBox = cast event.target;
value = cast(chk.selected, Null<Bool>); // Need to cast to nullable bool or the compiler will get mad.
}
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
// Edit the event data to place.
if (value == null)
{
chartEditorState.eventDataToPlace.remove(event.target.id);
}
else
{
chartEditorState.eventDataToPlace.set(event.target.id, value);
}
// Edit the event data of any existing events.
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
{
for (songEvent in chartEditorState.currentEventSelection)
// Special handling for ease field to automatically detect and separate direction
// No, im not gonna kill myself
if (field.name == 'ease' && hasEaseDirField)
{
input.onChange = function(event:UIEvent) {
var value = event.target.value;
if (field.type == ENUM)
{
songEvent.eventKind = chartEditorState.eventKindToPlace;
songEvent.value = Reflect.copy(chartEditorState.eventDataToPlace);
var drp:DropDown = cast event.target;
value = drp.selectedItem?.value ?? field.defaultValue;
}
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
final currentData = new Map<String, Dynamic>();
for (key in chartEditorState.eventDataToPlace.keys())
currentData.set(key, chartEditorState.eventDataToPlace.get(key));
// Check if ease value contains direction and split it
if (value != null && Std.isOfType(value, String))
{
var converted = convertEaseDataForField(value, target);
if (converted.converted)
{
// Update the display to show base value
input.pauseEvent(UIEvent.CHANGE, true);
switch (input)
{
case Std.isOfType(_, DropDown) => true:
var dropDown:DropDown = cast input;
dropDown.value = converted.baseEase;
case Std.isOfType(_, TextField) => true:
var textField:TextField = cast input;
textField.text = converted.baseEase;
default:
}
input.resumeEvent(UIEvent.CHANGE, true, true);
for (key => val in currentData)
{
if (key != 'ease' && key != 'easeDir') chartEditorState.eventDataToPlace.set(key, val);
}
chartEditorState.eventDataToPlace.set('ease', converted.baseEase);
chartEditorState.eventDataToPlace.set('easeDir', converted.easeDir);
}
else
{
for (key => val in currentData)
{
if (key != 'ease') chartEditorState.eventDataToPlace.set(key, val);
}
chartEditorState.eventDataToPlace.set(event.target.id, value);
}
}
else
{
for (key => val in currentData)
{
if (key != 'ease') chartEditorState.eventDataToPlace.set(key, val);
}
chartEditorState.eventDataToPlace.set(event.target.id, value);
}
// Edit the event data of any existing events.
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
{
for (songEvent in chartEditorState.currentEventSelection)
{
songEvent.eventKind = chartEditorState.eventKindToPlace;
songEvent.value = Reflect.copy(chartEditorState.eventDataToPlace);
}
chartEditorState.saveDataDirty = true;
chartEditorState.noteDisplayDirty = true;
chartEditorState.notePreviewDirty = true;
chartEditorState.noteTooltipsDirty = true;
}
};
}
else
{
// Standard onChange handler for non-ease fields
input.onChange = function(event:UIEvent) {
var value = event.target.value;
if (field.type == ENUM)
{
var drp:DropDown = cast event.target;
value = drp.selectedItem?.value ?? field.defaultValue;
}
else if (field.type == BOOL)
{
var chk:CheckBox = cast event.target;
value = cast(chk.selected, Null<Bool>);
}
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
// Update the event data to place.
if (value == null)
{
chartEditorState.eventDataToPlace.remove(event.target.id);
}
else
{
chartEditorState.eventDataToPlace.set(event.target.id, value);
}
// Edit the event data of any existing events.
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
{
for (songEvent in chartEditorState.currentEventSelection)
{
songEvent.eventKind = chartEditorState.eventKindToPlace;
songEvent.value = Reflect.copy(chartEditorState.eventDataToPlace);
}
chartEditorState.saveDataDirty = true;
chartEditorState.noteDisplayDirty = true;
chartEditorState.notePreviewDirty = true;
chartEditorState.noteTooltipsDirty = true;
}
chartEditorState.saveDataDirty = true;
chartEditorState.noteDisplayDirty = true;
chartEditorState.notePreviewDirty = true;
chartEditorState.noteTooltipsDirty = true;
}
}
}
}
/**
* Converts ease data in the event data map by splitting combined ease values
* @return Whether conversion occurred
*/
function convertEaseData(data:haxe.DynamicAccess<Dynamic>):Bool
{
if (data == null) return false;
var easeValue = data.get('ease');
if (easeValue != null && Std.isOfType(easeValue, String))
{
var easeString:String = easeValue;
trace('convertEaseData: Processing ease string "${easeString}"');
if (SongEvent.EASE_TYPE_DIR_REGEX.match(easeString))
{
var baseEase = SongEvent.EASE_TYPE_DIR_REGEX.matchedLeft();
var easeDir = SongEvent.EASE_TYPE_DIR_REGEX.matched(0);
// Update the event data with separated values
data.set('ease', baseEase);
data.set('easeDir', easeDir);
trace('Auto-split ease on load: ${easeString} -> ${baseEase} + ${easeDir}');
return true;
}
else
{
trace('convertEaseData: No direction suffix found in "${easeString}"');
}
}
else
{
trace('convertEaseData: easeValue is null or not a string: ${easeValue}');
}
return false;
}
/**
* Converts ease data for a specific field value and updates the UI
* @return Object with conversion result
*/
function convertEaseDataForField(easeValue:String, target:Box):{converted:Bool, baseEase:String, easeDir:String}
{
if (easeValue != null && SongEvent.EASE_TYPE_DIR_REGEX.match(easeValue))
{
var baseEase = SongEvent.EASE_TYPE_DIR_REGEX.matchedLeft();
var easeDir = SongEvent.EASE_TYPE_DIR_REGEX.matched(0);
// Find and update the easeDir field if it exists
var easeDirField:Component = target.findComponent('easeDir', Component);
if (easeDirField != null)
{
easeDirField.pauseEvent(UIEvent.CHANGE, true);
switch (easeDirField)
{
case Std.isOfType(_, DropDown) => true:
var easeDirDropDown:DropDown = cast easeDirField;
easeDirDropDown.value = easeDir;
case Std.isOfType(_, TextField) => true:
var easeDirTextField:TextField = cast easeDirField;
easeDirTextField.text = easeDir;
default:
}
easeDirField.resumeEvent(UIEvent.CHANGE, true, true);
trace('ChartEditorToolboxHandler - Auto-split ease: ${easeValue} -> ${baseEase} + ${easeDir}');
return {converted: true, baseEase: baseEase, easeDir: easeDir};
}
}
return {converted: false, baseEase: easeValue, easeDir: ''};
}
public static function build(chartEditorState:ChartEditorState):ChartEditorEventDataToolbox
{
return new ChartEditorEventDataToolbox(chartEditorState);