From 217cade22c13d0e8971c28c0c627ea93f2e89a7e Mon Sep 17 00:00:00 2001 From: lunarcleint <88809950+lunarcleint@users.noreply.github.com> Date: Sat, 23 Mar 2024 05:08:53 -0700 Subject: [PATCH] Exporting to other engines wip --- source/funkin/backend/chart/Chart.hx | 3 +- .../{BaseGameParser.hx => FNFLegacyParser.hx} | 99 +++++++++++++++++-- source/funkin/editors/charter/Charter.hx | 16 +++ 3 files changed, 111 insertions(+), 7 deletions(-) rename source/funkin/backend/chart/{BaseGameParser.hx => FNFLegacyParser.hx} (52%) diff --git a/source/funkin/backend/chart/Chart.hx b/source/funkin/backend/chart/Chart.hx index 0b5dffab..a1376e82 100644 --- a/source/funkin/backend/chart/Chart.hx +++ b/source/funkin/backend/chart/Chart.hx @@ -1,5 +1,6 @@ package funkin.backend.chart; +import funkin.backend.system.Conductor; import funkin.backend.chart.ChartData; import flixel.util.FlxColor; import haxe.io.Path; @@ -143,7 +144,7 @@ class Chart { base = data; } else { // base game chart - BaseGameParser.parse(data, base); + FNFLegacyParser.parse(data, base); } #end } diff --git a/source/funkin/backend/chart/BaseGameParser.hx b/source/funkin/backend/chart/FNFLegacyParser.hx similarity index 52% rename from source/funkin/backend/chart/BaseGameParser.hx rename to source/funkin/backend/chart/FNFLegacyParser.hx index 9d017621..c962ec0a 100644 --- a/source/funkin/backend/chart/BaseGameParser.hx +++ b/source/funkin/backend/chart/FNFLegacyParser.hx @@ -1,6 +1,9 @@ package funkin.backend.chart; -class BaseGameParser { +import funkin.backend.chart.ChartData.ChartEvent; +import funkin.backend.system.Conductor; + +class FNFLegacyParser { public static function parse(data:Dynamic, result:ChartData) { // base fnf chart parsing var data:SwagSong = data; @@ -109,7 +112,90 @@ class BaseGameParser { curTime += curCrochet * beatsPerMeasure; } } + + // have conductor set up BEFORE you run this :D -lunar + public static function encode(chart:ChartData):Dynamic { + var base:SwagSong = __convertToSwagSong(chart); + base.notes = __convertToSwagSections(chart); + + 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 + ]); + } + + return {song: base}; + } + + // To make it easier to write the psych parser... -lunar + @:noCompletion public static function __convertToSwagSong(chart:ChartData):SwagSong { + var base:SwagSong = { + song: chart.meta.name, + notes: null, + bpm: chart.meta.bpm, + needsVoices: chart.meta.needsVoices, + speed: chart.scrollSpeed, + + player1: null, + player2: null, + validScore: true + }; + + for (strumLine in chart.strumLines) + switch (strumLine.type) { + case OPPONENT: + 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]; + } + + return base; + } + + @:noCompletion public static function __convertToSwagSections(chart:ChartData):Array { + var events:Array = chart.events.copy(); + + var measures:Float = Conductor.getMeasuresLength(); + var sections:Int = Math.floor(measures) + (measures % 1 > 0 ? 1 : 0); + + var notes:Array = cast new haxe.ds.Vector(sections); + for (section in 0...sections) { + var baseSection:SwagSection = { + sectionNotes: [], + lengthInSteps: Std.int(Conductor.getMeasureLength()), + mustHitSection: notes[section-1] != null ? notes[section-1].mustHitSection : false, + bpm: notes[section-1] != null ? notes[section-1].bpm : chart.meta.bpm, + changeBPM: false, + altAnim: notes[section-1] != null ? notes[section-1].altAnim : false + }; + + var sectionEndTime:Float = Conductor.getTimeForStep(Conductor.getMeasureLength() * (section+1)); + while(events.length > 0 && events.last().time <= sectionEndTime) { + var event:ChartEvent = events.pop(); + switch (event.name) { + case "Camera Movement": + baseSection.mustHitSection = chart.strumLines[event.params[0]].type == PLAYER; + case "Alt Animation Toggle": + baseSection.altAnim = event.params[0] || event.params[1]; + case "BPM Change": + baseSection.changeBPM = true; + baseSection.bpm = event.params[0]; + } + } + notes[section] = baseSection; + } + return notes; + } } + typedef SwagSong = { var song:String; @@ -117,13 +203,13 @@ typedef SwagSong = var bpm:Float; var needsVoices:Bool; var speed:Float; - var stage:String; - var noteTypes:Array; + var ?stage:String; + var ?noteTypes:Array; var player1:String; var player2:String; - var gf:String; - var gfVersion:String; + var ?gf:String; + var ?gfVersion:String; var validScore:Bool; // ADDITIONAL STUFF THAT MAY NOT BE PRESENT IN CHART @@ -136,9 +222,10 @@ typedef SwagSection = { var sectionNotes:Array; var lengthInSteps:Int; + var ?typeOfSection:Int; var mustHitSection:Bool; var bpm:Float; var changeBPM:Bool; var altAnim:Null; - @:optional var camTarget:Null; + var ?camTarget:Null; } diff --git a/source/funkin/editors/charter/Charter.hx b/source/funkin/editors/charter/Charter.hx index 9211b5fc..59be523c 100644 --- a/source/funkin/editors/charter/Charter.hx +++ b/source/funkin/editors/charter/Charter.hx @@ -164,6 +164,15 @@ class Charter extends UIState { onSelect: _file_meta_saveas, }, null, + { + label: "Export As FNF Legacy...", + onSelect: _file_saveas_fnflegacy, + }, + { + label: "Export As Psych Engine...", + onSelect: _file_saveas_psych, + }, + null, { label: "Exit", onSelect: _file_exit @@ -1323,6 +1332,13 @@ class Charter extends UIState { })); } + function _file_saveas_fnflegacy(_) { + openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), 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(