From 333d12993003fba6b8922d813ecffe28dd9c4235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Person=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Fri, 29 Nov 2024 20:38:20 -0500 Subject: [PATCH 01/12] idk wtf im doing lol --- src/moonchart/backend/FormatData.hx | 6 +- src/moonchart/formats/fnf/FNFImaginative.hx | 110 ++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/moonchart/formats/fnf/FNFImaginative.hx diff --git a/src/moonchart/backend/FormatData.hx b/src/moonchart/backend/FormatData.hx index d7cde96..edd2389 100644 --- a/src/moonchart/backend/FormatData.hx +++ b/src/moonchart/backend/FormatData.hx @@ -22,6 +22,7 @@ enum abstract Format(String) from String to String var FNF_KADE; var FNF_MARU; var FNF_CODENAME; + var FNF_IMAGINATIVE; var FNF_LUDUM_DARE; var FNF_VSLICE; var GUITAR_HERO; @@ -39,8 +40,9 @@ enum abstract Format(String) from String to String { return [ FNFLegacy.__getFormat(), FNFPsych.__getFormat(), FNFFpsPlus.__getFormat(), FNFKade.__getFormat(), FNFMaru.__getFormat(), - FNFCodename.__getFormat(), FNFLudumDare.__getFormat(), FNFVSlice.__getFormat(), GuitarHero.__getFormat(), OsuMania.__getFormat(), - Quaver.__getFormat(), StepMania.__getFormat(), StepManiaShark.__getFormat(), Midi.__getFormat()]; + FNFCodename.__getFormat(), FNFImaginative.__getFormat(), FNFLudumDare.__getFormat(), FNFVSlice.__getFormat(), GuitarHero.__getFormat(), OsuMania.__getFormat(), + Quaver.__getFormat(), StepMania.__getFormat(), StepManiaShark.__getFormat(), Midi.__getFormat() + ]; } } diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx new file mode 100644 index 0000000..ce744ac --- /dev/null +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -0,0 +1,110 @@ +package moonchart.formats.fnf; + +import haxe.io.Path; +import moonchart.backend.FormatData; +import moonchart.backend.Optimizer; +import moonchart.backend.Timing; +import moonchart.backend.Util; +import moonchart.formats.BasicFormat; + +// Chart +typedef FNFImaginativeNote = { + var id:Int; + var length:Float; + var time:Float; + var ?characters:Array; + var type:String; +} + +typedef FNFImaginativeArrowField = { + var tag:String; + var characters:Array; + var notes:Array; +} + +typedef FNFImaginativeCharacter = { + var tag:String; + var name:String; + var position:String; +} + +typedef FNFImaginativeFieldSettings = { + var ?cameraTarget:String; + var order:Array; + var enemy:String; + var player:String; +} + +typedef FNFImaginativeEvent = { + var name:String; + var params:Array; + var time:Float; + var ?sub:Int; +} + +typedef FNFImaginativeChart = { + var speed:Float; + var stage:String; + var fields:Array; + var characters:Array; + var fieldSettings:FNFImaginativeFieldSettings; + var ?events:Array; +} + +// Meta +typedef FNFImaginativeCheckpoint = { // used for bpm changes + var time:Float; + var bpm:Float; + var signature:Array; +} + +typedef FNFImaginativeAllowedModes = { + var playAsEnemy:Bool; + var p2AsEnemy:Bool; +} + +typedef FNFImaginativeAudioMeta = { + var artist:String; + var name:String; + var bpm:Float; + var signature:Array; + var ?offset:Float; + var checkpoints:Array; +} + +typedef FNFImaginativeSongMeta = { + var name:String; + var folder:String; + var icon:String; + var startingDiff:Int; + var difficulties:Array; + var variants:Array; + var ?color:FlxColor; + var allowedModes:FNFImaginativeAllowedModes; +} + +class FNFImaginative extends BasicJsonFormat { + public static function __getFormat():FormatData { + return { + ID: FNF_IMAGINATIVE, + name: "FNF (Imaginative)", + description: "Divided per strumline FNF format with lots of metadata.", + extension: "json", + hasMetaFile: TRUE, + metaFileExtension: "json", + specialValues: [''], + handler: FNFImaginative, + formatFile: FNFMaru.formatFile + } + } + + public function new(?data:FNFImaginativeChart, ?meta:FNFImaginativeAudioMeta) { + super({timeFormat: STEPS, supportsDiffs: false, supportsEvents: true}); + this.data = data; + this.meta = meta; + beautify = true; + } + + public static function formatTitle(title:String):String + return Path.normalize(title); +} \ No newline at end of file From 33bf04f9bc67bf266ba7bafd74c048ccec407845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Tue, 3 Dec 2024 10:09:25 -0500 Subject: [PATCH 02/12] update README.md --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index bfabe66..39191e0 100644 --- a/README.md +++ b/README.md @@ -31,19 +31,20 @@ var meta:String = vsliceChart.meta; // String containing the FNF (V-Slice) meta ## Available formats | Format | File Extension | |----------------------|----------------------| -| [FNF (Legacy)](https://github.com/FunkinCrew/Funkin/tree/v0.2.7.1) | json | -| [FNF (Psych Engine)](https://github.com/ShadowMario/FNF-PsychEngine) | json | -| [FNF (FPS +)](https://github.com/ThatRozebudDude/FPS-Plus-Public) | json | -| [FNF (Kade Engine)](https://github.com/Kade-github/Kade-Engine) | json | -| [FNF (Maru)](https://github.com/MaybeMaru/Maru-Funkin) | json | -| [FNF (Codename)](https://github.com/FNF-CNE-Devs/CodenameEngine) | json | -| [FNF (Ludum Dare)](https://github.com/FunkinCrew/Funkin/tree/1.0.0) | json / png | -| [FNF (V-Slice)](https://github.com/FunkinCrew/Funkin) | json | -| [Guitar Hero](https://clonehero.net/) | chart | -| [Osu! Mania](https://osu.ppy.sh/) | osu | -| [Quaver](https://quavergame.com/) | qua | -| [StepMania](https://www.stepmania.com/) | sm | -| [StepManiaShark](https://www.stepmania.com/) | ssc | +| [FNF (Legacy)](https://github.com/FunkinCrew/Funkin/tree/v0.2.7.1) | json | +| [FNF (Psych Engine)](https://github.com/ShadowMario/FNF-PsychEngine) | json | +| [FNF (FPS +)](https://github.com/ThatRozebudDude/FPS-Plus-Public) | json | +| [FNF (Kade Engine)](https://github.com/Kade-github/Kade-Engine) | json | +| [FNF (Maru)](https://github.com/MaybeMaru/Maru-Funkin) | json | +| [FNF (Codename)](https://github.com/FNF-CNE-Devs/CodenameEngine) | json | +| [FNF (Imaginative)](https://github.com/Funkin-Imaginative/imaginative.engine) | json | +| [FNF (Ludum Dare)](https://github.com/FunkinCrew/Funkin/tree/1.0.0) | json / png | +| [FNF (V-Slice)](https://github.com/FunkinCrew/Funkin) | json | +| [Guitar Hero](https://clonehero.net/) | chart | +| [Osu! Mania](https://osu.ppy.sh/) | osu | +| [Quaver](https://quavergame.com/) | qua | +| [StepMania](https://www.stepmania.com/) | sm | +| [StepManiaShark](https://www.stepmania.com/) | ssc | ## Encountered a problem? If you discover a bug or run into any other issue while using the library, please don't hesitate to open a [GitHub issue](https://github.com/MaybeMaru/moonchart/issues).
From fa1c34f29b16d959d67590617aaf54c626d7dccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Tue, 3 Dec 2024 10:31:50 -0500 Subject: [PATCH 03/12] update FNFImaginative.hx --- src/moonchart/formats/fnf/FNFImaginative.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index ce744ac..3d78ed2 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -88,7 +88,7 @@ class FNFImaginative extends BasicJsonFormat Date: Tue, 17 Dec 2024 15:05:02 -0500 Subject: [PATCH 04/12] added the documentation my engine has if that helps --- src/moonchart/formats/fnf/FNFImaginative.hx | 171 ++++++++++++++++++-- 1 file changed, 157 insertions(+), 14 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index 3d78ed2..7f569e9 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -9,77 +9,220 @@ import moonchart.formats.BasicFormat; // Chart typedef FNFImaginativeNote = { + /** + * The note direction id. + */ var id:Int; - var length:Float; + /** + * NOTE: As of rn this is actually in milliseconds!!!!! + * The length of a sustain in steps. + */ + @:default(0) var length:Float; + /** + * NOTE: As of rn this is actually in milliseconds!!!!! + * The note position in steps. + */ var time:Float; + /** + * Characters this note will mess with instead of the fields main ones. + */ var ?characters:Array; + /** + * The note type. + */ var type:String; } typedef FNFImaginativeArrowField = { + /** + * The arrow field tag name. + */ var tag:String; + /** + * Characters to be assigned as singers for this field. + */ var characters:Array; + /** + * Array of notes to load. + */ var notes:Array; + /** + * The independent field scroll speed. + */ + var ?speed:Float; } typedef FNFImaginativeCharacter = { + /** + * The character tag name. + */ var tag:String; - var name:String; + /** + * The character to load. + */ + @:default('boyfriend') var name:String; + /** + * The location the character will be placed. + */ var position:String; + /** + * The character's vocal suffix override. + */ + var ?vocals:String; } typedef FNFImaginativeFieldSettings = { + /** + * The starting camera target + */ var ?cameraTarget:String; + /** + * The arrow field order. + */ var order:Array; + /** + * The enemy field. + */ var enemy:String; + /** + * The player field. + */ var player:String; } typedef FNFImaginativeEvent = { + /** + * The event name. + */ var name:String; - var params:Array; + /** + * The event parameters. + */ + var params:Array>; + /** + * NOTE: As of rn this is actually in milliseconds!!!!! + * The event position in steps. + */ var time:Float; - var ?sub:Int; + /** + * This is used for event stacking detection. + */ + @:default(0) var ?sub:Int; } typedef FNFImaginativeChart = { - var speed:Float; - var stage:String; + /** + * The song scroll speed. + */ + @:default(2.6) var speed:Float; + /** + * The stage this song will take place. + */ + @:default('void') var stage:String; + /** + * Array of arrow fields to load. + */ var fields:Array; + /** + * Array of characters to load. + */ var characters:Array; + /** + * Field settings. + */ var fieldSettings:FNFImaginativeFieldSettings; + /** + * Chart specific events. + */ var ?events:Array; } // Meta typedef FNFImaginativeCheckpoint = { // used for bpm changes + /** + * The position of the song in milliseconds. + */ var time:Float; + /** + * The "beats per minute" at that point. + */ var bpm:Float; + /** + * The time signature at that point. + */ var signature:Array; } typedef FNFImaginativeAllowedModes = { - var playAsEnemy:Bool; - var p2AsEnemy:Bool; + /** + * If true, this song allows you to play as the enemy. + */ + @:default(false) var playAsEnemy:Bool; + /** + * If true, this song allows you to go against another player. + */ + @:default(false) var p2AsEnemy:Bool; } typedef FNFImaginativeAudioMeta = { - var artist:String; + /** + * The composer of the song. + */ + @:default('Unassigned') var artist:String; + /** + * The display name of the song. + */ var name:String; - var bpm:Float; - var signature:Array; - var ?offset:Float; - var checkpoints:Array; + /** + * The bpm at the start of the song. + */ + @:default(100) var bpm:Float; + /** + * The time signature at the start of the song. + */ + @:default([4, 4]) var signature:Array; + /** + * The audio offset. + */ + @:default(0) var ?offset:Float; + /** + * Contains all known bpm changes. + */ + var checkpoints:Array; } typedef FNFImaginativeSongMeta = { + /** + * The song display name. + */ var name:String; + /** + * The song folder name. + */ var folder:String; + /** + * The song icon. + */ var icon:String; + /** + * The starting difficulty. + */ var startingDiff:Int; + /** + * The difficulties listing. + */ var difficulties:Array; + /** + * The variations listing. + */ var variants:Array; + /** + * The song color. + */ var ?color:FlxColor; + /** + * Allowed modes for the song. + */ var allowedModes:FNFImaginativeAllowedModes; } @@ -92,7 +235,7 @@ class FNFImaginative extends BasicJsonFormat Date: Tue, 3 Jun 2025 21:15:01 -0400 Subject: [PATCH 05/12] idk wtf im doing --- src/moonchart/formats/fnf/FNFImaginative.hx | 49 +++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index 7f569e9..e4e4ece 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -235,15 +235,15 @@ class FNFImaginative extends BasicJsonFormat = chartResolve.notes.get(diffId); + var basicMeta:BasicMetaData = chart.meta; + + var fields:Array = []; + for (i in 0...2) { + fields.push({ + tag: '', + characters: switch (i) { + case 0: [meta.extraData.get(PLAYER_2)]; + case 1: [meta.extraData.get(PLAYER_1)]; + default: []; + }, + notes: [] + }); + } + + for (note in basicNotes) { + var field:FNFImaginativeArrowField = fields[Std.int(lane / 4)]; + if (field == null) + continue; + + field.notes = []; + } + + data = { + speed: 2.6, + stage: 'void', + fields: [], + characters: [], + fieldSettings: {}, + events: [] + } + + meta = {} + + return this; + } } \ No newline at end of file From 0f21840e46f5a3e424b3011c1a871cf35815ac2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Fri, 6 Jun 2025 18:48:53 -0400 Subject: [PATCH 06/12] PROGRESS --- src/moonchart/formats/fnf/FNFImaginative.hx | 72 +++++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index e4e4ece..e6b30f3 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -188,7 +188,7 @@ typedef FNFImaginativeAudioMeta = { /** * Contains all known bpm changes. */ - var checkpoints:Array; + var checkpoints:Array; } typedef FNFImaginativeSongMeta = { @@ -243,7 +243,7 @@ class FNFImaginative extends BasicJsonFormat = chartResolve.notes.get(diffId); var basicMeta:BasicMetaData = chart.meta; + var characters:Array = []; + for (i in 0...3) { + characters.push({ + tag: switch (i) { + case 0: 'enemy'; + case 1: 'player'; + case 2: 'spectator'; + }, + name: switch (i) { + case 0: meta.extraData.get(PLAYER_2); + case 1: meta.extraData.get(PLAYER_1); + case 2: meta.extraData.get(PLAYER_3); + }, + position: switch (i) { + case 0: 'left'; + case 1: 'right'; + case 2: 'center'; + }, + }); + } + var fields:Array = []; for (i in 0...2) { fields.push({ tag: '', characters: switch (i) { - case 0: [meta.extraData.get(PLAYER_2)]; - case 1: [meta.extraData.get(PLAYER_1)]; + case 0: ['enemy']; + case 1: ['player']; default: []; }, notes: [] @@ -276,19 +297,46 @@ class FNFImaginative extends BasicJsonFormat = meta.bpmChanges; + var initChange:BasicBPMChange = bpmChanges.shift(); + meta = { + artist: meta.extraData.get(SONG_ARTIST) ?? Moonchart.DEFAULT_ARTIST, + name: meta.title, + bpm: initChange.bpm, + signature: [initChange.stepsPerBeat, initChange.beatsPerMeasure], + offset: meta.offset, + checkpoints: [ + for (change in bpmChanges) { + { + time: change.time, + bpm: change.bpm, + signature: [change.stepsPerBeat, change.beatsPerMeasure] + } + } + ] + } return this; } From f06d64421482d6852039685d69c993308816c1be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Fri, 6 Jun 2025 18:50:41 -0400 Subject: [PATCH 07/12] woops --- src/moonchart/formats/fnf/FNFImaginative.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index e6b30f3..76b46c6 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -311,7 +311,7 @@ class FNFImaginative extends BasicJsonFormat Date: Fri, 6 Jun 2025 20:24:39 -0400 Subject: [PATCH 08/12] Actually works now, lmao. --- src/moonchart/formats/fnf/FNFImaginative.hx | 51 +++++++++++---------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index 76b46c6..7b374c3 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -1,11 +1,12 @@ package moonchart.formats.fnf; import haxe.io.Path; +import flixel.util.FlxColor; +import flixel.util.typeLimit.OneOfFour; import moonchart.backend.FormatData; -import moonchart.backend.Optimizer; -import moonchart.backend.Timing; import moonchart.backend.Util; import moonchart.formats.BasicFormat; +import moonchart.formats.fnf.legacy.FNFLegacy.FNFLegacyMetaValues; // Chart typedef FNFImaginativeNote = { @@ -265,16 +266,19 @@ class FNFImaginative extends BasicJsonFormat = []; for (i in 0...2) { fields.push({ - tag: '', - characters: switch (i) { - case 0: ['enemy']; - case 1: ['player']; - default: []; + tag: switch (i) { + case 0: 'enemy'; + case 1: 'player'; + case 2: 'spectator'; + default: 'UNKNOWN'; }, + characters: [characters[i]], notes: [] }); } for (note in basicNotes) { - var field:FNFImaginativeArrowField = fields[Std.int(lane / 4)]; + var field:FNFImaginativeArrowField = fields[Std.int(note.lane / 4)]; if (field == null) continue; field.notes.push({ - id: lane % 4, + id: note.lane % 4, length: note.length, time: note.time, type: note.type @@ -306,8 +311,8 @@ class FNFImaginative extends BasicJsonFormat = meta.bpmChanges; + var bpmChanges:Array = basicMeta.bpmChanges; var initChange:BasicBPMChange = bpmChanges.shift(); meta = { - artist: meta.extraData.get(SONG_ARTIST) ?? Moonchart.DEFAULT_ARTIST, - name: meta.title, + artist: basicMeta.extraData.get(SONG_ARTIST) ?? Moonchart.DEFAULT_ARTIST, + name: basicMeta.title, bpm: initChange.bpm, - signature: [initChange.stepsPerBeat, initChange.beatsPerMeasure], - offset: meta.offset, + signature: [Std.int(initChange.stepsPerBeat), Std.int(initChange.beatsPerMeasure)], + offset: basicMeta.offset, checkpoints: [ for (change in bpmChanges) { { time: change.time, bpm: change.bpm, - signature: [change.stepsPerBeat, change.beatsPerMeasure] + signature: [Std.int(change.stepsPerBeat), Std.int(change.beatsPerMeasure)] } } ] From 117d0819d6bdd3bab4ba7036e50268d8c7c1426b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Fri, 6 Jun 2025 20:30:53 -0400 Subject: [PATCH 09/12] small thingy --- src/moonchart/formats/fnf/FNFImaginative.hx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index 7b374c3..99fd2d4 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -260,7 +260,8 @@ class FNFImaginative extends BasicJsonFormat = []; - for (i in 0...3) { + var charCap:Int = basicMeta.extraData.exists(FNFLegacyMetaValues.PLAYER_3) ? 3 : (basicMeta.extraData.get(FNFLegacyMetaValues.PLAYER_3) == null ? 2 : 3); + for (i in 0...charCap) { characters.push({ tag: switch (i) { case 0: 'enemy'; @@ -286,12 +287,7 @@ class FNFImaginative extends BasicJsonFormat = []; for (i in 0...2) { fields.push({ - tag: switch (i) { - case 0: 'enemy'; - case 1: 'player'; - case 2: 'spectator'; - default: 'UNKNOWN'; - }, + tag: characters[i], characters: [characters[i]], notes: [] }); From 295328febe072e146e8e3446e8360c256c8a91b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Tue, 10 Jun 2025 21:11:47 -0400 Subject: [PATCH 10/12] woops --- src/moonchart/formats/fnf/FNFImaginative.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index 99fd2d4..e243c9f 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -287,8 +287,8 @@ class FNFImaginative extends BasicJsonFormat = []; for (i in 0...2) { fields.push({ - tag: characters[i], - characters: [characters[i]], + tag: characters[i].tag, + characters: [characters[i].tag], notes: [] }); } From 63496c90fdd1b5f77d74989b10d7531ef96dea81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Mon, 3 Nov 2025 19:45:54 -0500 Subject: [PATCH 11/12] Update FNFImaginative.hx --- src/moonchart/formats/fnf/FNFImaginative.hx | 127 +++++++++++++++++--- 1 file changed, 110 insertions(+), 17 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index e243c9f..3e698dd 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -4,9 +4,12 @@ import haxe.io.Path; import flixel.util.FlxColor; import flixel.util.typeLimit.OneOfFour; import moonchart.backend.FormatData; +import moonchart.backend.Optimizer; +import moonchart.backend.Timing; import moonchart.backend.Util; import moonchart.formats.BasicFormat; -import moonchart.formats.fnf.legacy.FNFLegacy.FNFLegacyMetaValues; +import moonchart.formats.fnf.FNFGlobal; +import moonchart.formats.fnf.legacy.FNFLegacy; // Chart typedef FNFImaginativeNote = { @@ -14,13 +17,13 @@ typedef FNFImaginativeNote = { * The note direction id. */ var id:Int; + // NOTE: As of rn this is actually in milliseconds!!!!! /** - * NOTE: As of rn this is actually in milliseconds!!!!! * The length of a sustain in steps. */ @:default(0) var length:Float; + // NOTE: As of rn this is actually in milliseconds!!!!! /** - * NOTE: As of rn this is actually in milliseconds!!!!! * The note position in steps. */ var time:Float; @@ -92,23 +95,25 @@ typedef FNFImaginativeFieldSettings = { } typedef FNFImaginativeEvent = { + // NOTE: As of rn this is actually in milliseconds!!!!! /** - * The event name. + * The event position in steps. */ - var name:String; + var time:Float; /** - * The event parameters. + * Each event to trigger. */ - var params:Array>; + var data:Array; +} +typedef FNFImaginativeSubEvent = { /** - * NOTE: As of rn this is actually in milliseconds!!!!! - * The event position in steps. + * The event name. */ - var time:Float; + var name:String; /** - * This is used for event stacking detection. + * The event parameters. */ - @:default(0) var ?sub:Int; + var params:Array>; } typedef FNFImaginativeChart = { @@ -227,27 +232,38 @@ typedef FNFImaginativeSongMeta = { var allowedModes:FNFImaginativeAllowedModes; } +enum abstract FNFImaginativeNoteType(String) from String to String { + var IMAG_ALT_ANIM = "Alt Animation"; + var IMAG_NO_ANIM = "No Animation"; +} + class FNFImaginative extends BasicJsonFormat { public static function __getFormat():FormatData { return { ID: FNF_IMAGINATIVE, - name: "FNF (Imaginative)", - description: "A unique format for adding characters, strumlines and vocal instances.", - extension: "json", + name: 'FNF (Imaginative)', + description: 'A unique format for adding characters, strumlines and vocal instances.', + extension: 'json', hasMetaFile: TRUE, - metaFileExtension: "json", + metaFileExtension: 'json', specialValues: ['"speed":', '?"stage":', '_"fields":', '_"characters":', '_"fieldSettings":'], formatFile: FNFMaru.formatFile, handler: FNFImaginative } } + public var noteTypeResolver(default, null):FNFNoteTypeResolver; + public function new(?data:FNFImaginativeChart, ?meta:FNFImaginativeAudioMeta) { - // will be in STEPS but idk how to fully do in my engine as of rn + // NOTE: will be in STEPS but idk how to fully do that as of rn super({timeFormat: MILLISECONDS, supportsDiffs: false, supportsEvents: true}); this.data = data; this.meta = meta; beautify = true; + + noteTypeResolver = FNFGlobal.createNoteTypeResolver(); + noteTypeResolver.register(FNFImaginativeNoteType.IMAG_ALT_ANIM, BasicFNFNoteType.ALT_ANIM); + noteTypeResolver.register(FNFImaginativeNoteType.IMAG_NO_ANIM, BasicFNFNoteType.NO_ANIM); } public static function formatTitle(title:String):String @@ -341,4 +357,81 @@ class FNFImaginative extends BasicJsonFormat { + var notes:Array = []; + for (field in data.fields) + for (note in field.notes) + notes.push({ + time: note.time, + lane: note.id, + length: note.length, + type: note.type + }); + Timing.sortNotes(notes); + return notes; + } + + override function getEvents():Array { + var events:Array = []; + for (event in data.events) + for (data in event.data) + events.push(Util.makeArrayEvent(event.time, data.name, data.params)); + Timing.sortEvents(events); + return events; + } + + function getArrowField(tags:Array):FNFImaginativeArrowField { + for (field in data.fields) + if (tags.contains(field.tag)) + return field; + return null; + } + + override function getChartMeta():BasicMetaData { + var bpmChanges:Array = [ + { + time: 0, + bpm: meta.bpm, + stepsPerBeat: meta.signature[0], + beatsPerMeasure: meta.signature[1] + } + ]; + for (checkpoint in meta.checkpoints) + bpmChanges.push({ + time: checkpoint.time, + bpm: checkpoint.bpm, + stepsPerBeat: checkpoint.signature[0], + beatsPerMeasure: checkpoint.signature[1] + }); + Timing.sortBPMChanges(bpmChanges); + return { + title: meta.name, + bpmChanges: bpmChanges, + offset: 0, + scrollSpeeds: [diffs[0] => data.speed], + extraData: [ + PLAYER_1 => getArrowField(['player', 'boyfriend', 'bf'])?.characters[0] ?? 'boyfriend', + PLAYER_2 => getArrowField(['enemy', 'opponent', 'dad'])?.characters[0] ?? 'dad', + PLAYER_3 => getArrowField(['spectator', 'gf', 'girlfriend'])?.characters[0] ?? 'gf', + SONG_ARTIST => meta.artist ?? Moonchart.DEFAULT_ARTIST, + SONG_CHARTER => Moonchart.DEFAULT_CHARTER, // no variable for this yet + STAGE => data.stage + ] + } + } + + override function fromFile(path:String, ?meta:StringInput, ?diff:FormatDifficulty):FNFImaginative { + return fromJson(Util.getText(path), Util.getText(meta), diff); + } + + override function fromJson(data:String, ?meta:StringInput, ?diff:FormatDifficulty):FNFImaginative { + super.fromJson(data, meta, diff); + Optimizer.addDefaultValues(this.data, { + fields: [for (i in 0...2) {tag: i == 0 ? 'enemy' : 'player', characters: [i == 0 ? 'enemy' : 'player'], notes: []}], + characters: [for (i in 0...2) {tag: i == 0 ? 'enemy' : 'player', position: 'UNKNOWN'}], + fieldSettings: {cameraTarget: 'player', order: ['enemy', 'player'], enemy: 'enemy', player: 'player'} + }); + return this; + } } \ No newline at end of file From a3b3aedb58dfe8a2ea974d5546914abe5d964f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=92=9C=20Rodney=2C=20An=20Imaginative=20Furball=20?= =?UTF-8?q?=F0=9F=92=99?= Date: Tue, 4 Nov 2025 21:12:50 -0500 Subject: [PATCH 12/12] VSlice Event Conversion --- src/moonchart/formats/fnf/FNFImaginative.hx | 168 ++++++++++++++++++-- 1 file changed, 153 insertions(+), 15 deletions(-) diff --git a/src/moonchart/formats/fnf/FNFImaginative.hx b/src/moonchart/formats/fnf/FNFImaginative.hx index 3e698dd..c0a9670 100644 --- a/src/moonchart/formats/fnf/FNFImaginative.hx +++ b/src/moonchart/formats/fnf/FNFImaginative.hx @@ -54,6 +54,10 @@ typedef FNFImaginativeArrowField = { * The independent field scroll speed. */ var ?speed:Float; + /** + * The starting strum count of the field. + */ + @:default('4') var ?startCount:Int; } typedef FNFImaginativeCharacter = { @@ -113,7 +117,7 @@ typedef FNFImaginativeSubEvent = { /** * The event parameters. */ - var params:Array>; + var params:Array; } typedef FNFImaginativeChart = { @@ -269,13 +273,13 @@ class FNFImaginative extends BasicJsonFormat = chartResolve.notes.get(diffId); var basicMeta:BasicMetaData = chart.meta; - var characters:Array = []; + var characters:Array = Util.makeArray(0); var charCap:Int = basicMeta.extraData.exists(FNFLegacyMetaValues.PLAYER_3) ? 3 : (basicMeta.extraData.get(FNFLegacyMetaValues.PLAYER_3) == null ? 2 : 3); for (i in 0...charCap) { characters.push({ @@ -283,7 +287,7 @@ class FNFImaginative extends BasicJsonFormat = []; + var fields:Array = Util.makeArray(0); for (i in 0...2) { fields.push({ tag: characters[i].tag, characters: [characters[i].tag], - notes: [] + notes: Util.makeArray(0) }); } + var basicNotes:Array = Timing.sortNotes(chartResolve.notes.get(diffId)); for (note in basicNotes) { var field:FNFImaginativeArrowField = fields[Std.int(note.lane / 4)]; - if (field == null) - continue; - + if (field == null) continue; field.notes.push({ id: note.lane % 4, length: note.length, @@ -321,6 +324,141 @@ class FNFImaginative extends BasicJsonFormat return Util.sortValues(a.time, b.time)); + + var events:Array = Util.makeArray(0); + var basicEvents = /* Timing.sortEvents */(chart.data.events); + // trace(haxe.Json.stringify(basicEvents, '\t')); + for (i => event in basicEvents) { + // helper for making events for imaginative + inline function makeEvent(name:String, params:Array):Void { + if (i - 1 > -1 && event.time == events[i - 1].time) { + // doing psychs event stacking method + events[i - 1].data.push({name: name, params: params}); + } else { + events.push({ + time: event.time, + data: [ + {name: name, params: params} + ] + }); + } + } + + // vslice conversion process + if (basicMeta.inputFormats.contains(FNF_VSLICE)) { + switch (event.name) { + case 'FocusCamera': + var target:Int = event.data?.char ?? 0; + var x:Float = event.data?.x ?? 0; + var y:Float = event.data?.y ?? 0; + var duration:Float = event.data?.duration ?? 4; + var ease:String = event.data?.ease ?? '[none]'; + if (ease == 'INSTANT') ease = '[instant]'; + if (ease == 'CLASSIC') ease = '[none]'; + + if (target == -1) + makeEvent('Focus Camera To Custom Position', [x, y, duration, ease, /* _UNKNOWN_, false, */ 'disable']); + else + makeEvent('Focus Camera To Character', [ + 'character', + switch (target) { + case 0: 'player'; + case 1: 'enemy'; + case 2: 'spectator'; + default: _UNKNOWN_; + }, + x, y, duration, ease, + // _UNKNOWN_, false, // idr wtf these where 😭 + 'disable' // how camera displacement should act when tweening if its enabled + ]); + + case 'PlayAnimation': + var target:String = event.data?.target ?? 'player'; + target = switch (target) { + case 'boyfriend' | 'bf': 'player'; + case 'dad' | 'opponent': 'enemy'; + case 'girlfriend' | 'gf': 'spectator'; + default: target; + } + makeEvent('Play Sprite Animation', [ + target == 'enemy' || target == 'player' || target == 'spectator' ? 'character' : 'sprite', + target, + event.data?.anim ?? _UNKNOWN_, + 'Unclear', // animation context + event.data?.force ?? false, + false, // reversed + 0 // starting frame + ]); + + case 'ScrollSpeed': + var target:String = switch (event.data?.strumline) { + case 'opponent': 'enemy'; + case 'player': 'player'; + default: '[global]'; + } + var ease:String = event.data?.ease ?? 'linear'; + if (ease == 'INSTANT') ease = '[instant]'; + makeEvent('Manage Scroll Speed', [ + target, + event.data?.scroll ?? 1, + event.data?.duration ?? 4, + ease, + event.data?.absolute ?? false, + ]); + + case 'SetCameraBop': + // TODO: Write this. + + // case 'SetCharacter': + // TODO: Write this. + + case 'SetHealthIcon': + var target:Int = event.data?.char ?? 0; + var iconId:String = event.data?.id ?? 'boyfriend'; + // MAYBE: Write this? + + // case 'SetStage': + // TODO: Write this. + + case 'ZoomCamera': + var ease:String = event.data?.ease ?? 'linear'; + if (ease == 'INSTANT') ease = '[instant]'; + // sets the default zoom and lerps handle the rest + // if (ease == 'CLASSIC') ease = '[none]'; + makeEvent('Manage Camera Zoom', [ + event.data?.zoom ?? 1, + event.data?.duration ?? 4, + ease, + (event.data?.mode ?? 'stage') == 'stage' + ]); + default: + // UNKNOWN + } + } + // psych conversion process + if (basicMeta.inputFormats.contains(FNF_LEGACY_PSYCH)) { + switch (event.name) { + case 'Play Animation': + /* makeEvent('Play Sprite Animation', [ + // + ]); */ + default: + // UNKNOWN + } + // TODO: Write this. + } + if (basicMeta.inputFormats.contains(FNF_CODENAME)) { + // codename conversion process + // TODO: Write this. + } + // jic + if (basicMeta.inputFormats.contains(FNF_IMAGINATIVE)) { + // TODO: Write this. + } + } + events.sort((a, b) -> return Util.sortValues(a.time, b.time)); + // trace(haxe.Json.stringify(events, '\t')); data = { speed: basicMeta.scrollSpeeds.get(diffId) ?? Util.mapFirst(basicMeta.scrollSpeeds) ?? 2.6, @@ -333,7 +471,7 @@ class FNFImaginative extends BasicJsonFormat = basicMeta.bpmChanges; @@ -359,7 +497,7 @@ class FNFImaginative extends BasicJsonFormat { - var notes:Array = []; + var notes:Array = Util.makeArray(0); for (field in data.fields) for (note in field.notes) notes.push({ @@ -373,7 +511,7 @@ class FNFImaginative extends BasicJsonFormat { - var events:Array = []; + var events:Array = Util.makeArray(0); for (event in data.events) for (data in event.data) events.push(Util.makeArrayEvent(event.time, data.name, data.params)); @@ -428,8 +566,8 @@ class FNFImaginative extends BasicJsonFormat