From cfe209067cb3dbb28b7796bf34d2f1f62381b808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=8D=9A=7ENex?= <87421482+NexIsDumb@users.noreply.github.com> Date: Fri, 4 Apr 2025 23:28:49 +0200 Subject: [PATCH] updated vslice structures + using the class funcs --- source/funkin/backend/chart/ChartData.hx | 1 - source/funkin/backend/chart/VSliceParser.hx | 212 ++++++++---------- source/funkin/backend/system/Flags.hx | 6 +- .../editors/charter/SongCreationScreen.hx | 67 ++---- 4 files changed, 111 insertions(+), 175 deletions(-) diff --git a/source/funkin/backend/chart/ChartData.hx b/source/funkin/backend/chart/ChartData.hx index 25e98597..34baba43 100644 --- a/source/funkin/backend/chart/ChartData.hx +++ b/source/funkin/backend/chart/ChartData.hx @@ -27,7 +27,6 @@ typedef ChartMetaData = { public var ?opponentModeAllowed:Bool; public var ?customValues:Dynamic; public var ?needsVoices:Bool; - public var ?artist:String; // NOT TO BE EXPORTED public var ?parsedColor:FlxColor; diff --git a/source/funkin/backend/chart/VSliceParser.hx b/source/funkin/backend/chart/VSliceParser.hx index 5686d768..f970a38a 100644 --- a/source/funkin/backend/chart/VSliceParser.hx +++ b/source/funkin/backend/chart/VSliceParser.hx @@ -2,10 +2,37 @@ package funkin.backend.chart; import funkin.backend.chart.ChartData.ChartMetaData; +typedef ChartDataWithInfo = { + var diffName:String; + var chart:ChartData; +} + // These new structures are kinda a mess to port, i love and hate them at the same time; why the hell are every difficulty in the same file??? - Nex class VSliceParser { + public static function parse(metaData:Dynamic, chartData:Dynamic, resultMeta:ChartMetaData, resultCharts:Array, ?songID:String) { + var metaData:SwagMetadata = metaData; + var chartData:NewSwagSong = chartData; + + parseMeta(metaData, resultMeta, songID); + + for (diff in Reflect.fields(chartData.notes)) + { + var base:ChartData = { + strumLines: [], + noteTypes: [], + events: [], + meta: {name: null}, + scrollSpeed: Reflect.field(chartData.scrollSpeed, diff), + stage: Flags.DEFAULT_STAGE, + codenameChart: true + }; + parseChart(Reflect.field(chartData.notes, diff), metaData, chartData.events, base); + resultCharts.push({diffName: diff, chart: base}); + } + } + public static function parseChart(data:Dynamic, metaData:Dynamic, events:Dynamic, result:ChartData) { - // base fnf chart parsing + // vslice chart parsing var data:Array = data; var metadata:SwagMetadata = metaData; var events:Array = events; @@ -129,92 +156,30 @@ class VSliceParser { }); } } - - /*var camFocusedBF:Bool = false; - var altAnims:Bool = false; - var beatsPerMeasure:Float = data.beatsPerMeasure.getDefault(Flags.DEFAULT_BEATS_PER_MEASURE); - var curBPM:Float = firstTimeChange.bpm; - var curTime:Float = 0; - var curCrochet:Float = ((60 / curBPM) * 1000); - - if (data.notes != null) for(section in data.notes) { - if (section == null) { - curTime += curCrochet * beatsPerMeasure; - continue; // Yoshi Engine charts crash fix - } - - if (camFocusedBF != (camFocusedBF = section.mustHitSection)) { - result.events.push({ - time: curTime, - name: "Camera Movement", - params: [camFocusedBF ? 1 : 0] - }); - } - - if (section.altAnim == null) section.altAnim = false; - if (altAnims != (altAnims = section.altAnim)) { - result.events.push({ - time: curTime, - name: "Alt Animation Toggle", - params: [altAnims, false, 0] - }); - } - - if (section.sectionNotes != null) for(note in section.sectionNotes) { - if (note[1] < 0) continue; - - var daStrumTime:Float = note[0]; - var daNoteData:Int = Std.int(note[1] % 8); - var daNoteType:Int = Std.int(note[1] / 8); - var gottaHitNote:Bool = daNoteData >= 4 ? !section.mustHitSection : section.mustHitSection; - - if (note.length > 2) { - if (note[3] is Int && data.noteTypes != null) - daNoteType = Chart.addNoteType(result, data.noteTypes[Std.int(note[3])-1]); - else if (note[3] is String) - daNoteType = Chart.addNoteType(result, note[3]); - } else { - if(data.noteTypes != null) - daNoteType = Chart.addNoteType(result, data.noteTypes[daNoteType-1]); - } - - result.strumLines[gottaHitNote ? 1 : 0].notes.push({ - time: daStrumTime, - id: daNoteData % 4, - type: daNoteType, - sLen: note[2] - }); - } - - if (section.changeBPM && section.bpm != curBPM) { - curCrochet = ((60 / (curBPM = section.bpm)) * 1000); - - result.events.push({ - time: curTime, - name: "BPM Change", - params: [section.bpm] - }); - } - - curTime += curCrochet * beatsPerMeasure; - }*/ } - public static function parseMeta(data:Dynamic, result:ChartMetaData) { + public static function parseMeta(data:Dynamic, result:ChartMetaData, ?songID:String) { var data:SwagMetadata = data; - result.name = data.songName; - result.artist = data.artist; - - result.customValues = {}; - result.customValues.timeChanges = data.timeChanges; + var songName = data.songName; + var songID:String = songID == null ? songName.toLowerCase().replace(" ", "-") : songID; var firstTimeChange:SwagTimeChange = data.timeChanges[0]; - result.bpm = firstTimeChange.bpm; - result.beatsPerMeasure = firstTimeChange.b != null ? firstTimeChange.b : Flags.DEFAULT_BEATS_PER_MEASURE; - result.difficulties = data.playData.difficulties.concat(data.playData.songVariations); - Reflect.deleteField(data.playData, "difficulties"); + result.name = songID; + result.bpm = firstTimeChange.bpm.getDefault(Flags.DEFAULT_BPM); + result.beatsPerMeasure = firstTimeChange.n.getDefault(Flags.DEFAULT_BEATS_PER_MEASURE); + result.stepsPerBeat = firstTimeChange.d.getDefault(Flags.DEFAULT_STEPS_PER_BEAT); + result.displayName = songName; + result.icon = Flags.DEFAULT_HEALTH_ICON; + result.color = "#FFFFFF"; + //result.parsedColor = 0xFFFFFF; + result.opponentModeAllowed = true; + result.coopAllowed = true; + result.difficulties = data.playData.difficulties.concat(data.playData.songVariations.getDefault([])); - for (field in Reflect.fields(data.playData)) + if (result.customValues == null) result.customValues = {}; + result.customValues.artist = data.artist; + if (data.charter != null) result.customValues.charter = data.charter; + for (field in Reflect.fields(data.playData)) if (field != "difficulties" && field != "songVariations" && field != "characters" && field != "stage") Reflect.setProperty(result.customValues, field, Reflect.getProperty(data.playData, field)); } @@ -256,7 +221,7 @@ class VSliceParser { var result:SwagMetadata = { songName: meta.name, timeFormat: MILLISECONDS, - artist: meta.artist, + artist: "", timeChanges: defTimeCh, looped: false, generatedBy: 'V-Slice Chart Importer (Codename Engine)', @@ -290,17 +255,17 @@ class VSliceParser { // METADATA STRUCTURES typedef SwagMetadata = { - var timeFormat:SwagTimeFormat; - var artist:String; - var songName:String; - var playData:SwagPlayData; - var timeChanges:Array; - var generatedBy:String; - var looped:Bool; var version:String; - + var songName:String; + var artist:String; + var ?charter:String; var ?divisions:Int; + var ?looped:Bool; var ?offsets:SwagSongOffsets; + var playData:SwagPlayData; + var generatedBy:String; + var ?timeFormat:SwagTimeFormat; + var timeChanges:Array; } enum abstract SwagTimeFormat(String) from String to String @@ -312,35 +277,12 @@ enum abstract SwagTimeFormat(String) from String to String typedef SwagTimeChange = { - var ?d:Int; // Time Signature Den - var ?n:Int; // Time Signature Num var t:Int; // Time Stamp var ?b:Int; // Beat Time - var ?bt:Array; // Beat Tuplets var bpm:Float; -} - -typedef SwagPlayData = -{ - var album:String; - var previewStart:Float; - var previewEnd:Float; - var stage:String; - var characters:SwagCharactersList; - var songVariations:Array; - var difficulties:Array; - var noteStyle:String; -} - -typedef SwagCharactersList = -{ - var player:String; - var girlfriend:String; - var opponent:String; - var instrumental:String; - var altInstrumentals:Array; - var opponentVocals:Array; - var playerVocals:Array; + var ?n:Int; // Time Signature Num + var ?d:Int; // Time Signature Den + var ?bt:Array; // Beat Tuplets } typedef SwagSongOffsets = @@ -348,6 +290,31 @@ typedef SwagSongOffsets = var ?instrumental:Float; var ?altInstrumentals:Dynamic; var ?vocals:Dynamic; + var ?altVocals:Dynamic; +} + +typedef SwagPlayData = +{ + var ?songVariations:Array; + var difficulties:Array; + var characters:SwagCharactersList; + var stage:String; + var noteStyle:String; + var ?ratings:Dynamic; + var ?album:String; + var ?previewStart:Int; + var ?previewEnd:Int; +} + +typedef SwagCharactersList = +{ + var ?player:String; + var ?girlfriend:String; + var ?opponent:String; + var ?instrumental:String; + var ?altInstrumentals:Array; + var ?opponentVocals:Array; + var ?playerVocals:Array; } // CHART STRUCTURE @@ -364,13 +331,20 @@ typedef SwagEvent = { var t:Float; // Time var e:String; // Event Kind - var v:Dynamic; // Value (Map) + var ?v:Dynamic; // Value (Map) } typedef SwagNote = { var t:Float; // Time var d:Int; // Data - var l:Float; // Length - var k:String; // Kind + var ?l:Float; // Length + var ?k:String; // Kind + var ?p:Array; // Params +} + +typedef SwagNoteParamsData = +{ + var n:String; // Name + var v:Dynamic; // Value } \ No newline at end of file diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx index 4f7577fc..719e90fc 100644 --- a/source/funkin/backend/system/Flags.hx +++ b/source/funkin/backend/system/Flags.hx @@ -59,7 +59,7 @@ class Flags { public static var WEEKS_LIST_MOD_MODE:Allow<"prepend", "override", "append"> = "override"; public static var DEFAULT_BPM:Float = 100.0; - public static var DEFAULT_BEATS_PER_MEASURE:Float = 4; + public static var DEFAULT_BEATS_PER_MEASURE:Int = 4; public static var DEFAULT_STEPS_PER_BEAT:Int = 4; public static var SUPPORTED_CHART_RUNTIME_FORMATS:Array = ["Legacy", "Psych Engine"]; @@ -69,8 +69,8 @@ class Flags { public static var VSLICE_SONG_CHART_DATA_VERSION:String = "2.0.0"; public static var VSLICE_DEFAULT_NOTE_STYLE:String = 'funkin'; public static var VSLICE_DEFAULT_ALBUM_ID:String = 'volume1'; - public static var VSLICE_DEFAULT_PREVIEW_START:Float = 0; - public static var VSLICE_DEFAULT_PREVIEW_END:Float = 15000; + public static var VSLICE_DEFAULT_PREVIEW_START:Int = 0; + public static var VSLICE_DEFAULT_PREVIEW_END:Int = 15000; /** * Default background colors for songs without bg color diff --git a/source/funkin/editors/charter/SongCreationScreen.hx b/source/funkin/editors/charter/SongCreationScreen.hx index 2fdf9ee9..9cb27cbe 100644 --- a/source/funkin/editors/charter/SongCreationScreen.hx +++ b/source/funkin/editors/charter/SongCreationScreen.hx @@ -168,7 +168,7 @@ class SongCreationScreen extends UISubstateWindow { var menuTitle:UIText; selectFormatGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Import From:", 28)); - engineDropdown = new UIDropDown(menuTitle.x, menuTitle.y + menuTitle.height + 36, 480, 32, ["Psych/Legacy FNF (Can also work on runtime)", "V-Slice", "V-Slice Project (.fnfc)"]); + engineDropdown = new UIDropDown(menuTitle.x, menuTitle.y + menuTitle.height + 36, 480, 32, ["Psych/Legacy FNF", "V-Slice", "V-Slice Project (.fnfc)"]); selectFormatGroup.add(engineDropdown); addLabelOn(engineDropdown, "Chart Format"); @@ -356,8 +356,7 @@ class SongCreationScreen extends UISubstateWindow { var fileContent = field.data; files.set(fileName, fileContent); } - saveVslice(files); - + saveFromVSlice(files); case "V-Slice": var songId = importIdTextBox.label.text; var files:Map = []; @@ -365,7 +364,7 @@ class SongCreationScreen extends UISubstateWindow { files.set('${songId}-chart.json', importChartFile.file); files.set('Inst.${Flags.SOUND_EXT}', importInstExplorer.file); files.set('Voices.${Flags.SOUND_EXT}', importVoicesExplorer.file); - saveVslice(files, songId); + saveFromVSlice(files, songId); } } else { for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper]) @@ -393,61 +392,25 @@ class SongCreationScreen extends UISubstateWindow { } } - function saveVslice(files:Map, ?name:String) { + function saveFromVSlice(files:Map, ?name:String) { var songId = name == null && files.exists("manifest.json") ? Json.parse(files.get("manifest.json")).songId : name; - var vslicemeta = Json.parse(files.get('${songId}-metadata.json')); - var firstTimeChange = vslicemeta.timeChanges[0]; - var vslicechart = Json.parse(files.get('${songId}-chart.json')); - var difficulties = Reflect.fields(vslicechart.notes); - + var vslicemeta:SwagMetadata = Json.parse(files.get('${songId}-metadata.json')); + var vslicechart:NewSwagSong = Json.parse(files.get('${songId}-chart.json')); var playData = vslicemeta.playData; - var instFile = files.get('Inst.${Flags.SOUND_EXT}'); - var voicesFiles = files.get('Voices.${Flags.SOUND_EXT}'); //it may exist - var playerVoices = files.get('Voices-${playData.characters.playerVocals != null ? playData.characters.playerVocals[0] : playData.characters.player}.${Flags.SOUND_EXT}'); - var oppVoices = files.get('Voices-${playData.characters.opponentVocals != null ? playData.characters.opponentVocals[0] : playData.characters.opponent}.${Flags.SOUND_EXT}'); - - var meta:ChartMetaData = { - name: songId, - bpm: CoolUtil.getDefault(firstTimeChange.bpm, 100), - beatsPerMeasure: CoolUtil.getDefault(firstTimeChange.n, Flags.DEFAULT_BEATS_PER_MEASURE), - stepsPerBeat: CoolUtil.getDefault(firstTimeChange.d, 4), - displayName: vslicemeta.songName, - icon: Flags.DEFAULT_HEALTH_ICON, - color: "#FFFFFF", - //parsedColor: 0xFFFFFF, - opponentModeAllowed: true, - coopAllowed: true, - difficulties: difficulties - }; + var meta:ChartMetaData = {name: songId}; + var diffCharts:Array = []; + VSliceParser.parse(vslicemeta, vslicechart, meta, diffCharts, songId); if (onSave != null) onSave({ meta: meta, - instBytes: instFile, - voicesBytes: voicesFiles, - playerVocals: playerVoices, - oppVocals: oppVoices, - }, (songFolder:String, creation: SongCreationData) -> { + instBytes: files.get('Inst.${Flags.SOUND_EXT}'), + voicesBytes: files.get('Voices.${Flags.SOUND_EXT}'), //it may exist + playerVocals: files.get('Voices-${playData.characters.playerVocals != null ? playData.characters.playerVocals[0] : playData.characters.player}.${Flags.SOUND_EXT}'), + oppVocals: files.get('Voices-${playData.characters.opponentVocals != null ? playData.characters.opponentVocals[0] : playData.characters.opponent}.${Flags.SOUND_EXT}'), + }, (songFolder:String, creation:SongCreationData) -> { #if sys - for (diff in difficulties) - { - var vsliceChartData = Reflect.field(vslicechart.notes, diff); - var chartPath = Paths.chart(songId, diff); - var base:ChartData = { - strumLines: [], - noteTypes: [], - events: [], - meta: { - name: null - }, - scrollSpeed: Reflect.field(vslicechart.scrollSpeed, diff), - stage: Flags.DEFAULT_STAGE, - codenameChart: true, - fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS) - }; - VSliceParser.parseChart(vsliceChartData, vslicemeta, vslicechart.events, base); - CoolUtil.safeSaveFile('$songFolder/charts/$diff.json', Json.stringify(base, Flags.JSON_PRETTY_PRINT)); - } + for (diff in diffCharts) CoolUtil.safeSaveFile('$songFolder/charts/${diff.diffName}.json', Json.stringify(diff.chart, Flags.JSON_PRETTY_PRINT)); #end }); }