Skip to content

Commit 49856e7

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

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
@@ -3345,8 +3345,14 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
33453345
menubarItemToggleToolboxEventData.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT, event.value);
33463346
menubarItemToggleToolboxFreeplay.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_FREEPLAY_LAYOUT, event.value);
33473347
menubarItemToggleToolboxPlaytestProperties.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT, event.value);
3348-
menubarItemToggleToolboxPlayerPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
3349-
menubarItemToggleToolboxOpponentPreview.onChange = event -> this.setToolboxState(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
3348+
menubarItemToggleToolboxPlayerPreview.onChange = event -> {
3349+
this.setToolboxState(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT, event.value);
3350+
playerPreviewDirty = event.value;
3351+
}
3352+
menubarItemToggleToolboxOpponentPreview.onChange = event -> {
3353+
this.setToolboxState(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT, event.value);
3354+
opponentPreviewDirty = event.value;
3355+
}
33503356

33513357
// TODO: Pass specific HaxeUI components to add context menus to them.
33523358
// registerContextMenu(null, Paths.ui('chart-editor/context/test'));
@@ -3669,7 +3675,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
36693675
var oldStepTime:Float = Conductor.instance.currentStepTime;
36703676
var oldSongPosition:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset;
36713677
updateSongTime();
3672-
handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
3678+
handleMusicPositionUpdate(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
36733679
// Resync vocals.
36743680
if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
36753681
{
@@ -3687,7 +3693,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
36873693
// Else, move the entire view.
36883694
var oldSongPosition:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset;
36893695
updateSongTime();
3690-
handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
3696+
handleMusicPositionUpdate(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset);
36913697
// Resync vocals.
36923698
if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
36933699
{
@@ -3904,7 +3910,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
39043910
// If a new event is needed, call buildEventSprite.
39053911
var eventSprite:ChartEditorEventSprite = renderedEvents.recycle(() -> new ChartEditorEventSprite(this), false, true);
39063912
eventSprite.parentState = this;
3907-
trace('Creating new Event... (${renderedEvents.members.length})');
3913+
// trace('Creating new Event... (${renderedEvents.members.length})');
39083914

39093915
if (eventData?.value != null && (eventData?.value?.ease != null && eventData?.value?.easeDir == null))
39103916
{
@@ -5392,8 +5398,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
53925398
function handleToolboxes():Void
53935399
{
53945400
handleDifficultyToolbox();
5395-
// handlePlayerPreviewToolbox();
5396-
// handleOpponentPreviewToolbox();
5401+
handlePlayerPreviewToolbox();
5402+
handleOpponentPreviewToolbox();
53975403
}
53985404

53995405
function handleDifficultyToolbox():Void
@@ -5416,15 +5422,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
54165422
function handlePlayerPreviewToolbox():Void
54175423
{
54185424
// Manage the Select Difficulty tree view.
5419-
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
5425+
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolboxUnCast(CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT);
54205426
if (charPreviewToolbox == null) return;
5421-
54225427
// TODO: Re-enable the player preview once we figure out the performance issues.
5423-
var charPlayer:Null<CharacterPlayer> = null; // charPreviewToolbox.findComponent('charPlayer');
5428+
var charPlayer:Null<CharacterPlayer> = charPreviewToolbox.findComponent('charPlayer');
54245429
if (charPlayer == null) return;
5425-
5426-
currentPlayerCharacterPlayer = charPlayer;
5427-
54285430
if (playerPreviewDirty)
54295431
{
54305432
playerPreviewDirty = false;
@@ -5442,28 +5444,28 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
54425444
charPlayer.targetScale = 0.5;
54435445

54445446
charPreviewToolbox.title = 'Player Preview - ${charPlayer.charName}';
5447+
charPreviewToolbox.invalidateComponentLayout();
54455448
}
54465449

54475450
if (charPreviewToolbox != null && !charPreviewToolbox.minimized)
54485451
{
54495452
charPreviewToolbox.width = charPlayer.width + 32;
54505453
charPreviewToolbox.height = charPlayer.height + 64;
54515454
}
5455+
currentPlayerCharacterPlayer = charPlayer;
54525456
}
54535457
}
54545458

54555459
function handleOpponentPreviewToolbox():Void
54565460
{
54575461
// Manage the Select Difficulty tree view.
5458-
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolbox_OLD(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
5462+
var charPreviewToolbox:Null<CollapsibleDialog> = this.getToolboxUnCast(CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT);
54595463
if (charPreviewToolbox == null) return;
54605464

54615465
// TODO: Re-enable the player preview once we figure out the performance issues.
5462-
var charPlayer:Null<CharacterPlayer> = null; // charPreviewToolbox.findComponent('charPlayer');
5466+
var charPlayer:Null<CharacterPlayer> = charPreviewToolbox.findComponent('charOpponent');
54635467
if (charPlayer == null) return;
54645468

5465-
currentOpponentCharacterPlayer = charPlayer;
5466-
54675469
if (opponentPreviewDirty)
54685470
{
54695471
opponentPreviewDirty = false;
@@ -5481,13 +5483,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
54815483
charPlayer.targetScale = 0.5;
54825484

54835485
charPreviewToolbox.title = 'Opponent Preview - ${charPlayer.charName}';
5486+
charPreviewToolbox.invalidateComponentLayout();
54845487
}
54855488

54865489
if (charPreviewToolbox != null && !charPreviewToolbox.minimized)
54875490
{
54885491
charPreviewToolbox.width = charPlayer.width + 32;
54895492
charPreviewToolbox.height = charPlayer.height + 64;
54905493
}
5494+
currentOpponentCharacterPlayer = charPlayer;
54915495
}
54925496
}
54935497

@@ -5745,32 +5749,40 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
57455749
/**
57465750
* Handle aligning the health icons next to the grid.
57475751
*/
5752+
var _charIconData = null;
5753+
5754+
@:access(funkin.play.character.BaseCharacter)
57485755
function handleHealthIcons():Void
57495756
{
57505757
if (healthIconsDirty)
57515758
{
5752-
var charDataBF = CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.player);
5753-
var charDataDad = CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.opponent);
5759+
_charIconData = currentPlayerCharacterPlayer?.character?._data ?? CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.player);
5760+
57545761
if (healthIconBF != null)
57555762
{
5756-
healthIconBF.configure(charDataBF?.healthIcon);
5763+
healthIconBF.configure(_charIconData?.healthIcon);
57575764
healthIconBF.size *= 0.5; // Make the icon smaller in Chart Editor.
57585765
healthIconBF.flipX = !healthIconBF.flipX; // BF faces the other way.
57595766
}
5767+
57605768
if (buttonSelectPlayer != null)
57615769
{
5762-
buttonSelectPlayer.text = charDataBF?.name ?? 'Player';
5770+
buttonSelectPlayer.text = _charIconData?.name ?? 'Player';
57635771
}
5772+
5773+
_charIconData = currentOpponentCharacterPlayer?.character?._data ?? CharacterDataParser.fetchCharacterData(currentSongMetadata.playData.characters.opponent);
5774+
57645775
if (healthIconDad != null)
57655776
{
5766-
healthIconDad.configure(charDataDad?.healthIcon);
5777+
healthIconDad.configure(_charIconData?.healthIcon);
57675778
healthIconDad.size *= 0.5; // Make the icon smaller in Chart Editor.
57685779
}
57695780
if (buttonSelectOpponent != null)
57705781
{
5771-
buttonSelectOpponent.text = charDataDad?.name ?? 'Opponent';
5782+
buttonSelectOpponent.text = _charIconData?.name ?? 'Opponent';
57725783
}
57735784
healthIconsDirty = false;
5785+
_charIconData = null;
57745786
}
57755787

57765788
// Right align, and visibly center, the BF health icon.
@@ -6818,9 +6830,20 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
68186830
/**
68196831
* Handle the playback of hitsounds.
68206832
*/
6821-
function handleHitsounds(oldSongPosition:Float, newSongPosition:Float):Void
6833+
var _scriptNoteObj:NoteSprite = null;
6834+
6835+
var _noteScriptEvent:NoteScriptEvent = null;
6836+
6837+
var _currentEvents = null;
6838+
var _allowedEvents = null;
6839+
var _eventTarget:Null<CharacterPlayer> = null;
6840+
6841+
public static var _allowedEventsNames:Array<String> = ['PlayAnimation'];
6842+
6843+
function handleMusicPositionUpdate(oldSongPosition:Float, newSongPosition:Float):Void
68226844
{
6823-
if (!hitsoundsEnabled) return;
6845+
_currentEvents = SongDataUtils.getEventsInTimeRange(currentSongChartEventData, oldSongPosition, newSongPosition);
6846+
_allowedEvents = SongDataUtils.getEventsWithKind(_currentEvents, _allowedEventsNames);
68246847

68256848
// Assume notes are sorted by time.
68266849
for (noteData in currentSongChartNoteData)
@@ -6830,32 +6853,66 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
68306853
if (noteData.time < oldSongPosition) // Note is in the past.
68316854
continue;
68326855

6833-
if (noteData.time > newSongPosition) // Note is in the future.
6834-
return; // Assume all notes are also in the future.
6856+
if (noteData.time > newSongPosition) break;
68356857

6836-
// Note was just hit.
6858+
/**
6859+
* We hit a note.
6860+
* We're gonna create scripted event and dispatch it al over ChartEditor.
6861+
*/
6862+
_scriptNoteObj = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
6863+
_scriptNoteObj.noteData = noteData;
6864+
_scriptNoteObj.kill();
6865+
_scriptNoteObj.direction = _scriptNoteObj.noteData?.getDirection() ?? 0;
6866+
_scriptNoteObj.scrollFactor.set();
68376867

6838-
// Character preview.
6839-
6840-
// NoteScriptEvent takes a sprite, ehe. Need to rework that.
6841-
var tempNote:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
6842-
tempNote.noteData = noteData;
6843-
tempNote.scrollFactor.set(0, 0);
6844-
var event:NoteScriptEvent = new HitNoteScriptEvent(tempNote, 0.0, 0, 'perfect', false, 0);
6845-
dispatchEvent(event);
6868+
_noteScriptEvent = new HitNoteScriptEvent(_scriptNoteObj, 0.0, 0, (noteData.getStrumlineIndex() == 0 ? 'perfect' : 'sick'), false, 0);
6869+
dispatchEvent(_noteScriptEvent);
68466870

68476871
// Calling event.cancelEvent() skips all the other logic! Neat!
6848-
if (event.eventCanceled) continue;
6872+
if (_noteScriptEvent.eventCanceled)
6873+
{
6874+
_scriptNoteObj.destroy();
6875+
_scriptNoteObj = null;
6876+
6877+
_noteScriptEvent = null;
6878+
6879+
continue;
6880+
}
68496881

68506882
// Hitsounds.
6851-
switch (noteData.getStrumlineIndex())
6883+
if (hitsoundsEnabled) switch (noteData.getStrumlineIndex())
68526884
{
68536885
case 0: // Player
68546886
if (hitsoundVolumePlayer > 0) this.playSound(Paths.sound('chartingSounds/hitNotePlayer'), hitsoundVolumePlayer);
68556887
case 1: // Opponent
68566888
if (hitsoundVolumeOpponent > 0) this.playSound(Paths.sound('chartingSounds/hitNoteOpponent'), hitsoundVolumeOpponent);
68576889
}
68586890
}
6891+
// Clearing memory before next event call.
6892+
_scriptNoteObj?.destroy();
6893+
_scriptNoteObj = null;
6894+
6895+
_noteScriptEvent = null;
6896+
for (data in _allowedEvents)
6897+
{
6898+
switch (data.eventKind)
6899+
{
6900+
case "PlayAnimation":
6901+
switch (data.getString('target').toLowerCase().trim())
6902+
{
6903+
case 'boyfriend' | 'bf' | 'player':
6904+
_eventTarget = currentPlayerCharacterPlayer;
6905+
case 'dad' | 'opponent' | 'enemy':
6906+
_eventTarget = currentOpponentCharacterPlayer;
6907+
default:
6908+
}
6909+
if (_eventTarget != null) _eventTarget.playAnimManually(data.getString('anim') ?? 'idle', data.getBool('force') ?? false);
6910+
}
6911+
}
6912+
6913+
_currentEvents = null;
6914+
_allowedEvents.resize(0);
6915+
_eventTarget = null;
68596916
}
68606917

68616918
function stopAudioPlayback():Void
@@ -6925,6 +6982,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
69256982

69266983
// Many things get reset when song length changes.
69276984
healthIconsDirty = true;
6985+
playerPreviewDirty = true;
6986+
opponentPreviewDirty = true;
69286987
}
69296988

69306989
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)