diff --git a/source/engine/backend/BaseStage.hx b/source/engine/backend/BaseStage.hx index 7d9b667a..463c696b 100644 --- a/source/engine/backend/BaseStage.hx +++ b/source/engine/backend/BaseStage.hx @@ -14,6 +14,7 @@ enum Countdown START; } +@:nullSafety class BaseStage extends FlxBasic { private var game(get, never):Dynamic; diff --git a/source/engine/backend/ClientPrefs.hx b/source/engine/backend/ClientPrefs.hx index b34ad042..979dbe1f 100644 --- a/source/engine/backend/ClientPrefs.hx +++ b/source/engine/backend/ClientPrefs.hx @@ -6,7 +6,9 @@ import flixel.input.gamepad.FlxGamepadInputID; import states.TitleState; // Add a variable here and it will get automatically saved -@:structInit class SaveVariables +@:structInit +@:nullSafety +class SaveVariables { // Mobile and Mobile Controls Releated public var extraButtons:String = "NONE"; // mobile extra button option diff --git a/source/engine/backend/Conductor.hx b/source/engine/backend/Conductor.hx index dace4c25..1f5cbf50 100644 --- a/source/engine/backend/Conductor.hx +++ b/source/engine/backend/Conductor.hx @@ -12,6 +12,7 @@ typedef BPMChangeEvent = @:optional var stepCrochet:Float; } +@:nullSafety class Conductor { public static var bpm(default, set):Float = 100; @@ -25,13 +26,16 @@ class Conductor public static var bpmChangeMap:Array = []; - public static function getCrotchetAtTime(time:Float) + inline static function getStepCrochet(event:BPMChangeEvent):Float + return event.stepCrochet ?? stepCrochet; + + public static function getCrotchetAtTime(time:Float):Float { var lastChange = getBPMFromSeconds(time); - return lastChange.stepCrochet * 4; + return getStepCrochet(lastChange) * 4; } - public static function getBPMFromSeconds(time:Float) + public static function getBPMFromSeconds(time:Float):BPMChangeEvent { var lastChange:BPMChangeEvent = { stepTime: 0, @@ -48,7 +52,7 @@ class Conductor return lastChange; } - public static function getBPMFromStep(step:Float) + public static function getBPMFromStep(step:Float):BPMChangeEvent { var lastChange:BPMChangeEvent = { stepTime: 0, @@ -69,19 +73,19 @@ class Conductor { var step = beat * 4; var lastChange = getBPMFromStep(step); - return lastChange.songTime + (step - lastChange.stepTime) * (lastChange.stepCrochet / 1000); + return lastChange.songTime + (step - lastChange.stepTime) * (getStepCrochet(lastChange) / 1000); } - public static function getStep(time:Float) + public static function getStep(time:Float):Float { var lastChange = getBPMFromSeconds(time); - return lastChange.stepTime + (time - lastChange.songTime) / lastChange.stepCrochet; + return lastChange.stepTime + (time - lastChange.songTime) / getStepCrochet(lastChange); } - public static function getStepRounded(time:Float) + public static function getStepRounded(time:Float):Float { var lastChange = getBPMFromSeconds(time); - return lastChange.stepTime + Math.floor(time - lastChange.songTime) / lastChange.stepCrochet; + return lastChange.stepTime + Math.floor(time - lastChange.songTime) / getStepCrochet(lastChange); } public static function getBeat(time:Float) @@ -122,12 +126,12 @@ class Conductor //trace("new BPM map BUDDY " + bpmChangeMap); } - static function getSectionBeats(song:SwagSong, section:Int) + static function getSectionBeats(song:SwagSong, section:Int):Float { var val:Null = null; if (song.notes[section] != null) val = song.notes[section].sectionBeats; - return val != null ? val : 4; + return val ?? 4; } inline public static function calculateCrochet(bpm:Float) diff --git a/source/engine/backend/Controls.hx b/source/engine/backend/Controls.hx index 5d681958..f7f95f4b 100644 --- a/source/engine/backend/Controls.hx +++ b/source/engine/backend/Controls.hx @@ -5,15 +5,9 @@ import flixel.input.gamepad.FlxGamepadInputID; import flixel.input.gamepad.mappings.FlxGamepadMapping; import flixel.input.keyboard.FlxKey; +@:nullSafety class Controls { - // Keeping same use cases on stuff for it to be easier to understand/use - // I'd have removed it but this makes it a lot less annoying to use in my opinion - // You do NOT have to create these variables/getters for adding new keys, - // but you will instead have to use: - // controls.justPressed("ui_up") instead of controls.UI_UP - // Dumb but easily usable code, or Smart but complicated? Your choice. - // Also idk how to use macros they're weird as fuck lol // Pressed buttons (directions) public var UI_UP_P(get, never):Bool; public var UI_DOWN_P(get, never):Bool; @@ -24,299 +18,257 @@ class Controls public var NOTE_LEFT_P(get, never):Bool; public var NOTE_RIGHT_P(get, never):Bool; - private function get_UI_UP_P() + // Held buttons (directions) + public var UI_UP(get, never):Bool; + public var UI_DOWN(get, never):Bool; + public var UI_LEFT(get, never):Bool; + public var UI_RIGHT(get, never):Bool; + public var NOTE_UP(get, never):Bool; + public var NOTE_DOWN(get, never):Bool; + public var NOTE_LEFT(get, never):Bool; + public var NOTE_RIGHT(get, never):Bool; + + // Released buttons (directions) + public var UI_UP_R(get, never):Bool; + public var UI_DOWN_R(get, never):Bool; + public var UI_LEFT_R(get, never):Bool; + public var UI_RIGHT_R(get, never):Bool; + public var NOTE_UP_R(get, never):Bool; + public var NOTE_DOWN_R(get, never):Bool; + public var NOTE_LEFT_R(get, never):Bool; + public var NOTE_RIGHT_R(get, never):Bool; + + // Pressed buttons (others) + public var ACCEPT(get, never):Bool; + public var BACK(get, never):Bool; + public var PAUSE(get, never):Bool; + public var RESET(get, never):Bool; + + inline function get_UI_UP_P() return justPressed('ui_up'); - private function get_UI_DOWN_P() + inline function get_UI_DOWN_P() return justPressed('ui_down'); - private function get_UI_LEFT_P() + inline function get_UI_LEFT_P() return justPressed('ui_left'); - private function get_UI_RIGHT_P() + inline function get_UI_RIGHT_P() return justPressed('ui_right'); - private function get_NOTE_UP_P() + inline function get_NOTE_UP_P() return justPressed('note_up'); - private function get_NOTE_DOWN_P() + inline function get_NOTE_DOWN_P() return justPressed('note_down'); - private function get_NOTE_LEFT_P() + inline function get_NOTE_LEFT_P() return justPressed('note_left'); - private function get_NOTE_RIGHT_P() + inline function get_NOTE_RIGHT_P() return justPressed('note_right'); - // Held buttons (directions) - public var UI_UP(get, never):Bool; - public var UI_DOWN(get, never):Bool; - public var UI_LEFT(get, never):Bool; - public var UI_RIGHT(get, never):Bool; - public var NOTE_UP(get, never):Bool; - public var NOTE_DOWN(get, never):Bool; - public var NOTE_LEFT(get, never):Bool; - public var NOTE_RIGHT(get, never):Bool; - - private function get_UI_UP() + inline function get_UI_UP() return pressed('ui_up'); - private function get_UI_DOWN() + inline function get_UI_DOWN() return pressed('ui_down'); - private function get_UI_LEFT() + inline function get_UI_LEFT() return pressed('ui_left'); - private function get_UI_RIGHT() + inline function get_UI_RIGHT() return pressed('ui_right'); - private function get_NOTE_UP() + inline function get_NOTE_UP() return pressed('note_up'); - private function get_NOTE_DOWN() + inline function get_NOTE_DOWN() return pressed('note_down'); - private function get_NOTE_LEFT() + inline function get_NOTE_LEFT() return pressed('note_left'); - private function get_NOTE_RIGHT() + inline function get_NOTE_RIGHT() return pressed('note_right'); - // Released buttons (directions) - public var UI_UP_R(get, never):Bool; - public var UI_DOWN_R(get, never):Bool; - public var UI_LEFT_R(get, never):Bool; - public var UI_RIGHT_R(get, never):Bool; - public var NOTE_UP_R(get, never):Bool; - public var NOTE_DOWN_R(get, never):Bool; - public var NOTE_LEFT_R(get, never):Bool; - public var NOTE_RIGHT_R(get, never):Bool; - - private function get_UI_UP_R() + inline function get_UI_UP_R() return justReleased('ui_up'); - private function get_UI_DOWN_R() + inline function get_UI_DOWN_R() return justReleased('ui_down'); - private function get_UI_LEFT_R() + inline function get_UI_LEFT_R() return justReleased('ui_left'); - private function get_UI_RIGHT_R() + inline function get_UI_RIGHT_R() return justReleased('ui_right'); - private function get_NOTE_UP_R() + inline function get_NOTE_UP_R() return justReleased('note_up'); - private function get_NOTE_DOWN_R() + inline function get_NOTE_DOWN_R() return justReleased('note_down'); - private function get_NOTE_LEFT_R() + inline function get_NOTE_LEFT_R() return justReleased('note_left'); - private function get_NOTE_RIGHT_R() + inline function get_NOTE_RIGHT_R() return justReleased('note_right'); - // Pressed buttons (others) - public var ACCEPT(get, never):Bool; - public var BACK(get, never):Bool; - public var PAUSE(get, never):Bool; - public var RESET(get, never):Bool; - - private function get_ACCEPT() + inline function get_ACCEPT() return justPressed('accept'); - private function get_BACK() + inline function get_BACK() return justPressed('back'); - private function get_PAUSE() + inline function get_PAUSE() return justPressed('pause'); - private function get_RESET() + inline function get_RESET() return justPressed('reset'); - // Gamepad, Keyboard & Mobile stuff public var keyboardBinds:Map>; public var gamepadBinds:Map>; #if FEATURE_MOBILE_CONTROLS public var mobileBinds:Map>; #end - public function justPressed(key:String) + public function justPressed(key:String):Bool { - var result:Bool = (FlxG.keys.anyJustPressed(keyboardBinds[key]) == true); - if (result) + var kbBind = keyboardBinds[key]; + if (kbBind != null && FlxG.keys.anyJustPressed(kbBind)) + { controllerMode = false; + return true; + } - return result - || _myGamepadJustPressed(gamepadBinds[key]) == true - #if FEATURE_MOBILE_CONTROLS || mobileCJustPressed(mobileBinds[key]) == true - || touchPadJustPressed(mobileBinds[key]) == true #end; - } - - public function pressed(key:String) - { - var result:Bool = (FlxG.keys.anyPressed(keyboardBinds[key]) == true); - if (result) - controllerMode = false; + var gpBind = gamepadBinds[key]; + if (gpBind != null && _checkGamepad(gpBind, FlxG.gamepads.anyJustPressed)) + return true; - return result - || _myGamepadPressed(gamepadBinds[key]) == true - #if FEATURE_MOBILE_CONTROLS || mobileCPressed(mobileBinds[key]) == true - || touchPadPressed(mobileBinds[key]) == true #end; + #if FEATURE_MOBILE_CONTROLS + var mbBind = mobileBinds[key]; + if (mbBind != null && (mobileCJustPressed(mbBind) || touchPadJustPressed(mbBind))) + return true; + #end + return false; } - public function justReleased(key:String) + public function pressed(key:String):Bool { - var result:Bool = (FlxG.keys.anyJustReleased(keyboardBinds[key]) == true); - if (result) + var kbBind = keyboardBinds[key]; + if (kbBind != null && FlxG.keys.anyPressed(kbBind)) + { controllerMode = false; + return true; + } - return result - || _myGamepadJustReleased(gamepadBinds[key]) == true - #if FEATURE_MOBILE_CONTROLS || mobileCJustReleased(mobileBinds[key]) == true - || touchPadJustReleased(mobileBinds[key]) == true #end; - } - - public var controllerMode:Bool = false; + var gpBind = gamepadBinds[key]; + if (gpBind != null && _checkGamepad(gpBind, FlxG.gamepads.anyPressed)) + return true; - private function _myGamepadJustPressed(keys:Array):Bool - { - if (keys != null) - { - for (key in keys) - { - if (FlxG.gamepads.anyJustPressed(key) == true) - { - controllerMode = true; - return true; - } - } - } + #if FEATURE_MOBILE_CONTROLS + var mbBind = mobileBinds[key]; + if (mbBind != null && (mobileCPressed(mbBind) || touchPadPressed(mbBind))) + return true; + #end return false; } - private function _myGamepadPressed(keys:Array):Bool + public function justReleased(key:String):Bool { - if (keys != null) + var kbBind = keyboardBinds[key]; + if (kbBind != null && FlxG.keys.anyJustReleased(kbBind)) { - for (key in keys) - { - if (FlxG.gamepads.anyPressed(key) == true) - { - controllerMode = true; - return true; - } - } + controllerMode = false; + return true; } + + var gpBind = gamepadBinds[key]; + if (gpBind != null && _checkGamepad(gpBind, FlxG.gamepads.anyJustReleased)) + return true; + + #if FEATURE_MOBILE_CONTROLS + var mbBind = mobileBinds[key]; + if (mbBind != null && (mobileCJustReleased(mbBind) || touchPadJustReleased(mbBind))) + return true; + #end return false; } - private function _myGamepadJustReleased(keys:Array):Bool + public var controllerMode:Bool = false; + + function _checkGamepad(keys:Array, checkFn:FlxGamepadInputID->Bool):Bool { - if (keys != null) - { - for (key in keys) + for (key in keys) + if (checkFn(key) == true) { - if (FlxG.gamepads.anyJustReleased(key) == true) - { - controllerMode = true; - return true; - } + controllerMode = true; + return true; } - } return false; } #if FEATURE_MOBILE_CONTROLS public var isInSubstate:Bool = false; // don't worry about this it becomes true and false on it's own in MusicBeatSubstate - public var requestedInstance(get, default):Dynamic; // is set to MusicBeatState or MusicBeatSubstate when the constructor is called - public var requestedMobileC(get, default):IMobileControls; // for PlayState and EditorPlayState (hitbox and touchPad) + public var requestedInstance(get, default):Null = null; // is set to MusicBeatState or MusicBeatSubstate when the constructor is called + public var requestedMobileC(get, default):Null = null; // for PlayState and EditorPlayState (hitbox and touchPad) public var mobileC(get, never):Bool; private function touchPadPressed(keys:Array):Bool { - if (keys != null && requestedInstance.touchPad != null) - if (requestedInstance.touchPad.anyPressed(keys) == true) - return true; - - return false; + var tp = requestedInstance?.touchPad; + return keys != null && tp != null && tp.anyPressed(keys); } private function touchPadJustPressed(keys:Array):Bool { - if (keys != null && requestedInstance.touchPad != null) - if (requestedInstance.touchPad.anyJustPressed(keys) == true) - return true; - - return false; + var tp = requestedInstance?.touchPad; + return keys != null && tp != null && tp.anyJustPressed(keys); } private function touchPadJustReleased(keys:Array):Bool { - if (keys != null && requestedInstance.touchPad != null) - if (requestedInstance.touchPad.anyJustReleased(keys) == true) - return true; - - return false; + var tp = requestedInstance?.touchPad; + return keys != null && tp != null && tp.anyJustReleased(keys); } private function mobileCPressed(keys:Array):Bool { - if (keys != null && requestedMobileC != null) - if (requestedMobileC.instance.anyPressed(keys)) - return true; - - return false; + var mc = requestedMobileC; + return keys != null && mc != null && mc.instance.anyPressed(keys); } private function mobileCJustPressed(keys:Array):Bool { - if (keys != null && requestedMobileC != null) - if (requestedMobileC.instance.anyJustPressed(keys)) - return true; - - return false; + var mc = requestedMobileC; + return keys != null && mc != null && mc.instance.anyJustPressed(keys); } private function mobileCJustReleased(keys:Array):Bool { - if (keys != null && requestedMobileC != null) - if (requestedMobileC.instance.anyJustReleased(keys)) - return true; - - return false; + var mc = requestedMobileC; + return keys != null && mc != null && mc.instance.anyJustReleased(keys); } @:noCompletion private function get_requestedInstance():Dynamic - { - if (isInSubstate) - return MusicBeatSubstate.instance; - else - return MusicBeatState.getState(); - } + return isInSubstate ? MusicBeatSubstate.instance : MusicBeatState.getState(); @:noCompletion private function get_requestedMobileC():IMobileControls - { return requestedInstance.mobileControls; - } @:noCompletion private function get_mobileC():Bool - { - if (ClientPrefs.data.controlsAlpha >= 0.1) - return true; - else - return false; - } + return ClientPrefs.data.controlsAlpha >= 0.1; #else public var isInSubstate:Bool = false; public var mobileC:Bool = false; #end - // IGNORE THESE - public static var instance:Controls; + public static var instance:Null = null; public function new() { diff --git a/source/engine/backend/CoolUtil.hx b/source/engine/backend/CoolUtil.hx index 0c1483c2..dfa35402 100644 --- a/source/engine/backend/CoolUtil.hx +++ b/source/engine/backend/CoolUtil.hx @@ -6,6 +6,7 @@ import openfl.utils.Assets; import sys.io.Process; #end +@:nullSafety class CoolUtil { public static function quantize(f:Float, snap:Float) @@ -21,12 +22,12 @@ class CoolUtil public static function coolTextFile(path:String):Array { - var daList:String = null; + var fileContent:Null = null; var formatted:Array = path.split(':'); // prevent "shared:", "preload:" and other library names on file path path = formatted[formatted.length - 1]; if (FileSystem.exists(path)) - daList = File.getContent(path); - return daList != null ? listFromString(daList) : []; + fileContent = File.getContent(path); + return fileContent != null ? listFromString(fileContent) : []; } public static function colorFromString(color:String):FlxColor @@ -39,7 +40,7 @@ class CoolUtil var colorNum:Null = FlxColor.fromString(color); if (colorNum == null) colorNum = FlxColor.fromString('#$color'); - return colorNum != null ? colorNum : FlxColor.WHITE; + return colorNum ?? FlxColor.WHITE; } public static function listFromString(string:String):Array @@ -47,13 +48,13 @@ class CoolUtil if (string == null) return [""]; - var daList:Array = []; - daList = string.trim().split('\n'); + var lines:Array = []; + lines = string.trim().split('\n'); - for (i in 0...daList.length) - daList[i] = daList[i].trim(); + for (i in 0...lines.length) + lines[i] = lines[i].trim(); - return daList; + return lines; } public static function floorDecimal(value:Float, decimals:Int):Float @@ -80,21 +81,24 @@ class CoolUtil if (colorOfThisPixel != 0) { if (countByColor.exists(colorOfThisPixel)) - countByColor[colorOfThisPixel] = countByColor[colorOfThisPixel] + 1; + { + countByColor[colorOfThisPixel] = (countByColor[colorOfThisPixel] ?? 0) + 1; + } else if (countByColor[colorOfThisPixel] != 13520687 - (2 * 13520687)) countByColor[colorOfThisPixel] = 1; } } } - var maxCount = 0; + var maxCount:Int = 0; var maxKey:Int = 0; // after the loop this will store the max color countByColor[FlxColor.BLACK] = 0; for (key in countByColor.keys()) { - if (countByColor[key] >= maxCount) + var count = countByColor[key]; + if (count != null && count >= maxCount) { - maxCount = countByColor[key]; + maxCount = count; maxKey = key; } } @@ -102,13 +106,13 @@ class CoolUtil return maxKey; } - public static function numberArray(max:Int, ?min = 0):Array + public static function numberArray(max:Int, min:Int = 0):Array { - var dumbArray:Array = []; + var result:Array = []; for (i in min...max) - dumbArray.push(i); + result.push(i); - return dumbArray; + return result; } public static function browserLoad(site:String) @@ -152,6 +156,7 @@ class CoolUtil @crowplexus **/ @:access(flixel.util.FlxSave.validate) + @:nullSafety(Off) public static function getSavePath():String { final company:String = FlxG.stage.application.meta.get('company'); @@ -162,14 +167,12 @@ class CoolUtil public static function loadSong(?name:String = null, ?difficultyNum:Int = -1) { - if (name == null || name.length < 1) - name = PlayState.SONG.song; - if (difficultyNum == -1) - difficultyNum = PlayState.storyDifficulty; - - var poop:String = Highscore.formatSong(name, difficultyNum); - PlayState.SONG = Song.loadFromJson(poop, name); - PlayState.storyDifficulty = difficultyNum; + var finalName:String = (name == null || name.length < 1) ? PlayState.SONG.song : name; + var finalDiff:Int = (difficultyNum == null || difficultyNum == -1) ? PlayState.storyDifficulty : difficultyNum; + + var formattedSongName:String = Highscore.formatSong(finalName, finalDiff); + PlayState.SONG = Song.loadFromJson(formattedSongName, finalName); + PlayState.storyDifficulty = finalDiff; LoadingState.prepareToSong(); LoadingState.loadAndSwitchState(new PlayState()); @@ -252,7 +255,7 @@ class CoolUtil return (result == Math.NaN) ? 1.0 : result; } - public static function easeInBack(x:Float, ?c:Float = 1.70158):Float + public static function easeInBack(x:Float, c:Float = 1.70158):Float { if (x <= 0.0) return 0.0; @@ -261,7 +264,7 @@ class CoolUtil return (1 + c) * x * x * x - c * x * x; } - public static function easeOutBack(x:Float, ?c:Float = 1.70158):Float + public static function easeOutBack(x:Float, c:Float = 1.70158):Float { if (x <= 0.0) return 0.0; diff --git a/source/engine/backend/CrashHandler.hx b/source/engine/backend/CrashHandler.hx index cd846150..f7613686 100644 --- a/source/engine/backend/CrashHandler.hx +++ b/source/engine/backend/CrashHandler.hx @@ -11,6 +11,7 @@ using flixel.util.FlxArrayUtil; * Crash Handler. * @author MAJigsaw77 and Homura Akemi (HomuHomu833) */ +@:nullSafety class CrashHandler { public static function init():Void diff --git a/source/engine/backend/CustomFadeTransition.hx b/source/engine/backend/CustomFadeTransition.hx index 565b602b..b098c7e3 100644 --- a/source/engine/backend/CustomFadeTransition.hx +++ b/source/engine/backend/CustomFadeTransition.hx @@ -1,10 +1,12 @@ package backend; +import flixel.util.FlxColor; import flixel.util.FlxGradient; +@:nullSafety class CustomFadeTransition extends MusicBeatSubstate { - public static var finishCallback:Void->Void; + public static var finishCallback:NullVoid> = null; var isTransIn:Bool = false; var transBlack:FlxSprite; @@ -14,16 +16,16 @@ class CustomFadeTransition extends MusicBeatSubstate public function new(duration:Float, isTransIn:Bool) { + transGradient = new FlxSprite(); + transBlack = new FlxSprite(); this.duration = duration; this.isTransIn = isTransIn; super(); - } - override function create() - { cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]]; var width:Int = Std.int(FlxG.width / Math.max(camera.zoom, 0.001)); var height:Int = Std.int(FlxG.height / Math.max(camera.zoom, 0.001)); + transGradient = FlxGradient.createGradientFlxSprite(1, height, (isTransIn ? [0x0, FlxColor.BLACK] : [FlxColor.BLACK, 0x0])); transGradient.scale.x = width; transGradient.updateHitbox(); @@ -31,7 +33,7 @@ class CustomFadeTransition extends MusicBeatSubstate transGradient.screenCenter(X); add(transGradient); - transBlack = new FlxSprite().makeGraphic(1, 1, FlxColor.BLACK); + transBlack.makeGraphic(1, 1, FlxColor.BLACK); transBlack.scale.set(width, height + 400); transBlack.updateHitbox(); transBlack.scrollFactor.set(); @@ -42,8 +44,6 @@ class CustomFadeTransition extends MusicBeatSubstate transGradient.y = transBlack.y - transBlack.height; else transGradient.y = -transGradient.height; - - super.create(); } override function update(elapsed:Float) diff --git a/source/engine/backend/Difficulty.hx b/source/engine/backend/Difficulty.hx index 5d4f003a..c8416a87 100644 --- a/source/engine/backend/Difficulty.hx +++ b/source/engine/backend/Difficulty.hx @@ -1,5 +1,6 @@ package backend; +@:nullSafety class Difficulty { public static var defaultList(default, never):Array = ['Easy', 'Normal', 'Hard']; @@ -28,7 +29,7 @@ class Difficulty if (week == null) week = WeekData.getCurrentWeek(); - var diffStr:String = week.difficulties; + var diffStr:Null = week?.difficulties; if (diffStr != null && diffStr.length > 0) { var diffs:Array = diffStr.trim().split(','); @@ -70,12 +71,13 @@ class Difficulty { final idx:Int = num ?? PlayState.storyDifficulty; final raw:String = list[idx]; - final dash:String = includeDash ? "-" : ""; + final includeVal:Bool = includeDash ?? true; + final dash:String = includeVal ? "-" : ""; if (raw.toLowerCase() == "erect" || raw.toLowerCase() == "nightmare") return dash + "Erect"; - return includeDash ? "" : null; + return includeVal ? "" : null; } inline public static function getDefault():String diff --git a/source/engine/backend/Discord.hx b/source/engine/backend/Discord.hx index 5c846559..7dc4cee6 100644 --- a/source/engine/backend/Discord.hx +++ b/source/engine/backend/Discord.hx @@ -6,6 +6,7 @@ import lime.app.Application; import hxdiscord_rpc.Discord; import hxdiscord_rpc.Types; +@:nullSafety class DiscordClient { public static var isInitialized:Bool = false; @@ -42,11 +43,13 @@ class DiscordClient private static function onReady(request:cpp.RawConstPointer):Void { var requestPtr:cpp.Star = cpp.ConstPointer.fromRaw(request).ptr; + var username:String = (requestPtr != null && requestPtr.username != null) ? requestPtr.username : ''; + var discriminator:String = (requestPtr != null && requestPtr.discriminator != null) ? requestPtr.discriminator : '0'; - if (Std.parseInt(cast(requestPtr.discriminator, String)) != 0) // New Discord IDs/Discriminator system - trace('(Discord) Connected to User (${cast (requestPtr.username, String)}#${cast (requestPtr.discriminator, String)})'); + if (Std.parseInt(discriminator) != 0) // New Discord IDs/Discriminator system + trace('(Discord) Connected to User ($username#$discriminator)'); else // Old discriminators - trace('(Discord) Connected to User (${cast (requestPtr.username, String)})'); + trace('(Discord) Connected to User ($username)'); changePresence(); } @@ -67,7 +70,7 @@ class DiscordClient discordHandlers.ready = cpp.Function.fromStaticFunction(onReady); discordHandlers.disconnected = cpp.Function.fromStaticFunction(onDisconnected); discordHandlers.errored = cpp.Function.fromStaticFunction(onError); - Discord.Initialize(clientID, cpp.RawPointer.addressOf(discordHandlers), #if (hxdiscord_rpc > "1.2.4") false #else 1 #end, null); + Discord.Initialize(clientID, cpp.RawPointer.addressOf(discordHandlers), #if (hxdiscord_rpc > "1.2.4") false #else 1 #end, ""); if (!isInitialized) trace("(Discord) Client initialized"); @@ -93,19 +96,21 @@ class DiscordClient ?endTimestamp:Float) { var startTimestamp:Float = 0; - if (hasStartTimestamp) + var hasTimestamp:Bool = (hasStartTimestamp == true); + var endTime:Float = endTimestamp ?? 0; + if (hasTimestamp) startTimestamp = Date.now().getTime(); - if (endTimestamp > 0) - endTimestamp = startTimestamp + endTimestamp; + if (endTime > 0) + endTime = startTimestamp + endTime; - presence.details = details; - presence.state = state; + presence.details = details ?? 'In the Menus'; + presence.state = state ?? ''; presence.largeImageKey = 'icon'; presence.largeImageText = "Version: " + states.MainMenuState.shadowEngineVersion; - presence.smallImageKey = smallImageKey; + presence.smallImageKey = smallImageKey ?? ''; // Obtained times are in milliseconds so they are divided so Discord can use it presence.startTimestamp = Std.int(startTimestamp / 1000); - presence.endTimestamp = Std.int(endTimestamp / 1000); + presence.endTimestamp = Std.int(endTime / 1000); updatePresence(); // trace('Discord RPC Updated. Arguments: $details, $state, $smallImageKey, $hasStartTimestamp, $endTimestamp'); diff --git a/source/engine/backend/EaseUtil.hx b/source/engine/backend/EaseUtil.hx index 5716020d..376937ad 100644 --- a/source/engine/backend/EaseUtil.hx +++ b/source/engine/backend/EaseUtil.hx @@ -2,6 +2,7 @@ package backend; +@:nullSafety class EaseUtil { public static inline function stepped(steps:Int):Float->Float diff --git a/source/engine/backend/FunkinPreloader.hx b/source/engine/backend/FunkinPreloader.hx index b24c6f3a..59c88251 100644 --- a/source/engine/backend/FunkinPreloader.hx +++ b/source/engine/backend/FunkinPreloader.hx @@ -20,6 +20,7 @@ import backend.Paths; using StringTools; // @:bitmap("assets/preloader/banner.png") +@:nullSafety class LogoImage extends BitmapData { } diff --git a/source/engine/backend/Highscore.hx b/source/engine/backend/Highscore.hx index 4a5bdc20..9907ef10 100644 --- a/source/engine/backend/Highscore.hx +++ b/source/engine/backend/Highscore.hx @@ -1,5 +1,6 @@ package backend; +@:nullSafety class Highscore { public static var weekScores:Map = new Map(); @@ -8,51 +9,53 @@ class Highscore public static function resetSong(song:String, diff:Int = 0):Void { - var daSong:String = formatSong(song, diff); - setScore(daSong, 0); - setRating(daSong, 0); + var key:String = formatSong(song, diff); + setScore(key, 0); + setRating(key, 0); } public static function resetWeek(week:String, diff:Int = 0):Void { - var daWeek:String = formatSong(week, diff); - setWeekScore(daWeek, 0); + var key:String = formatSong(week, diff); + setWeekScore(key, 0); } - public static function saveScore(song:String, score:Int = 0, ?diff:Int = 0, ?rating:Float = -1):Void + public static function saveScore(song:String, score:Int = 0, diff:Int = 0, rating:Float = -1):Void { if (song == null) return; - var daSong:String = formatSong(song, diff); + var key:String = formatSong(song, diff); - if (songScores.exists(daSong)) + if (songScores.exists(key)) { - if (songScores.get(daSong) < score) + var existingScore = songScores.get(key); + if (existingScore != null && existingScore < score) { - setScore(daSong, score); + setScore(key, score); if (rating >= 0) - setRating(daSong, rating); + setRating(key, rating); } } else { - setScore(daSong, score); + setScore(key, score); if (rating >= 0) - setRating(daSong, rating); + setRating(key, rating); } } - public static function saveWeekScore(week:String, score:Int = 0, ?diff:Int = 0):Void + public static function saveWeekScore(week:String, score:Int = 0, diff:Int = 0):Void { - var daWeek:String = formatSong(week, diff); + var key:String = formatSong(week, diff); - if (weekScores.exists(daWeek)) + if (weekScores.exists(key)) { - if (weekScores.get(daWeek) < score) - setWeekScore(daWeek, score); + var existingScore = weekScores.get(key); + if (existingScore != null && existingScore < score) + setWeekScore(key, score); } else - setWeekScore(daWeek, score); + setWeekScore(key, score); } /** @@ -89,29 +92,32 @@ class Highscore public static function getScore(song:String, diff:Int):Int { - var daSong:String = formatSong(song, diff); - if (!songScores.exists(daSong)) - setScore(daSong, 0); + var key:String = formatSong(song, diff); + if (!songScores.exists(key)) + setScore(key, 0); - return songScores.get(daSong); + var result = songScores.get(key); + return result ?? 0; } public static function getRating(song:String, diff:Int):Float { - var daSong:String = formatSong(song, diff); - if (!songRating.exists(daSong)) - setRating(daSong, 0); + var key:String = formatSong(song, diff); + if (!songRating.exists(key)) + setRating(key, 0); - return songRating.get(daSong); + var result = songRating.get(key); + return result ?? 0; } public static function getWeekScore(week:String, diff:Int):Int { - var daWeek:String = formatSong(week, diff); - if (!weekScores.exists(daWeek)) - setWeekScore(daWeek, 0); + var key:String = formatSong(week, diff); + if (!weekScores.exists(key)) + setWeekScore(key, 0); - return weekScores.get(daWeek); + var result = weekScores.get(key); + return result ?? 0; } public static function load():Void diff --git a/source/engine/backend/IMusicState.hx b/source/engine/backend/IMusicState.hx index b0acf4e0..56c405f6 100644 --- a/source/engine/backend/IMusicState.hx +++ b/source/engine/backend/IMusicState.hx @@ -5,9 +5,10 @@ import flixel.addons.transition.FlxTransitionableState; import flixel.util.FlxSave; import backend.rendering.PsychCamera; +@:nullSafety interface IMusicState { - public var stateInstance:FlxState; + public var stateInstance:Null; public var members(default, null):Array; @@ -90,13 +91,13 @@ interface IMusicState public function stepHit():Void; public function beatHit():Void; public function sectionHit():Void; - function getBeatsOnSection():Null; + function getBeatsOnSection():Float; #if (FEATURE_LUA || FEATURE_HSCRIPT) public function addTextToDebug(text:String, color:FlxColor):Void; #end - public function getLuaObject(tag:String, text:Bool = true):FlxSprite; + public function getLuaObject(tag:String, text:Bool = true):Null; #if FEATURE_LUA public function startLuasNamed(luaFile:String):Bool; @@ -113,7 +114,7 @@ interface IMusicState public function callOnLuas(funcToCall:String, args:Array = null, ignoreStops:Bool = false, exclusions:Array = null, excludeValues:Array = null):Dynamic; - public function callOnHScript(funcToCall:String, args:Array = null, ?ignoreStops:Bool = false, exclusions:Array = null, + public function callOnHScript(funcToCall:String, args:Array = null, ignoreStops:Bool = false, exclusions:Array = null, excludeValues:Array = null):Dynamic; public function setOnScripts(variable:String, arg:Dynamic, exclusions:Array = null):Void; diff --git a/source/engine/backend/InputFormatter.hx b/source/engine/backend/InputFormatter.hx index 7b1f0dd4..06bc44d3 100644 --- a/source/engine/backend/InputFormatter.hx +++ b/source/engine/backend/InputFormatter.hx @@ -5,6 +5,7 @@ import flixel.input.gamepad.FlxGamepad; import flixel.input.gamepad.FlxGamepadInputID; import flixel.input.gamepad.FlxGamepadManager; +@:nullSafety class InputFormatter { public static function getKeyName(key:FlxKey):String @@ -108,7 +109,7 @@ class InputFormatter public static function getGamepadName(key:FlxGamepadInputID) { var gamepad:FlxGamepad = FlxG.gamepads.firstActive; - var model:FlxGamepadModel = gamepad != null ? gamepad.detectedModel : UNKNOWN; + var model:FlxGamepadModel = gamepad?.detectedModel ?? UNKNOWN; switch (key) { diff --git a/source/engine/backend/Main.hx b/source/engine/backend/Main.hx index 4cf20c48..95fcafa3 100644 --- a/source/engine/backend/Main.hx +++ b/source/engine/backend/Main.hx @@ -21,6 +21,7 @@ import lime.ui.WindowVSyncMode; import states.TitleState; import openfl.events.KeyboardEvent; +@:nullSafety class Main extends Sprite { public static final game = { @@ -33,7 +34,7 @@ class Main extends Sprite startFullscreen: false // if the game should start at fullscreen mode }; - public static var fpsVar:Framerate; + public static var fpsVar:Null = null; public static function main():Void { @@ -164,6 +165,7 @@ class Main extends Sprite static function resetSpriteCache(sprite:Sprite):Void { + @:nullSafety(Off) @:privateAccess { sprite.__cacheBitmap = null; @@ -173,7 +175,7 @@ class Main extends Sprite function toggleFullScreen(event:KeyboardEvent):Void { - if (Controls.instance.justReleased('fullscreen')) + if (Controls.instance != null && Controls.instance.justReleased('fullscreen')) FlxG.fullscreen = !FlxG.fullscreen; } diff --git a/source/engine/backend/Mods.hx b/source/engine/backend/Mods.hx index 9995c6a9..8d989336 100644 --- a/source/engine/backend/Mods.hx +++ b/source/engine/backend/Mods.hx @@ -7,6 +7,7 @@ typedef ModsList = all:Array }; +@:nullSafety class Mods { static public var currentModDirectory:String = ''; @@ -144,7 +145,7 @@ class Mods { try { - var rawJson:String = File.getContent(path); + var rawJson:Null = File.getContent(path); if (rawJson != null && rawJson.length > 0) return Json.parse(rawJson, path); } diff --git a/source/engine/backend/MusicBeatState.hx b/source/engine/backend/MusicBeatState.hx index 4261971c..37e0ffd0 100644 --- a/source/engine/backend/MusicBeatState.hx +++ b/source/engine/backend/MusicBeatState.hx @@ -5,9 +5,10 @@ import flixel.util.FlxSave; import backend.rendering.PsychCamera; import haxe.io.Path; +@:nullSafety class MusicBeatState extends FlxTransitionableState implements IMusicState { - public var stateInstance:FlxState = null; + public var stateInstance:Null = null; private var curSection:Int = 0; private var stepsToDo:Int = 0; @@ -37,27 +38,33 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState #end #if (FEATURE_LUA || FEATURE_HSCRIPT) - private var luaDebugGroup:FlxTypedGroup; - private var luaDebugCam:ShadowCamera; - private var currentClassName:String; + private var luaDebugGroup:Null> = null; + private var luaDebugCam:Null = null; + private var currentClassName:String = ''; #end public var variables:Map = new Map(); public var controls(get, never):Controls; - private function get_controls() + private static var _fallbackControls:Null = null; + + private function get_controls():Controls { - return Controls.instance; + if (Controls.instance != null) + return Controls.instance; + if (_fallbackControls == null) + _fallbackControls = new Controls(); + return _fallbackControls; } #if FEATURE_MOBILE_CONTROLS - public var touchPad:TouchPad; - public var touchPadCam:ShadowCamera; - public var luaTouchPad:TouchPad; - public var luaTouchPadCam:ShadowCamera; - public var mobileControls:IMobileControls; - public var mobileControlsCam:ShadowCamera; + public var touchPad:Null = null; + public var touchPadCam:Null = null; + public var luaTouchPad:Null = null; + public var luaTouchPadCam:Null = null; + public var mobileControls:Null = null; + public var mobileControlsCam:Null = null; public function addTouchPad(DPad:String, Action:String) { @@ -135,7 +142,7 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState public function makeLuaTouchPad(DPadMode:String, ActionMode:String) { - if (members.contains(luaTouchPad)) + if (luaTouchPad != null && members.contains(luaTouchPad)) return; if (!variables.exists("luaTouchPad")) @@ -151,6 +158,8 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState return; var target = LuaUtils.getTargetInstance(); + if (target == null) + return; target.insert(target.members.length + 1, luaTouchPad); } @@ -181,13 +190,15 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonPressed(MobileInputID.fromString(button)); + { + return luaTouchPad.buttonPressed(cast MobileInputID.fromString(button)); + } else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyPressed(idArray); } else @@ -201,13 +212,15 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonJustPressed(MobileInputID.fromString(button)); + { + return luaTouchPad.buttonJustPressed(cast MobileInputID.fromString(button)); + } else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyJustPressed(idArray); } else @@ -221,13 +234,15 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonJustReleased(MobileInputID.fromString(button)); + { + return luaTouchPad.buttonJustReleased(cast MobileInputID.fromString(button)); + } else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyJustReleased(idArray); } else @@ -241,13 +256,15 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonJustReleased(MobileInputID.fromString(button)); + { + return luaTouchPad.buttonReleased(cast MobileInputID.fromString(button)); + } else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyReleased(idArray); } else @@ -457,10 +474,9 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState private function updateCurStep():Void { var lastChange = Conductor.getBPMFromSeconds(Conductor.songPosition); - - var shit = ((Conductor.songPosition - ClientPrefs.data.noteOffset) - lastChange.songTime) / lastChange.stepCrochet; - curDecStep = lastChange.stepTime + shit; - curStep = lastChange.stepTime + Math.floor(shit); + var stepOffset = ((Conductor.songPosition - ClientPrefs.data.noteOffset) - lastChange.songTime) / (lastChange.stepCrochet ?? Conductor.stepCrochet); + curDecStep = lastChange.stepTime + stepOffset; + curStep = lastChange.stepTime + Math.floor(stepOffset); } public static function switchState(nextState:FlxState = null) @@ -559,12 +575,12 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState func(stage); } - public function getBeatsOnSection() + public function getBeatsOnSection():Float { - var val:Null = 4; + var val:Null = null; if (PlayState.SONG != null && PlayState.SONG.notes[curSection] != null) val = PlayState.SONG.notes[curSection].sectionBeats; - return val == null ? 4 : val; + return val ?? 4; } #if (FEATURE_LUA || FEATURE_HSCRIPT) @@ -593,7 +609,7 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState } #end - public function getLuaObject(tag:String, text:Bool = true):FlxSprite + public function getLuaObject(tag:String, text:Bool = true):Null { #if FEATURE_LUA if (modchartSprites.exists(tag)) @@ -720,9 +736,10 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState if (len <= 0) len = e.message.length; addTextToDebug('ERROR - ' + e.message.substr(0, len), FlxColor.RED); - var newScript:HScript = cast(SScript.global.get(file), HScript); - if (newScript != null) + var scriptFromGlobal = SScript.global.get(file); + if (scriptFromGlobal != null) { + var newScript:HScript = cast scriptFromGlobal; newScript.destroy(); hscriptArray.remove(newScript); } @@ -794,7 +811,7 @@ class MusicBeatState extends FlxTransitionableState implements IMusicState return returnVal; } - public function callOnHScript(funcToCall:String, args:Array = null, ?ignoreStops:Bool = false, exclusions:Array = null, + public function callOnHScript(funcToCall:String, args:Array = null, ignoreStops:Bool = false, exclusions:Array = null, excludeValues:Array = null):Dynamic { var returnVal:Dynamic = LuaUtils.Function_Continue; diff --git a/source/engine/backend/MusicBeatSubstate.hx b/source/engine/backend/MusicBeatSubstate.hx index 66409a96..708e0a44 100644 --- a/source/engine/backend/MusicBeatSubstate.hx +++ b/source/engine/backend/MusicBeatSubstate.hx @@ -3,10 +3,11 @@ package backend; import flixel.util.FlxSave; import haxe.io.Path; +@:nullSafety class MusicBeatSubstate extends FlxSubState implements IMusicState { - public var stateInstance:FlxState = null; - public static var instance:MusicBeatSubstate; + public var stateInstance:Null = null; + public static var instance:Null = null; private var curSection:Int = 0; private var stepsToDo:Int = 0; @@ -39,25 +40,33 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState #end #if (FEATURE_LUA || FEATURE_HSCRIPT) - private var luaDebugGroup:FlxTypedGroup; - private var luaDebugCam:ShadowCamera; - private var currentClassName:String; + private var luaDebugGroup:Null> = null; + private var luaDebugCam:Null = null; + private var currentClassName:String = ''; #end public var variables:Map = new Map(); public var controls(get, never):Controls; + private static var _fallbackControls:Null = null; + private function get_controls():Controls - return Controls.instance; + { + if (Controls.instance != null) + return Controls.instance; + if (_fallbackControls == null) + _fallbackControls = new Controls(); + return _fallbackControls; + } #if FEATURE_MOBILE_CONTROLS - public var touchPad:TouchPad; - public var touchPadCam:ShadowCamera; - public var luaTouchPad:TouchPad; - public var luaTouchPadCam:ShadowCamera; - public var mobileControls:IMobileControls; - public var mobileControlsCam:ShadowCamera; + public var touchPad:Null = null; + public var touchPadCam:Null = null; + public var luaTouchPad:Null = null; + public var luaTouchPadCam:Null = null; + public var mobileControls:Null = null; + public var mobileControlsCam:Null = null; public function addTouchPad(DPad:String, Action:String) { @@ -135,7 +144,7 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState public function makeLuaTouchPad(DPadMode:String, ActionMode:String) { - if (members.contains(luaTouchPad)) + if (luaTouchPad != null && members.contains(luaTouchPad)) return; if (!variables.exists("luaTouchPad")) @@ -151,6 +160,8 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState return; var target = LuaUtils.getTargetInstance(); + if (target == null) + return; target.insert(target.members.length + 1, luaTouchPad); } @@ -181,17 +192,15 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonPressed(MobileInputID.fromString(button)); + return luaTouchPad.buttonPressed(cast MobileInputID.fromString(button)); else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyPressed(idArray); } - else - return false; } return false; } @@ -201,13 +210,13 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonJustPressed(MobileInputID.fromString(button)); + return luaTouchPad.buttonJustPressed(cast MobileInputID.fromString(button)); else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyJustPressed(idArray); } else @@ -221,13 +230,15 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonJustReleased(MobileInputID.fromString(button)); + { + return luaTouchPad.buttonJustReleased(cast MobileInputID.fromString(button)); + } else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyJustReleased(idArray); } else @@ -241,13 +252,15 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState if (luaTouchPad != null) { if (Std.isOfType(button, String)) - return luaTouchPad.buttonJustReleased(MobileInputID.fromString(button)); + { + return luaTouchPad.buttonReleased(cast MobileInputID.fromString(button)); + } else if (Std.isOfType(button, Array)) { - var FUCK:Array = button; + var buttonIds:Array = button; // haxe said "You Can't Iterate On A Dyanmic Value Please Specificy Iterator or Iterable *insert nerd emoji*" so that's the only i found to fix var idArray:Array = []; - for (strId in FUCK) - idArray.push(MobileInputID.fromString(strId)); + for (strId in buttonIds) + idArray.push(cast MobileInputID.fromString(strId)); return luaTouchPad.anyReleased(idArray); } else @@ -424,10 +437,9 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState private function updateCurStep():Void { var lastChange = Conductor.getBPMFromSeconds(Conductor.songPosition); - - var shit = ((Conductor.songPosition - ClientPrefs.data.noteOffset) - lastChange.songTime) / lastChange.stepCrochet; - curDecStep = lastChange.stepTime + shit; - curStep = lastChange.stepTime + Math.floor(shit); + var stepOffset = ((Conductor.songPosition - ClientPrefs.data.noteOffset) - lastChange.songTime) / (lastChange.stepCrochet ?? Conductor.stepCrochet); + curDecStep = lastChange.stepTime + stepOffset; + curStep = lastChange.stepTime + Math.floor(stepOffset); } public function stepHit():Void @@ -449,12 +461,12 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState callOnScripts('onSectionHit'); } - public function getBeatsOnSection() + public function getBeatsOnSection():Float { - var val:Null = 4; + var val:Null = null; if (PlayState.SONG != null && PlayState.SONG.notes[curSection] != null) val = PlayState.SONG.notes[curSection].sectionBeats; - return val == null ? 4 : val; + return val ?? 4; } #if (FEATURE_LUA || FEATURE_HSCRIPT) @@ -483,7 +495,7 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState } #end - public function getLuaObject(tag:String, text:Bool = true):FlxSprite + public function getLuaObject(tag:String, text:Bool = true):Null { #if FEATURE_LUA if (modchartSprites.exists(tag)) @@ -609,9 +621,10 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState if (len <= 0) len = e.message.length; addTextToDebug('ERROR - ' + e.message.substr(0, len), FlxColor.RED); - var newScript:HScript = cast(SScript.global.get(file), HScript); - if (newScript != null) + var scriptFromGlobal = SScript.global.get(file); + if (scriptFromGlobal != null) { + var newScript:HScript = cast scriptFromGlobal; newScript.destroy(); hscriptArray.remove(newScript); } @@ -683,7 +696,7 @@ class MusicBeatSubstate extends FlxSubState implements IMusicState return returnVal; } - public function callOnHScript(funcToCall:String, args:Array = null, ?ignoreStops:Bool = false, exclusions:Array = null, + public function callOnHScript(funcToCall:String, args:Array = null, ignoreStops:Bool = false, exclusions:Array = null, excludeValues:Array = null):Dynamic { var returnVal:Dynamic = LuaUtils.Function_Continue; diff --git a/source/engine/backend/Native.hx b/source/engine/backend/Native.hx index 6aab072f..81c7e09e 100644 --- a/source/engine/backend/Native.hx +++ b/source/engine/backend/Native.hx @@ -20,6 +20,7 @@ package backend; #if cpp @:headerCode('#include ') #end +@:nullSafety class Native { public static function disableErrorReporting():Void diff --git a/source/engine/backend/NoteTypesConfig.hx b/source/engine/backend/NoteTypesConfig.hx index 58cd9bd4..e0a0a468 100644 --- a/source/engine/backend/NoteTypesConfig.hx +++ b/source/engine/backend/NoteTypesConfig.hx @@ -8,6 +8,7 @@ typedef NoteTypeProperty = value:Dynamic } +@:nullSafety class NoteTypesConfig { private static var noteTypesData:Map> = new Map>(); @@ -20,9 +21,12 @@ class NoteTypesConfig if (noteTypesData.exists(name)) return noteTypesData.get(name); - var str:String = Paths.getTextFromFile('custom_notetypes/$name.txt'); + var str:Null = Paths.getTextFromFile('custom_notetypes/$name.txt'); if (str == null || !str.contains(':') || !str.contains('=')) + { noteTypesData.set(name, null); + return null; + } var parsed:Array = []; var lines:Array = CoolUtil.listFromString(str); @@ -53,7 +57,7 @@ class NoteTypesConfig public static function applyNoteTypeData(note:Note, name:String) { - var data:Array = loadNoteTypeData(name); + var data:Null> = loadNoteTypeData(name); if (data == null || data.length < 1) return; @@ -99,7 +103,9 @@ class NoteTypesConfig for (i in 0...propArray.length) { var str:Dynamic = propArray[i]; - var id:Int = Std.parseInt(str.substr(0, str.length - 1).trim()); + var id:Null = Std.parseInt(str.substr(0, str.length - 1).trim()); + if (id == null) + id = 0; if (i < propArray.length - 1) obj = obj[id]; // middles else if (setProp) @@ -117,7 +123,7 @@ class NoteTypesConfig return Reflect.getProperty(obj, slice); } - private static function _interpretValue(value:String):Any + private static function _interpretValue(value:String):Null { if (value.charAt(0) == "'" || value.charAt(0) == '"') { diff --git a/source/engine/backend/Paths.hx b/source/engine/backend/Paths.hx index 0d08f30c..551b98e4 100644 --- a/source/engine/backend/Paths.hx +++ b/source/engine/backend/Paths.hx @@ -14,6 +14,7 @@ import openfl.geom.Rectangle; import openfl.media.Sound; import animate.FlxAnimateFrames; +@:nullSafety class Paths { public static final IMAGE_EXT:String = "png"; @@ -107,7 +108,7 @@ class Paths openfl.Assets.cache.clear("songs"); } - public static function getPath(file:String, ?type:AssetType = TEXT, ?library:Null = null, ?modsAllowed:Bool = false):String + public static function getPath(file:String, ?type:AssetType = TEXT, ?library:Null = null, modsAllowed:Bool = false):String { #if USING_GPU_TEXTURES if (file.endsWith(IMAGE_EXT) && FileSystem.exists(haxe.io.Path.withoutExtension(file) + '.$GPU_IMAGE_EXT')) @@ -210,7 +211,7 @@ class Paths return 'assets/fonts/$key'; } - public static function fileExists(key:String, type:AssetType, ?ignoreMods:Bool = false, ?library:String = null):Bool + public static function fileExists(key:String, type:AssetType, ignoreMods:Bool = false, ?library:String = null):Bool { var path:String = getPath(key, type, library, false); @@ -224,7 +225,7 @@ class Paths if (FileSystem.exists(mods(Mods.currentModDirectory + '/' + modKey)) || FileSystem.exists(mods(modKey))) return true; - + #if USING_GPU_TEXTURES if (modKey.endsWith(IMAGE_EXT)) { @@ -258,10 +259,10 @@ class Paths } } - public static function image(key:String, ?library:String = null):FlxGraphic + public static function image(key:String, ?library:String = null):Null { - var bitmap:BitmapData = null; - var file:String = null; + var bitmap:Null = null; + var file:String = ''; #if FEATURE_MODS file = modsImages(key); @@ -269,11 +270,15 @@ class Paths { if (!localTrackedAssets.contains(file)) localTrackedAssets.push(file); - return currentTrackedAssets.get(file); + var asset = currentTrackedAssets.get(file); + if (asset != null) + return asset; } else if (FileSystem.exists(file)) { - bitmap = BitmapData.fromBytes(File.getBytes(file)); + var bytes = File.getBytes(file); + if (bytes != null) + bitmap = BitmapData.fromBytes(bytes); } else #end @@ -285,12 +290,19 @@ class Paths { if (!localTrackedAssets.contains(file)) localTrackedAssets.push(file); - return currentTrackedAssets.get(file); + var asset = currentTrackedAssets.get(file); + if (asset != null) + return asset; } else if (FileSystem.exists(file)) - bitmap = BitmapData.fromBytes(File.getBytes(file)); + { + var bytes = File.getBytes(file); + if (bytes != null) + bitmap = BitmapData.fromBytes(bytes); + } - if (bitmap != null) break; + if (bitmap != null) + break; } } @@ -302,23 +314,34 @@ class Paths } trace('Failed to load image: $file'); - + if (currentTrackedAssets.exists('__flixel_logo')) { if (!localTrackedAssets.contains('__flixel_logo')) localTrackedAssets.push('__flixel_logo'); - return currentTrackedAssets.get('__flixel_logo'); + var logo = currentTrackedAssets.get('__flixel_logo'); + if (logo != null) + return logo; } - return cacheBitmap('__flixel_logo', FlxAssets.getBitmapFromClass(GraphicLogo)); + var fallback = cacheBitmap('__flixel_logo', FlxAssets.getBitmapFromClass(GraphicLogo)); + if (fallback != null) + return fallback; + + trace("Failed to load fallback image"); + return null; } - public static function cacheBitmap(file:String, ?bitmap:BitmapData = null):FlxGraphic + public static function cacheBitmap(file:String, ?bitmap:Null = null):Null { if (bitmap == null) { if (FileSystem.exists(file)) - bitmap = BitmapData.fromBytes(File.getBytes(file)); + { + var bytes = File.getBytes(file); + if (bytes != null) + bitmap = BitmapData.fromBytes(bytes); + } if (bitmap == null) return null; @@ -342,7 +365,7 @@ class Paths return newGraphic; } - public static function getTextFromFile(key:String, ?ignoreMods:Bool = false):String + public static function getTextFromFile(key:String, ignoreMods:Bool = false):Null { #if FEATURE_MODS if (!ignoreMods) @@ -360,34 +383,34 @@ class Paths return null; } - public static function sound(key:String, ?library:String):Sound + public static function sound(key:String, ?library:String):Null { return returnSound('sounds', key, library); } - inline public static function soundRandom(key:String, min:Int, max:Int, ?library:String):Sound + inline public static function soundRandom(key:String, min:Int, max:Int, ?library:String):Null { return sound(key + FlxG.random.int(min, max), library); } - inline public static function music(key:String, ?library:String):Sound + inline public static function music(key:String, ?library:String):Null { return returnSound('music', key, library); } - inline public static function voices(song:String, postfix:String = null):Any + inline public static function voices(song:String, postfix:String = null):Null { var songKey:String = 'songs/${formatToSongPath(song)}/Voices${postfix != null ? '-$postfix' : ''}${LOADOLD ? "-Old" : ""}'; return returnSound(null, songKey); } - inline public static function inst(song:String, postfix:String = null):Sound + inline public static function inst(song:String, postfix:String = null):Null { var songKey:String = 'songs/${formatToSongPath(song)}/Inst${postfix != null ? '-$postfix' : ''}${LOADOLD ? "-Old" : ""}'; return returnSound(null, songKey); } - public static function returnSound(path:Null, key:String, ?library:String):Sound + public static function returnSound(path:Null, key:String, ?library:String):Null { #if FEATURE_MODS var modLibPath:String = ''; @@ -403,7 +426,9 @@ class Paths currentTrackedSounds.set(file, Sound.fromFile(file)); if (!localTrackedAssets.contains(file)) localTrackedAssets.push(file); - return currentTrackedSounds.get(file); + var sound = currentTrackedSounds.get(file); + if (sound != null) + return sound; } #end @@ -419,81 +444,149 @@ class Paths var retKey:String = (path != null) ? '$path/$key' : key; retKey = getPath('$retKey.ogg', SOUND, library); if (FileSystem.exists(retKey)) - currentTrackedSounds.set(gottenPath, Sound.fromBytes(File.getBytes(retKey))); + { + var bytes = File.getBytes(retKey); + if (bytes != null) + currentTrackedSounds.set(gottenPath, Sound.fromBytes(bytes)); + } } if (!localTrackedAssets.contains(gottenPath)) localTrackedAssets.push(gottenPath); - return currentTrackedSounds.get(gottenPath); + var result = currentTrackedSounds.get(gottenPath); + if (result != null) + return result; + trace("Failed to load sound: " + gottenPath); + return null; } - public static function getAtlas(key:String, ?library:String = null):FlxAtlasFrames + public static function getAtlas(key:String, ?library:String = null):Null { - var imageLoaded:FlxGraphic = image(key, library); + var imageLoaded = image(key, library); + if (imageLoaded == null) + { + trace("Failed to load image for atlas: " + key); + return null; + } var xmlPath:String = getPath('images/$key.xml', TEXT, library, true); #if FEATURE_MODS var modXml:String = modsXml(key); if (FileSystem.exists(modXml)) - return FlxAtlasFrames.fromSparrow(imageLoaded, File.getContent(modXml)); + { + var content = File.getContent(modXml); + if (content != null) + return FlxAtlasFrames.fromSparrow(imageLoaded, content); + } #end if (FileSystem.exists(xmlPath)) - return FlxAtlasFrames.fromSparrow(imageLoaded, File.getContent(xmlPath)); + { + var content = File.getContent(xmlPath); + if (content != null) + return FlxAtlasFrames.fromSparrow(imageLoaded, content); + } var jsonPath:String = getPath('images/$key.json', TEXT, library, true); #if FEATURE_MODS var modJson:String = modsImagesJson(key); if (FileSystem.exists(modJson)) - return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, File.getContent(modJson)); + { + var content = File.getContent(modJson); + if (content != null) + return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, content); + } #end if (FileSystem.exists(jsonPath)) - return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, File.getContent(jsonPath)); + { + var content = File.getContent(jsonPath); + if (content != null) + return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, content); + } return getPackerAtlas(key, library); } - public static function getSparrowAtlas(key:String, ?library:String = null):FlxAtlasFrames + public static function getSparrowAtlas(key:String, ?library:String = null):Null { - var imageLoaded:FlxGraphic = image(key, library); + var imageLoaded = image(key, library); + if (imageLoaded == null) + { + trace("Failed to load image for sparrow atlas: " + key); + return null; + } #if FEATURE_MODS var modXml:String = modsXml(key); if (FileSystem.exists(modXml)) - return FlxAtlasFrames.fromSparrow(imageLoaded, File.getContent(modXml)); + { + var content = File.getContent(modXml); + if (content != null) + return FlxAtlasFrames.fromSparrow(imageLoaded, content); + } #end var xmlPath:String = getPath('images/$key.xml', library); - return FlxAtlasFrames.fromSparrow(imageLoaded, File.getContent(xmlPath)); + var content = File.getContent(xmlPath); + if (content != null) + return FlxAtlasFrames.fromSparrow(imageLoaded, content); + trace("Failed to load sparrow atlas: " + key); + return null; } - public static function getPackerAtlas(key:String, ?library:String = null):FlxAtlasFrames + public static function getPackerAtlas(key:String, ?library:String = null):Null { - var imageLoaded:FlxGraphic = image(key, library); + var imageLoaded = image(key, library); + if (imageLoaded == null) + { + trace("Failed to load image for packer atlas: " + key); + return null; + } #if FEATURE_MODS var modTxt:String = modsTxt(key); if (FileSystem.exists(modTxt)) - return FlxAtlasFrames.fromSpriteSheetPacker(imageLoaded, File.getContent(modTxt)); + { + var content = File.getContent(modTxt); + if (content != null) + return FlxAtlasFrames.fromSpriteSheetPacker(imageLoaded, content); + } #end var txtPath:String = getPath('images/$key.txt', library); - return FlxAtlasFrames.fromSpriteSheetPacker(imageLoaded, File.getContent(txtPath)); + var content = File.getContent(txtPath); + if (content != null) + return FlxAtlasFrames.fromSpriteSheetPacker(imageLoaded, content); + trace("Failed to load packer atlas: " + key); + return null; } - public static function getAsepriteAtlas(key:String, ?library:String = null):FlxAtlasFrames + public static function getAsepriteAtlas(key:String, ?library:String = null):Null { - var imageLoaded:FlxGraphic = image(key, library); + var imageLoaded = image(key, library); + if (imageLoaded == null) + { + trace("Failed to load image for aseprite atlas: " + key); + return null; + } #if FEATURE_MODS var modJson:String = modsImagesJson(key); if (FileSystem.exists(modJson)) - return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, File.getContent(modJson)); + { + var content = File.getContent(modJson); + if (content != null) + return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, content); + } #end var jsonPath:String = getPath('images/$key.json', library); - return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, File.getContent(jsonPath)); + var content = File.getContent(jsonPath); + if (content != null) + return FlxAtlasFrames.fromTexturePackerJson(imageLoaded, content); + trace("Failed to load aseprite atlas: " + key); + return null; } public static function getTextureAtlas(key:String, ?library:String = null, ?settings:FlxAnimateSettings):FlxAnimateFrames diff --git a/source/engine/backend/Rating.hx b/source/engine/backend/Rating.hx index 2a03d58a..c780366e 100644 --- a/source/engine/backend/Rating.hx +++ b/source/engine/backend/Rating.hx @@ -1,5 +1,6 @@ package backend; +@:nullSafety class Rating { public var name:String = ''; diff --git a/source/engine/backend/Section.hx b/source/engine/backend/Section.hx index 66707217..1c2bb823 100644 --- a/source/engine/backend/Section.hx +++ b/source/engine/backend/Section.hx @@ -11,6 +11,7 @@ typedef SwagSection = var altAnim:Bool; } +@:nullSafety class Section { public var sectionNotes:Array = []; diff --git a/source/engine/backend/Song.hx b/source/engine/backend/Song.hx index a7ebd49c..70ac550d 100644 --- a/source/engine/backend/Song.hx +++ b/source/engine/backend/Song.hx @@ -32,24 +32,25 @@ typedef SwagSong = @:optional var format:String; } +@:nullSafety class Song { public var song:String; public var notes:Array; - public var events:Array; + public var events:Array = []; public var bpm:Float; public var needsVoices:Bool = true; - public var playerArrowSkin:String; - public var opponentArrowSkin:String; - public var splashSkin:String; - public var gameOverChar:String; - public var gameOverSound:String; - public var gameOverLoop:String; - public var gameOverEnd:String; + public var playerArrowSkin:String = ''; + public var opponentArrowSkin:String = ''; + public var splashSkin:String = ''; + public var gameOverChar:String = ''; + public var gameOverSound:String = ''; + public var gameOverLoop:String = ''; + public var gameOverEnd:String = ''; public var disableNoteRGB(get, set):Bool; public var disableNoteCustomColor:Bool = false; public var speed:Float = 1; - public var stage:String; + public var stage:String = ''; public var player1:String = 'bf'; public var player2:String = 'dad'; public var gfVersion:String = 'gf'; @@ -116,23 +117,23 @@ class Song public static function loadFromJson(jsonInput:String, ?folder:String):SwagSong { - var formattedFolder:String = Paths.formatToSongPath(folder); + var formattedFolder:String = Paths.formatToSongPath(folder ?? ''); var formattedSong:String = Paths.formatToSongPath(jsonInput); var path:String = ""; - var rawJson:String = null; + var rawJson:Null = null; #if FEATURE_MODS var modPath:String = Paths.modsJson(formattedFolder + '/' + formattedSong); if (FileSystem.exists(modPath)) { path = modPath; - rawJson = File.getContent(modPath).trim(); + rawJson = File.getContent(modPath)?.trim(); } #end if (rawJson == null) { path = Paths.json(formattedFolder + '/' + formattedSong); - rawJson = File.getContent(path).trim(); + rawJson = File.getContent(path)?.trim(); } // LOL GOING THROUGH THE BULLSHIT TO CLEAN IDK WHATS STRANGE @@ -140,7 +141,7 @@ class Song while (!rawJson.endsWith("}")) rawJson = rawJson.substr(0, rawJson.length - 1); - var songJson:Dynamic = parseJSONshit(rawJson, path); + var songJson:Dynamic = parseJSONshit(rawJson ?? '', path); if (!jsonInput.startsWith("events")) StageData.loadDirectory(songJson); diff --git a/source/engine/backend/StageData.hx b/source/engine/backend/StageData.hx index c42e028c..03bd2854 100644 --- a/source/engine/backend/StageData.hx +++ b/source/engine/backend/StageData.hx @@ -35,6 +35,7 @@ enum abstract LoadFilters(Int) from Int from UInt to Int to UInt var FREEPLAY:Int = (1 << 3); } +@:nullSafety class StageData { public static function dummy():StageFile @@ -57,7 +58,7 @@ class StageData }; } - public static var forceNextDirectory:String = null; + public static var forceNextDirectory:Null = null; public static function loadDirectory(SONG:SwagSong) { @@ -79,7 +80,7 @@ class StageData stage = 'stage'; } - var stageFile:StageFile = getStageFile(stage); + var stageFile:Null = getStageFile(stage); if (stageFile == null) // preventing crashes { forceNextDirectory = ''; @@ -90,10 +91,10 @@ class StageData } } - public static function getStageFile(stage:String):StageFile + public static function getStageFile(stage:String):Null { var path:String = Paths.getSharedPath('stages/' + stage + '.json'); - var rawJson:String = null; + var rawJson:Null = null; #if FEATURE_MODS var modPath:String = Paths.modFolders('stages/' + stage + '.json'); if (FileSystem.exists(modPath)) @@ -106,7 +107,9 @@ class StageData if (FileSystem.exists(path)) rawJson = File.getContent(path); - return cast Json.parse(rawJson, path); + if (rawJson != null) + return cast Json.parse(rawJson, path); + return null; } public static function vanillaSongStage(songName):String @@ -114,8 +117,8 @@ class StageData public static var reservedNames:Array = ['gf', 'gfGroup', 'dad', 'dadGroup', 'boyfriend', 'boyfriendGroup']; // blocks these names from being used on stage editor's name input text - public static function addObjectsToState(objectList:Array, gf:FlxSprite, dad:FlxSprite, boyfriend:FlxSprite, ?group:Dynamic = null, - ?ignoreFilters:Bool = false) + public static function addObjectsToState(objectList:Array, gf:FlxSprite, dad:FlxSprite, boyfriend:FlxSprite, group:Dynamic = null, + ignoreFilters:Bool = false) { var addedObjects:Map = []; for (num => data in objectList) @@ -159,9 +162,17 @@ class StageData if (data.type != 'square') { if (data.type == 'sprite') - spr.loadGraphic(Paths.image(data.image)); + { + var graphic = Paths.image(data.image); + if (graphic != null) + spr.loadGraphic(graphic); + } else - spr.frames = Paths.getAtlas(data.image); + { + var atlas = Paths.getAtlas(data.image); + if (atlas != null) + spr.frames = atlas; + } if (data.type == 'animatedSprite' && data.animations != null) { diff --git a/source/engine/backend/WeekData.hx b/source/engine/backend/WeekData.hx index 9e848af3..a4824cd4 100644 --- a/source/engine/backend/WeekData.hx +++ b/source/engine/backend/WeekData.hx @@ -19,6 +19,7 @@ typedef WeekFile = var difficulties:String; } +@:nullSafety class WeekData { public static var weeksLoaded:Map = new Map(); @@ -27,20 +28,20 @@ class WeekData public var folder:String = ''; // JSON variables - public var songs:Array; - public var weekCharacters:Array; - public var weekBackground:String; - public var weekBefore:String; - public var storyName:String; - public var weekName:String; - public var freeplayColor:Array; - public var startUnlocked:Bool; - public var hiddenUntilUnlocked:Bool; - public var hideStoryMode:Bool; - public var hideFreeplay:Bool; - public var difficulties:String; - - public var fileName:String; + public var songs:Array = []; + public var weekCharacters:Array = []; + public var weekBackground:String = ''; + public var weekBefore:String = ''; + public var storyName:String = ''; + public var weekName:String = ''; + public var freeplayColor:Array = [146, 113, 253]; + public var startUnlocked:Bool = true; + public var hiddenUntilUnlocked:Bool = false; + public var hideStoryMode:Bool = false; + public var hideFreeplay:Bool = false; + public var difficulties:String = ''; + + public var fileName:String = ''; public static function createWeekFile():WeekFile { @@ -110,7 +111,7 @@ class WeekData var fileToCheck:String = directories[j] + 'weeks/' + sexList[i] + '.json'; if (!weeksLoaded.exists(sexList[i])) { - var week:WeekFile = getWeekFile(fileToCheck); + var week:Null = getWeekFile(fileToCheck); if (week != null) { var weekFile:WeekData = new WeekData(week, sexList[i]); @@ -185,7 +186,7 @@ class WeekData { if (!weeksLoaded.exists(weekToCheck)) { - var week:WeekFile = getWeekFile(path); + var week:Null = getWeekFile(path); if (week != null) { var weekFile:WeekData = new WeekData(week, weekToCheck); @@ -204,9 +205,9 @@ class WeekData } } - private static function getWeekFile(path:String):WeekFile + private static function getWeekFile(path:String):Null { - var rawJson:String = null; + var rawJson:Null = null; if (FileSystem.exists(path)) { rawJson = File.getContent(path); @@ -234,7 +235,7 @@ class WeekData } // Used on LoadingState, nothing really too relevant - public static function getCurrentWeek():WeekData + public static function getCurrentWeek():Null { return weeksLoaded.get(weeksList[PlayState.storyWeek]); } diff --git a/source/engine/backend/codename/MathUtil.hx b/source/engine/backend/codename/MathUtil.hx index cd39e70e..3a370637 100644 --- a/source/engine/backend/codename/MathUtil.hx +++ b/source/engine/backend/codename/MathUtil.hx @@ -2,6 +2,7 @@ package backend.codename; import haxe.macro.Expr; +@:nullSafety final class MathUtil { /** diff --git a/source/engine/backend/codename/MemoryUtil.hx b/source/engine/backend/codename/MemoryUtil.hx index bf027da9..d612d59b 100644 --- a/source/engine/backend/codename/MemoryUtil.hx +++ b/source/engine/backend/codename/MemoryUtil.hx @@ -29,6 +29,7 @@ using StringTools; #endif ') #end +@:nullSafety final class MemoryUtil { /** @@ -190,7 +191,7 @@ final class MemoryUtil if (process.exitCode() == 0) memoryOutput = Std.int(Std.parseFloat(process.stdout.readAll().toString().trim().split("\n")[1])); if (memoryOutput != -1) - return memoryMap[memoryOutput] == null ? 'Unknown ($memoryOutput)' : memoryMap[memoryOutput]; + return memoryMap[memoryOutput] ?? 'Unknown ($memoryOutput)'; #elseif (mac || ios) var process = new Process("system_profiler", ["SPMemoryDataType"]); var reg = ~/Type: (.+)/; diff --git a/source/engine/backend/codename/RegisteryUtil.hx b/source/engine/backend/codename/RegisteryUtil.hx index 4fcdbc95..2cab9efb 100644 --- a/source/engine/backend/codename/RegisteryUtil.hx +++ b/source/engine/backend/codename/RegisteryUtil.hx @@ -17,6 +17,7 @@ enum abstract RegistryHive(Int) #include ') #end +@:nullSafety class RegistryUtil { #if (windows && cpp) diff --git a/source/engine/backend/codename/ThreadUtil.hx b/source/engine/backend/codename/ThreadUtil.hx index 6dde6385..3eed411f 100644 --- a/source/engine/backend/codename/ThreadUtil.hx +++ b/source/engine/backend/codename/ThreadUtil.hx @@ -9,6 +9,7 @@ import sys.thread.Mutex; private typedef Thread = Dynamic; #end +@:nullSafety final class ThreadUtil { inline static function error(text:String) diff --git a/source/engine/backend/io/File.hx b/source/engine/backend/io/File.hx index 9d202897..ea9b3dd4 100644 --- a/source/engine/backend/io/File.hx +++ b/source/engine/backend/io/File.hx @@ -13,6 +13,7 @@ import sys.io.FileOutput; * Unified file class that works with both native file access and OpenFL assets. * @see https://github.com/Psych-Slice/P-Slice/blob/master/source/mikolka/funkin/custom/NativeFileSystem.hx */ +@:nullSafety class File { inline static function cwd(path:String):String diff --git a/source/engine/backend/io/FileSystem.hx b/source/engine/backend/io/FileSystem.hx index 1b6c6b40..2e3180e9 100644 --- a/source/engine/backend/io/FileSystem.hx +++ b/source/engine/backend/io/FileSystem.hx @@ -12,6 +12,7 @@ using StringTools; * Unified file system class that works with both native file access and OpenFL assets. * @see https://github.com/Psych-Slice/P-Slice/blob/master/source/mikolka/funkin/custom/NativeFileSystem.hx */ +@:nullSafety class FileSystem { inline static function cwd(path:String):String diff --git a/source/engine/backend/rendering/PsychCamera.hx b/source/engine/backend/rendering/PsychCamera.hx index 2bb75ac0..71b995f4 100644 --- a/source/engine/backend/rendering/PsychCamera.hx +++ b/source/engine/backend/rendering/PsychCamera.hx @@ -2,6 +2,8 @@ package backend.rendering; // PsychCamera handles followLerp based on elapsed // and stops camera from snapping at higher framerates + +@:nullSafety class PsychCamera extends ShadowCamera { override public function update(elapsed:Float):Void @@ -16,7 +18,10 @@ class PsychCamera extends ShadowCamera updateFlash(elapsed); updateFade(elapsed); - flashSprite.filters = filtersEnabled ? filters : null; + if (filtersEnabled && filters != null) + flashSprite.filters = filters; + else + flashSprite.filters = []; updateFlashSpritePosition(); updateShake(elapsed); @@ -100,7 +105,7 @@ class PsychCamera extends ShadowCamera } } - var mult:Float = 1 - Math.exp(-elapsed * followLerp); + var mult:Float = 1 - Math.exp(-(elapsed ?? 1) * followLerp); scroll.x += (_scrollTarget.x - scroll.x) * mult; scroll.y += (_scrollTarget.y - scroll.y) * mult; // trace('lerp on this frame: $mult'); diff --git a/source/engine/backend/rendering/ShadowCamera.hx b/source/engine/backend/rendering/ShadowCamera.hx index 02ee9102..a45d6423 100644 --- a/source/engine/backend/rendering/ShadowCamera.hx +++ b/source/engine/backend/rendering/ShadowCamera.hx @@ -45,6 +45,7 @@ using backend.BitmapDataUtil; @:access(flixel.graphics.frames.FlxFrame) @:access(openfl.display.OpenGLRenderer) @:access(openfl.geom.ColorTransform) +@:nullSafety class ShadowCamera extends FlxCamera { /** @@ -98,7 +99,7 @@ class ShadowCamera extends FlxCamera public var id:String; var _blendShader:RuntimeCustomBlendShader; - var _backgroundFrame:FlxFrame; + var _backgroundFrame:Null; var _blendRenderTexture:RenderTexture; var _backgroundRenderTexture:RenderTexture; @@ -112,8 +113,11 @@ class ShadowCamera extends FlxCamera this.id = id; - _backgroundFrame = new FlxFrame(new FlxGraphic('', null)); - _backgroundFrame.frame = new FlxRect(); + @:nullSafety(Off) + { + _backgroundFrame = new FlxFrame(new FlxGraphic('', null)); + _backgroundFrame.frame = new FlxRect(); + } _blendShader = new RuntimeCustomBlendShader(); @@ -124,7 +128,8 @@ class ShadowCamera extends FlxCamera _cameraTexture = new BitmapData(this.width, this.height); } - override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader):Void + override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, + ?shader:FlxShader):Void { var shouldUseShader:Bool = (!hasKhronosExtension && KHR_BLEND_MODES.contains(blend)) || SHADER_REQUIRED_BLEND_MODES.contains(blend); @@ -133,7 +138,8 @@ class ShadowCamera extends FlxCamera if (shouldUseShader) { _cameraTexture.drawCameraScreen(this); - _backgroundFrame.frame.set(0, 0, this.width, this.height); + if (_backgroundFrame != null) + _backgroundFrame.frame.set(0, 0, this.width, this.height); // Clear the camera's graphics // It'll get redrawn anyway @@ -160,14 +166,16 @@ class ShadowCamera extends FlxCamera _blendShader.blendSwag = blend; _blendShader.updateViewInfo(width, height, this); - _backgroundFrame.parent.bitmap = _blendRenderTexture.graphic.bitmap; + if (_backgroundFrame != null) + _backgroundFrame.parent.bitmap = _blendRenderTexture.graphic.bitmap; _backgroundRenderTexture.init(Std.int(this.width * Lib.current.stage.window.scale), Std.int(this.height * Lib.current.stage.window.scale)); _backgroundRenderTexture.drawToCamera((camera, matrix) -> { camera.zoom = this.zoom; matrix.scale(Lib.current.stage.window.scale, Lib.current.stage.window.scale); - camera.drawPixels(_backgroundFrame, null, matrix, canvas.transform.colorTransform, null, false, _blendShader); + if (_backgroundFrame != null) + camera.drawPixels(_backgroundFrame, null, matrix, canvas.transform.colorTransform, null, false, _blendShader); }); _backgroundRenderTexture.render(); @@ -185,24 +193,24 @@ class ShadowCamera extends FlxCamera } } - override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader):FlxDrawQuadsItem + override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, + ?shader:FlxShader):FlxDrawQuadsItem { // Can't batch complex non-coherent blends, so always force a new batch if (hasKhronosExtension && !(OpenGLRenderer.__coherentBlendsSupported ?? false) && KHR_BLEND_MODES.contains(blend)) { - var itemToReturn = null; - - if (FlxCamera._storageTilesHead != null) + var itemToReturn:FlxDrawQuadsItem = if (FlxCamera._storageTilesHead != null) { - itemToReturn = FlxCamera._storageTilesHead; + var item = FlxCamera._storageTilesHead; var newHead = FlxCamera._storageTilesHead.nextTyped; - itemToReturn.reset(); + item.reset(); FlxCamera._storageTilesHead = newHead; + item; } else { - itemToReturn = new FlxDrawQuadsItem(); - } + new FlxDrawQuadsItem(); + }; // TODO: catch this error when the dev actually messes up, not in the draw phase if (graphic.isDestroyed) @@ -213,7 +221,8 @@ class ShadowCamera extends FlxCamera itemToReturn.colored = colored; itemToReturn.hasColorOffsets = hasColorOffsets; itemToReturn.blend = blend; - itemToReturn.shader = shader; + if (shader != null) + itemToReturn.shader = shader; itemToReturn.nextTyped = _headTiles; _headTiles = itemToReturn; @@ -236,7 +245,8 @@ class ShadowCamera extends FlxCamera return super.startQuadBatch(graphic, colored, hasColorOffsets, blend, smooth, shader); } - override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader):FlxDrawTrianglesItem + override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, + ?shader:FlxShader):FlxDrawTrianglesItem { if (hasKhronosExtension && !(OpenGLRenderer.__coherentBlendsSupported ?? false) && KHR_BLEND_MODES.contains(blend)) return getNewDrawTrianglesItem(graphic, smoothing, isColored, blend, hasColorOffsets, shader); diff --git a/source/engine/backend/rendering/ShadowCameraFrontEnd.hx b/source/engine/backend/rendering/ShadowCameraFrontEnd.hx index 136bff39..3ca5cb82 100644 --- a/source/engine/backend/rendering/ShadowCameraFrontEnd.hx +++ b/source/engine/backend/rendering/ShadowCameraFrontEnd.hx @@ -6,6 +6,7 @@ import flixel.system.frontEnds.CameraFrontEnd; /** * A `CameraFrontEnd` override that uses `ShadowCamera`! */ +@:nullSafety class ShadowCameraFrontEnd extends CameraFrontEnd { public override function reset(?newCamera:FlxCamera):Void diff --git a/source/engine/backend/ui/ShadowStyle.hx b/source/engine/backend/ui/ShadowStyle.hx index 07511c0e..f9fa47f2 100644 --- a/source/engine/backend/ui/ShadowStyle.hx +++ b/source/engine/backend/ui/ShadowStyle.hx @@ -5,9 +5,10 @@ import flixel.group.FlxSpriteGroup; import flixel.util.FlxColor; import backend.ClientPrefs; +@:nullSafety class ShadowStyle { - private static var _focusedPanel:FlxSpriteGroup = null; + private static var _focusedPanel:Null = null; public static function setFocus(panel:FlxSpriteGroup):Void { @@ -24,7 +25,7 @@ class ShadowStyle _focusedPanel = null; } - public static function getFocusedPanel():FlxSpriteGroup + public static function getFocusedPanel():Null { return _focusedPanel; } @@ -178,7 +179,7 @@ class ShadowStyle public static function applySavedTheme():Void { - var theme:String = ClientPrefs.data.uiTheme != null ? ClientPrefs.data.uiTheme : ShadowTHEME_DARK; + var theme:String = ClientPrefs.data.uiTheme ?? ShadowTHEME_DARK; setShadowThemeByName(theme); } diff --git a/source/engine/backend/ui/components/controls/ShadowButton.hx b/source/engine/backend/ui/components/controls/ShadowButton.hx index 6447a8af..ca7354ce 100644 --- a/source/engine/backend/ui/components/controls/ShadowButton.hx +++ b/source/engine/backend/ui/components/controls/ShadowButton.hx @@ -9,33 +9,35 @@ import flixel.util.FlxColor; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowButton extends FlxSpriteGroup { - public var bg:FlxSprite; - public var label:FlxText; - public var callback:Void->Void; + public var bg:FlxSprite = new FlxSprite(); + public var label:FlxText = new FlxText(); + public var callback:NullVoid>; - var _width:Int; - var _height:Int; + var _width:Int = 100; + var _height:Int = 28; var _hovered:Bool = false; var _pressed:Bool = false; var _mousePos:FlxPoint = new FlxPoint(); public function new(x:Float, y:Float, text:String, ?onClick:Void->Void, width:Int = 100, height:Int = 28) { - super(x, y); _width = width; _height = height; callback = onClick; - bg = new FlxSprite(); - drawBackground(ShadowStyle.BG_MEDIUM, ShadowStyle.BORDER_DARK); - add(bg); - - label = new FlxText(0, 0, width, text); + label.text = text; + label.fieldWidth = width; label.setFormat(Paths.font(ShadowStyle.FONT_DEFAULT), ShadowStyle.FONT_SIZE_MD, ShadowStyle.TEXT_PRIMARY, CENTER); label.antialiasing = ShadowStyle.antialiasing; label.y = (_height - label.height) / 2; + + drawBackground(ShadowStyle.BG_MEDIUM, ShadowStyle.BORDER_DARK); + + super(x, y); + add(bg); add(label); } diff --git a/source/engine/backend/ui/components/controls/ShadowCheckbox.hx b/source/engine/backend/ui/components/controls/ShadowCheckbox.hx index 16277f86..788f16b2 100644 --- a/source/engine/backend/ui/components/controls/ShadowCheckbox.hx +++ b/source/engine/backend/ui/components/controls/ShadowCheckbox.hx @@ -9,35 +9,37 @@ import flixel.util.FlxColor; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowCheckbox extends FlxSpriteGroup { public var checked(get, set):Bool; - public var callback:Bool->Void; - public var box:FlxSprite; - public var checkmark:FlxSprite; - public var label:FlxText; + public var callback:NullVoid>; + public var box:FlxSprite = new FlxSprite(); + public var checkmark:FlxSprite = new FlxSprite(); + public var label:FlxText = new FlxText(); - var _size:Int; + var _size:Int = 16; var _hovered:Bool = false; var _checked:Bool = false; var _mousePos:FlxPoint = new FlxPoint(); public function new(x:Float, y:Float, text:String, defaultValue:Bool = false, ?onChange:Bool->Void) { - super(x, y); _size = ShadowStyle.HEIGHT_CHECKBOX; callback = onChange; - box = new FlxSprite(); drawBox(ShadowStyle.BORDER_DARK); + + super(x, y); add(box); - checkmark = new FlxSprite(); drawCheckmark(); checkmark.visible = false; add(checkmark); - label = new FlxText(_size + ShadowStyle.SPACING_SM, 0, 0, text); + label.text = text; + label.fieldWidth = 0; + label.x = _size +ShadowStyle.SPACING_SM; label.setFormat(Paths.font(ShadowStyle.FONT_DEFAULT), ShadowStyle.FONT_SIZE_MD, ShadowStyle.TEXT_PRIMARY); label.antialiasing = ShadowStyle.antialiasing; label.y = (_size - label.height) / 2; diff --git a/source/engine/backend/ui/components/controls/ShadowDropdown.hx b/source/engine/backend/ui/components/controls/ShadowDropdown.hx index c593616e..a6fcc172 100644 --- a/source/engine/backend/ui/components/controls/ShadowDropdown.hx +++ b/source/engine/backend/ui/components/controls/ShadowDropdown.hx @@ -10,31 +10,32 @@ import flixel.FlxCamera; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowDropdown extends FlxSpriteGroup { public var selectedIndex(get, set):Int; - public var selectedLabel(get, null):String; - public var callback:Int->Void; + public var selectedLabel(get, null):String = ""; + public var callback:NullVoid>; public var hasFocus:Bool = false; private static var _instances:Array = []; private static var _clickConsumedFrame:Int = -1; - private static var _clickConsumer:ShadowDropdown = null; - - var options:Array; - var header:FlxSprite; - var headerText:FlxText; - var arrow:FlxSprite; - var dropList:ShadowDropdownList; - var listBg:FlxSprite; + private static var _clickConsumer:Null = null; + + var options:Array = []; + var header:FlxSprite = new FlxSprite(); + var headerText:FlxText = new FlxText(); + var arrow:FlxSprite = new FlxSprite(); + var dropList:Null; + var listBg:Null; var isOpen:Bool = false; - var _rowHighlight:FlxSprite; + var _rowHighlight:Null; var _rowItems:Array = []; - - var _width:Int; - var _height:Int; - var _maxVisible:Int; + + var _width:Int = 150; + var _height:Int = 28; + var _maxVisible:Int = 6; var _scrollIndex:Int = 0; var _headerHovered:Bool = false; var _selectedIndex:Int = 0; @@ -50,26 +51,26 @@ class ShadowDropdown extends FlxSpriteGroup public function new(x:Float, y:Float, items:Array, ?onChange:Int->Void, width:Int = 150, maxVisibleItems:Int = 6) { - super(x, y); - - _instances.push(this); options = items; callback = onChange; _width = width; _height = ShadowStyle.HEIGHT_INPUT; _maxVisible = maxVisibleItems; - header = new FlxSprite(0, 0); drawHeader(ShadowStyle.BORDER_DARK); + + super(x, y); add(header); - headerText = new FlxText(ShadowStyle.SPACING_SM, 0, _width - 24, options.length > 0 ? options[0] : ""); + headerText.text = options.length > 0 ? options[0] : ""; + headerText.fieldWidth = _width - 24; + headerText.x = ShadowStyle.SPACING_SM; headerText.setFormat(Paths.font(ShadowStyle.FONT_DEFAULT), ShadowStyle.FONT_SIZE_MD, ShadowStyle.TEXT_PRIMARY); headerText.antialiasing = ShadowStyle.antialiasing; headerText.y = (_height - headerText.height) / 2; add(headerText); - arrow = new FlxSprite(_width - 16, 0); + arrow.setPosition(_width - 16, 0); drawArrow(); add(arrow); @@ -80,6 +81,8 @@ class ShadowDropdown extends FlxSpriteGroup dropList.active = false; add(dropList); + _instances.push(this); + _ignoreClickUntilTick = Std.int(FlxG.game.ticks); _ignoreUntilMouseRelease = (FlxG.mouse.pressed || FlxG.mouse.pressedRight || FlxG.mouse.pressedMiddle); @@ -239,12 +242,13 @@ class ShadowDropdown extends FlxSpriteGroup { if (dropList == null) return; + var dl:ShadowDropdownList = dropList; if (listBg == null) { listBg = new FlxSprite(0, 0); listBg.cameras = cameras; - dropList.add(listBg); + dl.add(listBg); } if (_rowHighlight == null) @@ -253,7 +257,7 @@ class ShadowDropdown extends FlxSpriteGroup _rowHighlight.makeGraphic(_width - 2, _height, ShadowStyle.BG_MEDIUM); _rowHighlight.visible = false; _rowHighlight.cameras = cameras; - dropList.add(_rowHighlight); + dl.add(_rowHighlight); } while (_rowItems.length < _maxVisible) @@ -264,7 +268,7 @@ class ShadowDropdown extends FlxSpriteGroup t.visible = false; t.cameras = cameras; _rowItems.push(t); - dropList.add(t); + dl.add(t); } } @@ -317,25 +321,32 @@ class ShadowDropdown extends FlxSpriteGroup } ensureListAssets(); - _rowHighlight.x = this.x; + if (_rowHighlight != null) + _rowHighlight.x = this.x; var listHeight:Int = visibleCount * _height; - listBg.makeGraphic(_width, listHeight, ShadowStyle.BG_DARK, true); - for (i in 0..._width) - listBg.pixels.setPixel32(i, listHeight - 1, ShadowStyle.BORDER_DARK); - for (i in 0...listHeight) + if (listBg != null) { - listBg.pixels.setPixel32(0, i, ShadowStyle.BORDER_DARK); - listBg.pixels.setPixel32(_width - 1, i, ShadowStyle.BORDER_DARK); + listBg.makeGraphic(_width, listHeight, ShadowStyle.BG_DARK, true); + for (i in 0..._width) + listBg.pixels.setPixel32(i, listHeight - 1, ShadowStyle.BORDER_DARK); + for (i in 0...listHeight) + { + listBg.pixels.setPixel32(0, i, ShadowStyle.BORDER_DARK); + listBg.pixels.setPixel32(_width - 1, i, ShadowStyle.BORDER_DARK); + } + listBg.x = this.x; + listBg.y = this.y + _height; + listBg.visible = true; } - listBg.x = this.x; - listBg.y = this.y + _height; - listBg.visible = true; - dropList.visible = true; - dropList.exists = true; - dropList.active = true; + if (dropList != null) + { + dropList.visible = true; + dropList.exists = true; + dropList.active = true; + } var highlightIndex:Int = -1; diff --git a/source/engine/backend/ui/components/controls/ShadowList.hx b/source/engine/backend/ui/components/controls/ShadowList.hx index ebda8204..33013858 100644 --- a/source/engine/backend/ui/components/controls/ShadowList.hx +++ b/source/engine/backend/ui/components/controls/ShadowList.hx @@ -10,10 +10,11 @@ import backend.Paths; import backend.ui.ShadowStyle; import backend.ui.components.text.ShadowLabel; +@:nullSafety class ShadowList extends FlxSpriteGroup { public var selectedIndex(get, set):Int; - public var callback:Int->Void; + public var callback:NullVoid>; public var items:Array = []; var bg:FlxSprite; diff --git a/source/engine/backend/ui/components/controls/ShadowSlider.hx b/source/engine/backend/ui/components/controls/ShadowSlider.hx index 89540e8c..9b8679e1 100644 --- a/source/engine/backend/ui/components/controls/ShadowSlider.hx +++ b/source/engine/backend/ui/components/controls/ShadowSlider.hx @@ -9,23 +9,24 @@ import flixel.util.FlxColor; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowSlider extends FlxSpriteGroup { public var value(get, set):Float; - public var callback:Float->Void; + public var callback:NullVoid>; public var min:Float; public var max:Float; public var decimals:Int; public var showValue:Bool; - var track:FlxSprite; - var fill:FlxSprite; - var thumb:FlxSprite; - var valueText:FlxText; + var track:FlxSprite = new FlxSprite(); + var fill:FlxSprite = new FlxSprite(); + var thumb:FlxSprite = new FlxSprite(); + var valueText:Null; - var _width:Int; - var _height:Int; + var _width:Int = 150; + var _height:Int = 28; var _thumbWidth:Int = 12; var _thumbHeight:Int = 20; var _trackHeight:Int = 8; @@ -34,10 +35,9 @@ class ShadowSlider extends FlxSpriteGroup var _hovered:Bool = false; var _mousePos:FlxPoint = new FlxPoint(); - public function new(x:Float, y:Float, minValue:Float, maxValue:Float, defaultValue:Float, ?onChange:Float->Void, width:Int = 150, decimalPlaces:Int = 1, showValueLabel:Bool = true) + public function new(x:Float, y:Float, minValue:Float, maxValue:Float, defaultValue:Float, ?onChange:Float->Void, width:Int = 150, decimalPlaces:Int = 1, + showValueLabel:Bool = true) { - super(x, y); - min = minValue; max = maxValue; decimals = decimalPlaces; @@ -47,15 +47,17 @@ class ShadowSlider extends FlxSpriteGroup _height = ShadowStyle.HEIGHT_INPUT; var trackY:Int = Std.int((_height - _trackHeight) / 2); - track = new FlxSprite(0, trackY); + track.y = trackY; drawTrack(); + + super(x, y); add(track); - fill = new FlxSprite(1, trackY + 1); + fill.setPosition(1, trackY + 1); fill.makeGraphic(1, _trackHeight - 2, ShadowStyle.ACCENT, true); add(fill); - thumb = new FlxSprite(0, Std.int((_height - _thumbHeight) / 2)); + thumb.y = Std.int((_height - _thumbHeight) / 2); drawThumb(ShadowStyle.BG_LIGHT); add(thumb); diff --git a/source/engine/backend/ui/components/controls/ShadowStepper.hx b/source/engine/backend/ui/components/controls/ShadowStepper.hx index c0aa508a..c1a754ea 100644 --- a/source/engine/backend/ui/components/controls/ShadowStepper.hx +++ b/source/engine/backend/ui/components/controls/ShadowStepper.hx @@ -9,23 +9,24 @@ import flixel.util.FlxColor; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowStepper extends FlxSpriteGroup { public var value(get, set):Float; - public var callback:Float->Void; + public var callback:NullVoid>; public var min:Float; public var max:Float; public var step:Float; public var decimals:Int; - var bg:FlxSprite; - var valueText:FlxText; - var upArrow:FlxSprite; - var downArrow:FlxSprite; + var bg:FlxSprite = new FlxSprite(); + var valueText:FlxText = new FlxText(); + var upArrow:FlxSprite = new FlxSprite(); + var downArrow:FlxSprite = new FlxSprite(); - var _width:Int; - var _height:Int; + var _width:Int = 64; + var _height:Int = 28; var _arrowWidth:Int = 16; var _upHovered:Bool = false; var _downHovered:Bool = false; @@ -34,10 +35,9 @@ class ShadowStepper extends FlxSpriteGroup var _scrollSpeed:Float = 40; var _mousePos:FlxPoint = new FlxPoint(); - public function new(x:Float, y:Float, stepSize:Float = 1, defaultValue:Float = 0, minValue:Float = -999, maxValue:Float = 999, decimalPlaces:Int = 0, ?onChange:Float->Void, width:Int = 64) + public function new(x:Float, y:Float, stepSize:Float = 1, defaultValue:Float = 0, minValue:Float = -999, maxValue:Float = 999, decimalPlaces:Int = 0, + ?onChange:Float->Void, width:Int = 64) { - super(x, y); - step = stepSize; min = minValue; max = maxValue; @@ -46,16 +46,17 @@ class ShadowStepper extends FlxSpriteGroup _width = width; _height = ShadowStyle.HEIGHT_INPUT; - bg = new FlxSprite(); drawBackground(); + + super(x, y); add(bg); var arrowHeight:Int = Std.int(_height / 2); - upArrow = new FlxSprite(_width - _arrowWidth, 0); + upArrow.setPosition(_width - _arrowWidth, 0); drawUpArrow(ShadowStyle.TEXT_SECONDARY, arrowHeight); add(upArrow); - downArrow = new FlxSprite(_width - _arrowWidth, arrowHeight); + downArrow.setPosition(_width - _arrowWidth, arrowHeight); drawDownArrow(ShadowStyle.TEXT_SECONDARY, arrowHeight); add(downArrow); diff --git a/source/engine/backend/ui/components/layout/ShadowPanel.hx b/source/engine/backend/ui/components/layout/ShadowPanel.hx index 9f248b49..0763f919 100644 --- a/source/engine/backend/ui/components/layout/ShadowPanel.hx +++ b/source/engine/backend/ui/components/layout/ShadowPanel.hx @@ -8,20 +8,21 @@ import flixel.util.FlxColor; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowPanel extends FlxSpriteGroup { - public var bg:FlxSprite; - public var title(default, set):String; + public var bg:FlxSprite = new FlxSprite(); + public var title(default, set):String = ""; public var collapsed(default, set):Bool = false; public var showMinimizeButton:Bool = true; - var headerBar:FlxSprite; - var titleText:FlxText; - var minimizeBtn:FlxSprite; + var headerBar:FlxSprite = new FlxSprite(); + var titleText:FlxText = new FlxText(); + var minimizeBtn:FlxSprite = new FlxSprite(); - var _width:Int; - var _height:Int; - var _contentHeight:Int; + var _width:Int = 300; + var _height:Int = 200; + var _contentHeight:Int = 176; var _dragging:Bool = false; var _dragOffsetX:Float = 0; @@ -42,22 +43,20 @@ class ShadowPanel extends FlxSpriteGroup _width = width; _height = height; _contentHeight = height - ShadowStyle.HEIGHT_HEADER; - this.title = title; + this.title = title ?? ""; - var fill = bgColor != null ? bgColor : ShadowStyle.BG_DARK; - var border = borderColor != null ? borderColor : ShadowStyle.BORDER_DARK; + var fill = bgColor ?? ShadowStyle.BG_DARK; + var border = borderColor ?? ShadowStyle.BORDER_DARK; - headerBar = new FlxSprite(); drawHeaderBar(); add(headerBar); - titleText = new FlxText(ShadowStyle.SPACING_SM, 0, _width, title != null ? title : ""); + titleText = new FlxText(ShadowStyle.SPACING_SM, 0, _width, this.title); titleText.setFormat(Paths.font(ShadowStyle.FONT_DEFAULT), ShadowStyle.FONT_SIZE_MD, ShadowStyle.TEXT_PRIMARY, LEFT); titleText.antialiasing = ShadowStyle.antialiasing; titleText.y = (ShadowStyle.HEIGHT_HEADER - titleText.height) / 2; add(titleText); - minimizeBtn = new FlxSprite(); drawMinimizeButton(false); minimizeBtn.y = (ShadowStyle.HEIGHT_HEADER - ShadowStyle.SIZE_HEADER_BTN) / 2; add(minimizeBtn); @@ -162,7 +161,7 @@ class ShadowPanel extends FlxSpriteGroup { title = value; if (titleText != null) - titleText.text = value != null ? value : ""; + titleText.text = value ?? ""; return value; } @@ -192,8 +191,8 @@ class ShadowPanel extends FlxSpriteGroup _height = height; _contentHeight = height - ShadowStyle.HEIGHT_HEADER; - var fill = bgColor != null ? bgColor : ShadowStyle.BG_DARK; - var border = borderColor != null ? borderColor : ShadowStyle.BORDER_DARK; + var fill = bgColor ?? ShadowStyle.BG_DARK; + var border = borderColor ?? ShadowStyle.BORDER_DARK; drawHeaderBar(); drawBackground(fill, border); diff --git a/source/engine/backend/ui/components/layout/ShadowTabMenu.hx b/source/engine/backend/ui/components/layout/ShadowTabMenu.hx index 29af6f1f..287de3e9 100644 --- a/source/engine/backend/ui/components/layout/ShadowTabMenu.hx +++ b/source/engine/backend/ui/components/layout/ShadowTabMenu.hx @@ -15,26 +15,27 @@ typedef TabDef = var label:String; } +@:nullSafety class ShadowTabMenu extends FlxSpriteGroup { public var selectedTab(get, set):Int; - public var callback:Int->Void; + public var callback:NullVoid>; public var collapsed(default, set):Bool = false; public var showMinimizeButton(default, set):Bool = true; var tabs:Array; - var tabButtons:Array; - var tabContents:Map; - var panelBg:FlxSprite; - var tabBar:FlxSprite; - var accentLine:FlxSprite; - var minimizeBtn:FlxSprite; - - var _width:Int; - var _height:Int; - - var _tabWidth:Int; - var _tabAreaWidth:Int; + var tabButtons:Array = []; + var tabContents:Map = new Map(); + var panelBg:FlxSprite = new FlxSprite(); + var tabBar:FlxSprite = new FlxSprite(); + var accentLine:FlxSprite = new FlxSprite(); + var minimizeBtn:FlxSprite = new FlxSprite(); + + var _width:Int = 400; + var _height:Int = 300; + + var _tabWidth:Int = 0; + var _tabAreaWidth:Int = 0; var _tabStartX:Int = 0; var _headerRightPad:Int = 3; @@ -61,14 +62,10 @@ class ShadowTabMenu extends FlxSpriteGroup _width = width; _height = height; - tabContents = new Map(); - tabButtons = []; - - panelBg = new FlxSprite(0, ShadowStyle.HEIGHT_TAB); + panelBg.setPosition(0, ShadowStyle.HEIGHT_TAB); drawPanel(); add(panelBg); - tabBar = new FlxSprite(); drawTabBar(); add(tabBar); @@ -359,7 +356,7 @@ class ShadowTabMenu extends FlxSpriteGroup return value; } - public function getTabGroup(name:String):FlxSpriteGroup + public function getTabGroup(name:String):Null return tabContents.get(name); public function addToTab(name:String, sprite:FlxSprite) diff --git a/source/engine/backend/ui/components/text/ShadowInputText.hx b/source/engine/backend/ui/components/text/ShadowInputText.hx index a4d2c55b..a10b241f 100644 --- a/source/engine/backend/ui/components/text/ShadowInputText.hx +++ b/source/engine/backend/ui/components/text/ShadowInputText.hx @@ -17,6 +17,7 @@ import openfl.geom.Matrix; import openfl.geom.Rectangle; import backend.ui.components.controls.ShadowDropdown; +@:nullSafety class ShadowInputText extends FlxText { public static inline var NO_FILTER:Int = 0; @@ -34,7 +35,7 @@ class ShadowInputText extends FlxText public static inline var ENTER_ACTION:String = "enter"; public static inline var INPUT_ACTION:String = "input"; - public var customFilterPattern(default, set):EReg; + public var customFilterPattern(default, set):EReg = ~/^.*$/; function set_customFilterPattern(cfp:EReg) { @@ -43,9 +44,9 @@ class ShadowInputText extends FlxText return customFilterPattern; } - public var callback:String->String->Void; + public var callback:NullString->Void>; public var background:Bool = false; - public var caretColor(default, set):Int; + public var caretColor(default, set):Int = FlxColor.BLACK; function set_caretColor(i:Int):Int { @@ -64,27 +65,27 @@ class ShadowInputText extends FlxText } public var selectionColor(default, set):FlxColor = FlxColor.fromRGB(0, 0, 0, 96); - public var params(default, set):Array; + public var params(default, set):Array = []; public var passwordMode(get, set):Bool; public var hasFocus(default, set):Bool = false; public var caretIndex(default, set):Int = 0; - public var focusGained:Void->Void; - public var focusLost:Void->Void; + public var focusGained:NullVoid>; + public var focusLost:NullVoid>; public var forceCase(default, set):Int = ALL_CASES; public var maxLength(default, set):Int = 0; - public var lines(default, set):Int; + public var lines(default, set):Int = 1; public var filterMode(default, set):Int = NO_FILTER; public var fieldBorderColor(default, set):Int = FlxColor.BLACK; public var fieldBorderThickness(default, set):Int = 1; public var backgroundColor(default, set):Int = FlxColor.WHITE; - private var backgroundSprite:FlxSprite; - private var _caretTimer:FlxTimer; - private var caret:FlxSprite; - private var selectionSprite:FlxSprite; - private var fieldBorderSprite:FlxSprite; + private var backgroundSprite:FlxSprite = new FlxSprite(); + private var _caretTimer:Null = null; + private var caret:FlxSprite = new FlxSprite(); + private var selectionSprite:FlxSprite = new FlxSprite(); + private var fieldBorderSprite:FlxSprite = new FlxSprite(); private var _scrollBoundIndeces:{left:Int, right:Int} = {left: 0, right: 0}; - private var _charBoundaries:Array; - private var lastScroll:Int; + private var _charBoundaries:Null> = null; + private var lastScroll:Int = 0; private var _selectionAnchor:Int = 0; private var _selecting:Bool = false; private var _suppressCaretScroll:Bool = false; @@ -92,32 +93,32 @@ class ShadowInputText extends FlxText public function new(X:Float = 0, Y:Float = 0, Width:Int = 150, ?Text:String, size:Int = 8, TextColor:Int = FlxColor.BLACK, BackgroundColor:Int = FlxColor.WHITE, EmbeddedFont:Bool = true) { - super(X, Y, Width, Text, size, EmbeddedFont); - backgroundColor = BackgroundColor; - if (BackgroundColor != FlxColor.TRANSPARENT) background = true; - color = TextColor; - caretColor = TextColor; - - caret = new FlxSprite(); - caret.makeGraphic(caretWidth, Std.int(size + 2)); + caret.makeGraphic(caretWidth, Std.int((size ?? 8) + 2)); _caretTimer = new FlxTimer(); - selectionSprite = new FlxSprite(X, Y); + selectionSprite.x = X; + selectionSprite.y = Y; selectionSprite.visible = false; - caretIndex = 0; - _selectionAnchor = caretIndex; - hasFocus = false; - if (background) { - fieldBorderSprite = new FlxSprite(X, Y); - backgroundSprite = new FlxSprite(X, Y); + fieldBorderSprite.setPosition(X, Y); + backgroundSprite.setPosition(X, Y); } + super(X, Y, Width, Text, size, EmbeddedFont); + backgroundColor = BackgroundColor; + + color = TextColor; + caretColor = TextColor; + + caretIndex = 0; + _selectionAnchor = caretIndex; + hasFocus = false; + lines = 1; FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 1); @@ -197,7 +198,9 @@ class ShadowInputText extends FlxText #end } - if (caretColor != caret.color || caret.height != size + 2) + @:nullSafety(Off) + var actualSize:Int = (size > 0) ? size : 8; + if (caretColor != caret.color || caret.height != actualSize + 2) caret.color = caretColor; drawSprite(caret); @@ -208,7 +211,7 @@ class ShadowInputText extends FlxText #end } - private function drawSprite(Sprite:FlxSprite):Void + private function drawSprite(Sprite:Null):Void { if (Sprite != null && Sprite.visible) { @@ -684,7 +687,7 @@ class ShadowInputText extends FlxText #end } - private function getCharBoundaries(charIndex:Int):Rectangle + private function getCharBoundaries(charIndex:Int):Null { if (_charBoundaries == null || _charBoundaries.length == 0 || charIndex < 0) return null; @@ -710,7 +713,7 @@ class ShadowInputText extends FlxText { if (text != null && text.length > 0 && _charBoundaries != null && _charBoundaries.length > 0) { - var boundary:Rectangle = getCharBoundaries(text.length - 1); + var boundary:Null = getCharBoundaries(text.length - 1); if (boundary != null) return x + boundary.right + 4; } @@ -763,7 +766,19 @@ class ShadowInputText extends FlxText if (selectionSprite == null || textField == null) return; - if (text == null || text.length == 0 || !hasSelection() || _charBoundaries == null || _charBoundaries.length == 0) + if (text == null || text.length == 0 || !hasSelection()) + { + selectionSprite.visible = false; + return; + } + + if (_charBoundaries == null) + { + selectionSprite.visible = false; + return; + } + + if (_charBoundaries.length == 0) { selectionSprite.visible = false; return; @@ -882,10 +897,13 @@ class ShadowInputText extends FlxText if (i == 0) textH = textField.textHeight; - _charBoundaries[i].x = magicX + lastW; - _charBoundaries[i].y = magicY; - _charBoundaries[i].width = (textW - lastW); - _charBoundaries[i].height = textH; + if (_charBoundaries != null && _charBoundaries[i] != null) + { + _charBoundaries[i].x = magicX + lastW; + _charBoundaries[i].y = magicY; + _charBoundaries[i].width = (textW - lastW); + _charBoundaries[i].height = textH; + } lastW = textW; } @@ -990,7 +1008,7 @@ class ShadowInputText extends FlxText if (targetIndex > textLen) targetIndex = textLen; - var boundary:Rectangle = null; + var boundary:Null = null; // caret at very end uses last char boundary if (targetIndex == textLen && textLen > 0) @@ -1087,7 +1105,7 @@ class ShadowInputText extends FlxText return; } - var boundary:Rectangle = null; + var boundary:Null = null; var targetIndex:Int = caretIndex; if (targetIndex < 0) targetIndex = 0; @@ -1220,7 +1238,9 @@ class ShadowInputText extends FlxText if (caret != null) { - final caretHeight = Std.int(size + 2); + @:nullSafety(Off) + var actualSizeInt:Int = (size > 0) ? size : 8; + final caretHeight:Int = actualSizeInt + 2; var cw:Int = caretWidth; var ch:Int = caretHeight; @@ -1469,7 +1489,7 @@ class ShadowInputText extends FlxText return caretIndex; } - var boundaries:Rectangle = null; + var boundaries:Null = null; if (caretIndex < textLen) { diff --git a/source/engine/backend/ui/components/text/ShadowLabel.hx b/source/engine/backend/ui/components/text/ShadowLabel.hx index 7df474b9..a7eb177a 100644 --- a/source/engine/backend/ui/components/text/ShadowLabel.hx +++ b/source/engine/backend/ui/components/text/ShadowLabel.hx @@ -5,13 +5,14 @@ import flixel.util.FlxColor; import backend.Paths; import backend.ui.ShadowStyle; +@:nullSafety class ShadowLabel extends FlxText { public function new(x:Float, y:Float, text:String, ?size:Int, ?color:FlxColor, fieldWidth:Int = 0) { super(x, y, fieldWidth, text); - var fontSize:Int = size != null ? size : ShadowStyle.FONT_SIZE_MD; - var textColor = color != null ? color : ShadowStyle.TEXT_PRIMARY; + var fontSize:Int = size ?? ShadowStyle.FONT_SIZE_MD; + var textColor = color ?? ShadowStyle.TEXT_PRIMARY; setFormat(Paths.font(ShadowStyle.FONT_DEFAULT), fontSize, textColor); antialiasing = ShadowStyle.antialiasing; } diff --git a/source/engine/backend/ui/components/text/ShadowTextInput.hx b/source/engine/backend/ui/components/text/ShadowTextInput.hx index cf634706..9dda84e1 100644 --- a/source/engine/backend/ui/components/text/ShadowTextInput.hx +++ b/source/engine/backend/ui/components/text/ShadowTextInput.hx @@ -9,30 +9,31 @@ import backend.ui.ShadowStyle; import backend.ui.components.text.ShadowInputText; import backend.ui.components.controls.ShadowDropdown; +@:nullSafety class ShadowTextInput extends FlxSpriteGroup { - public var input:ShadowInputText; - public var callback:String->Void; + public var input:Null = null; + public var callback:NullVoid>; public var text(get, set):String; - var bg:FlxSprite; - var _width:Int; - var _height:Int; + var bg:FlxSprite = new FlxSprite(); + var _width:Int = 150; + var _height:Int = 28; var _hovered:Bool = false; public function new(x:Float, y:Float, width:Int, ?defaultText:String, ?onChange:String->Void) { - super(x, y); _width = width; _height = ShadowStyle.HEIGHT_INPUT; callback = onChange; - bg = new FlxSprite(); + super(x, y); + bg.makeGraphic(_width, _height, ShadowStyle.BG_INPUT, true); drawBorder(ShadowStyle.BORDER_DARK); add(bg); - var startText:String = defaultText != null ? defaultText : ""; + var startText:String = defaultText ?? ""; input = new ShadowInputText(2, 0, _width - 4, "", ShadowStyle.FONT_SIZE_MD, ShadowStyle.TEXT_PRIMARY, FlxColor.TRANSPARENT, true); input.setFormat(Paths.font(ShadowStyle.FONT_DEFAULT), ShadowStyle.FONT_SIZE_MD, ShadowStyle.TEXT_PRIMARY); input.antialiasing = ShadowStyle.antialiasing; @@ -96,7 +97,7 @@ class ShadowTextInput extends FlxSpriteGroup input.hasFocus = value; function get_text():String - return input != null ? input.text : ""; + return input?.text ?? ""; function set_text(value:String):String { diff --git a/source/engine/cutscenes/CutsceneHandler.hx b/source/engine/cutscenes/CutsceneHandler.hx index b1011e9b..08adc094 100644 --- a/source/engine/cutscenes/CutsceneHandler.hx +++ b/source/engine/cutscenes/CutsceneHandler.hx @@ -3,15 +3,16 @@ package cutscenes; import flixel.FlxBasic; import flixel.util.FlxSort; +@:nullSafety class CutsceneHandler extends FlxBasic { public var timedEvents:Array = []; - public var finishCallback:Void->Void = null; - public var finishCallback2:Void->Void = null; - public var onStart:Void->Void = null; + public var finishCallback:NullVoid> = null; + public var finishCallback2:NullVoid> = null; + public var onStart:NullVoid> = null; public var endTime:Float = 0; public var objects:Array = []; - public var music:String = null; + public var music:Null = null; public function new() { @@ -21,13 +22,17 @@ class CutsceneHandler extends FlxBasic { if (music != null) { - FlxG.sound.playMusic(Paths.music(music), 0, false); - FlxG.sound.music.fadeIn(); + var musicPath = Paths.music(music); + if (musicPath != null) + FlxG.sound.playMusic(musicPath, 0, false); + var musicSound = FlxG.sound.music; + if (musicSound != null) + musicSound.fadeIn(); } if (onStart != null) onStart(); }); - PlayState.instance.add(this); + PlayState.instance?.add(this); } private var cutsceneTime:Float = 0; @@ -46,25 +51,31 @@ class CutsceneHandler extends FlxBasic cutsceneTime += elapsed; if (endTime <= cutsceneTime) { - finishCallback(); + if (finishCallback != null) + finishCallback(); if (finishCallback2 != null) finishCallback2(); for (spr in objects) { - PlayState.instance.remove(spr); + PlayState.instance?.remove(spr); spr.kill(); spr.destroy(); } kill(); destroy(); - PlayState.instance.remove(this); + PlayState.instance?.remove(this); } while (timedEvents.length > 0 && timedEvents[0][0] <= cutsceneTime) { - timedEvents[0][1](); + var event:Array = timedEvents[0]; + if (event != null && event[1] != null) + { + var func:Void->Void = cast event[1]; + func(); + } timedEvents.shift(); } } diff --git a/source/engine/cutscenes/DialogueBox.hx b/source/engine/cutscenes/DialogueBox.hx index e16a6aae..42a6470d 100644 --- a/source/engine/cutscenes/DialogueBox.hx +++ b/source/engine/cutscenes/DialogueBox.hx @@ -2,6 +2,7 @@ package cutscenes; import flixel.addons.text.FlxTypeText; +@:nullSafety class DialogueBox extends FlxSpriteGroup { var box:FlxSprite; diff --git a/source/engine/cutscenes/DialogueBoxPsych.hx b/source/engine/cutscenes/DialogueBoxPsych.hx index 53a8f202..0b479ff6 100644 --- a/source/engine/cutscenes/DialogueBoxPsych.hx +++ b/source/engine/cutscenes/DialogueBoxPsych.hx @@ -22,6 +22,7 @@ typedef DialogueLine = } // TO DO: Clean code? Maybe? idk +@:nullSafety class DialogueBoxPsych extends FlxSpriteGroup { public static var DEFAULT_TEXT_X = 175; @@ -30,15 +31,15 @@ class DialogueBoxPsych extends FlxSpriteGroup var scrollSpeed = 4000; - var dialogue:TypedAlphabet; - var dialogueList:DialogueFile = null; + var dialogue:Null = null; + var dialogueList:Null = null; - public var finishThing:Void->Void; - public var nextDialogueThing:Void->Void = null; - public var skipDialogueThing:Void->Void = null; + public var finishThing:NullVoid> = null; + public var nextDialogueThing:NullVoid> = null; + public var skipDialogueThing:NullVoid> = null; - var bgFade:FlxSprite = null; - var box:FlxSprite; + var bgFade:Null; + var box:Null; var textToType:String = ''; var arrayCharacters:Array = []; @@ -62,8 +63,12 @@ class DialogueBoxPsych extends FlxSpriteGroup if (song != null && song != '') { - FlxG.sound.playMusic(Paths.music(song), 0); - FlxG.sound.music.fadeIn(2, 0, 1); + var musicPath = Paths.music(song); + if (musicPath != null) + FlxG.sound.playMusic(musicPath, 0); + var music = FlxG.sound.music; + if (music != null) + music.fadeIn(2, 0, 1); } bgFade = new FlxSprite(-500, -500).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.WHITE); @@ -77,7 +82,9 @@ class DialogueBoxPsych extends FlxSpriteGroup box = new FlxSprite(70, 370); box.antialiasing = ClientPrefs.data.antialiasing; - box.frames = Paths.getSparrowAtlas('speech_bubble'); + var boxAtlas = Paths.getSparrowAtlas('speech_bubble'); + if (boxAtlas != null) + box.frames = boxAtlas; box.scrollFactor.set(); box.animation.addByPrefix('normal', 'speech bubble normal', 24); box.animation.addByPrefix('normalOpen', 'Speech Bubble Normal Open', 24, false); @@ -93,9 +100,12 @@ class DialogueBoxPsych extends FlxSpriteGroup box.updateHitbox(); add(box); - daText = new TypedAlphabet(DEFAULT_TEXT_X, DEFAULT_TEXT_Y, ''); - daText.setScale(0.7); - add(daText); + alphabetText = new TypedAlphabet(DEFAULT_TEXT_X, DEFAULT_TEXT_Y, ''); + if (alphabetText != null) + { + alphabetText.setScale(0.7); + add(alphabetText); + } startNextDialog(); } @@ -109,13 +119,15 @@ class DialogueBoxPsych extends FlxSpriteGroup function spawnCharacters() { + if (dialogueList == null) + return; var charsMap:Map = new Map(); for (i in 0...dialogueList.dialogue.length) { if (dialogueList.dialogue[i] != null) { - var charToAdd:String = dialogueList.dialogue[i].portrait; - if (!charsMap.exists(charToAdd) || !charsMap.get(charToAdd)) + var charToAdd:Null = dialogueList.dialogue[i].portrait; + if (charToAdd != null && (!charsMap.exists(charToAdd) || charsMap.get(charToAdd) != true)) { charsMap.set(charToAdd, true); } @@ -127,35 +139,42 @@ class DialogueBoxPsych extends FlxSpriteGroup var x:Float = LEFT_CHAR_X; var y:Float = DEFAULT_CHAR_Y; var char:DialogueCharacter = new DialogueCharacter(x + offsetPos, y, individualChar); - char.setGraphicSize(Std.int(char.width * DialogueCharacter.DEFAULT_SCALE * char.jsonFile.scale)); - char.updateHitbox(); - char.scrollFactor.set(); - char.alpha = 0.00001; - add(char); - - var saveY:Bool = false; - switch (char.jsonFile.dialogue_pos) + var jsonFile = char.jsonFile; + if (jsonFile != null) { - case 'center': - char.x = FlxG.width / 2; - char.x -= char.width / 2; - y = char.y; - char.y = FlxG.height + 50; - saveY = true; - case 'right': - x = FlxG.width - char.width + RIGHT_CHAR_X; - char.x = x - offsetPos; + char.setGraphicSize(Std.int(char.width * DialogueCharacter.DEFAULT_SCALE * jsonFile.scale)); + char.updateHitbox(); + char.scrollFactor.set(); + char.alpha = 0.00001; + add(char); + + var saveY:Bool = false; + switch (jsonFile.dialogue_pos) + { + case 'center': + char.x = FlxG.width / 2; + char.x -= char.width / 2; + y = char.y; + char.y = FlxG.height + 50; + saveY = true; + case 'right': + x = FlxG.width - char.width + RIGHT_CHAR_X; + char.x = x - offsetPos; + } + if (jsonFile.position != null && jsonFile.position.length >= 2) + { + x += jsonFile.position[0]; + y += jsonFile.position[1]; + char.x += jsonFile.position[0]; + char.y += jsonFile.position[1]; + } + char.startingPos = (saveY ? y : x); } - x += char.jsonFile.position[0]; - y += char.jsonFile.position[1]; - char.x += char.jsonFile.position[0]; - char.y += char.jsonFile.position[1]; - char.startingPos = (saveY ? y : x); arrayCharacters.push(char); } } - var daText:TypedAlphabet = null; + var alphabetText:Null = null; var ignoreThisFrame:Bool = true; // First frame is reserved for loading dialogue images public var closeSound:String = 'dialogueClose'; @@ -172,76 +191,95 @@ class DialogueBoxPsych extends FlxSpriteGroup if (!dialogueEnded) { - bgFade.alpha += 0.5 * elapsed; - if (bgFade.alpha > 0.5) - bgFade.alpha = 0.5; + if (bgFade != null) + { + bgFade.alpha += 0.5 * elapsed; + if (bgFade.alpha > 0.5) + bgFade.alpha = 0.5; + } var justTouched:Bool = false; for (touch in FlxG.touches.list) if (touch.justPressed) justTouched = true; - if (Controls.instance.ACCEPT || justTouched) + var acceptPressed:Bool = false; + var controls = Controls.instance; + if (controls != null) + acceptPressed = controls.ACCEPT; + + if (acceptPressed || justTouched) { - if (!daText.finishedText) + if (alphabetText != null && !alphabetText.finishedText) { - daText.finishText(); + alphabetText.finishText(); if (skipDialogueThing != null) { skipDialogueThing(); } } - else if (currentText >= dialogueList.dialogue.length) + else if (dialogueList != null && currentText >= dialogueList.dialogue.length) { dialogueEnded = true; for (i in 0...textBoxTypes.length) { var checkArray:Array = ['', 'center-']; - var animName:String = box.animation.curAnim.name; - for (j in 0...checkArray.length) + if (box != null && box.animation != null && box.animation.curAnim != null) { - if (animName == checkArray[j] + textBoxTypes[i] || animName == checkArray[j] + textBoxTypes[i] + 'Open') + var animName:String = box.animation.curAnim.name; + for (j in 0...checkArray.length) { - box.animation.play(checkArray[j] + textBoxTypes[i] + 'Open', true); + if (animName == checkArray[j] + textBoxTypes[i] || animName == checkArray[j] + textBoxTypes[i] + 'Open') + { + box.animation.play(checkArray[j] + textBoxTypes[i] + 'Open', true); + } } } } - box.animation.curAnim.curFrame = box.animation.curAnim.frames.length - 1; - box.animation.curAnim.reverse(); - if (daText != null) + if (box != null && box.animation != null && box.animation.curAnim != null) + { + box.animation.curAnim.curFrame = box.animation.curAnim.frames.length - 1; + box.animation.curAnim.reverse(); + } + if (alphabetText != null) { - remove(daText); - daText.kill(); - daText.destroy(); + remove(alphabetText); + alphabetText.kill(); + alphabetText.destroy(); } - updateBoxOffsets(box); + if (box != null) + updateBoxOffsets(box); FlxG.sound.music.fadeOut(1, 0); } else { startNextDialog(); } - FlxG.sound.play(Paths.sound(closeSound), closeVolume); + var soundPath = Paths.sound(closeSound); + if (soundPath != null) + FlxG.sound.play(soundPath, closeVolume); } - else if (daText.finishedText) + else if (alphabetText != null && alphabetText.finishedText) { - var char:DialogueCharacter = arrayCharacters[lastCharacter]; - if (char != null && char.animation.curAnim != null && char.animationIsLoop() && char.animation.finished) + var char:Null = arrayCharacters[lastCharacter]; + if (char != null && char.animation != null && char.animation.curAnim != null && char.animationIsLoop() && char.animation.finished) { - char.playAnim(char.animation.curAnim.name, true); + var animName = char.animation.curAnim.name; + if (animName != null) + char.playAnim(animName, true); } } - else + else if (alphabetText != null) { - var char:DialogueCharacter = arrayCharacters[lastCharacter]; - if (char != null && char.animation.curAnim != null && char.animation.finished) + var char:Null = arrayCharacters[lastCharacter]; + if (char != null && char.animation != null && char.animation.curAnim != null && char.animation.finished) { char.animation.curAnim.restart(); } } - if (box.animation.curAnim.finished) + if (box != null && box.animation != null && box.animation.curAnim != null && box.animation.curAnim.finished) { for (i in 0...textBoxTypes.length) { @@ -265,9 +303,11 @@ class DialogueBoxPsych extends FlxSpriteGroup var char = arrayCharacters[i]; if (char != null) { + var jsonFile = char.jsonFile; + var pos:String = (jsonFile != null) ? jsonFile.dialogue_pos : 'left'; if (i != lastCharacter) { - switch (char.jsonFile.dialogue_pos) + switch (pos) { case 'left': char.x -= scrollSpeed * elapsed; @@ -288,7 +328,7 @@ class DialogueBoxPsych extends FlxSpriteGroup } else { - switch (char.jsonFile.dialogue_pos) + switch (pos) { case 'left': char.x += scrollSpeed * elapsed; @@ -313,7 +353,7 @@ class DialogueBoxPsych extends FlxSpriteGroup } else // Dialogue ending { - if (box != null && box.animation.curAnim.curFrame <= 0) + if (box != null && box.animation != null && box.animation.curAnim != null && box.animation.curAnim.curFrame <= 0) { remove(box); box.kill(); @@ -334,19 +374,21 @@ class DialogueBoxPsych extends FlxSpriteGroup for (i in 0...arrayCharacters.length) { - var leChar:DialogueCharacter = arrayCharacters[i]; - if (leChar != null) + var char:Null = arrayCharacters[i]; + if (char != null) { - switch (arrayCharacters[i].jsonFile.dialogue_pos) + var jsonFile = char.jsonFile; + var pos:String = (jsonFile != null) ? jsonFile.dialogue_pos : 'left'; + switch (pos) { case 'left': - leChar.x -= scrollSpeed * elapsed; + char.x -= scrollSpeed * elapsed; case 'center': - leChar.y += scrollSpeed * elapsed; + char.y += scrollSpeed * elapsed; case 'right': - leChar.x += scrollSpeed * elapsed; + char.x += scrollSpeed * elapsed; } - leChar.alpha -= elapsed * 10; + char.alpha -= elapsed * 10; } } @@ -354,15 +396,16 @@ class DialogueBoxPsych extends FlxSpriteGroup { for (i in 0...arrayCharacters.length) { - var leChar:DialogueCharacter = arrayCharacters[0]; - if (leChar != null) + var char:Null = arrayCharacters[0]; + if (char != null) { - arrayCharacters.remove(leChar); - remove(leChar); - leChar.destroy(); + arrayCharacters.remove(char); + remove(char); + char.destroy(); } } - finishThing(); + if (finishThing != null) + finishThing(); kill(); } } @@ -374,7 +417,9 @@ class DialogueBoxPsych extends FlxSpriteGroup function startNextDialog():Void { - var curDialogue:DialogueLine = null; + if (dialogueList == null) + return; + var curDialogue:Null = null; do { curDialogue = dialogueList.dialogue[currentText]; @@ -388,7 +433,7 @@ class DialogueBoxPsych extends FlxSpriteGroup if (curDialogue.speed == null || Math.isNaN(curDialogue.speed)) curDialogue.speed = 0.05; - var animName:String = curDialogue.boxState; + var animName:String = (curDialogue.boxState != null) ? curDialogue.boxState : 'normal'; var boxType:String = textBoxTypes[0]; for (i in 0...textBoxTypes.length) { @@ -399,49 +444,72 @@ class DialogueBoxPsych extends FlxSpriteGroup } var character:Int = 0; - box.visible = true; + if (box != null) + box.visible = true; for (i in 0...arrayCharacters.length) { - if (arrayCharacters[i].curCharacter == curDialogue.portrait) + var arrChar = arrayCharacters[i]; + if (arrChar != null && arrChar.curCharacter == curDialogue.portrait) { character = i; break; } } var centerPrefix:String = ''; - var lePosition:String = arrayCharacters[character].jsonFile.dialogue_pos; + var lePosition:String = 'left'; + var arrChar = arrayCharacters[character]; + if (arrChar != null) + { + var jsonFile = arrChar.jsonFile; + if (jsonFile != null) + lePosition = jsonFile.dialogue_pos; + } if (lePosition == 'center') centerPrefix = 'center-'; if (character != lastCharacter) { - box.animation.play(centerPrefix + boxType + 'Open', true); - updateBoxOffsets(box); - box.flipX = (lePosition == 'left'); + if (box != null) + { + box.animation.play(centerPrefix + boxType + 'Open', true); + updateBoxOffsets(box); + box.flipX = (lePosition == 'left'); + } } else if (boxType != lastBoxType) { - box.animation.play(centerPrefix + boxType, true); - updateBoxOffsets(box); + if (box != null) + { + box.animation.play(centerPrefix + boxType, true); + updateBoxOffsets(box); + } } lastCharacter = character; lastBoxType = boxType; - daText.text = curDialogue.text; - daText.delay = curDialogue.speed; - daText.sound = curDialogue.sound; - if (daText.sound == null || daText.sound.trim() == '') - daText.sound = 'dialogue'; - - daText.y = DEFAULT_TEXT_Y; - if (daText.rows > 2) - daText.y -= LONG_TEXT_ADD; + if (alphabetText != null && curDialogue.text != null) + alphabetText.text = curDialogue.text; + if (alphabetText != null && curDialogue.speed != null) + alphabetText.delay = curDialogue.speed; + if (alphabetText != null) + { + alphabetText.sound = (curDialogue.sound != null) ? curDialogue.sound : 'dialogue'; + var soundTrimmed = alphabetText.sound.trim(); + if (soundTrimmed == null || soundTrimmed == '') + alphabetText.sound = 'dialogue'; + + alphabetText.y = DEFAULT_TEXT_Y; + if (alphabetText.rows > 2) + alphabetText.y -= LONG_TEXT_ADD; + } - var char:DialogueCharacter = arrayCharacters[character]; + var char:Null = arrayCharacters[character]; if (char != null) { - char.playAnim(curDialogue.expression, daText.finishedText); - if (char.animation.curAnim != null) + var expression = curDialogue.expression; + var finished = (alphabetText != null) ? alphabetText.finishedText : false; + char.playAnim(expression, finished); + if (char.animation != null && char.animation.curAnim != null) { var rate:Float = 24 - (((curDialogue.speed - 0.05) / 5) * 480); if (rate < 12) @@ -459,26 +527,38 @@ class DialogueBoxPsych extends FlxSpriteGroup } } - public static function parseDialogue(path:String):DialogueFile + public static function parseDialogue(path:String):Null { if (FileSystem.exists(path)) - return cast Json.parse(File.getContent(path), path); - + { + var content = File.getContent(path); + if (content != null) + return cast Json.parse(content, path); + } return null; } // Had to make it static because of the editors - public static function updateBoxOffsets(box:FlxSprite) + public static function updateBoxOffsets(box:Null):Void { + if (box == null) + return; box.centerOffsets(); box.updateHitbox(); - if (box.animation.curAnim.name.startsWith('angry')) - { - box.offset.set(50, 65); - } - else if (box.animation.curAnim.name.startsWith('center-angry')) + if (box.animation != null && box.animation.curAnim != null && box.animation.curAnim.name != null) { - box.offset.set(50, 30); + if (box.animation.curAnim.name.startsWith('angry')) + { + box.offset.set(50, 65); + } + else if (box.animation.curAnim.name.startsWith('center-angry')) + { + box.offset.set(50, 30); + } + else + { + box.offset.set(10, 0); + } } else { diff --git a/source/engine/cutscenes/DialogueCharacter.hx b/source/engine/cutscenes/DialogueCharacter.hx index 19bd999b..5e3a9dc0 100644 --- a/source/engine/cutscenes/DialogueCharacter.hx +++ b/source/engine/cutscenes/DialogueCharacter.hx @@ -22,13 +22,14 @@ typedef DialogueCharacterFile = var scale:Float; } +@:nullSafety class DialogueCharacter extends FlxSprite { private static var IDLE_SUFFIX:String = '-IDLE'; public static var DEFAULT_CHARACTER:String = 'bf'; public static var DEFAULT_SCALE:Float = 0.7; - public var jsonFile:DialogueCharacterFile = null; + public var jsonFile:Null = null; public var dialogueAnimations:Map = new Map(); public var startingPos:Float = 0; // For center characters, it works as the starting Y, for everything else it works as starting X @@ -46,11 +47,17 @@ class DialogueCharacter extends FlxSprite this.curCharacter = character; reloadCharacterJson(character); - frames = Paths.getSparrowAtlas('dialogue/' + jsonFile.image); + if (jsonFile != null) + { + var img:String = jsonFile.image; + var atlas = Paths.getSparrowAtlas('dialogue/' + img); + if (atlas != null) + frames = atlas; + } reloadAnimations(); antialiasing = ClientPrefs.data.antialiasing; - if (jsonFile.no_antialiasing == true) + if (jsonFile != null && jsonFile.no_antialiasing == true) antialiasing = false; } @@ -68,14 +75,15 @@ class DialogueCharacter extends FlxSprite if (!FileSystem.exists(path)) path = Paths.getSharedPath(defaultPath); - var rawJson:String = File.getContent(path); - jsonFile = cast Json.parse(rawJson, path); + var rawJson:Null = File.getContent(path); + if (rawJson != null) + jsonFile = cast Json.parse(rawJson, path); } public function reloadAnimations() { dialogueAnimations.clear(); - if (jsonFile.animations != null && jsonFile.animations.length > 0) + if (jsonFile != null && jsonFile.animations != null && jsonFile.animations.length > 0) { for (anim in jsonFile.animations) { @@ -86,9 +94,9 @@ class DialogueCharacter extends FlxSprite } } - public function playAnim(animName:String = null, playIdle:Bool = false) + public function playAnim(animName:Null = null, playIdle:Bool = false) { - var leAnim:String = animName; + var targetAnim:Null = animName; if (animName == null || !dialogueAnimations.exists(animName)) // Anim is null, get a random animation { var arrayAnims:Array = []; @@ -98,38 +106,41 @@ class DialogueCharacter extends FlxSprite } if (arrayAnims.length > 0) { - leAnim = arrayAnims[FlxG.random.int(0, arrayAnims.length - 1)]; + targetAnim = arrayAnims[FlxG.random.int(0, arrayAnims.length - 1)]; } } - if (dialogueAnimations.exists(leAnim) - && (dialogueAnimations.get(leAnim).loop_name == null - || dialogueAnimations.get(leAnim).loop_name.length < 1 - || dialogueAnimations.get(leAnim).loop_name == dialogueAnimations.get(leAnim).idle_name)) + if (targetAnim != null && dialogueAnimations.exists(targetAnim)) { - playIdle = true; + var animData:Null = dialogueAnimations.get(targetAnim); + if (animData != null && (animData.loop_name == null || animData.loop_name.length < 1 || animData.loop_name == animData.idle_name)) + { + playIdle = true; + } } - animation.play(playIdle ? leAnim + IDLE_SUFFIX : leAnim, false); + if (targetAnim != null) + animation.play(playIdle ? targetAnim + IDLE_SUFFIX : targetAnim, false); - if (dialogueAnimations.exists(leAnim)) + if (targetAnim != null && dialogueAnimations.exists(targetAnim)) { - var anim:DialogueAnimArray = dialogueAnimations.get(leAnim); - if (playIdle) - { - offset.set(anim.idle_offsets[0], anim.idle_offsets[1]); - // trace('Setting idle offsets: ' + anim.idle_offsets); - } - else + var anim:Null = dialogueAnimations.get(targetAnim); + if (anim != null) { - offset.set(anim.loop_offsets[0], anim.loop_offsets[1]); - // trace('Setting loop offsets: ' + anim.loop_offsets); + if (playIdle) + { + offset.set(anim.idle_offsets[0], anim.idle_offsets[1]); + } + else + { + offset.set(anim.loop_offsets[0], anim.loop_offsets[1]); + } } } else { offset.set(0, 0); trace('Offsets not found! Dialogue character is badly formatted, anim: ' - + leAnim + + targetAnim + ', ' + (playIdle ? 'idle anim' : 'loop anim')); } diff --git a/source/engine/debug/codename/Framerate.hx b/source/engine/debug/codename/Framerate.hx index d946b2f2..b2a60b48 100644 --- a/source/engine/debug/codename/Framerate.hx +++ b/source/engine/debug/codename/Framerate.hx @@ -11,14 +11,15 @@ import openfl.text.TextFormat; import openfl.ui.Keyboard; import flixel.util.FlxTimer; +@:nullSafety class Framerate extends Sprite { - public static var instance:Framerate; + public static var instance:Null = null; public static var isLoaded:Bool = false; - public static var textFormat:TextFormat; - public static var fpsCounter:FramerateCounter; - public static var memoryCounter:MemoryCounter; + public static var textFormat:Null = null; + public static var fpsCounter:Null = null; + public static var memoryCounter:Null = null; public static var fontName:String = #if windows '${Sys.getEnv("windir")}\\Fonts\\consola.ttf' #else "_typewriter" #end; @@ -31,11 +32,11 @@ class Framerate extends Sprite public static var offset:FlxPoint = new FlxPoint(); - public var bgSprite:Bitmap; + public var bgSprite:Null = null; public var categories:Array = []; - @:isVar public static var __bitmap(get, null):BitmapData = null; + @:isVar public static var __bitmap(get, null):Null = null; private static function get___bitmap():BitmapData { @@ -59,9 +60,6 @@ class Framerate extends Sprite isLoaded = true; - x = 10; - y = 2; - FlxG.signals.gameResized.add(function(w, h) { setScale(Math.min(openfl.Lib.current.stage.stageWidth / FlxG.width, openfl.Lib.current.stage.stageHeight / FlxG.height)); @@ -69,12 +67,14 @@ class Framerate extends Sprite FlxG.stage.addEventListener(KeyboardEvent.KEY_UP, function(e:KeyboardEvent) { - if (Controls.instance.justReleased('fpsCounter')) + var ctrl = Controls.instance; + if (ctrl != null && ctrl.justReleased('fpsCounter')) { debugMode = (debugMode + 1) % 3; @:privateAccess { - memoryCounter.refreshText(memoryCounter.memory, memoryCounter.memoryPeak); + if (memoryCounter != null) + memoryCounter.refreshText(memoryCounter.memory, memoryCounter.memoryPeak); } } }); @@ -82,6 +82,8 @@ class Framerate extends Sprite if (__bitmap == null) __bitmap = new BitmapData(1, 1, 0xFF000000); + x = 10; + y = 2; bgSprite = new Bitmap(__bitmap); bgSprite.alpha = 0; addChild(bgSprite); @@ -95,8 +97,10 @@ class Framerate extends Sprite { for (c in categories) c.reload(); - memoryCounter.reload(); - fpsCounter.reload(); + if (memoryCounter != null) + memoryCounter.reload(); + if (fpsCounter != null) + fpsCounter.reload(); } private function __addCategory(category:FramerateCategory) @@ -105,7 +109,7 @@ class Framerate extends Sprite __addToList(category); } - private var __lastAddedSprite:DisplayObject = null; + private var __lastAddedSprite:Null = null; private function __addToList(spr:DisplayObject) { @@ -161,19 +165,29 @@ class Framerate extends Sprite if (alpha < 0.05) return; super.__enterFrame(t); - bgSprite.alpha = debugAlpha * 0.5; + if (bgSprite != null) + bgSprite.alpha = debugAlpha * 0.5; x = 10 + offset.x; y = 2 + offset.y; - var width = MathUtil.maxSmart(fpsCounter.width, memoryCounter.width) + (x * 2); - var height = memoryCounter.y + memoryCounter.height; - bgSprite.x = -x; - bgSprite.y = offset.x; - bgSprite.scaleX = width; - bgSprite.scaleY = height; + var width = 0.0; + var height = 0.0; + if (fpsCounter != null && memoryCounter != null) + { + width = MathUtil.maxSmart(fpsCounter.width, memoryCounter.width) + (x * 2); + height = memoryCounter.y + memoryCounter.height; + } + if (bgSprite != null) + { + bgSprite.x = -x; + bgSprite.y = offset.x; + bgSprite.scaleX = width; + bgSprite.scaleY = height; + } var selectable = debugMode == 2; // idk i tried to make it more readable:sob: - Nex + if (memoryCounter != null && fpsCounter != null) { memoryCounter.memoryText.selectable = memoryCounter.memoryPeakText.selectable = fpsCounter.fpsNum.selectable = fpsCounter.fpsLabel.selectable = selectable; } diff --git a/source/engine/debug/codename/FramerateCategory.hx b/source/engine/debug/codename/FramerateCategory.hx index e63c4d7c..081ab794 100644 --- a/source/engine/debug/codename/FramerateCategory.hx +++ b/source/engine/debug/codename/FramerateCategory.hx @@ -5,6 +5,7 @@ import openfl.display.Sprite; import openfl.text.TextField; import openfl.text.TextFormat; +@:nullSafety class FramerateCategory extends Sprite { public var title:TextField; @@ -18,7 +19,6 @@ class FramerateCategory extends Sprite { super(); - x = 10; this.title = new TextField(); this.text = new TextField(); @@ -40,6 +40,7 @@ class FramerateCategory extends Sprite this.text.multiline = true; this.text.y = this.title.y + this.title.height + 2; + x = 10; } public function reload() {} @@ -50,9 +51,10 @@ class FramerateCategory extends Sprite return; super.__enterFrame(t); - var width = Math.max(this.title.width, this.text.width) + (Framerate.instance.x * 2); + var instanceX = Framerate.instance?.x ?? 10; + var width = Math.max(this.title.width, this.text.width) + (instanceX * 2); var height = this.text.height + this.text.y; - bgSprite.x = -Framerate.instance.x; + bgSprite.x = -instanceX; bgSprite.scaleX = width; bgSprite.scaleY = height; } diff --git a/source/engine/debug/codename/FramerateCounter.hx b/source/engine/debug/codename/FramerateCounter.hx index aac1bfc5..e2c52060 100644 --- a/source/engine/debug/codename/FramerateCounter.hx +++ b/source/engine/debug/codename/FramerateCounter.hx @@ -4,6 +4,7 @@ import openfl.display.Sprite; import openfl.text.TextField; import openfl.text.TextFormat; +@:nullSafety class FramerateCounter extends Sprite { public var fpsNum:TextField; diff --git a/source/engine/debug/codename/MemoryCounter.hx b/source/engine/debug/codename/MemoryCounter.hx index c7de96ce..325df0c8 100644 --- a/source/engine/debug/codename/MemoryCounter.hx +++ b/source/engine/debug/codename/MemoryCounter.hx @@ -4,6 +4,7 @@ import openfl.display.Sprite; import openfl.text.TextField; import openfl.text.TextFormat; +@:nullSafety class MemoryCounter extends Sprite { public var memoryText:TextField; diff --git a/source/engine/debug/codename/SystemInfo.hx b/source/engine/debug/codename/SystemInfo.hx index 433ef500..b62e718b 100644 --- a/source/engine/debug/codename/SystemInfo.hx +++ b/source/engine/debug/codename/SystemInfo.hx @@ -26,6 +26,7 @@ using StringTools; @:headerInclude('sys/utsname.h') #end #end +@:nullSafety class SystemInfo extends FramerateCategory { public static var osInfo:String = "Unknown"; @@ -83,8 +84,9 @@ class SystemInfo extends FramerateCategory } #elseif windows var windowsCurrentVersionPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; - var buildNumber = Std.parseInt(RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "CurrentBuildNumber")); - var edition = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "ProductName"); + var buildNumStr = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "CurrentBuildNumber"); + var buildNumber:Int = (buildNumStr != null) ? Std.parseInt(buildNumStr) ?? 0 : 0; + var edition:String = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "ProductName") ?? "Unknown"; var lcuKey = "WinREVersion"; // Last Cumulative Update Key On Older Windows Versions if (buildNumber >= 22000) // Windows 11 Initial Release Build Number @@ -116,7 +118,7 @@ class SystemInfo extends FramerateCategory try { #if windows - cpuName = RegistryUtil.get(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString"); + cpuName = RegistryUtil.get(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString") ?? "Unknown"; #elseif mac var process = new Process("sysctl -a | grep brand_string"); // Somehow this isn't able to use the args but it still works if (process.exitCode() != 0) diff --git a/source/engine/mobile/backend/MobileData.hx b/source/engine/mobile/backend/MobileData.hx index 5e091076..fc33a1ba 100644 --- a/source/engine/mobile/backend/MobileData.hx +++ b/source/engine/mobile/backend/MobileData.hx @@ -10,6 +10,7 @@ import flixel.util.FlxSave; * ... * @author: Karim Akra */ +@:nullSafety class MobileData { public static var actionModes:Map = new Map(); @@ -18,7 +19,7 @@ class MobileData public static var mode(get, set):Int; public static var forcedMode:Null; - public static var save:FlxSave; + public static var save:Null; public static function init() { @@ -41,18 +42,23 @@ class MobileData public static function setTouchPadCustom(touchPad:TouchPad):Void { + if (save == null || save.data == null) + return; + if (save.data.buttons == null) { save.data.buttons = new Array(); - for (buttons in touchPad) - save.data.buttons.push(FlxPoint.get(buttons.x, buttons.y)); + for (button in touchPad) + if (button != null) + save.data.buttons.push(FlxPoint.get(button.x, button.y)); } else { var tempCount:Int = 0; - for (buttons in touchPad) + for (button in touchPad) { - save.data.buttons[tempCount] = FlxPoint.get(buttons.x, buttons.y); + if (button != null) + save.data.buttons[tempCount] = FlxPoint.get(button.x, button.y); tempCount++; } } @@ -64,15 +70,19 @@ class MobileData { var tempCount:Int = 0; - if (save.data.buttons == null) + if (save == null || save.data == null || save.data.buttons == null) return touchPad; - for (buttons in touchPad) + for (button in touchPad) { - if (save.data.buttons[tempCount] != null) + if (button != null) { - buttons.x = save.data.buttons[tempCount].x; - buttons.y = save.data.buttons[tempCount].y; + final btnData = save.data.buttons[tempCount]; + if (btnData != null) + { + button.x = btnData.x; + button.y = btnData.y; + } } tempCount++; } @@ -107,18 +117,24 @@ class MobileData if (Path.extension(file) == 'json') { file = Path.join([folder, Path.withoutDirectory(file)]); - var str = File.getContent(file); - var json:TouchButtonsData = cast Json.parse(str, file); - var mapKey:String = Path.withoutDirectory(Path.withoutExtension(file)); - map.set(mapKey, json); + final str = File.getContent(file); + if (str != null) + { + var json:TouchButtonsData = cast Json.parse(str); + var mapKey:String = Path.withoutDirectory(Path.withoutExtension(file)); + map.set(mapKey, json); + } } } } - static function set_mode(mode:Int = 3) + static function set_mode(mode:Int = 3):Int { - save.data.mobileControlsMode = mode; - save.flush(); + if (save != null) + { + save.data.mobileControlsMode = mode; + save.flush(); + } return mode; } @@ -127,13 +143,16 @@ class MobileData if (forcedMode != null) return forcedMode; - if (save.data.mobileControlsMode == null) + if (save != null) { - save.data.mobileControlsMode = 3; - save.flush(); + if (save.data.mobileControlsMode == null) + { + save.data.mobileControlsMode = 3; + save.flush(); + } + return save.data.mobileControlsMode; } - - return save.data.mobileControlsMode; + return 3; } } diff --git a/source/engine/mobile/backend/StorageUtil.hx b/source/engine/mobile/backend/StorageUtil.hx index 239f6b90..324eddb4 100644 --- a/source/engine/mobile/backend/StorageUtil.hx +++ b/source/engine/mobile/backend/StorageUtil.hx @@ -4,6 +4,7 @@ package mobile.backend; * A storage class for mobile. * @author Karim Akra and Homura Akemi (HomuHomu833) */ +@:nullSafety class StorageUtil { #if sys diff --git a/source/engine/mobile/backend/TouchUtil.hx b/source/engine/mobile/backend/TouchUtil.hx index 006ba6fb..795a138f 100644 --- a/source/engine/mobile/backend/TouchUtil.hx +++ b/source/engine/mobile/backend/TouchUtil.hx @@ -7,13 +7,14 @@ import flixel.input.touch.FlxTouch; * ... * @author: Karim Akra */ +@:nullSafety class TouchUtil { public static var pressed(get, never):Bool; public static var justPressed(get, never):Bool; public static var justReleased(get, never):Bool; public static var released(get, never):Bool; - public static var touch(get, never):FlxTouch; + public static var touch(get, never):Null; public static function overlaps(object:FlxObject, ?camera:FlxCamera):Bool { @@ -81,7 +82,7 @@ class TouchUtil } @:noCompletion - private static function get_touch():FlxTouch + private static function get_touch():Null { for (touch in FlxG.touches.list) if (touch != null) diff --git a/source/engine/mobile/input/MobileInputID.hx b/source/engine/mobile/input/MobileInputID.hx index fe432f24..6ed28ebf 100644 --- a/source/engine/mobile/input/MobileInputID.hx +++ b/source/engine/mobile/input/MobileInputID.hx @@ -9,6 +9,7 @@ import flixel.system.macros.FlxMacroUtil; * @author Karim Akra */ @:runtimeValue +@:nullSafety enum abstract MobileInputID(Int) from Int to Int { public static var fromStringMap(default, null):Map = FlxMacroUtil.buildMap("mobile.input.MobileInputID"); @@ -67,16 +68,18 @@ enum abstract MobileInputID(Int) from Int to Int var EXTRA_2 = 43; @:from - public static inline function fromString(s:String) + public static inline function fromString(s:String):MobileInputID { s = s.toUpperCase(); - return fromStringMap.exists(s) ? fromStringMap.get(s) : NONE; + final result = fromStringMap.get(s); + return result != null ? result : NONE; } @:to public inline function toString():String { - return toStringMap.get(this); + final result = toStringMap.get(this); + return result != null ? result : ''; } } -#end \ No newline at end of file +#end diff --git a/source/engine/mobile/input/MobileInputManager.hx b/source/engine/mobile/input/MobileInputManager.hx index aea65bdf..e0129083 100644 --- a/source/engine/mobile/input/MobileInputManager.hx +++ b/source/engine/mobile/input/MobileInputManager.hx @@ -8,6 +8,7 @@ import haxe.ds.Map; * A TouchButton group with functions for input handling * @author Karim Akra */ +@:nullSafety class MobileInputManager extends FlxTypedSpriteGroup { /** diff --git a/source/engine/mobile/objects/Hitbox.hx b/source/engine/mobile/objects/Hitbox.hx index f7ebd6d4..fcd1e150 100644 --- a/source/engine/mobile/objects/Hitbox.hx +++ b/source/engine/mobile/objects/Hitbox.hx @@ -13,6 +13,7 @@ import openfl.geom.Matrix; * * @author: Karim Akra and Homura Akemi (HomuHomu833) */ +@:nullSafety class Hitbox extends MobileInputManager implements IMobileControls { final offsetFir:Int = (ClientPrefs.data.hitboxPos ? Std.int(FlxG.height / 4) * 3 : 0); @@ -25,7 +26,7 @@ class Hitbox extends MobileInputManager implements IMobileControls public var buttonExtra:TouchButton = new TouchButton(0, 0, [MobileInputID.EXTRA_1]); public var buttonExtra2:TouchButton = new TouchButton(0, 0, [MobileInputID.EXTRA_2]); - public var instance:MobileInputManager; + public var instance:Null; public var onButtonDown:FlxTypedSignalVoid> = new FlxTypedSignalVoid>(); public var onButtonUp:FlxTypedSignalVoid> = new FlxTypedSignalVoid>(); @@ -34,6 +35,7 @@ class Hitbox extends MobileInputManager implements IMobileControls /** * Create the zone. */ + @:nullSafety(Off) public function new(?extraMode:ExtraActions = NONE) { super(); @@ -99,6 +101,7 @@ class Hitbox extends MobileInputManager implements IMobileControls } } + @:nullSafety(Off) private function createHint(X:Float, Y:Float, Width:Int, Height:Int, Color:Int = 0xFFFFFF):TouchButton { var hint = new TouchButton(X, Y); diff --git a/source/engine/mobile/objects/IMobileControls.hx b/source/engine/mobile/objects/IMobileControls.hx index b002b253..0e11e9ac 100644 --- a/source/engine/mobile/objects/IMobileControls.hx +++ b/source/engine/mobile/objects/IMobileControls.hx @@ -7,6 +7,7 @@ import flixel.util.FlxSignal.FlxTypedSignal; * ... * @author: Karim Akra */ +@:nullSafety interface IMobileControls { public var buttonLeft:TouchButton; diff --git a/source/engine/mobile/objects/MobileControls.hx b/source/engine/mobile/objects/MobileControls.hx index 64056042..e0a7e4cf 100644 --- a/source/engine/mobile/objects/MobileControls.hx +++ b/source/engine/mobile/objects/MobileControls.hx @@ -7,12 +7,13 @@ package mobile.objects; * ... * @author: Karim Akra */ +@:nullSafety class MobileControls extends FlxTypedSpriteGroup { - public var touchPad:TouchPad = new TouchPad('NONE', 'NONE', NONE); - public var hitbox:Hitbox = new Hitbox(NONE); + public var touchPad:Null = new TouchPad('NONE', 'NONE', NONE); + public var hitbox:Null = new Hitbox(NONE); - public function new(?forceType:Int, ?extra:Bool = true) + public function new(?forceType:Null, ?extra:Bool = true) { super(); MobileData.forcedMode = forceType; @@ -30,7 +31,7 @@ class MobileControls extends FlxTypedSpriteGroup alpha = ClientPrefs.data.controlsAlpha; } - private function initControler(controlMode:Int = 0, ?extra:Bool = true):Void + private function initControler(controlMode:Int = 0, extra:Bool = true):Void { var extraAction = MobileData.extraActions.get(ClientPrefs.data.extraButtons); if (!extra) diff --git a/source/engine/mobile/objects/TouchButton.hx b/source/engine/mobile/objects/TouchButton.hx index 6f3b84ed..435df877 100644 --- a/source/engine/mobile/objects/TouchButton.hx +++ b/source/engine/mobile/objects/TouchButton.hx @@ -13,6 +13,7 @@ import flixel.input.mouse.FlxMouseButton; * A simple button class that calls a function when clicked by the touch. * @author: Karim Akra and Homura Akemi (HomuHomu833) */ +@:nullSafety class TouchButton extends TypedTouchButton { /** @@ -33,7 +34,7 @@ class TouchButton extends TypedTouchButton /** * A simple tag that returns the button's graphic name in upper case. **/ - public var tag:String; + public var tag:String = ''; /** * The `MobileInputID` that are assigned to this button. @@ -77,6 +78,7 @@ class TouchButton extends TypedTouchButton #if !display @:generic #end +@:nullSafety(Off) class TypedTouchButton extends FlxSprite implements IFlxInput { /** @@ -577,6 +579,7 @@ class TypedTouchButton extends FlxSprite implements IFlxInput /** * Helper function for `TouchButton` which handles its events. */ +@:nullSafety(Off) private class TouchButtonEvent implements IFlxDestroyable { /** @@ -631,6 +634,7 @@ private class TouchButtonEvent implements IFlxDestroyable } } +@:nullSafety(Off) class ButtonBrightnessShader extends FlxShader { public var color(default, set):Null = FlxColor.WHITE; @@ -667,6 +671,7 @@ class ButtonBrightnessShader extends FlxShader } } +@:nullSafety enum StatusIndicators { // isn't very good looking diff --git a/source/engine/mobile/objects/TouchPad.hx b/source/engine/mobile/objects/TouchPad.hx index 44598a50..e3a4a218 100644 --- a/source/engine/mobile/objects/TouchPad.hx +++ b/source/engine/mobile/objects/TouchPad.hx @@ -8,6 +8,7 @@ import flixel.util.FlxSignal.FlxTypedSignal; * @author: Karim Akra and Homura Akemi (HomuHomu833) */ @:access(mobile.objects.TouchButton) +@:nullSafety class TouchPad extends MobileInputManager implements IMobileControls { public var buttonLeft:TouchButton = new TouchButton(0, 0, [MobileInputID.LEFT, MobileInputID.NOTE_LEFT]); @@ -47,7 +48,7 @@ class TouchPad extends MobileInputManager implements IMobileControls public var buttonExtra:TouchButton = new TouchButton(0, 0, [MobileInputID.EXTRA_1]); public var buttonExtra2:TouchButton = new TouchButton(0, 0, [MobileInputID.EXTRA_2]); - public var instance:MobileInputManager; + public var instance:Null; public var onButtonDown:FlxTypedSignalVoid> = new FlxTypedSignalVoid>(); public var onButtonUp:FlxTypedSignalVoid> = new FlxTypedSignalVoid>(); @@ -57,6 +58,7 @@ class TouchPad extends MobileInputManager implements IMobileControls * @param DPadMode The D-Pad mode. `LEFT_FULL` for example. * @param ActionMode The action buttons mode. `A_B_C` for example. */ + @:nullSafety(Off) public function new(DPad:String, Action:String, ?Extra:ExtraActions = NONE) { super(); @@ -122,6 +124,7 @@ class TouchPad extends MobileInputManager implements IMobileControls } } + @:nullSafety(Off) public function setExtrasDefaultPos() { var int:Int = 0; @@ -141,6 +144,7 @@ class TouchPad extends MobileInputManager implements IMobileControls MobileData.save.flush(); } + @:nullSafety(Off) public function setExtrasPos() { var int:Int = 0; @@ -162,7 +166,8 @@ class TouchPad extends MobileInputManager implements IMobileControls } } - private function createButton(X:Float, Y:Float, Graphic:String, ?Color:FlxColor = 0xFFFFFF, ?IDs:Array):TouchButton + @:nullSafety(Off) + private function createButton(X:Float, Y:Float, Graphic:String, ?Color:FlxColor, ?IDs:Array):TouchButton { var button = new TouchButton(X, Y, IDs); button.label = new FlxSprite(); diff --git a/source/engine/mobile/options/MobileOptionsSubState.hx b/source/engine/mobile/options/MobileOptionsSubState.hx index aaeaab10..e0064e17 100644 --- a/source/engine/mobile/options/MobileOptionsSubState.hx +++ b/source/engine/mobile/options/MobileOptionsSubState.hx @@ -4,13 +4,14 @@ import flixel.input.keyboard.FlxKey; import options.BaseOptionsMenu; import options.Option; +@:nullSafety class MobileOptionsSubState extends BaseOptionsMenu { #if FEATURE_MOBILE_CONTROLS final exControlTypes:Array = ["NONE", "SINGLE", "DOUBLE"]; final hintOptions:Array = ["No Gradient", "No Gradient (Old)", "Gradient", "Hidden"]; #end - var option:Option; + var option:Null