@@ -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
0 commit comments