mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-22 15:48: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
|
||||
- Bug where Dadbattle shows up as Dadbattle Erect when returning to freeplay
|
||||
- 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
|
||||
### 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!)
|
||||
- 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.
|
||||
- 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 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 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!)
|
||||
- Optimized animation handling for characters (thanks richTrash21!)
|
||||
- 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.
|
||||
if (_lostFocus && !_alreadyPaused)
|
||||
{
|
||||
trace('Resuming audio (${this._label}) on focus!');
|
||||
// trace('Resuming audio (${this._label}) on focus!');
|
||||
resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('Not resuming audio (${this._label}) on focus!');
|
||||
// trace('Not resuming audio (${this._label}) on focus!');
|
||||
}
|
||||
_lostFocus = false;
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
|||
*/
|
||||
override function onFocusLost():Void
|
||||
{
|
||||
trace('Focus lost, pausing audio!');
|
||||
// trace('Focus lost, pausing audio!');
|
||||
_lostFocus = true;
|
||||
_alreadyPaused = _paused;
|
||||
pause();
|
||||
|
|
|
@ -237,7 +237,7 @@ class GameOverSubState extends MusicBeatSubState
|
|||
}
|
||||
|
||||
// KEYBOARD ONLY: Restart the level when pressing the assigned key.
|
||||
if (controls.ACCEPT && blueballed)
|
||||
if (controls.ACCEPT && blueballed && !mustNotExit)
|
||||
{
|
||||
blueballed = false;
|
||||
confirmDeath();
|
||||
|
|
|
@ -53,8 +53,9 @@ class HealthIcon extends FunkinSprite
|
|||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -904,7 +904,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
|
||||
function set_notePreviewDirty(value:Bool):Bool
|
||||
{
|
||||
trace('Note preview dirtied!');
|
||||
// trace('Note preview dirtied!');
|
||||
return notePreviewDirty = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,15 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -201,7 +201,8 @@ class ChartEditorThemeHandler
|
|||
// Selection borders horizontally in the middle.
|
||||
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,
|
||||
GRID_BEAT_DIVIDER_WIDTH),
|
||||
|
|
|
@ -58,17 +58,8 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
|||
|
||||
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) {
|
||||
var eventType:String = event.data.value;
|
||||
var eventType:String = event.data.id;
|
||||
|
||||
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
|
||||
|
||||
|
@ -83,7 +74,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
|||
return;
|
||||
}
|
||||
|
||||
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema);
|
||||
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema, chartEditorState.eventKindToPlace);
|
||||
|
||||
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
|
||||
{
|
||||
|
@ -98,14 +89,40 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
|||
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
|
||||
{
|
||||
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())
|
||||
{
|
||||
|
@ -116,7 +133,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
|||
|
||||
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
|
||||
{
|
||||
|
@ -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.
|
||||
target.removeAllComponents();
|
||||
|
||||
|
@ -188,6 +211,9 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
|||
var dropDown:DropDown = new DropDown();
|
||||
dropDown.id = field.name;
|
||||
dropDown.width = 200.0;
|
||||
dropDown.dropdownSize = 10;
|
||||
dropDown.dropdownWidth = 300;
|
||||
dropDown.searchable = true;
|
||||
dropDown.dataSource = new ArrayDataSource();
|
||||
|
||||
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())
|
||||
{
|
||||
var optionValue:Null<Dynamic> = field.keys.get(optionName);
|
||||
trace('$optionName : $optionValue');
|
||||
// trace('$optionName : $optionValue');
|
||||
dropDown.dataSource.add({value: optionValue, text: optionName});
|
||||
}
|
||||
|
||||
dropDown.value = field.defaultValue;
|
||||
|
||||
// TODO: Add an option to customize sort.
|
||||
dropDown.dataSource.sort('text', ASCENDING);
|
||||
|
||||
input = dropDown;
|
||||
case STRING:
|
||||
input = new TextField();
|
||||
|
|
|
@ -3,11 +3,13 @@ package funkin.ui.debug.charting.util;
|
|||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.play.notes.notestyle.NoteStyle;
|
||||
import funkin.data.stage.StageData;
|
||||
import funkin.play.event.SongEvent;
|
||||
import funkin.data.stage.StageRegistry;
|
||||
import funkin.play.character.CharacterData;
|
||||
import haxe.ui.components.DropDown;
|
||||
import funkin.play.stage.Stage;
|
||||
import funkin.play.character.BaseCharacter.CharacterType;
|
||||
import funkin.data.event.SongEventRegistry;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
|
||||
/**
|
||||
|
@ -81,6 +83,42 @@ class ChartEditorDropdowns
|
|||
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.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue