added vslice fnfc format (psych import soon)
This commit is contained in:
@@ -4,8 +4,142 @@ import funkin.backend.chart.ChartData.ChartMetaData;
|
|||||||
|
|
||||||
// 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
|
// 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 BaseGameParser {
|
class BaseGameParser {
|
||||||
public static function parseChart(data:Dynamic, metaData:Dynamic, result:ChartData) {
|
public static function parseChart(data:Dynamic, metaData:Dynamic, events:Dynamic, result:ChartData) {
|
||||||
// TO DO
|
// base fnf chart parsing
|
||||||
|
var data:Array<SwagNote> = data;
|
||||||
|
var metadata:SwagMetadata = metaData;
|
||||||
|
var events:Array<SwagEvent> = events;
|
||||||
|
|
||||||
|
result.stage = metadata.playData.stage;
|
||||||
|
|
||||||
|
var p2isGF:Bool = false;
|
||||||
|
result.strumLines.push({
|
||||||
|
characters: [metadata.playData.characters.player],
|
||||||
|
type: 1,
|
||||||
|
position: "boyfriend",
|
||||||
|
notes: [],
|
||||||
|
vocalsSuffix: "-Player"
|
||||||
|
});
|
||||||
|
result.strumLines.push({
|
||||||
|
characters: [metadata.playData.characters.opponent],
|
||||||
|
type: 0,
|
||||||
|
position: (p2isGF = metadata.playData.characters.opponent.startsWith("gf")) ? "girlfriend" : "dad",
|
||||||
|
notes: [],
|
||||||
|
vocalsSuffix: "-Opponent"
|
||||||
|
});
|
||||||
|
var gfName = metadata.playData.characters.girlfriend;
|
||||||
|
if (!p2isGF && gfName != "none") {
|
||||||
|
result.strumLines.push({
|
||||||
|
characters: [gfName],
|
||||||
|
type: 2,
|
||||||
|
position: "girlfriend",
|
||||||
|
notes: [],
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstTimeChange = metadata.timeChanges[0];
|
||||||
|
result.meta.bpm = firstTimeChange.bpm;
|
||||||
|
result.meta.needsVoices = true;
|
||||||
|
|
||||||
|
for (note in data)
|
||||||
|
{
|
||||||
|
var daNoteType:Null<Int> = null;
|
||||||
|
if (note.k != null)
|
||||||
|
daNoteType = Chart.addNoteType(result, note.k);
|
||||||
|
|
||||||
|
var daNoteData:Int = Std.int(note.d % 8);
|
||||||
|
var isMustHit:Bool = Math.floor(daNoteData / 4) == 0;
|
||||||
|
|
||||||
|
result.strumLines[isMustHit ? 0 : 1].notes.push({
|
||||||
|
time: note.t,
|
||||||
|
id: daNoteData % 4,
|
||||||
|
type: daNoteType,
|
||||||
|
sLen: note.l
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (event in events)
|
||||||
|
{
|
||||||
|
switch (event.e)
|
||||||
|
{
|
||||||
|
case "FocusCamera":
|
||||||
|
result.events.push({
|
||||||
|
time: event.t,
|
||||||
|
name: "Camera Movement",
|
||||||
|
params: [event.v.char]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*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) {
|
||||||
@@ -29,7 +163,7 @@ class BaseGameParser {
|
|||||||
public static function encodeMeta(meta:ChartMetaData, ?chart:ChartData):SwagMetadata {
|
public static function encodeMeta(meta:ChartMetaData, ?chart:ChartData):SwagMetadata {
|
||||||
var addVars:Dynamic = meta.customValues;
|
var addVars:Dynamic = meta.customValues;
|
||||||
var defStage:String = addVars.stage != null ? addVars.stage : Flags.DEFAULT_STAGE;
|
var defStage:String = addVars.stage != null ? addVars.stage : Flags.DEFAULT_STAGE;
|
||||||
var defChars:SwagCharactersList = addVars.characters != null ? addVars.characters : {player: Flags.DEFAULT_CHARACTER, girlfriend: Flags.DEFAULT_GIRLFRIEND, opponent: Flags.DEFAULT_OPPONENT};
|
var defChars:SwagCharactersList = addVars.characters != null ? addVars.characters : {player: Flags.DEFAULT_CHARACTER, girlfriend: Flags.DEFAULT_GIRLFRIEND, opponent: Flags.DEFAULT_OPPONENT, playerVocals: [], opponentVocals: [], instrumental: '', altInstrumentals: []};
|
||||||
var defTimeCh:Array<SwagTimeChange>;
|
var defTimeCh:Array<SwagTimeChange>;
|
||||||
|
|
||||||
if (addVars.timeChanges != null && addVars.timeChanges.length > 0) {
|
if (addVars.timeChanges != null && addVars.timeChanges.length > 0) {
|
||||||
@@ -141,6 +275,10 @@ typedef SwagCharactersList =
|
|||||||
var player:String;
|
var player:String;
|
||||||
var girlfriend:String;
|
var girlfriend:String;
|
||||||
var opponent:String;
|
var opponent:String;
|
||||||
|
var instrumental:String;
|
||||||
|
var altInstrumentals:Array<String>;
|
||||||
|
var opponentVocals:Array<String>;
|
||||||
|
var playerVocals:Array<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef SwagSongOffsets =
|
typedef SwagSongOffsets =
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ class Chart {
|
|||||||
#if REGION
|
#if REGION
|
||||||
if (data != null) switch (detectChartFormat(data)) {
|
if (data != null) switch (detectChartFormat(data)) {
|
||||||
case CODENAME:
|
case CODENAME:
|
||||||
// backward compat on events since its caused problems
|
// backward compat on events since it caused problems
|
||||||
var eventTypesToString:Map<Int, String> = [
|
var eventTypesToString:Map<Int, String> = [
|
||||||
-1 => "HScript Call",
|
-1 => "HScript Call",
|
||||||
0 => "Unknown",
|
0 => "Unknown",
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class CharterSelection extends EditorTreeMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if sys
|
#if sys
|
||||||
public function saveSong(creation:SongCreationData) {
|
public function saveSong(creation:SongCreationData, ?callback:String -> SongCreationData -> Void) {
|
||||||
var songAlreadyExists:Bool = [for (s in freeplayList.songs) s.name.toLowerCase()].contains(creation.meta.name.toLowerCase());
|
var songAlreadyExists:Bool = [for (s in freeplayList.songs) s.name.toLowerCase()].contains(creation.meta.name.toLowerCase());
|
||||||
|
|
||||||
if (songAlreadyExists) {
|
if (songAlreadyExists) {
|
||||||
@@ -117,8 +117,14 @@ class CharterSelection extends EditorTreeMenu {
|
|||||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, Flags.JSON_PRETTY_PRINT));
|
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, Flags.JSON_PRETTY_PRINT));
|
||||||
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Flags.SOUND_EXT}', creation.instBytes);
|
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Flags.SOUND_EXT}', creation.instBytes);
|
||||||
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Flags.SOUND_EXT}', creation.voicesBytes);
|
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Flags.SOUND_EXT}', creation.voicesBytes);
|
||||||
|
|
||||||
|
if (creation.playerVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Player.${Flags.SOUND_EXT}', creation.playerVocals);
|
||||||
|
if (creation.oppVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Opponent.${Flags.SOUND_EXT}', creation.oppVocals);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
if (callback != null)
|
||||||
|
callback(songFolder, creation);
|
||||||
|
|
||||||
var option = new EditorIconOption(creation.meta.name, "Press ACCEPT to choose a difficulty to edit.", creation.meta.icon, function() {
|
var option = new EditorIconOption(creation.meta.name, "Press ACCEPT to choose a difficulty to edit.", creation.meta.icon, function() {
|
||||||
curSong = creation.meta;
|
curSong = creation.meta;
|
||||||
var list:Array<OptionType> = [
|
var list:Array<OptionType> = [
|
||||||
|
|||||||
@@ -3,17 +3,23 @@ package funkin.editors.charter;
|
|||||||
import flixel.group.FlxGroup;
|
import flixel.group.FlxGroup;
|
||||||
import flixel.text.FlxText.FlxTextFormat;
|
import flixel.text.FlxText.FlxTextFormat;
|
||||||
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
||||||
import funkin.backend.chart.ChartData.ChartMetaData;
|
import funkin.backend.chart.BaseGameParser;
|
||||||
|
import funkin.backend.chart.ChartData;
|
||||||
|
import funkin.backend.utils.ZipUtil;
|
||||||
|
import haxe.Json;
|
||||||
import haxe.io.Bytes;
|
import haxe.io.Bytes;
|
||||||
|
import haxe.io.BytesInput;
|
||||||
|
|
||||||
typedef SongCreationData = {
|
typedef SongCreationData = {
|
||||||
var meta:ChartMetaData;
|
var meta:ChartMetaData;
|
||||||
var instBytes:Bytes;
|
var instBytes:Bytes;
|
||||||
var voicesBytes:Bytes;
|
var voicesBytes:Bytes;
|
||||||
|
@:optional var playerVocals:Bytes;
|
||||||
|
@:optional var oppVocals:Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SongCreationScreen extends UISubstateWindow {
|
class SongCreationScreen extends UISubstateWindow {
|
||||||
private var onSave:Null<SongCreationData> -> Void = null;
|
private var onSave:Null<SongCreationData> -> Null<String -> SongCreationData -> Void> -> Void = null;
|
||||||
|
|
||||||
public var songNameTextBox:UITextBox;
|
public var songNameTextBox:UITextBox;
|
||||||
public var bpmStepper:UINumericStepper;
|
public var bpmStepper:UINumericStepper;
|
||||||
@@ -21,6 +27,7 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
public var stepsPerBeatStepper :UINumericStepper;
|
public var stepsPerBeatStepper :UINumericStepper;
|
||||||
public var instExplorer:UIFileExplorer;
|
public var instExplorer:UIFileExplorer;
|
||||||
public var voicesExplorer:UIFileExplorer;
|
public var voicesExplorer:UIFileExplorer;
|
||||||
|
public var importFrom:UIButton;
|
||||||
|
|
||||||
public var displayNameTextBox:UITextBox;
|
public var displayNameTextBox:UITextBox;
|
||||||
public var iconTextBox:UITextBox;
|
public var iconTextBox:UITextBox;
|
||||||
@@ -30,6 +37,14 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
public var colorWheel:UIColorwheel;
|
public var colorWheel:UIColorwheel;
|
||||||
public var difficultiesTextBox:UITextBox;
|
public var difficultiesTextBox:UITextBox;
|
||||||
|
|
||||||
|
public var engineDropdown:UIDropDown;
|
||||||
|
public var createSong:UIButton;
|
||||||
|
|
||||||
|
public var importInstExplorer:UIFileExplorer;
|
||||||
|
public var importVoicesExplorer:UIFileExplorer;
|
||||||
|
|
||||||
|
public var importChartFile:UIFileExplorer;
|
||||||
|
|
||||||
public var backButton:UIButton;
|
public var backButton:UIButton;
|
||||||
public var saveButton:UIButton;
|
public var saveButton:UIButton;
|
||||||
public var closeButton:UIButton;
|
public var closeButton:UIButton;
|
||||||
@@ -37,11 +52,21 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
public var songDataGroup:FlxGroup = new FlxGroup();
|
public var songDataGroup:FlxGroup = new FlxGroup();
|
||||||
public var menuDataGroup:FlxGroup = new FlxGroup();
|
public var menuDataGroup:FlxGroup = new FlxGroup();
|
||||||
|
|
||||||
|
public var selectFormatGroup:FlxGroup = new FlxGroup();
|
||||||
|
public var importAudioGroup:FlxGroup = new FlxGroup();
|
||||||
|
public var importChartGroup:FlxGroup = new FlxGroup();
|
||||||
|
|
||||||
public var pages:Array<FlxGroup> = [];
|
public var pages:Array<FlxGroup> = [];
|
||||||
public var pageSizes:Array<FlxPoint> = [];
|
public var pageSizes:Array<FlxPoint> = [];
|
||||||
|
|
||||||
|
public var importPages:Array<FlxGroup> = [];
|
||||||
|
public var importPageSizes:Array<FlxPoint> = [];
|
||||||
|
|
||||||
|
public var isImporting = false;
|
||||||
|
|
||||||
public var curPage:Int = 0;
|
public var curPage:Int = 0;
|
||||||
|
|
||||||
public function new(?onSave:SongCreationData->Void) {
|
public function new(?onSave:SongCreationData -> Null<String -> SongCreationData -> Void> -> Void) {
|
||||||
super();
|
super();
|
||||||
if (onSave != null) this.onSave = onSave;
|
if (onSave != null) this.onSave = onSave;
|
||||||
}
|
}
|
||||||
@@ -80,8 +105,6 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
|
||||||
songDataGroup.add(stepsPerBeatStepper);
|
songDataGroup.add(stepsPerBeatStepper);
|
||||||
|
|
||||||
var voicesUIText:UIText = null;
|
|
||||||
|
|
||||||
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (res) {
|
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Flags.SOUND_EXT, function (res) {
|
||||||
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
|
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
|
||||||
instExplorer.members.push(audioPlayer);
|
instExplorer.members.push(audioPlayer);
|
||||||
@@ -100,6 +123,14 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
songDataGroup.add(voicesExplorer);
|
songDataGroup.add(voicesExplorer);
|
||||||
addLabelOn(voicesExplorer, "Vocal Audio File");
|
addLabelOn(voicesExplorer, "Vocal Audio File");
|
||||||
|
|
||||||
|
importFrom = new UIButton(windowSpr.x + 20, windowSpr.y + windowSpr.bHeight - 16 - 32, "Import From...", function() {
|
||||||
|
winTitle = "Importing Song";
|
||||||
|
isImporting = true;
|
||||||
|
updatePagesTexts();
|
||||||
|
refreshPages();
|
||||||
|
}, 150);
|
||||||
|
songDataGroup.add(importFrom);
|
||||||
|
|
||||||
var menuTitle:UIText;
|
var menuTitle:UIText;
|
||||||
menuDataGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Menus Data (Freeplay/Story)", 28));
|
menuDataGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Menus Data (Freeplay/Story)", 28));
|
||||||
|
|
||||||
@@ -132,7 +163,53 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
for (checkbox in [opponentModeCheckbox, coopAllowedCheckbox])
|
for (checkbox in [opponentModeCheckbox, coopAllowedCheckbox])
|
||||||
{checkbox.y += 6; checkbox.x += 4;}
|
{checkbox.y += 6; checkbox.x += 4;}
|
||||||
|
|
||||||
|
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, 320, 32, ["Psych/Legacy FNF", "V-Slice Project (.fnfc)"]);
|
||||||
|
selectFormatGroup.add(engineDropdown);
|
||||||
|
addLabelOn(engineDropdown, "Chart Format");
|
||||||
|
|
||||||
|
createSong = new UIButton(windowSpr.x + 20, windowSpr.y + windowSpr.bHeight - 16 - 32, "< Back", function() {
|
||||||
|
winTitle = "Creating New Song";
|
||||||
|
isImporting = false;
|
||||||
|
updatePagesTexts();
|
||||||
|
refreshPages();
|
||||||
|
}, 120);
|
||||||
|
selectFormatGroup.add(createSong);
|
||||||
|
|
||||||
|
var menuTitle:UIText;
|
||||||
|
importAudioGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Add Audios", 28));
|
||||||
|
|
||||||
|
importInstExplorer = new UIFileExplorer(menuTitle.x, menuTitle.y + menuTitle.height + 36, null, null, Flags.SOUND_EXT, function (res) {
|
||||||
|
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(importInstExplorer.x + 8, importInstExplorer.y + 8, res);
|
||||||
|
importInstExplorer.members.push(audioPlayer);
|
||||||
|
importInstExplorer.uiElement = audioPlayer;
|
||||||
|
});
|
||||||
|
importAudioGroup.add(importInstExplorer);
|
||||||
|
addLabelOn(importInstExplorer, "Inst Audio File").applyMarkup(
|
||||||
|
"Inst Audio File $* Required$",
|
||||||
|
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
|
||||||
|
|
||||||
|
importVoicesExplorer = new UIFileExplorer(importInstExplorer.x + 320 + 26, importInstExplorer.y, null, null, Flags.SOUND_EXT, function (res) {
|
||||||
|
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(importVoicesExplorer.x + 8, importVoicesExplorer.y + 8, res);
|
||||||
|
importVoicesExplorer.members.push(audioPlayer);
|
||||||
|
importVoicesExplorer.uiElement = audioPlayer;
|
||||||
|
});
|
||||||
|
importAudioGroup.add(importVoicesExplorer);
|
||||||
|
addLabelOn(importVoicesExplorer, "Vocal Audio File");
|
||||||
|
|
||||||
|
var menuTitle:UIText;
|
||||||
|
importChartGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Add Chart", 28));
|
||||||
|
|
||||||
|
importChartFile = new UIFileExplorer(menuTitle.x, menuTitle.y + menuTitle.height + 36, null, null, "fnfc");
|
||||||
|
importChartGroup.add(importChartFile);
|
||||||
|
addLabelOn(importChartFile, "Chart File").applyMarkup(
|
||||||
|
"Chart File $* Required$",
|
||||||
|
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
|
||||||
|
|
||||||
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, "Save & Close", function() {
|
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, "Save & Close", function() {
|
||||||
|
var pages = isImporting ? importPages : pages;
|
||||||
if (curPage == pages.length-1) {
|
if (curPage == pages.length-1) {
|
||||||
saveSongInfo();
|
saveSongInfo();
|
||||||
close();
|
close();
|
||||||
@@ -165,17 +242,36 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
pages.push(cast add(menuDataGroup));
|
pages.push(cast add(menuDataGroup));
|
||||||
pageSizes.push(FlxPoint.get(748 - 32 + 40, 400));
|
pageSizes.push(FlxPoint.get(748 - 32 + 40, 400));
|
||||||
|
|
||||||
|
importPages.push(cast add(selectFormatGroup));
|
||||||
|
importPageSizes.push(FlxPoint.get(500, 250));
|
||||||
|
|
||||||
|
importPages.push(cast add(importAudioGroup));
|
||||||
|
importPageSizes.push(FlxPoint.get(705, 250));
|
||||||
|
|
||||||
|
importPages.push(cast add(importChartGroup));
|
||||||
|
importPageSizes.push(FlxPoint.get(460, 250));
|
||||||
|
|
||||||
refreshPages();
|
refreshPages();
|
||||||
updatePagesTexts();
|
updatePagesTexts();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function update(elapsed:Float) {
|
public override function update(elapsed:Float) {
|
||||||
if (curPage == 0) {
|
if (isImporting)
|
||||||
if (instExplorer.file != null)
|
{
|
||||||
saveButton.selectable = true;
|
if (curPage == 1) {
|
||||||
else saveButton.selectable = false;
|
importInstExplorer.selectable = importVoicesExplorer.selectable = (engineDropdown.index != 1);
|
||||||
|
saveButton.selectable = (engineDropdown.index == 1) ? true : (importInstExplorer.file != null);
|
||||||
|
} else if (curPage == 2) {
|
||||||
|
importChartFile.fileType = (engineDropdown.index == 1) ? "fnfc" : "json";
|
||||||
|
saveButton.selectable = (importChartFile.file != null);
|
||||||
} else
|
} else
|
||||||
saveButton.selectable = true;
|
saveButton.selectable = true;
|
||||||
|
} else {
|
||||||
|
if (curPage == 0)
|
||||||
|
saveButton.selectable = (instExplorer.file != null);
|
||||||
|
else
|
||||||
|
saveButton.selectable = true;
|
||||||
|
}
|
||||||
|
|
||||||
saveButton.alpha = saveButton.field.alpha = saveButton.selectable ? 1 : 0.4;
|
saveButton.alpha = saveButton.field.alpha = saveButton.selectable ? 1 : 0.4;
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
@@ -183,10 +279,15 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
|
|
||||||
function refreshPages() {
|
function refreshPages() {
|
||||||
for (i=>page in pages)
|
for (i=>page in pages)
|
||||||
page.visible = page.exists = i == curPage;
|
page.visible = page.exists = i == curPage && !isImporting;
|
||||||
|
|
||||||
|
for (i=>page in importPages)
|
||||||
|
page.visible = page.exists = i == curPage && isImporting;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePagesTexts() {
|
function updatePagesTexts() {
|
||||||
|
var pageSizes = isImporting ? importPageSizes : pageSizes;
|
||||||
|
var pages = isImporting ? importPages : pages;
|
||||||
windowSpr.bWidth = Std.int(pageSizes[curPage].x);
|
windowSpr.bWidth = Std.int(pageSizes[curPage].x);
|
||||||
windowSpr.bHeight = Std.int(pageSizes[curPage].y);
|
windowSpr.bHeight = Std.int(pageSizes[curPage].y);
|
||||||
|
|
||||||
@@ -194,7 +295,7 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
titleSpr.y = windowSpr.y + ((30 - titleSpr.height) / 2);
|
titleSpr.y = windowSpr.y + ((30 - titleSpr.height) / 2);
|
||||||
|
|
||||||
saveButton.field.text = curPage == pages.length-1 ? "Save & Close" : 'Next >';
|
saveButton.field.text = curPage == pages.length-1 ? "Save & Close" : 'Next >';
|
||||||
titleSpr.text = 'Creating New Song (${curPage+1}/${pages.length})';
|
titleSpr.text = '$winTitle (${curPage+1}/${pages.length})';
|
||||||
|
|
||||||
backButton.field.text = '< Back';
|
backButton.field.text = '< Back';
|
||||||
backButton.visible = backButton.exists = curPage > 0;
|
backButton.visible = backButton.exists = curPage > 0;
|
||||||
@@ -202,7 +303,7 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
backButton.x = (saveButton.x = windowSpr.x + windowSpr.bWidth - 20 - 125) - 20 - saveButton.bWidth;
|
backButton.x = (saveButton.x = windowSpr.x + windowSpr.bWidth - 20 - 125) - 20 - saveButton.bWidth;
|
||||||
closeButton.x = (curPage > 0 ? backButton : saveButton).x - 20 - saveButton.bWidth;
|
closeButton.x = (curPage > 0 ? backButton : saveButton).x - 20 - saveButton.bWidth;
|
||||||
|
|
||||||
for (button in [saveButton, backButton, closeButton])
|
for (button in [saveButton, backButton, closeButton, importFrom, createSong])
|
||||||
button.y = windowSpr.y + windowSpr.bHeight - 16 - 32;
|
button.y = windowSpr.y + windowSpr.bHeight - 16 - 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +327,78 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveSongInfo() {
|
function saveSongInfo() {
|
||||||
|
if (isImporting)
|
||||||
|
{
|
||||||
|
if (engineDropdown.index == 1)
|
||||||
|
{
|
||||||
|
var reader = new ZipReader(new BytesInput(importChartFile.file));
|
||||||
|
var fields = reader.read();
|
||||||
|
var files:Map<String, Any> = [];
|
||||||
|
|
||||||
|
for(k=>field in fields) {
|
||||||
|
var fileName = field.fileName;
|
||||||
|
var fileContent = field.data;
|
||||||
|
files.set(fileName, fileContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
var manifest = Json.parse(files.get("manifest.json"));
|
||||||
|
var vslicemeta = Json.parse(files.get('${manifest.songId}-metadata.json'));
|
||||||
|
var firstTimeChange = vslicemeta.timeChanges[0];
|
||||||
|
var vslicechart = Json.parse(files.get('${manifest.songId}-chart.json'));
|
||||||
|
var difficulties = Reflect.fields(vslicechart.notes);
|
||||||
|
|
||||||
|
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[0]}.${Flags.SOUND_EXT}');
|
||||||
|
var oppVoices = files.get('Voices-${playData.characters.opponentVocals[0]}.${Flags.SOUND_EXT}');
|
||||||
|
|
||||||
|
var meta:ChartMetaData = {
|
||||||
|
name: manifest.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,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (onSave != null) onSave({
|
||||||
|
meta: meta,
|
||||||
|
instBytes: instFile,
|
||||||
|
voicesBytes: voicesFiles,
|
||||||
|
playerVocals: playerVoices,
|
||||||
|
oppVocals: oppVoices,
|
||||||
|
}, (songFolder:String, creation: SongCreationData) -> {
|
||||||
|
#if sys
|
||||||
|
for (diff in difficulties)
|
||||||
|
{
|
||||||
|
var vsliceChartData = Reflect.field(vslicechart.notes, diff);
|
||||||
|
var chartPath = Paths.chart(manifest.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)
|
||||||
|
};
|
||||||
|
BaseGameParser.parseChart(vsliceChartData, vslicemeta, vslicechart.events, base);
|
||||||
|
CoolUtil.safeSaveFile('$songFolder/charts/$diff.json', Json.stringify(base, Flags.JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper])
|
for (stepper in [bpmStepper, beatsPerMeasureStepper, stepsPerBeatStepper])
|
||||||
@:privateAccess stepper.__onChange(stepper.label.text);
|
@:privateAccess stepper.__onChange(stepper.label.text);
|
||||||
|
|
||||||
@@ -247,7 +420,7 @@ class SongCreationScreen extends UISubstateWindow {
|
|||||||
meta: meta,
|
meta: meta,
|
||||||
instBytes: instExplorer.file,
|
instBytes: instExplorer.file,
|
||||||
voicesBytes: voicesExplorer.file
|
voicesBytes: voicesExplorer.file
|
||||||
});
|
}, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -15,12 +15,16 @@ class UIFileExplorer extends UISliceSprite {
|
|||||||
|
|
||||||
public var uiElement:UISprite;
|
public var uiElement:UISprite;
|
||||||
|
|
||||||
|
public var fileType:String = "txt";
|
||||||
|
|
||||||
public function new(x:Float, y:Float, ?w:Int, ?h:Int, fileType:String = "txt", ?onFile:Bytes->Void) {
|
public function new(x:Float, y:Float, ?w:Int, ?h:Int, fileType:String = "txt", ?onFile:Bytes->Void) {
|
||||||
super(x, y, (w != null ? w : 320), (h != null ? h : 58), 'editors/ui/inputbox');
|
super(x, y, (w != null ? w : 320), (h != null ? h : 58), 'editors/ui/inputbox');
|
||||||
|
this.fileType = fileType;
|
||||||
|
|
||||||
if (onFile != null) this.onFile = onFile;
|
if (onFile != null) this.onFile = onFile;
|
||||||
|
|
||||||
uploadButton = new UIButton(x + 8, y+ 8, "", function () {
|
uploadButton = new UIButton(x + 8, y+ 8, "", function () {
|
||||||
|
if (!selectable) return;
|
||||||
var fileDialog = new FileDialog();
|
var fileDialog = new FileDialog();
|
||||||
fileDialog.onOpen.add(function(res) {
|
fileDialog.onOpen.add(function(res) {
|
||||||
file = cast res;
|
file = cast res;
|
||||||
@@ -28,7 +32,7 @@ class UIFileExplorer extends UISliceSprite {
|
|||||||
|
|
||||||
if (this.onFile != null) this.onFile(file);
|
if (this.onFile != null) this.onFile(file);
|
||||||
});
|
});
|
||||||
fileDialog.open(fileType);
|
fileDialog.open(this.fileType);
|
||||||
}, bWidth - 16, bHeight - 16);
|
}, bWidth - 16, bHeight - 16);
|
||||||
members.push(uploadButton);
|
members.push(uploadButton);
|
||||||
|
|
||||||
@@ -63,6 +67,7 @@ class UIFileExplorer extends UISliceSprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function removeFile() {
|
public function removeFile() {
|
||||||
|
if (!selectable) return;
|
||||||
if (uiElement != null) {
|
if (uiElement != null) {
|
||||||
members.remove(uiElement);
|
members.remove(uiElement);
|
||||||
uiElement.destroy();
|
uiElement.destroy();
|
||||||
|
|||||||
Reference in New Issue
Block a user