to be polished

This commit is contained in:
Frakist
2024-01-31 21:44:16 +02:00
parent 3585905450
commit bc30119934
5 changed files with 332 additions and 47 deletions
@@ -0,0 +1,271 @@
package funkin.editors.charter;
import funkin.game.HealthIcon;
import funkin.backend.chart.ChartData;
import haxe.io.Bytes;
typedef ChartCreationData = {
var name:String;
var chart:ChartData;
var meta:Dynamic;
var ?instBytes:Bytes;
var ?voicesBytes:Bytes;
}
class ChartCreationScreen extends UISubstateWindow {
private var onSave:Null<ChartCreationData> -> Void = null;
public var difficultyNameTextBox:UITextBox;
public var scrollSpeedTextBox:UINumericStepper;
public var stageTextBox:UITextBox;
public var strumLineList:UIButtonList<StrumLineButton>;
public var instExplorer:UIFileExplorer;
public var voicesExplorer:UIFileExplorer;
public var bpmStepper:UINumericStepper;
public var beatsPerMeasureStepper:UINumericStepper;
public var stepsPerBeatStepper:UINumericStepper;
public var saveButton:UIButton;
public var closeButton:UIButton;
public function new(?onSave:ChartCreationData->Void) {
super();
if (onSave != null) this.onSave = onSave;
}
public override function create() {
winTitle = "Creating New Chart";
winWidth = 948 - 32 + 40;
winHeight = 520;
super.create();
function addLabelOn(ui:UISprite, text:String):UIText {
var text:UIText = new UIText(ui.x, ui.y - 24, 0, text);
ui.members.push(text);
return text;
}
var chartTitle:UIText;
add(chartTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Chart Info", 28));
difficultyNameTextBox = new UITextBox(chartTitle.x, chartTitle.y + chartTitle.height + 36, "Difficulty Name", 200);
add(difficultyNameTextBox);
addLabelOn(difficultyNameTextBox, "Difficulty Name");
scrollSpeedTextBox = new UINumericStepper(difficultyNameTextBox.x + 200 + 26, difficultyNameTextBox.y, 1.0, 0.1, 2, null, null, 90);
add(scrollSpeedTextBox);
addLabelOn(scrollSpeedTextBox, "Scroll Speed");
stageTextBox = new UITextBox(chartTitle.x, scrollSpeedTextBox.y + 32 + 36, "Stage", 125);
add(stageTextBox);
addLabelOn(stageTextBox, "Stage");
strumLineList = new UIButtonList<StrumLineButton>(scrollSpeedTextBox.x + 150 + 26, scrollSpeedTextBox.y, 520, 350, "", FlxPoint.get(510, 150), null, 5);
strumLineList.frames = Paths.getFrames('editors/ui/inputbox');
strumLineList.cameraSpacing = 0;
strumLineList.add(new StrumLineButton(0, "dad", 0, true));
strumLineList.add(new StrumLineButton(1, "bf", 1, true));
strumLineList.add(new StrumLineButton(2, "gf", 2, false));
add(strumLineList);
addLabelOn(strumLineList, "Strumlines");
var songTitle:UIText;
add(songTitle = new UIText(stageTextBox.x, stageTextBox.y + 32 + 26, 0, "Specific Song (OPTIONAL)", 28));
instExplorer = new UIFileExplorer(songTitle.x, songTitle.y + songTitle.height + 36, 174, null, Paths.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
instExplorer.members.push(audioPlayer);
instExplorer.uiElement = audioPlayer;
});
add(instExplorer);
addLabelOn(instExplorer, "Inst Audio File");
voicesExplorer = new UIFileExplorer(instExplorer.x + 174 + 26, instExplorer.y, 174, null, Paths.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(voicesExplorer.x + 8, voicesExplorer.y + 8, res);
voicesExplorer.members.push(audioPlayer);
voicesExplorer.uiElement = audioPlayer;
});
add(voicesExplorer);
addLabelOn(voicesExplorer, "Voices Audio File");
bpmStepper = new UINumericStepper(instExplorer.x, instExplorer.y + 58 + 36, 100, 1, 2, 1, null, 90);
add(bpmStepper);
addLabelOn(bpmStepper, "BPM");
beatsPerMeasureStepper = new UINumericStepper(bpmStepper.x + 60 + 26, bpmStepper.y, 4, 1, 0, 1, null, 54);
add(beatsPerMeasureStepper);
addLabelOn(beatsPerMeasureStepper, "Time Signature");
add(new UIText(beatsPerMeasureStepper.x + 30, beatsPerMeasureStepper.y + 3, 0, "/", 22));
stepsPerBeatStepper = new UINumericStepper(beatsPerMeasureStepper.x + 30 + 24, beatsPerMeasureStepper.y, 4, 1, 0, 1, null, 54);
add(stepsPerBeatStepper);
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, "Create Chart", function() {
createChart();
close();
}, 125);
add(saveButton);
closeButton = new UIButton(saveButton.x - 20 - saveButton.bWidth, saveButton.y, "Cancel", function() {
close();
}, 125);
add(closeButton);
closeButton.color = 0xFFFF0000;
}
function createChart() {
var strlines = [];
for (strline in strumLineList.buttons.members) {
strlines.push({
characters: [for (charb in strline.characterList.buttons.members) charb.textBox.label.text],
type: strline.typeDropDown.index,
notes: [],
position: null,
visible: strline.visibleCheckBox.checked,
strumPos: [0, strline.positionYStepper.value],
strumLinePos: strline.positionXStepper.value,
});
}
var chartData:ChartData = {
codenameChart: true,
strumLines: strlines,
stage: stageTextBox.label.text,
scrollSpeed: scrollSpeedTextBox.value,
events: [],
noteTypes: [],
meta: null
}
if (onSave != null) onSave({
name: difficultyNameTextBox.label.text,
chart: chartData,
meta: {
bpm: bpmStepper.value,
beatsPerMeasure: beatsPerMeasureStepper.value,
stepsPerBeat: stepsPerBeatStepper.value
},
instBytes: instExplorer.file,
voicesBytes: voicesExplorer.file
});
}
}
class StrumLineButton extends UIButton {
public var numberText:UIText;
public var positionXStepper:UINumericStepper;
public var positionXStepperText:UIText;
public var positionYStepper:UINumericStepper;
public var positionYStepperText:UIText;
public var typeDropDownText:UIText;
public var typeDropDown:UIDropDown;
public var visibleCheckBoxText:UIText;
public var visibleCheckBox:UICheckbox;
public var characterList:UIButtonList<CompressedCharacterButton>;
public function new(id:Int, char:String, type:Int, visible:Bool) {
super(0, 0, '', function () {}, 510, 150);
numberText = new UIText(5, 5, 0, 'Strumline #$id');
members.push(numberText);
positionXStepperText = new UIText(numberText.x, numberText.y + 26, 0, "X (ratio)");
members.push(positionXStepperText);
positionXStepper = new UINumericStepper(positionXStepperText.x, positionXStepperText.y + 24, 1.0, 0.1, 2, null, null, 90);
members.push(positionXStepper);
positionYStepperText = new UIText(positionXStepper.x + 60 + 26, positionXStepper.y, 0, "Y");
members.push(positionYStepperText);
positionYStepper = new UINumericStepper(positionYStepperText.x, positionYStepperText.y + 24, 1.0, 0.1, 2, null, null, 90);
members.push(positionYStepper);
visibleCheckBoxText = new UIText(positionXStepper.x + 90 + 26, positionXStepper.y, 0, "Visible?");
members.push(visibleCheckBoxText);
visibleCheckBox = new UICheckbox(visibleCheckBoxText.x, positionYStepperText.y + 24, "Visible", visible);
members.push(visibleCheckBox);
typeDropDownText = new UIText(positionXStepper.x, positionXStepper.y + 32 + 36, 0, "Type");
members.push(typeDropDownText);
typeDropDown = new UIDropDown(typeDropDownText.x, typeDropDownText.y + 24, 165, 32, ["OPPONENT", "PLAYER", "ADDITIONAL"], type);
members.push(typeDropDown);
characterList = new UIButtonList<CompressedCharacterButton>(numberText.x + 265 + 26, numberText.y, 210, 140, "", FlxPoint.get(200, 40), null, 5);
characterList.frames = Paths.getFrames('editors/ui/inputbox');
characterList.cameraSpacing = 0;
characterList.add(new CompressedCharacterButton(char, [], characterList));
members.push(characterList);
}
public override function update(elapsed) {
numberText.follow(this, 5, 5);
positionXStepperText.follow(numberText, 0, 26);
positionXStepper.follow(positionXStepperText, 0, 24);
positionYStepperText.follow(positionXStepperText, 65 + 26, 0);
positionYStepper.follow(positionYStepperText, 0, 24);
visibleCheckBoxText.follow(positionYStepperText, 65 + 26, 0);
visibleCheckBox.follow(visibleCheckBoxText, 0, 24);
typeDropDownText.follow(positionXStepper, 0, 36);
typeDropDown.follow(typeDropDownText, 0, 24);
characterList.follow(numberText, 265 + 26, 0);
super.update(elapsed);
}
}
class CompressedCharacterButton extends UIButton {
public var charIcon:HealthIcon;
public var textBox:UIAutoCompleteTextBox;
public var deleteButton:UIButton;
public var deleteIcon:FlxSprite;
public function new(char:String, charsList:Array<String>, parent:UIButtonList<CompressedCharacterButton>) {
super(0, 0, "", null, 200, 40);
autoAlpha = false;
charIcon = new HealthIcon(funkin.game.Character.getIconFromCharName(char));
charIcon.scale.set(0.2, 0.2);
charIcon.updateHitbox();
charIcon.setPosition(10, bHeight/2 - charIcon.height / 2);
charIcon.scrollFactor.set(1,1);
members.push(charIcon);
members.push(textBox = new UIAutoCompleteTextBox(charIcon.x + charIcon.width + 16, bHeight/2 - (32/2), char, 115));
textBox.suggestItems = charsList;
textBox.antialiasing = true;
textBox.onChange = function(char:String) {
char = funkin.game.Character.getIconFromCharName(char);
var image = Paths.image("icons/" + char);
if(!Assets.exists(image))
image = Paths.image("icons/face");
charIcon.loadGraphic(image, true, 150, 150);
charIcon.updateHitbox();
}
deleteButton = new UIButton(textBox.x + 115 + 16, bHeight/2 - (32/2), "", function () {
parent.remove(this);
}, 32);
deleteButton.color = 0xFFFF0000;
deleteButton.autoAlpha = false;
members.push(deleteButton);
deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button'));
deleteIcon.antialiasing = false;
members.push(deleteIcon);
}
override function update(elapsed) {
charIcon.follow(this, 6, bHeight / 2 - charIcon.height / 2);
textBox.follow(charIcon, charIcon.width + 6, 0);
deleteButton.follow(textBox, 115 + 6, 0);
deleteIcon.follow(deleteButton, 15 / 2, 8);
deleteButton.selectable = selectable;
deleteButton.shouldPress = shouldPress;
super.update(elapsed);
}
}
@@ -1,8 +1,10 @@
package funkin.editors.charter;
import funkin.backend.chart.ChartData.ChartMetaData;
import haxe.Json;
import funkin.backend.assets.ModsFolder;
import funkin.editors.charter.SongCreationScreen.SongCreationData;
import funkin.editors.charter.ChartCreationScreen.ChartCreationData;
import funkin.options.type.NewOption;
import funkin.backend.system.framerate.Framerate;
import flixel.util.FlxColor;
@@ -15,6 +17,7 @@ using StringTools;
class CharterSelection extends EditorTreeMenu {
public var freeplayList:FreeplaySonglist;
public var curSong:ChartMetaData;
public override function create() {
bgType = "charter";
@@ -26,21 +29,20 @@ class CharterSelection extends EditorTreeMenu {
var list:Array<OptionType> = [
for(s in freeplayList.songs) new EditorIconOption(s.name, "Press ACCEPT to choose a difficulty to edit.", s.icon, function() {
curSong = s;
var list:Array<OptionType> = [
for(d in s.difficulties) if (d != "") new TextOption(d, "Press ACCEPT to edit the chart for the selected difficulty", function() {
FlxG.switchState(new Charter(s.name, d));
})
];
list.push(new NewOption("New Difficulty", "New Difficulty", function() {
openSubState(new UIWarningSubstate("New Difficulty: Feature Not Implemented!", "This feature isnt implemented yet. Please wait for more cne updates to have this functional.\n\n\n- Codename Devs", [
{label: "Ok", color: 0xFFFF0000, onClick: function(t) {}}
]));
FlxG.state.openSubState(new ChartCreationScreen(saveChart));
}));
optionsTree.add(new OptionsScreen(s.name, "Select a difficulty to continue.", list));
}, s.parsedColor.getDefault(0xFFFFFFFF))
];
list.insert(0, new NewOption("New Chart", "New Chart", function() {
list.insert(0, new NewOption("New Song", "New Song", function() {
FlxG.state.openSubState(new SongCreationScreen(saveSong));
}));
@@ -130,4 +132,42 @@ class CharterSelection extends EditorTreeMenu {
freeplayList.songs.insert(0, creation.meta);
main.insert(1, option);
}
public function saveChart(creation:ChartCreationData) {
var difficultyAlreadlyExsits:Bool = curSong.difficulties.contains(creation.name);
if (difficultyAlreadlyExsits) {
openSubState(new UIWarningSubstate("Creating Chart: Error!", "The chart you are trying to create alreadly exists, if you would like to override it delete the chart first!", [
{label: "Ok", color: 0xFFFF0000, onClick: function(t) {}}
]));
return;
}
// Paths
var songFolder:String = '${Paths.getAssetsRoot()}/songs/${curSong.name}';
var chartFile:String = '$songFolder/${creation.name}.json';
// Make Meta File For Chart
if (creation.instBytes != null) {
var chartMeta = Json.parse(sys.io.File.getContent('$songFolder/meta.json'));
chartMeta.bpm = creation.meta.bpm;
chartMeta.beatsPerMeasure = creation.meta.beatsPerMeasure;
chartMeta.stepsPerBeat = creation.meta.stepsPerBeat;
creation.chart.meta = chartMeta;
}
// Save Files
#if sys
sys.io.File.saveContent('$songFolder/charts/${creation.name}.json', Json.stringify(creation.chart, "\t"));
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst-${creation.name}.${Paths.SOUND_EXT}', creation.instBytes);
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices-${creation.name}.${Paths.SOUND_EXT}', creation.voicesBytes);
#end
//Add to List
curSong.difficulties.push(creation.name);
var option = new TextOption(creation.name, "Press ACCEPT to edit the chart for the selected difficulty", function() {
FlxG.switchState(new Charter(curSong.name, creation.name));
});
main.insert(main.length - 2, option);
}
}
@@ -102,7 +102,7 @@ class SongCreationScreen extends UISubstateWindow {
addLabelOn(needsVoicesCheckbox, "Needs Voices");
needsVoicesCheckbox.y += 6; needsVoicesCheckbox.x += 4;
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, Paths.SOUND_EXT, function (res) {
instExplorer = new UIFileExplorer(songNameTextBox.x, songNameTextBox.y + 32 + 36, null, null, Paths.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(instExplorer.x + 8, instExplorer.y + 8, res);
instExplorer.members.push(audioPlayer);
instExplorer.uiElement = audioPlayer;
@@ -112,7 +112,7 @@ class SongCreationScreen extends UISubstateWindow {
"Inst Audio File $* Required$",
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]);
voicesExplorer = new UIFileExplorer(instExplorer.x + 320 + 26, instExplorer.y, Paths.SOUND_EXT, function (res) {
voicesExplorer = new UIFileExplorer(instExplorer.x + 320 + 26, instExplorer.y, null, null, Paths.SOUND_EXT, function (res) {
var audioPlayer:UIAudioPlayer = new UIAudioPlayer(voicesExplorer.x + 8, voicesExplorer.y + 8, res);
voicesExplorer.members.push(audioPlayer);
voicesExplorer.uiElement = audioPlayer;
+9 -35
View File
@@ -13,7 +13,6 @@ class UIButtonList<T:UIButton> extends UIWindow {
public var addButton:UIButton;
public var addIcon:FlxSprite;
public var buttonCameras:FlxCamera;
public var cameraSpacing = 30;
public var buttonSpacing:Float = 16;
@@ -32,14 +31,9 @@ class UIButtonList<T:UIButton> extends UIWindow {
if (buttonOffset != null) this.buttonOffset = buttonOffset;
super(x, y, width, height, windowName);
buttonCameras = new FlxCamera(Std.int(x), Std.int(y+cameraSpacing), width, height-cameraSpacing-1);
FlxG.cameras.add(buttonCameras, false);
buttonCameras.bgColor = 0;
addButton = new UIButton(25, 16, "", null, Std.int(this.buttonSize.x));
addButton.autoAlpha = false;
addButton.color = 0xFF00FF00;
addButton.cameras = [buttonCameras];
addIcon = new FlxSprite(addButton.x + addButton.bHeight / 2, addButton.y + (32/2) - 8).loadGraphic(Paths.image('editors/charter/add-button'));
addIcon.antialiasing = false;
@@ -47,7 +41,7 @@ class UIButtonList<T:UIButton> extends UIWindow {
members.push(addButton);
members.push(buttons);
nextscrollY = buttonCameras.scroll.y = -this.buttonSpacing;
nextscrollY = -this.buttonSpacing;
}
public inline function add(button:T) {
@@ -75,22 +69,22 @@ class UIButtonList<T:UIButton> extends UIWindow {
if (curMoving != button) {
button.setPosition(
(bWidth/2) - (buttonSize.x/2) + buttonOffset.x,
CoolUtil.fpsLerp(button.y, ((buttonSize.y+buttonSpacing) * i) + buttonOffset.y, 0.25));
x + (bWidth/2) - (buttonSize.x/2) + buttonOffset.x,
CoolUtil.fpsLerp(button.y, y + nextscrollY + cameraSpacing + ((buttonSize.y+buttonSpacing) * i) + buttonOffset.y, 0.25));
}
if (button.hovered && FlxG.mouse.justPressed) curMoving = button;
}
if (addButton != null)
addButton.setPosition(
(bWidth/2) - (buttonSize.x/2) + buttonOffset.x,
CoolUtil.fpsLerp(addButton.y, ((buttonSize.y+buttonSpacing) * buttons.members.length) + buttonOffset.y, 0.25));
x + (bWidth/2) - (buttonSize.x/2) + buttonOffset.x,
CoolUtil.fpsLerp(addButton.y, y + nextscrollY + cameraSpacing + ((buttonSize.y+buttonSpacing) * buttons.members.length) + buttonOffset.y, 0.25));
if (curMoving != null) {
curMovingInterval += FlxG.mouse.deltaY;
if (Math.abs(curMovingInterval) > addButton.bHeight / 2) {
curMovingInterval = 999;
curMoving.y = CoolUtil.fpsLerp(curMoving.y, FlxG.mouse.getWorldPosition(buttonCameras).y - (curMoving.bHeight / 2), 0.3);
curMoving.y = CoolUtil.fpsLerp(curMoving.y, FlxG.mouse.screenY - (curMoving.bHeight / 2), 0.3);
buttons.sort(function(o, a:T, b:T) return FlxSort.byValues(o, a.y + (a.bHeight / 2), b.y + (a.bHeight / 2)), -1);
}
if (FlxG.mouse.justReleased) {
@@ -107,19 +101,16 @@ class UIButtonList<T:UIButton> extends UIWindow {
super.update(elapsed);
nextscrollY = FlxMath.bound(buttonCameras.scroll.y - (hovered ? FlxG.mouse.wheel : 0) * 12, -buttonSpacing, Math.max((addButton.y + 32 + (buttonSpacing*1.5)) - buttonCameras.height, -buttonSpacing));
nextscrollY = FlxMath.bound(nextscrollY - (hovered ? -FlxG.mouse.wheel : 0) * 12, -Math.max((addButton.y + 32 + (buttonSpacing*1.5)) - bHeight, -buttonSpacing), buttonSpacing);
if (curMoving != null && dragging) {
nextscrollY -= Math.min((bHeight - 100) - FlxG.mouse.getWorldPosition(buttonCameras).y, 0) / 8;
nextscrollY += Math.min(FlxG.mouse.getWorldPosition(buttonCameras).y - 100, 0) / 8;
nextscrollY -= Math.min((bHeight - 100) - FlxG.mouse.screenY, 0) / 8;
nextscrollY += Math.min(FlxG.mouse.screenY - 100, 0) / 8;
}
buttonCameras.scroll.y = nextscrollY;
for (i => button in buttons.members) {
if (button == null) continue;
button.selectable = button.shouldPress = (hovered && !dragging);
button.cameras = [buttonCameras];
if (button.ID != i) {
if (dragCallback != null) dragCallback(cast button, button.ID, i);
button.ID = i; // Ok back to normal :D
@@ -127,22 +118,5 @@ class UIButtonList<T:UIButton> extends UIWindow {
}
addButton.selectable = (hovered && !dragging);
if (__lastDrawCameras[0] != null) {
buttonCameras.height = bHeight - cameraSpacing - 1; // -1 for the little gap at the bottom of the window
buttonCameras.x = x - __lastDrawCameras[0].scroll.x;
buttonCameras.y = y + cameraSpacing - __lastDrawCameras[0].scroll.y;
buttonCameras.zoom = __lastDrawCameras[0].zoom;
}
}
override function destroy() {
super.destroy();
if(buttonCameras != null) {
if (FlxG.cameras.list.contains(buttonCameras))
FlxG.cameras.remove(buttonCameras);
buttonCameras = null;
}
}
}
+6 -6
View File
@@ -15,8 +15,8 @@ class UIFileExplorer extends UISliceSprite {
public var uiElement:UISprite;
public function new(x:Float, y:Float, fileType:String = "txt", ?onFile:Bytes->Void) {
super(x, y, 320, 58, 'editors/ui/inputbox');
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');
if (onFile != null) this.onFile = onFile;
@@ -29,18 +29,18 @@ class UIFileExplorer extends UISliceSprite {
if (this.onFile != null) this.onFile(file);
});
fileDialog.open(fileType);
}, 320 - 16, 58 - 16);
}, bWidth - 16, bHeight - 16);
members.push(uploadButton);
uploadIcon = new FlxSprite(uploadButton.x + (uploadButton.bWidth / 2) - 8, uploadButton.y + ((58-16)/2) - 8).loadGraphic(Paths.image('editors/ui/upload-button'));
uploadIcon = new FlxSprite(uploadButton.x + (uploadButton.bWidth / 2) - 8, uploadButton.y + ((bHeight-16)/2) - 8).loadGraphic(Paths.image('editors/ui/upload-button'));
uploadIcon.antialiasing = false;
uploadButton.members.push(uploadIcon);
deleteButton = new UIButton(x + 320 - (58 - 16) - 8, y + 8, "", removeFile, 58 - 16, 58 - 16);
deleteButton = new UIButton(x + bWidth - (bHeight - 16) - 8, y + 8, "", removeFile, bHeight - 16, bHeight - 16);
deleteButton.color = 0xFFFF0000;
members.push(deleteButton);
deleteIcon = new FlxSprite(deleteButton.x + ((58 - 16)/2) - 8, deleteButton.y + ((58 - 16)/2) - 8).loadGraphic(Paths.image('editors/delete-button'));
deleteIcon = new FlxSprite(deleteButton.x + ((bHeight - 16)/2) - 8, deleteButton.y + ((bHeight - 16)/2) - 8).loadGraphic(Paths.image('editors/delete-button'));
deleteIcon.antialiasing = false;
members.push(deleteIcon);