From bb5ad66313a915db2880786005f4a08ff0e5a267 Mon Sep 17 00:00:00 2001 From: lunarcleint <88809950+lunarcleint@users.noreply.github.com> Date: Sat, 23 Mar 2024 06:34:03 -0700 Subject: [PATCH] psych engine exporter Co-authored-by: Ne_Eo --- .../funkin/backend/chart/FNFLegacyParser.hx | 6 +- source/funkin/backend/chart/PsychParser.hx | 89 +++++++++++++++++++ source/funkin/editors/charter/Charter.hx | 16 ++-- 3 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 source/funkin/backend/chart/PsychParser.hx diff --git a/source/funkin/backend/chart/FNFLegacyParser.hx b/source/funkin/backend/chart/FNFLegacyParser.hx index c962ec0a..279e174c 100644 --- a/source/funkin/backend/chart/FNFLegacyParser.hx +++ b/source/funkin/backend/chart/FNFLegacyParser.hx @@ -152,9 +152,7 @@ class FNFLegacyParser { if (base.player2 == null) base.player2 = strumLine.characters.getDefault(["dad"])[0]; case PLAYER: if (base.player1 == null) base.player1 = strumLine.characters.getDefault(["bf"])[0]; - case ADDITIONAL: - // if (base.gf == null || base.gfVersion == null) - // base.gf = base.gfVersion = strumLine.characters.getDefault(["gf"])[0]; + case ADDITIONAL: // do nothing } return base; @@ -205,6 +203,7 @@ typedef SwagSong = var speed:Float; var ?stage:String; var ?noteTypes:Array; + var ?events:Array; var player1:String; var player2:String; @@ -224,6 +223,7 @@ typedef SwagSection = var lengthInSteps:Int; var ?typeOfSection:Int; var mustHitSection:Bool; + var ?gfSection:Bool; var bpm:Float; var changeBPM:Bool; var altAnim:Null; diff --git a/source/funkin/backend/chart/PsychParser.hx b/source/funkin/backend/chart/PsychParser.hx new file mode 100644 index 00000000..1d718a84 --- /dev/null +++ b/source/funkin/backend/chart/PsychParser.hx @@ -0,0 +1,89 @@ +package funkin.backend.chart; + +import funkin.backend.chart.ChartData.ChartEvent; +import funkin.backend.chart.FNFLegacyParser.SwagSong; +import funkin.backend.system.Conductor; + +class PsychParser { + public static function parse(data:Dynamic, result:ChartData) + FNFLegacyParser.parse(data, result); + + public static function encode(chart:ChartData):Dynamic { + var base:SwagSong = FNFLegacyParser.__convertToSwagSong(chart); + base.notes = FNFLegacyParser.__convertToSwagSections(chart); + base.stage = chart.stage; + + for (strumLine in chart.strumLines) + if (strumLine.type == ADDITIONAL && base.gfVersion == null) + base.gfVersion = strumLine.characters.getDefault(["gf"])[0]; + + for (strumLine in chart.strumLines) + for (note in strumLine.notes) { + var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength()); + if (section > 0 && section < base.notes.length) + base.notes[section].sectionNotes.push([ + note.time, // TIME + note.id + (strumLine.type == PLAYER ? 3 : 0), // DATA + note.sLen, // SUSTAIN LENGTH + chart.noteTypes.getDefault([""])[note.type] // NOTE TYPE + ]); + } + + base.events = []; + + var groupedEvents:Array> = []; + var __last:Array = null; + var __lastTime:Float = Math.NaN; + for (e in chart.events) { + if (e == null) continue; + if (__last != null && __lastTime == e.time) + __last.push(e); + else { + __last = [e]; + __lastTime = e.time; + groupedEvents.push(__last); + } + } + + for (events in groupedEvents) { + var psychEvents:Array = []; + for (event in events) + switch (event.name) { + case "Add Camera Zoom": + psychEvents.push([ + event.name, + event.params[1] == "camGame" ? event.params[0] : 0, // CAMERA ZOOM + event.params[1] == "camHUD" ? event.params[0] : 0, // UI ZOOM + ]); + case "Play Animation": + psychEvents.push([ + event.name, + event.params[1], // ANIMATION TO PLAY + switch (chart.strumLines[event.params[0]].type) { // CHARACTER + case PLAYER: "bf"; + case OPPONENT: "dad"; + case ADDITIONAL: "gf"; + } + ]); + case "Scroll Speed Change": + var eventStep:Float = Conductor.getStepForTime(event.time); + psychEvents.push([ + "Change Scroll Speed", + event.params[1]/chart.scrollSpeed, // SCROLL SPEED MULTIPLER + Conductor.getTimeForStep(eventStep+event.params[2]) - Conductor.getTimeForStep(eventStep), // TIME + ]); + default: + // TODO: allow custom formats in event.json + var split:Float = event.params.length / 2; + + var val1:String = [for (arg in 0...Math.ceil(split)) event.params[arg]].join(","); + var val2:String = [for (arg in Math.ceil(split)...event.params.length) event.params[arg]].join(","); + + psychEvents.push([event.name, val1, val2]); + } + base.events.push([events[0].time, psychEvents]); + } + + return {song: base}; + } +} diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx index 59be523c..72bfd3e0 100644 --- a/source/funkin/editors/charter/Charter.hx +++ b/source/funkin/editors/charter/Charter.hx @@ -1293,7 +1293,7 @@ class Charter extends UIState { } function _file_saveas(_) { - openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false)), { + openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false), null, Options.editorPrettyPrint ? "\t" : null), { defaultSaveFile: '${__diff.toLowerCase()}.json' })); undos.save(); @@ -1309,7 +1309,7 @@ class Charter extends UIState { } function _file_saveas_no_events(_) { - openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false)), { + openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false), null, Options.editorPrettyPrint ? "\t" : null), { defaultSaveFile: '${__diff.toLowerCase()}.json' })); undos.save(); @@ -1333,17 +1333,21 @@ class Charter extends UIState { } function _file_saveas_fnflegacy(_) { - openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), Options.editorPrettyPrint ? "\t" : null), { + openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), { + defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json', + })); + } + function _file_saveas_psych(_) { + openSubState(new SaveSubstate(Json.stringify(PsychParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), { defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json', })); } - function _file_saveas_psych(_) {} function _file_events_save(_) { #if sys CoolUtil.safeSaveFile( '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/events.json', - Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}) + Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null) ); #else _file_events_saveas(_); @@ -1352,7 +1356,7 @@ class Charter extends UIState { function _file_events_saveas(_) { #if sys - openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}), { + openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null), { defaultSaveFile: 'events.json' })); #end