Skip to content

Commit 46f6695

Browse files
PurSnakeComedyLost
authored andcommitted
Chart Editor Character previews
Co-Authored-By: ComedyLost <[email protected]>
1 parent c39046d commit 46f6695

File tree

5 files changed

+142
-63
lines changed

5 files changed

+142
-63
lines changed

source/funkin/ui/debug/charting/ChartEditorState.hx

Lines changed: 97 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3326,8 +3326,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
33263326
menubarItemToggleToolboxEventData.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT, event.value);
33273327
menubarItemToggleToolboxFreeplay.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_FREEPLAY_LAYOUT, event.value);
33283328
menubarItemToggleToolboxPlaytestProperties.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT, event.value);
3329-
menubarItemToggleToolboxPlayerPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
3330-
menubarItemToggleToolboxOpponentPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
3329+
menubarItemToggleToolboxPlayerPreview.onChange = event -> {
3330+
this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
3331+
playerPreviewDirty = event.value;
3332+
}
3333+
menubarItemToggleToolboxOpponentPreview.onChange = event -> {
3334+
this.setToolboxState(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
3335+
opponentPreviewDirty = event.value;
3336+
}
33313337

33323338
// TODO: Pass specific HaxeUI components to add context menus to them.
33333339
// registerContextMenu(null, Paths.ui('chart-editor/context/test'));
@@ -3650,7 +3656,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
36503656
var oldStepTime:Float = Conductor.instance.currentStepTime;
36513657
var oldSongPosition:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset;
36523658
updateSongTime();
3653-
handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
3659+
handleMusicPositionUpdate(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
36543660
// Resync vocals.
36553661
if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
36563662
{
@@ -3668,7 +3674,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
36683674
// Else, move the entire view.
36693675
var oldSongPosition:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset;
36703676
updateSongTime();
3671-
handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
3677+
handleMusicPositionUpdate(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
36723678
// Resync vocals.
36733679
if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
36743680
{
@@ -3885,7 +3891,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
38853891
// If a new event is needed, call buildEventSprite.
38863892
var eventSprite:ChartEditorEventSprite = renderedEvents.recycle(() -> new ChartEditorEventSprite(this), false, true);
38873893
eventSprite.parentState = this;
3888-
trace('Creating new Event... (${renderedEvents.members.length})');
3894+
// trace('Creating new Event... (${renderedEvents.members.length})');
38893895

38903896
if (eventData?.value != null && (eventData?.value?.ease != null && eventData?.value?.easeDir == null))
38913897
{
@@ -5373,8 +5379,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
53735379
function handleToolboxes():Void
53745380
{
53755381
handleDifficultyToolbox();
5376-
// handlePlayerPreviewToolbox();
5377-
// handleOpponentPreviewToolbox();
5382+
handlePlayerPreviewToolbox();
5383+
handleOpponentPreviewToolbox();
53785384
}
53795385

53805386
function handleDifficultyToolbox():Void
@@ -5397,15 +5403,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
53975403
function handlePlayerPreviewToolbox():Void
53985404
{
53995405
// Manage the Select Difficulty tree view.
5400-
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
5406+
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolboxUnCast(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
54015407
if (charPreviewToolbox == null) return;
5402-
54035408
// TODO: Re-enable the player preview once we figure out the performance issues.
5404-
var charPlayer:Null<CharacterPlayer> = null; // charPreviewToolbox.findComponent('charPlayer');
5409+
var charPlayer:Null<CharacterPlayer> = charPreviewToolbox.findComponent('charPlayer');
54055410
if (charPlayer == null) return;
5406-
5407-
currentPlayerCharacterPlayer = charPlayer;
5408-
54095411
if (playerPreviewDirty)
54105412
{
54115413
playerPreviewDirty = false;
@@ -5423,28 +5425,28 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
54235425
charPlayer.targetScale = 0.5;
54245426

54255427
charPreviewToolbox.title = 'Player Preview - ${charPlayer.charName}';
5428+
charPreviewToolbox.invalidateComponentLayout();
54265429
}
54275430

54285431
if (charPreviewToolbox != null && !charPreviewToolbox.minimized)
54295432
{
54305433
charPreviewToolbox.width = charPlayer.width + 32;
54315434
charPreviewToolbox.height = charPlayer.height + 64;
54325435
}
5436+
currentPlayerCharacterPlayer = charPlayer;
54335437
}
54345438
}
54355439

54365440
function handleOpponentPreviewToolbox():Void
54375441
{
54385442
// Manage the Select Difficulty tree view.
5439-
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
5443+
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolboxUnCast(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
54405444
if (charPreviewToolbox == null) return;
54415445

54425446
// TODO: Re-enable the player preview once we figure out the performance issues.
5443-
var charPlayer:Null<CharacterPlayer> = null; // charPreviewToolbox.findComponent('charPlayer');
5447+
var charPlayer:Null<CharacterPlayer> = charPreviewToolbox.findComponent('charOpponent');
54445448
if (charPlayer == null) return;
54455449

5446-
currentOpponentCharacterPlayer = charPlayer;
5447-
54485450
if (opponentPreviewDirty)
54495451
{
54505452
opponentPreviewDirty = false;
@@ -5462,13 +5464,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
54625464
charPlayer.targetScale = 0.5;
54635465

54645466
charPreviewToolbox.title = 'Opponent Preview - ${charPlayer.charName}';
5467+
charPreviewToolbox.invalidateComponentLayout();
54655468
}
54665469

54675470
if (charPreviewToolbox != null && !charPreviewToolbox.minimized)
54685471
{
54695472
charPreviewToolbox.width = charPlayer.width + 32;
54705473
charPreviewToolbox.height = charPlayer.height + 64;
54715474
}
5475+
currentOpponentCharacterPlayer = charPlayer;
54725476
}
54735477
}
54745478

@@ -5726,32 +5730,40 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
57265730
/**
57275731
* Handle aligning the health icons next to the grid.
57285732
*/
5733+
var _charIconData = null;
5734+
5735+
@:access(funkin.play.character.BaseCharacter)
57295736
function handleHealthIcons():Void
57305737
{
57315738
if (healthIconsDirty)
57325739
{
5733-
var charDataBF = CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.player);
5734-
var charDataDad = CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.opponent);
5740+
_charIconData = currentPlayerCharacterPlayer?.character?._data ?? CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.player);
5741+
57355742
if (healthIconBF != null)
57365743
{
5737-
healthIconBF.configure(charDataBF?.healthIcon);
5744+
healthIconBF.configure(_charIconData?.healthIcon);
57385745
healthIconBF.size *= 0.5; // Make the icon smaller in Chart Editor.
57395746
healthIconBF.flipX = !healthIconBF.flipX; // BF faces the other way.
57405747
}
5748+
57415749
if (buttonSelectPlayer != null)
57425750
{
5743-
buttonSelectPlayer.text = charDataBF?.name ?? 'Player';
5751+
buttonSelectPlayer.text = _charIconData?.name ?? 'Player';
57445752
}
5753+
5754+
_charIconData = currentOpponentCharacterPlayer?.character?._data ?? CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.opponent);
5755+
57455756
if (healthIconDad != null)
57465757
{
5747-
healthIconDad.configure(charDataDad?.healthIcon);
5758+
healthIconDad.configure(_charIconData?.healthIcon);
57485759
healthIconDad.size *= 0.5; // Make the icon smaller in Chart Editor.
57495760
}
57505761
if (buttonSelectOpponent != null)
57515762
{
5752-
buttonSelectOpponent.text = charDataDad?.name ?? 'Opponent';
5763+
buttonSelectOpponent.text = _charIconData?.name ?? 'Opponent';
57535764
}
57545765
healthIconsDirty = false;
5766+
_charIconData = null;
57555767
}
57565768

57575769
// Right align, and visibly center, the BF health icon.
@@ -6799,9 +6811,20 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
67996811
/**
68006812
* Handle the playback of hitsounds.
68016813
*/
6802-
function handleHitsounds(oldSongPosition:Float, newSongPosition:Float):Void
6814+
var _scriptNoteObj:NoteSprite = null;
6815+
6816+
var _noteScriptEvent:NoteScriptEvent = null;
6817+
6818+
var _currentEvents = null;
6819+
var _allowedEvents = null;
6820+
var _eventTarget:Null<CharacterPlayer> = null;
6821+
6822+
public static var _allowedEventsNames:Array<String> = ['PlayAnimation'];
6823+
6824+
function handleMusicPositionUpdate(oldSongPosition:Float, newSongPosition:Float):Void
68036825
{
6804-
if (!hitsoundsEnabled) return;
6826+
_currentEvents = SongDataUtils.getEventsInTimeRange(currentSongChartEventData, oldSongPosition, newSongPosition);
6827+
_allowedEvents = SongDataUtils.getEventsWithKind(_currentEvents, _allowedEventsNames);
68056828

68066829
// Assume notes are sorted by time.
68076830
for (noteData in currentSongChartNoteData)
@@ -6811,32 +6834,66 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
68116834
if (noteData.time < oldSongPosition) // Note is in the past.
68126835
continue;
68136836

6814-
if (noteData.time > newSongPosition) // Note is in the future.
6815-
return; // Assume all notes are also in the future.
6837+
if (noteData.time > newSongPosition) break;
68166838

6817-
// Note was just hit.
6839+
/**
6840+
* We hit a note.
6841+
* We're gonna create scripted event and dispatch it al over ChartEditor.
6842+
*/
6843+
_scriptNoteObj = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
6844+
_scriptNoteObj.noteData = noteData;
6845+
_scriptNoteObj.kill();
6846+
_scriptNoteObj.direction = _scriptNoteObj.noteData?.getDirection() ?? 0;
6847+
_scriptNoteObj.scrollFactor.set();
68186848

6819-
// Character preview.
6820-
6821-
// NoteScriptEvent takes a sprite, ehe. Need to rework that.
6822-
var tempNote:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
6823-
tempNote.noteData = noteData;
6824-
tempNote.scrollFactor.set(0, 0);
6825-
var event:NoteScriptEvent = new HitNoteScriptEvent(tempNote, 0.0, 0, 'perfect', false, 0);
6826-
dispatchEvent(event);
6849+
_noteScriptEvent = new HitNoteScriptEvent(_scriptNoteObj, 0.0, 0, (noteData.getStrumlineIndex() == 0 ? 'perfect' : 'sick'), false, 0);
6850+
dispatchEvent(_noteScriptEvent);
68276851

68286852
// Calling event.cancelEvent() skips all the other logic! Neat!
6829-
if (event.eventCanceled) continue;
6853+
if (_noteScriptEvent.eventCanceled)
6854+
{
6855+
_scriptNoteObj.destroy();
6856+
_scriptNoteObj = null;
6857+
6858+
_noteScriptEvent = null;
6859+
6860+
continue;
6861+
}
68306862

68316863
// Hitsounds.
6832-
switch (noteData.getStrumlineIndex())
6864+
if (hitsoundsEnabled) switch (noteData.getStrumlineIndex())
68336865
{
68346866
case 0: // Player
68356867
if (hitsoundVolumePlayer > 0) this.playSound(Paths.sound('chartingSounds/hitNotePlayer'), hitsoundVolumePlayer);
68366868
case 1: // Opponent
68376869
if (hitsoundVolumeOpponent > 0) this.playSound(Paths.sound('chartingSounds/hitNoteOpponent'), hitsoundVolumeOpponent);
68386870
}
68396871
}
6872+
// Clearing memory before next event call.
6873+
_scriptNoteObj?.destroy();
6874+
_scriptNoteObj = null;
6875+
6876+
_noteScriptEvent = null;
6877+
for (data in _allowedEvents)
6878+
{
6879+
switch (data.eventKind)
6880+
{
6881+
case "PlayAnimation":
6882+
switch (data.getString('target').toLowerCase().trim())
6883+
{
6884+
case 'boyfriend' | 'bf' | 'player':
6885+
_eventTarget = currentPlayerCharacterPlayer;
6886+
case 'dad' | 'opponent' | 'enemy':
6887+
_eventTarget = currentOpponentCharacterPlayer;
6888+
default:
6889+
}
6890+
if (_eventTarget != null) _eventTarget.playAnimManually(data.getString('anim') ?? 'idle', data.getBool('force') ?? false);
6891+
}
6892+
}
6893+
6894+
_currentEvents = null;
6895+
_allowedEvents.resize(0);
6896+
_eventTarget = null;
68406897
}
68416898

68426899
function stopAudioPlayback():Void
@@ -6906,6 +6963,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
69066963

69076964
// Many things get reset when song length changes.
69086965
healthIconsDirty = true;
6966+
playerPreviewDirty = true;
6967+
opponentPreviewDirty = true;
69096968
}
69106969

69116970
public function loadSubtitles():Void

source/funkin/ui/debug/charting/dialogs/ChartEditorCharacterIconSelectorMenu.hx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,19 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
116116
charButton.onClick = _ -> {
117117
switch (charType)
118118
{
119-
case BF: chartEditorState.currentSongMetadata.playData.characters.player = charId;
119+
case BF:
120+
chartEditorState.currentSongMetadata.playData.characters.player = charId;
121+
chartEditorState.playerPreviewDirty = true;
120122
case GF: chartEditorState.currentSongMetadata.playData.characters.girlfriend = charId;
121-
case DAD: chartEditorState.currentSongMetadata.playData.characters.opponent = charId;
123+
case DAD:
124+
chartEditorState.currentSongMetadata.playData.characters.opponent = charId;
125+
chartEditorState.opponentPreviewDirty = true;
122126
default: throw 'Invalid charType: ' + charType;
123127
};
124128

125129
defaultText = (charId != "") ? '${charData.name} [${charId}]' : 'None';
126130
chartEditorState.healthIconsDirty = true;
131+
127132
chartEditorState.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
128133
};
129134

source/funkin/ui/debug/charting/handlers/ChartEditorToolboxHandler.hx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,14 @@ class ChartEditorToolboxHandler
204204
* @param id The asset ID of the toolbox layout.
205205
* @return The toolbox.
206206
*/
207-
public static function getToolbox_OLD(state:ChartEditorState, id:String):Null<CollapsibleDialog>
207+
public static function getToolboxUnCast(state:ChartEditorState, id:String):Null<CollapsibleDialog>
208208
{
209209
var toolbox:Null<CollapsibleDialog> = state.activeToolboxes.get(id);
210210

211211
// Initialize the toolbox without showing it.
212212
if (toolbox == null) toolbox = initToolbox(state, id);
213213

214-
if (toolbox == null) throw 'ChartEditorToolboxHandler.getToolbox_OLD() - Could not retrieve or build toolbox: $id';
214+
if (toolbox == null) throw 'ChartEditorToolboxHandler.getToolboxUnCast() - Could not retrieve or build toolbox: $id';
215215

216216
return toolbox;
217217
}
@@ -346,8 +346,8 @@ class ChartEditorToolboxHandler
346346
if (toolbox == null) return null;
347347

348348
// Starting position.
349-
toolbox.x = 200;
350-
toolbox.y = 350;
349+
toolbox.x = 700;
350+
toolbox.y = 150;
351351

352352
toolbox.onDialogClosed = function(event:DialogEvent) {
353353
state.menubarItemToggleToolboxPlayerPreview.selected = false;
@@ -376,14 +376,14 @@ class ChartEditorToolboxHandler
376376

377377
// Starting position.
378378
toolbox.x = 200;
379-
toolbox.y = 350;
379+
toolbox.y = 150;
380380

381381
toolbox.onDialogClosed = (event:DialogEvent) -> {
382382
state.menubarItemToggleToolboxOpponentPreview.selected = false;
383383
}
384384

385-
var charPlayer:Null<CharacterPlayer> = toolbox.findComponent('charPlayer');
386-
if (charPlayer == null) throw 'ChartEditorToolboxHandler.buildToolboxOpponentPreviewLayout() - Could not find charPlayer component.';
385+
var charPlayer:Null<CharacterPlayer> = toolbox.findComponent('charOpponent');
386+
if (charPlayer == null) throw 'ChartEditorToolboxHandler.buildToolboxOpponentPreviewLayout() - Could not find charOpponent component.';
387387
// TODO: We need to implement character swapping in ChartEditorState.
388388
charPlayer.loadCharacter('dad');
389389
charPlayer.characterType = CharacterType.DAD;

source/funkin/ui/debug/charting/toolboxes/ChartEditorDifficultyToolbox.hx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ class ChartEditorDifficultyToolbox extends ChartEditorBaseToolbox
142142
{
143143
chartEditorState.currentSongMetadata = songMetadata;
144144
chartEditorState.healthIconsDirty = true;
145+
chartEditorState.playerPreviewDirty = true;
146+
chartEditorState.opponentPreviewDirty = true;
147+
145148
chartEditorState.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_METADATA_LAYOUT);
146149
chartEditorState.success('Replaced Metadata', 'Replaced metadata with file (${fileReference.name})');
147150
}

0 commit comments

Comments
 (0)