diff --git a/Project.xml b/Project.xml
index 8dbb43618..a83db1677 100644
--- a/Project.xml
+++ b/Project.xml
@@ -20,6 +20,7 @@
+
@@ -96,8 +97,9 @@
+
-
+
@@ -150,8 +152,11 @@
+
+
+
@@ -159,7 +164,6 @@
-
@@ -172,7 +176,6 @@
-
@@ -182,18 +185,21 @@
+
+
+
-
-
-
+
+ -->
+ -->
+
@@ -213,12 +219,4 @@
-
-
-
-
-
-
-
-
diff --git a/hmm.json b/hmm.json
index 150a4f242..a3226281b 100644
--- a/hmm.json
+++ b/hmm.json
@@ -47,7 +47,7 @@
"name": "haxeui-core",
"type": "git",
"dir": null,
- "ref": "3590c94858fc6dbcf9b4d522cd644ad571269677",
+ "ref": "f5daafe93bdfa957538f199294a54e0476c805b7",
"url": "https://github.com/haxeui/haxeui-core/"
},
{
@@ -128,7 +128,7 @@
"name": "openfl",
"type": "git",
"dir": null,
- "ref": "d33d489a137ff8fdece4994cf1302f0b6334ed08",
+ "ref": "1591a6c5f1f72e65d711f7e17e8055df41424d94",
"url": "https://github.com/EliteMasterEric/openfl"
},
{
diff --git a/source/Main.hx b/source/Main.hx
index 1d7b73bb8..72209cd30 100644
--- a/source/Main.hx
+++ b/source/Main.hx
@@ -2,12 +2,13 @@ package;
import flixel.FlxGame;
import flixel.FlxState;
+import funkin.util.logging.CrashHandler;
import funkin.MemoryCounter;
import haxe.ui.Toolkit;
-import openfl.Lib;
import openfl.display.FPS;
import openfl.display.Sprite;
import openfl.events.Event;
+import openfl.Lib;
import openfl.media.Video;
import openfl.net.NetStream;
@@ -77,10 +78,18 @@ class Main extends Sprite
* -Eric
*/
+ CrashHandler.initialize();
+
+ CrashHandler.queryStatus();
+
initHaxeUI();
addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen));
+ #if hxcpp_debug_server
+ trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
+ #end
+
#if debug
fpsCounter = new FPS(10, 3, 0xFFFFFF);
addChild(fpsCounter);
diff --git a/source/Postbuild.hx b/source/Postbuild.hx
new file mode 100644
index 000000000..d48b670a4
--- /dev/null
+++ b/source/Postbuild.hx
@@ -0,0 +1,11 @@
+package source; // Yeah, I know...
+
+class Postbuild
+{
+ static function main()
+ {
+ trace('Postbuild');
+
+ // TODO: Maybe put a 'Build took X seconds' message here?
+ }
+}
diff --git a/source/Prebuild.hx b/source/Prebuild.hx
new file mode 100644
index 000000000..63782fc56
--- /dev/null
+++ b/source/Prebuild.hx
@@ -0,0 +1,9 @@
+package source; // Yeah, I know...
+
+class Prebuild
+{
+ static function main()
+ {
+ trace('Prebuild');
+ }
+}
diff --git a/source/funkin/Alphabet.hx b/source/funkin/Alphabet.hx
index 670496727..45e9a2aee 100644
--- a/source/funkin/Alphabet.hx
+++ b/source/funkin/Alphabet.hx
@@ -38,7 +38,7 @@ class Alphabet extends FlxSpriteGroup
var isBold:Bool = false;
- public function new(x:Float = 0.0, y:Float = 0.0, text:String = "", ?bold:Bool = false, typed:Bool = false)
+ public function new(x:Float = 0.0, y:Float = 0.0, text:String = "", bold:Bool = false, typed:Bool = false)
{
super(x, y);
diff --git a/source/funkin/CoolUtil.hx b/source/funkin/CoolUtil.hx
index 93fa937da..d07bb4e22 100644
--- a/source/funkin/CoolUtil.hx
+++ b/source/funkin/CoolUtil.hx
@@ -12,7 +12,6 @@ import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import funkin.play.PlayState;
import funkin.shaderslmfao.ScreenWipeShader;
-import haxe.Json;
import haxe.format.JsonParser;
import lime.math.Rectangle;
import lime.utils.Assets;
@@ -120,31 +119,6 @@ class CoolUtil
FlxG.camera.setFilters([new ShaderFilter(screenWipeShit)]);
}
- /**
- * Just saves the json with some default values hehe
- * @param json
- * @return String
- */
- public static inline function jsonStringify(data:Dynamic):String
- {
- return Json.stringify(data, null, "\t");
- }
-
- /**
- * Hashlink json encoding fix for some wacky bullshit
- * https://github.com/HaxeFoundation/haxe/issues/6930#issuecomment-384570392
- */
- public static function coolJSON(fileData:String)
- {
- var cont = fileData;
- function is(n:Int, what:Int)
- return cont.charCodeAt(n) == what;
- return JsonParser.parse(cont.substr(if (is(0, 65279)) /// looks like a HL target, skipping only first character here:
- 1 else if (is(0, 239) && is(1, 187) && is(2, 191)) /// it seems to be Neko or PHP, start from position 3:
- 3 else /// all other targets, that prepare the UTF string correctly
- 0));
- }
-
/*
* frame dependant lerp kinda lol
*/
diff --git a/source/funkin/Discord.hx b/source/funkin/Discord.hx
index 4fb6e9dcf..d2cf12535 100644
--- a/source/funkin/Discord.hx
+++ b/source/funkin/Discord.hx
@@ -64,7 +64,7 @@ class DiscordClient
trace("Discord Client initialized");
}
- public static function changePresence(details:String, state:Null, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
+ public static function changePresence(details:String, ?state:String, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
{
var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
diff --git a/source/funkin/FreeplayState.hx b/source/funkin/FreeplayState.hx
index dd87e7d36..c31e8c77b 100644
--- a/source/funkin/FreeplayState.hx
+++ b/source/funkin/FreeplayState.hx
@@ -464,7 +464,7 @@ class FreeplayState extends MusicBeatSubState
});
}
- public function generateSongList(?filterStuff:SongFilter, ?force:Bool = false)
+ public function generateSongList(?filterStuff:SongFilter, force:Bool = false)
{
curSelected = 0;
@@ -1045,7 +1045,7 @@ class FreeplaySongData
public var songCharacter:String = "";
public var isFav:Bool = false;
- public function new(song:String, levelId:String, songCharacter:String, ?isFav:Bool = false)
+ public function new(song:String, levelId:String, songCharacter:String, isFav:Bool = false)
{
this.songName = song;
this.levelId = levelId;
diff --git a/source/funkin/PauseSubState.hx b/source/funkin/PauseSubState.hx
index 9133a8fab..791a4bb9a 100644
--- a/source/funkin/PauseSubState.hx
+++ b/source/funkin/PauseSubState.hx
@@ -41,7 +41,7 @@ class PauseSubState extends MusicBeatSubState
var isChartingMode:Bool;
- public function new(?isChartingMode:Bool = false)
+ public function new(isChartingMode:Bool = false)
{
super();
diff --git a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx
index 74b348142..ae7a5708c 100644
--- a/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx
+++ b/source/funkin/graphics/adobeanimate/FlxAtlasSprite.hx
@@ -82,7 +82,7 @@ class FlxAtlasSprite extends FlxAnimate
* @param restart Whether to restart the animation if it is already playing.
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
*/
- public function playAnimation(id:String, ?restart:Bool = false, ?ignoreOther:Bool = false):Void
+ public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false):Void
{
// Skip if not allowed to play animations.
if ((!canPlayOtherAnims && !ignoreOther)) return;
diff --git a/source/funkin/play/GameOverSubState.hx b/source/funkin/play/GameOverSubState.hx
index b53937361..15ed0421e 100644
--- a/source/funkin/play/GameOverSubState.hx
+++ b/source/funkin/play/GameOverSubState.hx
@@ -255,7 +255,7 @@ class GameOverSubState extends MusicBeatSubState
* Starts the death music at the appropriate volume.
* @param startingVolume
*/
- function startDeathMusic(?startingVolume:Float = 1, ?force:Bool = false):Void
+ function startDeathMusic(?startingVolume:Float = 1, force:Bool = false):Void
{
var musicPath = Paths.music('gameOver' + musicSuffix);
if (isEnding)
diff --git a/source/funkin/play/character/AnimateAtlasCharacter.hx b/source/funkin/play/character/AnimateAtlasCharacter.hx
index 4f4b3f8f7..3523ec994 100644
--- a/source/funkin/play/character/AnimateAtlasCharacter.hx
+++ b/source/funkin/play/character/AnimateAtlasCharacter.hx
@@ -81,7 +81,7 @@ class AnimateAtlasCharacter extends BaseCharacter
super.onCreate(event);
}
- public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reverse:Bool = false):Void
+ public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reverse:Bool = false):Void
{
if ((!canPlayOtherAnims && !ignoreOther)) return;
diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx
index 72f968538..c7b58c393 100644
--- a/source/funkin/play/character/BaseCharacter.hx
+++ b/source/funkin/play/character/BaseCharacter.hx
@@ -570,7 +570,7 @@ class BaseCharacter extends Bopper
* @param miss If true, play the miss animation instead of the sing animation.
* @param suffix A suffix to append to the animation name, like `alt`.
*/
- public function playSingAnimation(dir:NoteDirection, ?miss:Bool = false, ?suffix:String = ''):Void
+ public function playSingAnimation(dir:NoteDirection, miss:Bool = false, ?suffix:String = ''):Void
{
var anim:String = 'sing${dir.nameUpper}${miss ? 'miss' : ''}${suffix != '' ? '-${suffix}' : ''}';
@@ -578,7 +578,7 @@ class BaseCharacter extends Bopper
playAnimation(anim, true);
}
- public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reversed:Bool = false):Void
+ public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reversed:Bool = false):Void
{
FlxG.watch.addQuick('playAnim(${characterName})', name);
// trace('playAnim(${characterName}): ${name}');
diff --git a/source/funkin/play/character/CharacterData.hx b/source/funkin/play/character/CharacterData.hx
index 710eb884b..f1b316b7f 100644
--- a/source/funkin/play/character/CharacterData.hx
+++ b/source/funkin/play/character/CharacterData.hx
@@ -190,7 +190,7 @@ class CharacterDataParser
* @param charId The character ID to fetch.
* @return The character instance, or null if the character was not found.
*/
- public static function fetchCharacter(charId:String, ?debug:Bool = false):Null
+ public static function fetchCharacter(charId:String, debug:Bool = false):Null
{
if (charId == null || charId == '' || !characterCache.exists(charId))
{
diff --git a/source/funkin/play/character/MultiSparrowCharacter.hx b/source/funkin/play/character/MultiSparrowCharacter.hx
index 34d89362f..968f613ff 100644
--- a/source/funkin/play/character/MultiSparrowCharacter.hx
+++ b/source/funkin/play/character/MultiSparrowCharacter.hx
@@ -181,7 +181,7 @@ class MultiSparrowCharacter extends BaseCharacter
trace('[MULTISPARROWCHAR] Successfully loaded ${animNames.length} animations for ${characterId}');
}
- public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reverse:Bool = false):Void
+ public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reverse:Bool = false):Void
{
// Make sure we ignore other animations if we're currently playing a forced one,
// unless we're forcing a new animation.
diff --git a/source/funkin/play/cutscene/dialogue/ConversationData.hx b/source/funkin/play/cutscene/dialogue/ConversationData.hx
index d2e3b74cf..749f1b7a1 100644
--- a/source/funkin/play/cutscene/dialogue/ConversationData.hx
+++ b/source/funkin/play/cutscene/dialogue/ConversationData.hx
@@ -208,7 +208,7 @@ class OutroData
public var type:OutroType;
public var data:Dynamic;
- public function new(typeStr:Null, data:Dynamic)
+ public function new(?typeStr:String, data:Dynamic)
{
this.type = typeStr ?? OutroType.NONE;
this.data = data;
diff --git a/source/funkin/play/cutscene/dialogue/DialogueBox.hx b/source/funkin/play/cutscene/dialogue/DialogueBox.hx
index 52564010a..bfc0e9233 100644
--- a/source/funkin/play/cutscene/dialogue/DialogueBox.hx
+++ b/source/funkin/play/cutscene/dialogue/DialogueBox.hx
@@ -172,7 +172,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
/**
* Set the sprite scale to the appropriate value.
- * @param scale
+ * @param scale
*/
public function setScale(scale:Null):Void
{
@@ -218,7 +218,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
* @param name The name of the current animation.
* @param frameNumber The number of the current frame.
* @param frameIndex The index of the current frame.
- *
+ *
* For example, if an animation was defined as having the indexes [3, 0, 1, 2],
* then the first callback would have frameNumber = 0 and frameIndex = 3.
*/
@@ -253,7 +253,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
* @param restart Whether to restart the animation if it is already playing.
* @param reversed If true, play the animation backwards, from the last frame to the first.
*/
- public function playAnimation(name:String, restart:Bool = false, ?reversed:Bool = false):Void
+ public function playAnimation(name:String, restart:Bool = false, reversed:Bool = false):Void
{
var correctName:String = correctAnimationName(name);
if (correctName == null) return;
@@ -266,7 +266,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
/**
* Ensure that a given animation exists before playing it.
* Will gracefully check for name, then name with stripped suffixes, then 'idle', then fail to play.
- * @param name
+ * @param name
*/
function correctAnimationName(name:String):String
{
diff --git a/source/funkin/play/cutscene/dialogue/DialogueBoxData.hx b/source/funkin/play/cutscene/dialogue/DialogueBoxData.hx
index 537a27129..801a01dd7 100644
--- a/source/funkin/play/cutscene/dialogue/DialogueBoxData.hx
+++ b/source/funkin/play/cutscene/dialogue/DialogueBoxData.hx
@@ -93,7 +93,7 @@ class DialogueBoxTextData
public var shadowColor:Null;
public var shadowWidth:Null;
- public function new(offsets:Null>, width:Null, size:Null, color:String, shadowColor:Null, shadowWidth:Null)
+ public function new(offsets:Null>, ?width:Int, ?size:Int, color:String, ?shadowColor:String, shadowWidth:Null)
{
this.offsets = offsets ?? [0, 0];
this.width = width ?? 300;
diff --git a/source/funkin/play/cutscene/dialogue/SpeakerData.hx b/source/funkin/play/cutscene/dialogue/SpeakerData.hx
index a0f9a3300..88883ead8 100644
--- a/source/funkin/play/cutscene/dialogue/SpeakerData.hx
+++ b/source/funkin/play/cutscene/dialogue/SpeakerData.hx
@@ -19,8 +19,8 @@ class SpeakerData
public var scale:Float;
public var animations:Array;
- public function new(version:String, name:String, assetPath:String, animations:Array, ?offsets:Array, ?flipX:Bool = false,
- ?isPixel:Bool = false, ?scale:Float = 1.0)
+ public function new(version:String, name:String, assetPath:String, animations:Array, ?offsets:Array, flipX:Bool = false,
+ isPixel:Bool = false, ?scale:Float = 1.0)
{
this.version = version;
this.name = name;
diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx
index b343bee86..8847636bd 100644
--- a/source/funkin/play/notes/Strumline.hx
+++ b/source/funkin/play/notes/Strumline.hx
@@ -271,7 +271,7 @@ class Strumline extends FlxSpriteGroup
* @param strumTime
* @return Float
*/
- static function calculateNoteYPos(strumTime:Float, ?vwoosh:Bool = true):Float
+ static function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float
{
// Make the note move faster visually as it moves offscreen.
var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0;
diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx
index fd45342a0..97871b657 100644
--- a/source/funkin/play/notes/notestyle/NoteStyle.hx
+++ b/source/funkin/play/notes/notestyle/NoteStyle.hx
@@ -113,7 +113,7 @@ class NoteStyle implements IRegistryEntry
return noteFrames;
}
- function getNoteAssetPath(?raw:Bool = false):String
+ function getNoteAssetPath(raw:Bool = false):String
{
if (raw)
{
@@ -161,7 +161,7 @@ class NoteStyle implements IRegistryEntry
return (result == null) ? fallback.fetchNoteAnimationData(dir) : result;
}
- public function getHoldNoteAssetPath(?raw:Bool = false):String
+ public function getHoldNoteAssetPath(raw:Bool = false):String
{
if (raw)
{
@@ -209,7 +209,7 @@ class NoteStyle implements IRegistryEntry
target.antialiasing = !_data.assets.noteStrumline.isPixel;
}
- function getStrumlineAssetPath(?raw:Bool = false):String
+ function getStrumlineAssetPath(raw:Bool = false):String
{
if (raw)
{
diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx
index ec89d8706..63610950f 100644
--- a/source/funkin/play/song/Song.hx
+++ b/source/funkin/play/song/Song.hx
@@ -72,7 +72,7 @@ class Song implements IPlayStateScriptedClass
@:allow(funkin.play.song.Song)
public static function buildRaw(songId:String, metadata:Array, variations:Array, charts:Map,
- ?validScore:Bool = false):Song
+ validScore:Bool = false):Song
{
var result:Song = new Song(songId, true);
@@ -150,7 +150,7 @@ class Song implements IPlayStateScriptedClass
/**
* Parse and cache the chart for all difficulties of this song.
*/
- public function cacheCharts(?force:Bool = false):Void
+ public function cacheCharts(force:Bool = false):Void
{
if (force)
{
diff --git a/source/funkin/play/song/SongData.hx b/source/funkin/play/song/SongData.hx
index 938ee0708..bf574c399 100644
--- a/source/funkin/play/song/SongData.hx
+++ b/source/funkin/play/song/SongData.hx
@@ -920,7 +920,7 @@ typedef RawSongTimeChange =
*/
abstract SongTimeChange(RawSongTimeChange) from RawSongTimeChange
{
- public function new(timeStamp:Float, beatTime:Null, bpm:Float, timeSignatureNum:Int = 4, timeSignatureDen:Int = 4, beatTuplets:Array)
+ public function new(timeStamp:Float, ?beatTime:Float, bpm:Float, timeSignatureNum:Int = 4, timeSignatureDen:Int = 4, beatTuplets:Array)
{
this =
{
diff --git a/source/funkin/play/song/SongDataUtils.hx b/source/funkin/play/song/SongDataUtils.hx
index 750d5f54b..a7cbd1b6c 100644
--- a/source/funkin/play/song/SongDataUtils.hx
+++ b/source/funkin/play/song/SongDataUtils.hx
@@ -123,7 +123,7 @@ class SongDataUtils
/**
* Sort an array of notes by strum time.
*/
- public static function sortNotes(notes:Array, ?desc:Bool = false):Array
+ public static function sortNotes(notes:Array, desc:Bool = false):Array
{
// TODO: Modifies the array in place. Is this okay?
notes.sort(function(a:SongNoteData, b:SongNoteData):Int {
@@ -135,7 +135,7 @@ class SongDataUtils
/**
* Sort an array of events by strum time.
*/
- public static function sortEvents(events:Array, ?desc:Bool = false):Array
+ public static function sortEvents(events:Array, desc:Bool = false):Array
{
// TODO: Modifies the array in place. Is this okay?
events.sort(function(a:SongEventData, b:SongEventData):Int {
diff --git a/source/funkin/play/song/SongValidator.hx b/source/funkin/play/song/SongValidator.hx
index d91dda1d9..16ea88664 100644
--- a/source/funkin/play/song/SongValidator.hx
+++ b/source/funkin/play/song/SongValidator.hx
@@ -63,9 +63,15 @@ class SongValidator
}
input.timeChanges = validateTimeChanges(input.timeChanges, songId);
+ if (input.timeChanges == null)
+ {
+ trace('[SONGDATA] Song ${songId} is missing a timeChanges field. ');
+ return null;
+ }
+
input.playData = validatePlayData(input.playData, songId);
- input.variation = '';
+ if (input.variation == null) input.variation = '';
return input;
}
@@ -79,6 +85,12 @@ class SongValidator
*/
public static function validatePlayData(input:SongPlayData, songId:String = 'unknown'):SongPlayData
{
+ if (input == null)
+ {
+ trace('[SONGDATA] Could not parse metadata.playData for song ${songId}');
+ return null;
+ }
+
return input;
}
@@ -91,6 +103,12 @@ class SongValidator
*/
public static function validateTimeChange(input:SongTimeChange, songId:String = 'unknown'):SongTimeChange
{
+ if (input == null)
+ {
+ trace('[SONGDATA] Could not parse metadata.timeChange for song ${songId}');
+ return null;
+ }
+
return input;
}
@@ -101,8 +119,8 @@ class SongValidator
{
if (input == null)
{
- trace('[SONGDATA] Song ${songId} is missing a timeChanges field. ');
- return [];
+ trace('[SONGDATA] Could not parse metadata.timeChange for song ${songId}');
+ return null;
}
input = input.map((timeChange) -> validateTimeChange(timeChange, songId));
diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx
index a144026f5..187b5ec32 100644
--- a/source/funkin/play/stage/Bopper.hx
+++ b/source/funkin/play/stage/Bopper.hx
@@ -268,7 +268,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
* @param reversed If true, play the animation backwards, from the last frame to the first.
*/
- public function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reversed:Bool = false):Void
+ public function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reversed:Bool = false):Void
{
if (!canPlayOtherAnims && !ignoreOther) return;
diff --git a/source/funkin/play/stage/Stage.hx b/source/funkin/play/stage/Stage.hx
index f4f380a0b..1ac9b0b67 100644
--- a/source/funkin/play/stage/Stage.hx
+++ b/source/funkin/play/stage/Stage.hx
@@ -450,7 +450,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
* @param pop If true, the character will be removed from the stage as well.
* @return The Boyfriend character.
*/
- public function getBoyfriend(?pop:Bool = false):BaseCharacter
+ public function getBoyfriend(pop:Bool = false):BaseCharacter
{
if (pop)
{
@@ -473,7 +473,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
* @param pop If true, the character will be removed from the stage as well.
* @return The player/Boyfriend character.
*/
- public function getPlayer(?pop:Bool = false):BaseCharacter
+ public function getPlayer(pop:Bool = false):BaseCharacter
{
return getBoyfriend(pop);
}
@@ -483,7 +483,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
* @param pop If true, the character will be removed from the stage as well.
* @return The Girlfriend character.
*/
- public function getGirlfriend(?pop:Bool = false):BaseCharacter
+ public function getGirlfriend(pop:Bool = false):BaseCharacter
{
if (pop)
{
@@ -506,7 +506,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
* @param pop If true, the character will be removed from the stage as well.
* @return The Dad character.
*/
- public function getDad(?pop:Bool = false):BaseCharacter
+ public function getDad(pop:Bool = false):BaseCharacter
{
if (pop)
{
@@ -529,7 +529,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
* @param pop If true, the character will be removed from the stage as well.
* @return The opponent character.
*/
- public function getOpponent(?pop:Bool = false):BaseCharacter
+ public function getOpponent(pop:Bool = false):BaseCharacter
{
return getDad(pop);
}
diff --git a/source/funkin/play/stage/StageData.hx b/source/funkin/play/stage/StageData.hx
index 867c6e1a5..c14e05aaf 100644
--- a/source/funkin/play/stage/StageData.hx
+++ b/source/funkin/play/stage/StageData.hx
@@ -503,7 +503,7 @@ typedef StageDataCharacter =
* Again, just like CSS.
* @default 0
*/
- zIndex:Null,
+ ?zIndex:Int,
/**
* The position to render the character at.
diff --git a/source/funkin/ui/debug/charting/ChartEditorCommand.hx b/source/funkin/ui/debug/charting/ChartEditorCommand.hx
index bf4d710dd..fd179c481 100644
--- a/source/funkin/ui/debug/charting/ChartEditorCommand.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorCommand.hx
@@ -225,7 +225,7 @@ class AddEventsCommand implements ChartEditorCommand
var events:Array;
var appendToSelection:Bool;
- public function new(events:Array, ?appendToSelection:Bool = false)
+ public function new(events:Array, appendToSelection:Bool = false)
{
this.events = events;
this.appendToSelection = appendToSelection;
diff --git a/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx b/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx
index df5a25b62..63dc8bd92 100644
--- a/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorDialogHandler.hx
@@ -258,7 +258,7 @@ class ChartEditorDialogHandler
* @return The dialog that was opened.
*/
@:haxe.warning("-WVarInit")
- public static function openUploadInstDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
+ public static function openUploadInstDialog(state:ChartEditorState, closable:Bool = true):Dialog
{
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT, true, closable);
@@ -578,7 +578,7 @@ class ChartEditorDialogHandler
* @param closable Whether the dialog can be closed by the user.
* @return The dialog that was opened.
*/
- public static function openUploadVocalsDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
+ public static function openUploadVocalsDialog(state:ChartEditorState, closable:Bool = true):Dialog
{
var charIdsForVocals:Array = [];
@@ -692,7 +692,7 @@ class ChartEditorDialogHandler
* @return The dialog that was opened.
*/
@:haxe.warning('-WVarInit')
- public static function openChartDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
+ public static function openChartDialog(state:ChartEditorState, closable:Bool = true):Dialog
{
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_OPEN_CHART_LAYOUT, true, closable);
@@ -765,6 +765,19 @@ class ChartEditorDialogHandler
var songMetadataVariation:SongMetadata = SongMigrator.migrateSongMetadata(songMetadataJson, 'import');
songMetadataVariation = SongValidator.validateSongMetadata(songMetadataVariation, 'import');
+ if (songMetadataVariation == null)
+ {
+ // Tell the user the load was not successful.
+ NotificationManager.instance.addNotification(
+ {
+ title: 'Failure',
+ body: 'Could not load metadata file (${path.file}.${path.ext})',
+ type: NotificationType.Error,
+ expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
+ });
+ return;
+ }
+
songMetadata.set(variation, songMetadataVariation);
// Tell the user the load was successful.
@@ -879,7 +892,7 @@ class ChartEditorDialogHandler
* @param closable
* @return Dialog
*/
- public static function openImportChartDialog(state:ChartEditorState, format:String, ?closable:Bool = true):Dialog
+ public static function openImportChartDialog(state:ChartEditorState, format:String, closable:Bool = true):Dialog
{
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_IMPORT_CHART_LAYOUT, true, closable);
diff --git a/source/funkin/ui/debug/charting/ChartEditorEventSprite.hx b/source/funkin/ui/debug/charting/ChartEditorEventSprite.hx
index 2cd9ab2fe..2524f014c 100644
--- a/source/funkin/ui/debug/charting/ChartEditorEventSprite.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorEventSprite.hx
@@ -26,12 +26,12 @@ class ChartEditorEventSprite extends FlxSprite
* The note data that this sprite represents.
* You can set this to null to kill the sprite and flag it for recycling.
*/
- public var eventData(default, set):SongEventData;
+ public var eventData(default, set):Null = null;
/**
* The image used for all song events. Cached for performance.
*/
- static var eventSpriteBasic:BitmapData;
+ static var eventSpriteBasic:Null = null;
public function new(parent:ChartEditorState)
{
@@ -49,7 +49,7 @@ class ChartEditorEventSprite extends FlxSprite
* Build a set of animations to allow displaying different types of chart events.
* @param force `true` to force rebuilding the frames.
*/
- static function buildFrames(?force:Bool = false):FlxFramesCollection
+ static function buildFrames(force:Bool = false):FlxFramesCollection
{
static var eventFrames:FlxFramesCollection = null;
@@ -112,7 +112,7 @@ class ChartEditorEventSprite extends FlxSprite
this.updateHitbox();
}
- function set_eventData(value:SongEventData):SongEventData
+ function set_eventData(value:Null):Null
{
this.eventData = value;
diff --git a/source/funkin/ui/debug/charting/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/ChartEditorNoteSprite.hx
index 14ffa3a76..0adbf1a20 100644
--- a/source/funkin/ui/debug/charting/ChartEditorNoteSprite.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorNoteSprite.hx
@@ -27,7 +27,7 @@ class ChartEditorNoteSprite extends FlxSprite
* The note data that this sprite represents.
* You can set this to null to kill the sprite and flag it for recycling.
*/
- public var noteData(default, set):SongNoteData;
+ public var noteData(default, set):Null;
/**
* The name of the note style currently in use.
@@ -70,7 +70,7 @@ class ChartEditorNoteSprite extends FlxSprite
this.animation.addByPrefix('tapRightPixel', 'pixel7');
}
- static var noteFrameCollection:FlxFramesCollection = null;
+ static var noteFrameCollection:Null = null;
/**
* We load all the note frames once, then reuse them.
@@ -108,7 +108,7 @@ class ChartEditorNoteSprite extends FlxSprite
}
}
- function set_noteData(value:SongNoteData):SongNoteData
+ function set_noteData(value:Null):Null
{
this.noteData = value;
diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx
index aa6e70714..83c052050 100644
--- a/source/funkin/ui/debug/charting/ChartEditorState.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorState.hx
@@ -1,5 +1,6 @@
package funkin.ui.debug.charting;
+import flixel.system.FlxAssets.FlxSoundAsset;
import flixel.math.FlxMath;
import haxe.ui.components.TextField;
import haxe.ui.components.DropDown;
@@ -85,6 +86,7 @@ using Lambda;
*/
// Give other classes access to private instance fields
+@:nullSafety
@:allow(funkin.ui.debug.charting.ChartEditorCommand)
@:allow(funkin.ui.debug.charting.ChartEditorDialogHandler)
@:allow(funkin.ui.debug.charting.ChartEditorThemeHandler)
@@ -238,7 +240,7 @@ class ChartEditorState extends HaxeUIState
* 40 means the playhead is 1 grid length below the base position.
* -40 means the playhead is 1 grid length above the base position.
*/
- var playheadPositionInPixels(default, set):Float;
+ var playheadPositionInPixels(default, set):Float = 0.0;
function set_playheadPositionInPixels(value:Float):Float
{
@@ -258,28 +260,40 @@ class ChartEditorState extends HaxeUIState
* playheadPosition, converted to steps.
* NOT dependant on BPM, because the size of a grid square does not change with BPM.
*/
- var playheadPositionInSteps(get, null):Float;
+ var playheadPositionInSteps(get, set):Float;
function get_playheadPositionInSteps():Float
{
return playheadPositionInPixels / GRID_SIZE;
}
+ function set_playheadPositionInSteps(value:Float):Float
+ {
+ playheadPositionInPixels = value * GRID_SIZE;
+ return value;
+ }
+
/**
* playheadPosition, converted to milliseconds.
* DEPENDANT on BPM, because the duration of a grid square changes with BPM.
*/
- var playheadPositionInMs(get, null):Float;
+ var playheadPositionInMs(get, set):Float;
function get_playheadPositionInMs():Float
{
return Conductor.getStepTimeInMs(playheadPositionInSteps);
}
+ function set_playheadPositionInMs(value:Float):Float
+ {
+ playheadPositionInSteps = Conductor.getTimeInSteps(value);
+ return value;
+ }
+
/**
* songLength, in milliseconds.
*/
- @:isVar var songLengthInMs(get, set):Float;
+ @:isVar var songLengthInMs(get, set):Float = 0;
function get_songLengthInMs():Float
{
@@ -337,7 +351,7 @@ class ChartEditorState extends HaxeUIState
* Dictates the appearance of many UI elements.
* Currently hardcoded to just Light and Dark.
*/
- var currentTheme(default, set):ChartEditorTheme = null;
+ var currentTheme(default, set):ChartEditorTheme = ChartEditorTheme.Light;
function set_currentTheme(value:ChartEditorTheme):ChartEditorTheme
{
@@ -350,9 +364,10 @@ class ChartEditorState extends HaxeUIState
/**
* Whether a skip button has been pressed on the playbar, and which one.
+ * `null` if no button has been pressed.
* This will be used to update the scrollPosition (in the same function that handles the scroll wheel), then cleared.
*/
- var playbarButtonPressed:String = null;
+ var playbarButtonPressed:Null = null;
/**
* Whether the head of the playbar is currently being dragged with the mouse by the user.
@@ -392,13 +407,15 @@ class ChartEditorState extends HaxeUIState
/**
* The character sprite in the Player Preview window.
+ * `null` until accessed.
*/
- var currentPlayerCharacterPlayer:CharacterPlayer = null;
+ var currentPlayerCharacterPlayer:Null = null;
/**
* The character sprite in the Opponent Preview window.
+ * `null` until accessed.
*/
- var currentOpponentCharacterPlayer:CharacterPlayer = null;
+ var currentOpponentCharacterPlayer:Null = null;
/**
* The currently selected live input style.
@@ -431,7 +448,7 @@ class ChartEditorState extends HaxeUIState
/**
* Whether hitsounds are enabled for at least one character.
*/
- var hitsoundsEnabled(get, null):Bool;
+ var hitsoundsEnabled(get, never):Bool;
function get_hitsoundsEnabled():Bool
{
@@ -452,14 +469,14 @@ class ChartEditorState extends HaxeUIState
* Whether the user's mouse cursor is hovering over a SOLID component of the HaxeUI.
* If so, ignore mouse events underneath.
*/
- var isCursorOverHaxeUI(get, null):Bool;
+ var isCursorOverHaxeUI(get, never):Bool;
function get_isCursorOverHaxeUI():Bool
{
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
}
- var isCursorOverHaxeUIButton(get, null):Bool;
+ var isCursorOverHaxeUIButton(get, never):Bool;
function get_isCursorOverHaxeUIButton():Bool
{
@@ -575,10 +592,13 @@ class ChartEditorState extends HaxeUIState
}
else
{
- // Stop the auto-save timer.
- autoSaveTimer.cancel();
- autoSaveTimer.destroy();
- autoSaveTimer = null;
+ if (autoSaveTimer != null)
+ {
+ // Stop the auto-save timer.
+ autoSaveTimer.cancel();
+ autoSaveTimer.destroy();
+ autoSaveTimer = null;
+ }
}
return saveDataDirty = value;
@@ -587,7 +607,7 @@ class ChartEditorState extends HaxeUIState
/**
* A timer used to auto-save the chart after a period of inactivity.
*/
- var autoSaveTimer:FlxTimer;
+ var autoSaveTimer:Null = null;
/**
* Whether the difficulty tree view in the toolbox has been modified and needs to be updated.
@@ -672,9 +692,10 @@ class ChartEditorState extends HaxeUIState
/**
* The position where the user clicked to start a selection.
+ * `null` if the user isn't currently selecting anything.
* The selection box extends from this point to the current mouse position.
*/
- var selectionBoxStartPos:FlxPoint = null;
+ var selectionBoxStartPos:Null = null;
/**
* Whether the user's last mouse click was on the playhead scroll area.
@@ -685,13 +706,14 @@ class ChartEditorState extends HaxeUIState
* Where the user's last mouse click was on the note preview scroll area.
* `null` if the user isn't clicking on the note preview.
*/
- var notePreviewScrollAreaStartPos:FlxPoint = null;
+ var notePreviewScrollAreaStartPos:Null = null;
/**
* The SongNoteData which is currently being placed.
+ * `null` if the user isn't currently placing a note.
* As the user drags, we will update this note's sustain length.
*/
- var currentPlaceNoteData:SongNoteData = null;
+ var currentPlaceNoteData:Null = null;
/**
* The Dialog components representing the currently available tool windows.
@@ -706,18 +728,21 @@ class ChartEditorState extends HaxeUIState
/**
* The audio track for the instrumental.
+ * `null` until an instrumental track is loaded.
*/
- var audioInstTrack:FlxSound;
+ var audioInstTrack:Null = null;
/**
* The raw byte data for the instrumental audio track.
+ * `null` until an instrumental track is loaded.
*/
- var audioInstTrackData:Bytes = null;
+ var audioInstTrackData:Null = null;
/**
* The audio track for the vocals.
+ * `null` until vocal track(s) are loaded.
*/
- var audioVocalTrackGroup:VoicesGroup;
+ var audioVocalTrackGroup:Null = null;
/**
* A map of the audio tracks for each character's vocals.
@@ -738,12 +763,12 @@ class ChartEditorState extends HaxeUIState
* - Keys are the variation IDs. At least one (`default`) must exist.
* - Values are the relevant metadata, ready to be serialized to JSON.
*/
- var songMetadata:Map;
+ var songMetadata:Map = [];
/**
* Retrieves the list of variations for the current song.
*/
- var availableVariations(get, null):Array;
+ var availableVariations(get, never):Array;
function get_availableVariations():Array
{
@@ -756,21 +781,28 @@ class ChartEditorState extends HaxeUIState
* Retrieves the list of difficulties for the current variation of the current song.
* ONLY CONTAINS DIFFICULTIES FOR THE CURRENT VARIATION so if on the default variation, erect/nightmare won't be included.
*/
- var availableDifficulties(get, null):Array;
+ var availableDifficulties(get, never):Array;
function get_availableDifficulties():Array
{
- return songMetadata.get(selectedVariation).playData.difficulties;
+ var m:Null = songMetadata.get(selectedVariation);
+ return m?.playData?.difficulties ?? [];
}
/**
* Retrieves the list of difficulties for ALL variations of the current song.
*/
- var allDifficulties(get, null):Array;
+ var allDifficulties(get, never):Array;
function get_allDifficulties():Array
{
- var result:Array> = [for (x in availableVariations) songMetadata.get(x).playData.difficulties];
+ var result:Array> = [
+ for (x in availableVariations)
+ {
+ var m:Null = songMetadata.get(x);
+ m?.playData?.difficulties ?? [];
+ }
+ ];
return result.flatten();
}
@@ -779,7 +811,7 @@ class ChartEditorState extends HaxeUIState
* - Keys are the variation IDs. At least one (`default`) must exist.
* - Values are the relevant chart data, ready to be serialized to JSON.
*/
- var songChartData:Map;
+ var songChartData:Map = [];
/**
* Convenience property to get the chart data for the current variation.
@@ -788,7 +820,7 @@ class ChartEditorState extends HaxeUIState
function get_currentSongMetadata():SongMetadata
{
- var result:SongMetadata = songMetadata.get(selectedVariation);
+ var result:Null = songMetadata.get(selectedVariation);
if (result == null)
{
result = new SongMetadata('Dad Battle', 'Kawai Sprite', selectedVariation);
@@ -810,7 +842,7 @@ class ChartEditorState extends HaxeUIState
function get_currentSongChartData():SongChartData
{
- var result:SongChartData = songChartData.get(selectedVariation);
+ var result:Null = songChartData.get(selectedVariation);
if (result == null)
{
result = new SongChartData(1.0, [], []);
@@ -944,7 +976,7 @@ class ChartEditorState extends HaxeUIState
return currentSongMetadata.songName = value;
}
- var currentSongId(get, null):String;
+ var currentSongId(get, never):String;
function get_currentSongId():String
{
@@ -968,7 +1000,7 @@ class ChartEditorState extends HaxeUIState
return currentSongMetadata.artist = value;
}
- var currentSongPlayableCharacters(get, null):Array;
+ var currentSongPlayableCharacters(get, never):Array;
function get_currentSongPlayableCharacters():Array
{
@@ -1025,7 +1057,7 @@ class ChartEditorState extends HaxeUIState
* SIGNALS
*/
// ==============================
- // public var onDifficultyChange(default, null):FlxTypedSignalVoid> = new FlxTypedSignalVoid>();
+ // public var onDifficultyChange(default, never):FlxTypedSignalVoid> = new FlxTypedSignalVoid>();
/**
* RENDER OBJECTS
*/
@@ -1034,7 +1066,7 @@ class ChartEditorState extends HaxeUIState
/**
* The IMAGE used for the grid. Updated by ChartEditorThemeHandler.
*/
- var gridBitmap:BitmapData;
+ var gridBitmap:Null = null;
/**
* The IMAGE used for the selection squares. Updated by ChartEditorThemeHandler.
@@ -1042,100 +1074,114 @@ class ChartEditorState extends HaxeUIState
* 1. A sprite is given this bitmap and placed over selected notes.
* 2. The image is split and used for a 9-slice sprite for the selection box.
*/
- var selectionSquareBitmap:BitmapData = null;
+ var selectionSquareBitmap:Null = null;
/**
* The IMAGE used for the note preview bitmap. Updated by ChartEditorThemeHandler.
* The image is split and used for a 9-slice sprite for the box over the note preview.
*/
- var notePreviewViewportBitmap:BitmapData = null;
+ var notePreviewViewportBitmap:Null = null;
/**
* The tiled sprite used to display the grid.
* The height is the length of the song, and scrolling is done by simply the sprite.
*/
- var gridTiledSprite:FlxSprite;
+ var gridTiledSprite:Null = null;
/**
* The playhead representing the current position in the song.
* Can move around on the grid independently of the view.
*/
- var gridPlayhead:FlxSpriteGroup;
+ var gridPlayhead:FlxSpriteGroup = new FlxSpriteGroup();
- var gridPlayheadScrollArea:FlxSprite;
+ var gridPlayheadScrollArea:Null = null;
/**
* A sprite used to indicate the note that will be placed on click.
*/
- var gridGhostNote:ChartEditorNoteSprite;
+ var gridGhostNote:Null = null;
/**
* A sprite used to indicate the event that will be placed on click.
*/
- var gridGhostEvent:ChartEditorEventSprite;
+ var gridGhostEvent:Null = null;
/**
* The waveform which (optionally) displays over the grid, underneath the notes and playhead.
*/
- var gridSpectrogram:PolygonSpectogram;
+ var gridSpectrogram:Null = null;
/**
* The sprite used to display the note preview area.
* We move this up and down to scroll the preview.
*/
- var notePreview:ChartEditorNotePreview;
+ var notePreview:Null = null;
/**
* The rectangular sprite used for representing the current viewport on the note preview.
* We move this up and down and resize it to represent the visible area.
*/
- var notePreviewViewport:FlxSliceSprite;
+ var notePreviewViewport:Null = null;
/**
* The rectangular sprite used for rendering the selection box.
* Uses a 9-slice to stretch the selection box to the correct size without warping.
*/
- var selectionBoxSprite:FlxSliceSprite;
+ var selectionBoxSprite:Null = null;
/**
* The opponent's health icon.
*/
- var healthIconDad:HealthIcon;
+ var healthIconDad:Null = null;
/**
* The player's health icon.
*/
- var healthIconBF:HealthIcon;
+ var healthIconBF:Null = null;
/**
* The purple background sprite.
*/
- var menuBG:FlxSprite;
+ var menuBG:Null = null;
+
+ /**
+ * The layout containing the playbar head slider.
+ */
+ var playbarHeadLayout:Null = null;
+
+ /**
+ * The playbar head slider.
+ */
+ var playbarHead:Null = null;
+
+ /**
+ * The current process that is lerping the scroll position.
+ * Used to cancel the previous lerp if the user scrolls again.
+ */
+ var currentScrollEase:Null;
/**
* The sprite group containing the note graphics.
* Only displays a subset of the data from `currentSongChartNoteData`,
* and kills notes that are off-screen to be recycled later.
*/
- var renderedNotes:FlxTypedSpriteGroup;
+ var renderedNotes:FlxTypedSpriteGroup = new FlxTypedSpriteGroup();
/**
* The sprite group containing the hold note graphics.
* Only displays a subset of the data from `currentSongChartNoteData`,
* and kills notes that are off-screen to be recycled later.
*/
- var renderedHoldNotes:FlxTypedSpriteGroup;
+ var renderedHoldNotes:FlxTypedSpriteGroup = new FlxTypedSpriteGroup();
/**
* The sprite group containing the song events.
* Only displays a subset of the data from `currentSongChartEventData`,
* and kills events that are off-screen to be recycled later.
*/
- var renderedEvents:FlxTypedSpriteGroup;
+ var renderedEvents:FlxTypedSpriteGroup = new FlxTypedSpriteGroup();
- var renderedSelectionSquares:FlxTypedSpriteGroup;
-
- var playbarHead:Slider;
+ var renderedSelectionSquares:FlxTypedSpriteGroup = new FlxTypedSpriteGroup();
public function new()
{
@@ -1159,7 +1205,7 @@ class ChartEditorState extends HaxeUIState
buildBackground();
- currentTheme = ChartEditorTheme.Light;
+ ChartEditorThemeHandler.updateTheme(this);
buildGrid();
// buildSpectrogram(audioInstTrack);
@@ -1213,6 +1259,8 @@ class ChartEditorState extends HaxeUIState
*/
function buildGrid():Void
{
+ if (gridBitmap == null) throw 'ERROR: Tried to build grid, but gridBitmap is null! Check ChartEditorThemeHandler.updateTheme().';
+
gridTiledSprite = new FlxTiledSprite(gridBitmap, gridBitmap.width, 1000, false, true);
gridTiledSprite.x = FlxG.width / 2 - GRID_SIZE * STRUMLINE_SIZE; // Center the grid.
gridTiledSprite.y = MENU_BAR_HEIGHT + GRID_TOP_PAD; // Push down to account for the menu bar.
@@ -1241,7 +1289,6 @@ class ChartEditorState extends HaxeUIState
gridPlayheadScrollArea.zIndex = 25;
// The playhead that show the current position in the song.
- gridPlayhead = new FlxSpriteGroup();
add(gridPlayhead);
gridPlayhead.zIndex = 30;
@@ -1279,6 +1326,8 @@ class ChartEditorState extends HaxeUIState
function buildSelectionBox():Void
{
+ if (selectionBoxSprite == null) throw 'ERROR: Tried to build selection box, but selectionBoxSprite is null! Check ChartEditorThemeHandler.updateTheme().';
+
selectionBoxSprite.scrollFactor.set(0, 0);
add(selectionBoxSprite);
selectionBoxSprite.zIndex = 30;
@@ -1288,6 +1337,9 @@ class ChartEditorState extends HaxeUIState
function setSelectionBoxBounds(bounds:FlxRect = null):Void
{
+ if (selectionBoxSprite == null)
+ throw 'ERROR: Tried to set selection box bounds, but selectionBoxSprite is null! Check ChartEditorThemeHandler.updateTheme().';
+
if (bounds == null)
{
selectionBoxSprite.visible = false;
@@ -1312,6 +1364,8 @@ class ChartEditorState extends HaxeUIState
notePreview.y = MENU_BAR_HEIGHT + GRID_TOP_PAD;
add(notePreview);
+ if (notePreviewViewport == null) throw 'ERROR: Tried to build note preview, but notePreviewViewport is null! Check ChartEditorThemeHandler.updateTheme().';
+
notePreviewViewport.scrollFactor.set(0, 0);
add(notePreviewViewport);
notePreviewViewport.zIndex = 30;
@@ -1323,6 +1377,9 @@ class ChartEditorState extends HaxeUIState
{
var bounds:FlxRect = new FlxRect();
+ // Return 0, 0, 0, 0 if the note preview doesn't exist for some reason.
+ if (notePreview == null) return bounds;
+
// Horizontal position and width are constant.
bounds.x = notePreview.x;
bounds.width = notePreview.width;
@@ -1356,6 +1413,9 @@ class ChartEditorState extends HaxeUIState
function setNotePreviewViewportBounds(bounds:FlxRect = null):Void
{
+ if (notePreviewViewport == null)
+ throw 'ERROR: Tried to set note preview viewport bounds, but notePreviewViewport is null! Check ChartEditorThemeHandler.updateTheme().';
+
if (bounds == null)
{
notePreviewViewport.visible = false;
@@ -1387,32 +1447,31 @@ class ChartEditorState extends HaxeUIState
*/
function buildNoteGroup():Void
{
- renderedHoldNotes = new FlxTypedSpriteGroup();
+ if (gridTiledSprite == null) throw 'ERROR: Tried to build note groups, but gridTiledSprite is null! Check ChartEditorState.buildGrid().';
+
renderedHoldNotes.setPosition(gridTiledSprite.x, gridTiledSprite.y);
add(renderedHoldNotes);
renderedHoldNotes.zIndex = 24;
- renderedNotes = new FlxTypedSpriteGroup();
renderedNotes.setPosition(gridTiledSprite.x, gridTiledSprite.y);
add(renderedNotes);
renderedNotes.zIndex = 25;
- renderedEvents = new FlxTypedSpriteGroup();
renderedEvents.setPosition(gridTiledSprite.x, gridTiledSprite.y);
add(renderedEvents);
renderedNotes.zIndex = 25;
- renderedSelectionSquares = new FlxTypedSpriteGroup();
renderedSelectionSquares.setPosition(gridTiledSprite.x, gridTiledSprite.y);
add(renderedSelectionSquares);
renderedNotes.zIndex = 26;
}
- var playbarHeadLayout:Component;
-
function buildAdditionalUI():Void
{
playbarHeadLayout = buildComponent(CHART_EDITOR_PLAYBARHEAD_LAYOUT);
+
+ if (playbarHeadLayout == null) throw 'ERROR: Failed to construct playbarHeadLayout! Check "${CHART_EDITOR_PLAYBARHEAD_LAYOUT}".';
+
playbarHeadLayout.zIndex = 110;
playbarHeadLayout.width = FlxG.width - 8;
@@ -1421,6 +1480,7 @@ class ChartEditorState extends HaxeUIState
playbarHeadLayout.y = FlxG.height - 48 - 8;
playbarHead = playbarHeadLayout.findComponent('playbarHead', Slider);
+ if (playbarHead == null) throw 'ERROR: Failed to fetch playbarHead from playbarHeadLayout! Check "${CHART_EDITOR_PLAYBARHEAD_LAYOUT}".';
playbarHead.allowFocus = false;
playbarHead.width = FlxG.width;
playbarHead.height = 10;
@@ -1445,7 +1505,7 @@ class ChartEditorState extends HaxeUIState
playbarHeadDragging = false;
// Set the song position to where the playhead was moved to.
- scrollPositionInPixels = songLengthInPixels * (playbarHead.value / 100);
+ scrollPositionInPixels = songLengthInPixels * (playbarHead?.value ?? 0 / 100);
// Update the conductor and audio tracks to match.
moveSongToScrollPosition();
@@ -1584,31 +1644,40 @@ class ChartEditorState extends HaxeUIState
addUIChangeListener('menubarItemOpponentHitsounds', event -> hitsoundsEnabledOpponent = event.value);
setUICheckboxSelected('menubarItemOpponentHitsounds', hitsoundsEnabledOpponent);
- var instVolumeLabel:Label = findComponent('menubarLabelVolumeInstrumental', Label);
- addUIChangeListener('menubarItemVolumeInstrumental', function(event:UIEvent) {
- var volume:Float = event.value / 100.0;
- if (audioInstTrack != null) audioInstTrack.volume = volume;
- instVolumeLabel.text = 'Instrumental - ${Std.int(event.value)}%';
- });
+ var instVolumeLabel:Null