mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-26 17:46:08 -05:00
Merge branch 'bugfix/chart-editor-event-toolbox-crash' into rewrite/master
This commit is contained in:
commit
4691e3d249
10 changed files with 120 additions and 27 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Fixed
|
### Fixed
|
||||||
- Bug where Dadbattle shows up as Dadbattle Erect when returning to freeplay
|
- Bug where Dadbattle shows up as Dadbattle Erect when returning to freeplay
|
||||||
- Fixed 2Hot not appearing under the "#" category in Freeplay menu
|
- Fixed 2Hot not appearing under the "#" category in Freeplay menu
|
||||||
|
- Fixed a bug where the Chart Editor would crash when attempting to select an event with the Event toolbox open
|
||||||
|
- Improved offsets for Pico and Tankman opponents so they don't slide around as much.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.4.0] - 2024-06-06
|
## [0.4.0] - 2024-06-06
|
||||||
### Added
|
### Added
|
||||||
|
@ -37,11 +41,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!)
|
- Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!)
|
||||||
- Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!)
|
- Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!)
|
||||||
- Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame.
|
- Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame.
|
||||||
|
- Improved the Event Toolbox in the Chart Editor; dropdowns are now bigger, include search field, and display elements in alphabetical order rather than a random order.
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed an issue where Nene's visualizer would not play on Desktop builds
|
- Fixed an issue where Nene's visualizer would not play on Desktop builds
|
||||||
- Fixed a bug where the game would silently fail to load saves on HTML5
|
- Fixed a bug where the game would silently fail to load saves on HTML5
|
||||||
- Fixed some bugs with the props on the Story Menu not bopping properly
|
- Fixed some bugs with the props on the Story Menu not bopping properly
|
||||||
- Improved offsets for Pico and Tankman opponents so they don't slide around as much.
|
- Additional fixes to the Loading bar on HTML5 (thanks lemz1!)
|
||||||
|
- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!)
|
||||||
|
- Fixed a camera bug in the Main Menu (thanks richTrash21!)
|
||||||
|
- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!)
|
||||||
|
- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!)
|
||||||
|
- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!)
|
||||||
|
- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!)
|
||||||
|
- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!)
|
||||||
|
- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!)
|
||||||
|
- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!)
|
||||||
|
- Improved debug logging for unscripted stages (thanks gamerbross!)
|
||||||
|
- Made improvements to compiling documentation (thanks gedehari!)
|
||||||
- Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!)
|
- Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!)
|
||||||
- Optimized animation handling for characters (thanks richTrash21!)
|
- Optimized animation handling for characters (thanks richTrash21!)
|
||||||
- Made improvements to compiling documentation (thanks gedehari!)
|
- Made improvements to compiling documentation (thanks gedehari!)
|
||||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 6421057faae19782fcda81349bbdeb40f014323e
|
Subproject commit f5a9f84e7f5246a27bd9397784d00f74973be825
|
|
@ -227,12 +227,12 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
// already paused before we lost focus.
|
// already paused before we lost focus.
|
||||||
if (_lostFocus && !_alreadyPaused)
|
if (_lostFocus && !_alreadyPaused)
|
||||||
{
|
{
|
||||||
trace('Resuming audio (${this._label}) on focus!');
|
// trace('Resuming audio (${this._label}) on focus!');
|
||||||
resume();
|
resume();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace('Not resuming audio (${this._label}) on focus!');
|
// trace('Not resuming audio (${this._label}) on focus!');
|
||||||
}
|
}
|
||||||
_lostFocus = false;
|
_lostFocus = false;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
*/
|
*/
|
||||||
override function onFocusLost():Void
|
override function onFocusLost():Void
|
||||||
{
|
{
|
||||||
trace('Focus lost, pausing audio!');
|
// trace('Focus lost, pausing audio!');
|
||||||
_lostFocus = true;
|
_lostFocus = true;
|
||||||
_alreadyPaused = _paused;
|
_alreadyPaused = _paused;
|
||||||
pause();
|
pause();
|
||||||
|
|
|
@ -237,7 +237,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
|
|
||||||
// KEYBOARD ONLY: Restart the level when pressing the assigned key.
|
// KEYBOARD ONLY: Restart the level when pressing the assigned key.
|
||||||
if (controls.ACCEPT && blueballed)
|
if (controls.ACCEPT && blueballed && !mustNotExit)
|
||||||
{
|
{
|
||||||
blueballed = false;
|
blueballed = false;
|
||||||
confirmDeath();
|
confirmDeath();
|
||||||
|
|
|
@ -53,8 +53,9 @@ class HealthIcon extends FunkinSprite
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the "bop" animation once every X steps.
|
* Apply the "bop" animation once every X steps.
|
||||||
|
* Defaults to once per beat.
|
||||||
*/
|
*/
|
||||||
public var bopEvery:Int = 4;
|
public var bopEvery:Int = Constants.STEPS_PER_BEAT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount, in degrees, to rotate the icon by when boping.
|
* The amount, in degrees, to rotate the icon by when boping.
|
||||||
|
|
|
@ -904,7 +904,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
function set_notePreviewDirty(value:Bool):Bool
|
function set_notePreviewDirty(value:Bool):Bool
|
||||||
{
|
{
|
||||||
trace('Note preview dirtied!');
|
// trace('Note preview dirtied!');
|
||||||
return notePreviewDirty = value;
|
return notePreviewDirty = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,15 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
{
|
{
|
||||||
var eventSelected = this.events[0];
|
var eventSelected = this.events[0];
|
||||||
|
|
||||||
|
if (state.eventKindToPlace == eventSelected.eventKind)
|
||||||
|
{
|
||||||
|
trace('Target event kind matches selection: ${eventSelected.eventKind}');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('Switching target event kind to match selection: ${state.eventKindToPlace} != ${eventSelected.eventKind}');
|
||||||
state.eventKindToPlace = eventSelected.eventKind;
|
state.eventKindToPlace = eventSelected.eventKind;
|
||||||
|
}
|
||||||
|
|
||||||
// This code is here to parse event data that's not built as a struct for some reason.
|
// This code is here to parse event data that's not built as a struct for some reason.
|
||||||
// TODO: Clean this up or get rid of it.
|
// TODO: Clean this up or get rid of it.
|
||||||
|
|
|
@ -201,7 +201,8 @@ class ChartEditorThemeHandler
|
||||||
// Selection borders horizontally in the middle.
|
// Selection borders horizontally in the middle.
|
||||||
for (i in 1...(Conductor.instance.stepsPerMeasure))
|
for (i in 1...(Conductor.instance.stepsPerMeasure))
|
||||||
{
|
{
|
||||||
if ((i % Conductor.instance.beatsPerMeasure) == 0)
|
// There may be a different number of beats per measure, but there's always 4 steps per beat.
|
||||||
|
if ((i % Constants.STEPS_PER_BEAT) == 0)
|
||||||
{
|
{
|
||||||
state.gridBitmap.fillRect(new Rectangle(0, (ChartEditorState.GRID_SIZE * i) - (GRID_BEAT_DIVIDER_WIDTH / 2), state.gridBitmap.width,
|
state.gridBitmap.fillRect(new Rectangle(0, (ChartEditorState.GRID_SIZE * i) - (GRID_BEAT_DIVIDER_WIDTH / 2), state.gridBitmap.width,
|
||||||
GRID_BEAT_DIVIDER_WIDTH),
|
GRID_BEAT_DIVIDER_WIDTH),
|
||||||
|
|
|
@ -58,17 +58,8 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
|
|
||||||
function initialize():Void
|
function initialize():Void
|
||||||
{
|
{
|
||||||
toolboxEventsEventKind.dataSource = new ArrayDataSource();
|
|
||||||
|
|
||||||
var songEvents:Array<SongEvent> = SongEventRegistry.listEvents();
|
|
||||||
|
|
||||||
for (event in songEvents)
|
|
||||||
{
|
|
||||||
toolboxEventsEventKind.dataSource.add({text: event.getTitle(), value: event.id});
|
|
||||||
}
|
|
||||||
|
|
||||||
toolboxEventsEventKind.onChange = function(event:UIEvent) {
|
toolboxEventsEventKind.onChange = function(event:UIEvent) {
|
||||||
var eventType:String = event.data.value;
|
var eventType:String = event.data.id;
|
||||||
|
|
||||||
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
|
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
|
||||||
|
|
||||||
|
@ -83,7 +74,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema);
|
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema, chartEditorState.eventKindToPlace);
|
||||||
|
|
||||||
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
|
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
|
||||||
{
|
{
|
||||||
|
@ -98,14 +89,40 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
chartEditorState.notePreviewDirty = true;
|
chartEditorState.notePreviewDirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toolboxEventsEventKind.value = chartEditorState.eventKindToPlace;
|
var startingEventValue = ChartEditorDropdowns.populateDropdownWithSongEvents(toolboxEventsEventKind, chartEditorState.eventKindToPlace);
|
||||||
|
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Starting event kind: ${startingEventValue}');
|
||||||
|
toolboxEventsEventKind.value = startingEventValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function refresh():Void
|
public override function refresh():Void
|
||||||
{
|
{
|
||||||
super.refresh();
|
super.refresh();
|
||||||
|
|
||||||
toolboxEventsEventKind.value = chartEditorState.eventKindToPlace;
|
var newDropdownElement = ChartEditorDropdowns.findDropdownElement(chartEditorState.eventKindToPlace, toolboxEventsEventKind);
|
||||||
|
|
||||||
|
if (newDropdownElement == null)
|
||||||
|
{
|
||||||
|
throw 'ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event kind not in dropdown: ${chartEditorState.eventKindToPlace}';
|
||||||
|
}
|
||||||
|
else if (toolboxEventsEventKind.value != newDropdownElement || lastEventKind != toolboxEventsEventKind.value.id)
|
||||||
|
{
|
||||||
|
toolboxEventsEventKind.value = newDropdownElement;
|
||||||
|
|
||||||
|
var schema:SongEventSchema = SongEventRegistry.getEventSchema(chartEditorState.eventKindToPlace);
|
||||||
|
if (schema == null)
|
||||||
|
{
|
||||||
|
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Unknown event kind: ${chartEditorState.eventKindToPlace}');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event kind changed: ${toolboxEventsEventKind.value.id} != ${newDropdownElement.id} != ${lastEventKind}, rebuilding form');
|
||||||
|
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema, chartEditorState.eventKindToPlace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event kind not changed: ${toolboxEventsEventKind.value} == ${newDropdownElement} == ${lastEventKind}');
|
||||||
|
}
|
||||||
|
|
||||||
for (pair in chartEditorState.eventDataToPlace.keyValueIterator())
|
for (pair in chartEditorState.eventDataToPlace.keyValueIterator())
|
||||||
{
|
{
|
||||||
|
@ -116,7 +133,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
|
|
||||||
if (field == null)
|
if (field == null)
|
||||||
{
|
{
|
||||||
throw 'ChartEditorToolboxHandler.refresh() - Field "${fieldId}" does not exist in the event data form.';
|
throw 'ChartEditorToolboxHandler.refresh() - Field "${fieldId}" does not exist in the event data form for kind ${lastEventKind}.';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -141,9 +158,15 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEventDataFormFromSchema(target:Box, schema:SongEventSchema):Void
|
var lastEventKind:String = 'unknown';
|
||||||
|
|
||||||
|
function buildEventDataFormFromSchema(target:Box, schema:SongEventSchema, eventKind:String):Void
|
||||||
{
|
{
|
||||||
trace(schema);
|
trace('Building event data form from schema for event kind: ${eventKind}');
|
||||||
|
// trace(schema);
|
||||||
|
|
||||||
|
lastEventKind = eventKind ?? 'unknown';
|
||||||
|
|
||||||
// Clear the frame.
|
// Clear the frame.
|
||||||
target.removeAllComponents();
|
target.removeAllComponents();
|
||||||
|
|
||||||
|
@ -188,6 +211,9 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
var dropDown:DropDown = new DropDown();
|
var dropDown:DropDown = new DropDown();
|
||||||
dropDown.id = field.name;
|
dropDown.id = field.name;
|
||||||
dropDown.width = 200.0;
|
dropDown.width = 200.0;
|
||||||
|
dropDown.dropdownSize = 10;
|
||||||
|
dropDown.dropdownWidth = 300;
|
||||||
|
dropDown.searchable = true;
|
||||||
dropDown.dataSource = new ArrayDataSource();
|
dropDown.dataSource = new ArrayDataSource();
|
||||||
|
|
||||||
if (field.keys == null) throw 'Field "${field.name}" is of Enum type but has no keys.';
|
if (field.keys == null) throw 'Field "${field.name}" is of Enum type but has no keys.';
|
||||||
|
@ -197,12 +223,15 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
for (optionName in field.keys.keys())
|
for (optionName in field.keys.keys())
|
||||||
{
|
{
|
||||||
var optionValue:Null<Dynamic> = 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});
|
||||||
}
|
}
|
||||||
|
|
||||||
dropDown.value = field.defaultValue;
|
dropDown.value = field.defaultValue;
|
||||||
|
|
||||||
|
// TODO: Add an option to customize sort.
|
||||||
|
dropDown.dataSource.sort('text', ASCENDING);
|
||||||
|
|
||||||
input = dropDown;
|
input = dropDown;
|
||||||
case STRING:
|
case STRING:
|
||||||
input = new TextField();
|
input = new TextField();
|
||||||
|
|
|
@ -3,11 +3,13 @@ package funkin.ui.debug.charting.util;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.play.notes.notestyle.NoteStyle;
|
import funkin.play.notes.notestyle.NoteStyle;
|
||||||
import funkin.data.stage.StageData;
|
import funkin.data.stage.StageData;
|
||||||
|
import funkin.play.event.SongEvent;
|
||||||
import funkin.data.stage.StageRegistry;
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
import haxe.ui.components.DropDown;
|
import haxe.ui.components.DropDown;
|
||||||
import funkin.play.stage.Stage;
|
import funkin.play.stage.Stage;
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
|
import funkin.data.event.SongEventRegistry;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,6 +83,42 @@ class ChartEditorDropdowns
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function populateDropdownWithSongEvents(dropDown:DropDown, startingEventId:String):DropDownEntry
|
||||||
|
{
|
||||||
|
dropDown.dataSource.clear();
|
||||||
|
|
||||||
|
var returnValue:DropDownEntry = {id: "FocusCamera", text: "Focus Camera"};
|
||||||
|
|
||||||
|
var songEvents:Array<SongEvent> = SongEventRegistry.listEvents();
|
||||||
|
|
||||||
|
for (event in songEvents)
|
||||||
|
{
|
||||||
|
var value = {id: event.id, text: event.getTitle()};
|
||||||
|
if (startingEventId == event.id) returnValue = value;
|
||||||
|
dropDown.dataSource.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropDown.dataSource.sort('text', ASCENDING);
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the ID of a dropdown element, find the corresponding entry in the dropdown's dataSource.
|
||||||
|
*/
|
||||||
|
public static function findDropdownElement(id:String, dropDown:DropDown):Null<DropDownEntry>
|
||||||
|
{
|
||||||
|
// Attempt to find the entry.
|
||||||
|
for (entryIndex in 0...dropDown.dataSource.size)
|
||||||
|
{
|
||||||
|
var entry = dropDown.dataSource.get(entryIndex);
|
||||||
|
if (entry.id == id) return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate a dropdown with a list of note styles.
|
* Populate a dropdown with a list of note styles.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue