mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-11-25 00:06:40 +00:00
New crash handler + Additional null safety for ChartEditorState (#130)
* A bunch of smaller syntax tweaks. * New crash handler catches and logs critical errors! * Chart editor now has null safety enabled. * Fix -W build issue. * Actually update hmm.json to use the crash handling branch * Fix issues causing crash handler to trigger
This commit is contained in:
parent
74dac9d830
commit
21f44edf1d
28
Project.xml
28
Project.xml
|
@ -20,6 +20,7 @@
|
|||
<!--Mobile-specific-->
|
||||
<window if="mobile" orientation="landscape" fullscreen="true" width="0" height="0" resizable="false" />
|
||||
<!-- _____________________________ Path Settings ____________________________ -->
|
||||
|
||||
<set name="BUILD_DIR" value="export/debug" if="debug" />
|
||||
<set name="BUILD_DIR" value="export/release" unless="debug" />
|
||||
<set name="BUILD_DIR" value="export/32bit" if="32bit" />
|
||||
|
@ -96,8 +97,9 @@
|
|||
<haxelib name="lime" /> <!-- Game engine backend -->
|
||||
<haxelib name="openfl" /> <!-- Game engine backend -->
|
||||
<haxelib name="flixel" /> <!-- Game engine -->
|
||||
|
||||
<haxedev set="webgl" />
|
||||
<!--In case you want to use the addons package-->
|
||||
|
||||
<haxelib name="flixel-addons" /> <!-- Additional utilities for Flixel -->
|
||||
<haxelib name="hscript" /> <!-- Scripting -->
|
||||
<haxelib name="flixel-ui" /> <!-- UI framework (deprecate this? -->
|
||||
|
@ -150,8 +152,11 @@
|
|||
<haxeflag name="--macro" value="include('flixel', true, [ 'flixel.addons.editors.spine.*', 'flixel.addons.nape.*', 'flixel.system.macros.*' ])" />
|
||||
<!-- Necessary to provide stack traces for HScript. -->
|
||||
<haxedef name="hscriptPos" />
|
||||
<haxedef name="safeMode"/>
|
||||
<haxedef name="HXCPP_CHECK_POINTER" />
|
||||
<haxedef name="HXCPP_STACK_LINE" />
|
||||
<haxedef name="HXCPP_STACK_TRACE" />
|
||||
<haxedef name="openfl-enable-handle-error" />
|
||||
<!-- This macro allows addition of new functionality to existing Flixel. -->
|
||||
<haxeflag name="--macro" value="addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')" />
|
||||
<!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
|
||||
|
@ -159,7 +164,6 @@
|
|||
<icon path="art/icon32.png" size="32" />
|
||||
<icon path="art/icon64.png" size="64" />
|
||||
<icon path="art/iconOG.png" />
|
||||
<!-- <haxedef name="SKIP_TO_PLAYSTATE" if="debug" /> -->
|
||||
<haxedef name="CAN_OPEN_LINKS" unless="switch" />
|
||||
<haxedef name="CAN_CHEAT" if="switch debug" />
|
||||
<haxedef name="haxeui_no_mouse_reset" />
|
||||
|
@ -172,7 +176,6 @@
|
|||
<!-- Difficulty, only used for week or song, defaults to 1 -->
|
||||
<!-- <haxedef name="dif" value="2" if="debug"/> -->
|
||||
</section>
|
||||
<!-- <haxedef name="CLEAR_INPUT_SAVE"/> -->
|
||||
<section if="newgrounds">
|
||||
<!-- Enables Ng.core.verbose -->
|
||||
<!-- <haxedef name="NG_VERBOSE" /> -->
|
||||
|
@ -182,18 +185,21 @@
|
|||
<!-- <haxedef name="NG_FORCE_EXPIRED_SESSION" if="debug" /> -->
|
||||
</section>
|
||||
|
||||
<!-- Uncomment this to wipe your input settings. -->
|
||||
<!-- <haxedef name="CLEAR_INPUT_SAVE"/> -->
|
||||
|
||||
<section if="debug" unless="NO_REDIRECT_ASSETS_FOLDER || html5">
|
||||
<!--
|
||||
Use the parent assets folder rather than the exported one
|
||||
No more will we accidentally undo our changes!
|
||||
TODO: Add a thing to disable this on builds meant for itch.io.
|
||||
-->
|
||||
<haxedef name="REDIRECT_ASSETS_FOLDER" />
|
||||
</section>
|
||||
|
||||
<!-- <prebuild haxe="trace('prebuilding');"/> -->
|
||||
<!-- <postbuild haxe="art/Postbuild.hx"/> -->
|
||||
<!-- <config:ios allow-provisioning-updates="true" team-id="" /> -->
|
||||
<!-- Run a script before and after building. -->
|
||||
<postbuild haxe="source/Prebuild.hx"/> -->
|
||||
<postbuild haxe="source/Postbuild.hx"/> -->
|
||||
|
||||
<!-- Options for Polymod -->
|
||||
<section if="polymod">
|
||||
<!-- Turns on additional debug logging. -->
|
||||
|
@ -213,12 +219,4 @@
|
|||
<!-- Determines the file in the mod folder used for the icon. -->
|
||||
<haxedef name="POLYMOD_MOD_ICON_FILE" value="_polymod_icon.png" />
|
||||
</section>
|
||||
<section if="TOOLS">
|
||||
<!-- Compiles tool for old song conversion shit -->
|
||||
<!-- Assumes you use it on windows/desktop!!!! -->
|
||||
<postbuild command="haxe -main art/SongConverter.hx --cs export/songShit" />
|
||||
<assets path="export/songShit/bin/SongConverter.exe" rename="SongConverter.exe" />
|
||||
<!-- <postbuild command='ren export/songShit/bin export/songShit/tools '/> -->
|
||||
<!-- <postbuild command='move export/songShit/tools export/release/windows/bin'/> -->
|
||||
</section>
|
||||
</project>
|
||||
|
|
4
hmm.json
4
hmm.json
|
@ -47,7 +47,7 @@
|
|||
"name": "haxeui-core",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "3590c94858fc6dbcf9b4d522cd644ad571269677",
|
||||
"ref": "f5daafe93bdfa957538f199294a54e0476c805b7",
|
||||
"url": "https://github.com/haxeui/haxeui-core/"
|
||||
},
|
||||
{
|
||||
|
@ -128,7 +128,7 @@
|
|||
"name": "openfl",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "d33d489a137ff8fdece4994cf1302f0b6334ed08",
|
||||
"ref": "1591a6c5f1f72e65d711f7e17e8055df41424d94",
|
||||
"url": "https://github.com/EliteMasterEric/openfl"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -2,12 +2,13 @@ package;
|
|||
|
||||
import flixel.FlxGame;
|
||||
import flixel.FlxState;
|
||||
import funkin.util.logging.CrashHandler;
|
||||
import funkin.MemoryCounter;
|
||||
import haxe.ui.Toolkit;
|
||||
import openfl.Lib;
|
||||
import openfl.display.FPS;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.events.Event;
|
||||
import openfl.Lib;
|
||||
import openfl.media.Video;
|
||||
import openfl.net.NetStream;
|
||||
|
||||
|
@ -77,10 +78,18 @@ class Main extends Sprite
|
|||
* -Eric
|
||||
*/
|
||||
|
||||
CrashHandler.initialize();
|
||||
|
||||
CrashHandler.queryStatus();
|
||||
|
||||
initHaxeUI();
|
||||
|
||||
addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen));
|
||||
|
||||
#if hxcpp_debug_server
|
||||
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
|
||||
#end
|
||||
|
||||
#if debug
|
||||
fpsCounter = new FPS(10, 3, 0xFFFFFF);
|
||||
addChild(fpsCounter);
|
||||
|
|
11
source/Postbuild.hx
Normal file
11
source/Postbuild.hx
Normal file
|
@ -0,0 +1,11 @@
|
|||
package source; // Yeah, I know...
|
||||
|
||||
class Postbuild
|
||||
{
|
||||
static function main()
|
||||
{
|
||||
trace('Postbuild');
|
||||
|
||||
// TODO: Maybe put a 'Build took X seconds' message here?
|
||||
}
|
||||
}
|
9
source/Prebuild.hx
Normal file
9
source/Prebuild.hx
Normal file
|
@ -0,0 +1,9 @@
|
|||
package source; // Yeah, I know...
|
||||
|
||||
class Prebuild
|
||||
{
|
||||
static function main()
|
||||
{
|
||||
trace('Prebuild');
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ class Alphabet extends FlxSpriteGroup
|
|||
|
||||
var isBold:Bool = false;
|
||||
|
||||
public function new(x:Float = 0.0, y:Float = 0.0, text:String = "", ?bold:Bool = false, typed:Bool = false)
|
||||
public function new(x:Float = 0.0, y:Float = 0.0, text:String = "", bold:Bool = false, typed:Bool = false)
|
||||
{
|
||||
super(x, y);
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import flixel.tweens.FlxEase;
|
|||
import flixel.tweens.FlxTween;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.shaderslmfao.ScreenWipeShader;
|
||||
import haxe.Json;
|
||||
import haxe.format.JsonParser;
|
||||
import lime.math.Rectangle;
|
||||
import lime.utils.Assets;
|
||||
|
@ -120,31 +119,6 @@ class CoolUtil
|
|||
FlxG.camera.setFilters([new ShaderFilter(screenWipeShit)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Just saves the json with some default values hehe
|
||||
* @param json
|
||||
* @return String
|
||||
*/
|
||||
public static inline function jsonStringify(data:Dynamic):String
|
||||
{
|
||||
return Json.stringify(data, null, "\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashlink json encoding fix for some wacky bullshit
|
||||
* https://github.com/HaxeFoundation/haxe/issues/6930#issuecomment-384570392
|
||||
*/
|
||||
public static function coolJSON(fileData:String)
|
||||
{
|
||||
var cont = fileData;
|
||||
function is(n:Int, what:Int)
|
||||
return cont.charCodeAt(n) == what;
|
||||
return JsonParser.parse(cont.substr(if (is(0, 65279)) /// looks like a HL target, skipping only first character here:
|
||||
1 else if (is(0, 239) && is(1, 187) && is(2, 191)) /// it seems to be Neko or PHP, start from position 3:
|
||||
3 else /// all other targets, that prepare the UTF string correctly
|
||||
0));
|
||||
}
|
||||
|
||||
/*
|
||||
* frame dependant lerp kinda lol
|
||||
*/
|
||||
|
|
|
@ -64,7 +64,7 @@ class DiscordClient
|
|||
trace("Discord Client initialized");
|
||||
}
|
||||
|
||||
public static function changePresence(details:String, state:Null<String>, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
|
||||
public static function changePresence(details:String, ?state:String, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
|
||||
{
|
||||
var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
|
||||
|
||||
|
|
|
@ -464,7 +464,7 @@ class FreeplayState extends MusicBeatSubState
|
|||
});
|
||||
}
|
||||
|
||||
public function generateSongList(?filterStuff:SongFilter, ?force:Bool = false)
|
||||
public function generateSongList(?filterStuff:SongFilter, force:Bool = false)
|
||||
{
|
||||
curSelected = 0;
|
||||
|
||||
|
@ -1045,7 +1045,7 @@ class FreeplaySongData
|
|||
public var songCharacter:String = "";
|
||||
public var isFav:Bool = false;
|
||||
|
||||
public function new(song:String, levelId:String, songCharacter:String, ?isFav:Bool = false)
|
||||
public function new(song:String, levelId:String, songCharacter:String, isFav:Bool = false)
|
||||
{
|
||||
this.songName = song;
|
||||
this.levelId = levelId;
|
||||
|
|
|
@ -41,7 +41,7 @@ class PauseSubState extends MusicBeatSubState
|
|||
|
||||
var isChartingMode:Bool;
|
||||
|
||||
public function new(?isChartingMode:Bool = false)
|
||||
public function new(isChartingMode:Bool = false)
|
||||
{
|
||||
super();
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class FlxAtlasSprite extends FlxAnimate
|
|||
* @param restart Whether to restart the animation if it is already playing.
|
||||
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
|
||||
*/
|
||||
public function playAnimation(id:String, ?restart:Bool = false, ?ignoreOther:Bool = false):Void
|
||||
public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false):Void
|
||||
{
|
||||
// Skip if not allowed to play animations.
|
||||
if ((!canPlayOtherAnims && !ignoreOther)) return;
|
||||
|
|
|
@ -255,7 +255,7 @@ class GameOverSubState extends MusicBeatSubState
|
|||
* Starts the death music at the appropriate volume.
|
||||
* @param startingVolume
|
||||
*/
|
||||
function startDeathMusic(?startingVolume:Float = 1, ?force:Bool = false):Void
|
||||
function startDeathMusic(?startingVolume:Float = 1, force:Bool = false):Void
|
||||
{
|
||||
var musicPath = Paths.music('gameOver' + musicSuffix);
|
||||
if (isEnding)
|
||||
|
|
|
@ -81,7 +81,7 @@ class AnimateAtlasCharacter extends BaseCharacter
|
|||
super.onCreate(event);
|
||||
}
|
||||
|
||||
public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reverse:Bool = false):Void
|
||||
public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reverse:Bool = false):Void
|
||||
{
|
||||
if ((!canPlayOtherAnims && !ignoreOther)) return;
|
||||
|
||||
|
|
|
@ -570,7 +570,7 @@ class BaseCharacter extends Bopper
|
|||
* @param miss If true, play the miss animation instead of the sing animation.
|
||||
* @param suffix A suffix to append to the animation name, like `alt`.
|
||||
*/
|
||||
public function playSingAnimation(dir:NoteDirection, ?miss:Bool = false, ?suffix:String = ''):Void
|
||||
public function playSingAnimation(dir:NoteDirection, miss:Bool = false, ?suffix:String = ''):Void
|
||||
{
|
||||
var anim:String = 'sing${dir.nameUpper}${miss ? 'miss' : ''}${suffix != '' ? '-${suffix}' : ''}';
|
||||
|
||||
|
@ -578,7 +578,7 @@ class BaseCharacter extends Bopper
|
|||
playAnimation(anim, true);
|
||||
}
|
||||
|
||||
public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reversed:Bool = false):Void
|
||||
public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reversed:Bool = false):Void
|
||||
{
|
||||
FlxG.watch.addQuick('playAnim(${characterName})', name);
|
||||
// trace('playAnim(${characterName}): ${name}');
|
||||
|
|
|
@ -190,7 +190,7 @@ class CharacterDataParser
|
|||
* @param charId The character ID to fetch.
|
||||
* @return The character instance, or null if the character was not found.
|
||||
*/
|
||||
public static function fetchCharacter(charId:String, ?debug:Bool = false):Null<BaseCharacter>
|
||||
public static function fetchCharacter(charId:String, debug:Bool = false):Null<BaseCharacter>
|
||||
{
|
||||
if (charId == null || charId == '' || !characterCache.exists(charId))
|
||||
{
|
||||
|
|
|
@ -181,7 +181,7 @@ class MultiSparrowCharacter extends BaseCharacter
|
|||
trace('[MULTISPARROWCHAR] Successfully loaded ${animNames.length} animations for ${characterId}');
|
||||
}
|
||||
|
||||
public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reverse:Bool = false):Void
|
||||
public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reverse:Bool = false):Void
|
||||
{
|
||||
// Make sure we ignore other animations if we're currently playing a forced one,
|
||||
// unless we're forcing a new animation.
|
||||
|
|
|
@ -208,7 +208,7 @@ class OutroData
|
|||
public var type:OutroType;
|
||||
public var data:Dynamic;
|
||||
|
||||
public function new(typeStr:Null<String>, data:Dynamic)
|
||||
public function new(?typeStr:String, data:Dynamic)
|
||||
{
|
||||
this.type = typeStr ?? OutroType.NONE;
|
||||
this.data = data;
|
||||
|
|
|
@ -172,7 +172,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
|
|||
|
||||
/**
|
||||
* Set the sprite scale to the appropriate value.
|
||||
* @param scale
|
||||
* @param scale
|
||||
*/
|
||||
public function setScale(scale:Null<Float>):Void
|
||||
{
|
||||
|
@ -218,7 +218,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
|
|||
* @param name The name of the current animation.
|
||||
* @param frameNumber The number of the current frame.
|
||||
* @param frameIndex The index of the current frame.
|
||||
*
|
||||
*
|
||||
* For example, if an animation was defined as having the indexes [3, 0, 1, 2],
|
||||
* then the first callback would have frameNumber = 0 and frameIndex = 3.
|
||||
*/
|
||||
|
@ -253,7 +253,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
|
|||
* @param restart Whether to restart the animation if it is already playing.
|
||||
* @param reversed If true, play the animation backwards, from the last frame to the first.
|
||||
*/
|
||||
public function playAnimation(name:String, restart:Bool = false, ?reversed:Bool = false):Void
|
||||
public function playAnimation(name:String, restart:Bool = false, reversed:Bool = false):Void
|
||||
{
|
||||
var correctName:String = correctAnimationName(name);
|
||||
if (correctName == null) return;
|
||||
|
@ -266,7 +266,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass
|
|||
/**
|
||||
* Ensure that a given animation exists before playing it.
|
||||
* Will gracefully check for name, then name with stripped suffixes, then 'idle', then fail to play.
|
||||
* @param name
|
||||
* @param name
|
||||
*/
|
||||
function correctAnimationName(name:String):String
|
||||
{
|
||||
|
|
|
@ -93,7 +93,7 @@ class DialogueBoxTextData
|
|||
public var shadowColor:Null<String>;
|
||||
public var shadowWidth:Null<Int>;
|
||||
|
||||
public function new(offsets:Null<Array<Float>>, width:Null<Int>, size:Null<Int>, color:String, shadowColor:Null<String>, shadowWidth:Null<Int>)
|
||||
public function new(offsets:Null<Array<Float>>, ?width:Int, ?size:Int, color:String, ?shadowColor:String, shadowWidth:Null<Int>)
|
||||
{
|
||||
this.offsets = offsets ?? [0, 0];
|
||||
this.width = width ?? 300;
|
||||
|
|
|
@ -19,8 +19,8 @@ class SpeakerData
|
|||
public var scale:Float;
|
||||
public var animations:Array<AnimationData>;
|
||||
|
||||
public function new(version:String, name:String, assetPath:String, animations:Array<AnimationData>, ?offsets:Array<Float>, ?flipX:Bool = false,
|
||||
?isPixel:Bool = false, ?scale:Float = 1.0)
|
||||
public function new(version:String, name:String, assetPath:String, animations:Array<AnimationData>, ?offsets:Array<Float>, flipX:Bool = false,
|
||||
isPixel:Bool = false, ?scale:Float = 1.0)
|
||||
{
|
||||
this.version = version;
|
||||
this.name = name;
|
||||
|
|
|
@ -271,7 +271,7 @@ class Strumline extends FlxSpriteGroup
|
|||
* @param strumTime
|
||||
* @return Float
|
||||
*/
|
||||
static function calculateNoteYPos(strumTime:Float, ?vwoosh:Bool = true):Float
|
||||
static function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float
|
||||
{
|
||||
// Make the note move faster visually as it moves offscreen.
|
||||
var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0;
|
||||
|
|
|
@ -113,7 +113,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
|||
return noteFrames;
|
||||
}
|
||||
|
||||
function getNoteAssetPath(?raw:Bool = false):String
|
||||
function getNoteAssetPath(raw:Bool = false):String
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
|||
return (result == null) ? fallback.fetchNoteAnimationData(dir) : result;
|
||||
}
|
||||
|
||||
public function getHoldNoteAssetPath(?raw:Bool = false):String
|
||||
public function getHoldNoteAssetPath(raw:Bool = false):String
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
|||
target.antialiasing = !_data.assets.noteStrumline.isPixel;
|
||||
}
|
||||
|
||||
function getStrumlineAssetPath(?raw:Bool = false):String
|
||||
function getStrumlineAssetPath(raw:Bool = false):String
|
||||
{
|
||||
if (raw)
|
||||
{
|
||||
|
|
|
@ -72,7 +72,7 @@ class Song implements IPlayStateScriptedClass
|
|||
|
||||
@:allow(funkin.play.song.Song)
|
||||
public static function buildRaw(songId:String, metadata:Array<SongMetadata>, variations:Array<String>, charts:Map<String, SongChartData>,
|
||||
?validScore:Bool = false):Song
|
||||
validScore:Bool = false):Song
|
||||
{
|
||||
var result:Song = new Song(songId, true);
|
||||
|
||||
|
@ -150,7 +150,7 @@ class Song implements IPlayStateScriptedClass
|
|||
/**
|
||||
* Parse and cache the chart for all difficulties of this song.
|
||||
*/
|
||||
public function cacheCharts(?force:Bool = false):Void
|
||||
public function cacheCharts(force:Bool = false):Void
|
||||
{
|
||||
if (force)
|
||||
{
|
||||
|
|
|
@ -920,7 +920,7 @@ typedef RawSongTimeChange =
|
|||
*/
|
||||
abstract SongTimeChange(RawSongTimeChange) from RawSongTimeChange
|
||||
{
|
||||
public function new(timeStamp:Float, beatTime:Null<Float>, bpm:Float, timeSignatureNum:Int = 4, timeSignatureDen:Int = 4, beatTuplets:Array<Int>)
|
||||
public function new(timeStamp:Float, ?beatTime:Float, bpm:Float, timeSignatureNum:Int = 4, timeSignatureDen:Int = 4, beatTuplets:Array<Int>)
|
||||
{
|
||||
this =
|
||||
{
|
||||
|
|
|
@ -123,7 +123,7 @@ class SongDataUtils
|
|||
/**
|
||||
* Sort an array of notes by strum time.
|
||||
*/
|
||||
public static function sortNotes(notes:Array<SongNoteData>, ?desc:Bool = false):Array<SongNoteData>
|
||||
public static function sortNotes(notes:Array<SongNoteData>, desc:Bool = false):Array<SongNoteData>
|
||||
{
|
||||
// TODO: Modifies the array in place. Is this okay?
|
||||
notes.sort(function(a:SongNoteData, b:SongNoteData):Int {
|
||||
|
@ -135,7 +135,7 @@ class SongDataUtils
|
|||
/**
|
||||
* Sort an array of events by strum time.
|
||||
*/
|
||||
public static function sortEvents(events:Array<SongEventData>, ?desc:Bool = false):Array<SongEventData>
|
||||
public static function sortEvents(events:Array<SongEventData>, desc:Bool = false):Array<SongEventData>
|
||||
{
|
||||
// TODO: Modifies the array in place. Is this okay?
|
||||
events.sort(function(a:SongEventData, b:SongEventData):Int {
|
||||
|
|
|
@ -63,9 +63,15 @@ class SongValidator
|
|||
}
|
||||
|
||||
input.timeChanges = validateTimeChanges(input.timeChanges, songId);
|
||||
if (input.timeChanges == null)
|
||||
{
|
||||
trace('[SONGDATA] Song ${songId} is missing a timeChanges field. ');
|
||||
return null;
|
||||
}
|
||||
|
||||
input.playData = validatePlayData(input.playData, songId);
|
||||
|
||||
input.variation = '';
|
||||
if (input.variation == null) input.variation = '';
|
||||
|
||||
return input;
|
||||
}
|
||||
|
@ -79,6 +85,12 @@ class SongValidator
|
|||
*/
|
||||
public static function validatePlayData(input:SongPlayData, songId:String = 'unknown'):SongPlayData
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
trace('[SONGDATA] Could not parse metadata.playData for song ${songId}');
|
||||
return null;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
@ -91,6 +103,12 @@ class SongValidator
|
|||
*/
|
||||
public static function validateTimeChange(input:SongTimeChange, songId:String = 'unknown'):SongTimeChange
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
trace('[SONGDATA] Could not parse metadata.timeChange for song ${songId}');
|
||||
return null;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
@ -101,8 +119,8 @@ class SongValidator
|
|||
{
|
||||
if (input == null)
|
||||
{
|
||||
trace('[SONGDATA] Song ${songId} is missing a timeChanges field. ');
|
||||
return [];
|
||||
trace('[SONGDATA] Could not parse metadata.timeChange for song ${songId}');
|
||||
return null;
|
||||
}
|
||||
|
||||
input = input.map((timeChange) -> validateTimeChange(timeChange, songId));
|
||||
|
|
|
@ -268,7 +268,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
|
||||
* @param reversed If true, play the animation backwards, from the last frame to the first.
|
||||
*/
|
||||
public function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reversed:Bool = false):Void
|
||||
public function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reversed:Bool = false):Void
|
||||
{
|
||||
if (!canPlayOtherAnims && !ignoreOther) return;
|
||||
|
||||
|
|
|
@ -450,7 +450,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
* @param pop If true, the character will be removed from the stage as well.
|
||||
* @return The Boyfriend character.
|
||||
*/
|
||||
public function getBoyfriend(?pop:Bool = false):BaseCharacter
|
||||
public function getBoyfriend(pop:Bool = false):BaseCharacter
|
||||
{
|
||||
if (pop)
|
||||
{
|
||||
|
@ -473,7 +473,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
* @param pop If true, the character will be removed from the stage as well.
|
||||
* @return The player/Boyfriend character.
|
||||
*/
|
||||
public function getPlayer(?pop:Bool = false):BaseCharacter
|
||||
public function getPlayer(pop:Bool = false):BaseCharacter
|
||||
{
|
||||
return getBoyfriend(pop);
|
||||
}
|
||||
|
@ -483,7 +483,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
* @param pop If true, the character will be removed from the stage as well.
|
||||
* @return The Girlfriend character.
|
||||
*/
|
||||
public function getGirlfriend(?pop:Bool = false):BaseCharacter
|
||||
public function getGirlfriend(pop:Bool = false):BaseCharacter
|
||||
{
|
||||
if (pop)
|
||||
{
|
||||
|
@ -506,7 +506,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
* @param pop If true, the character will be removed from the stage as well.
|
||||
* @return The Dad character.
|
||||
*/
|
||||
public function getDad(?pop:Bool = false):BaseCharacter
|
||||
public function getDad(pop:Bool = false):BaseCharacter
|
||||
{
|
||||
if (pop)
|
||||
{
|
||||
|
@ -529,7 +529,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass
|
|||
* @param pop If true, the character will be removed from the stage as well.
|
||||
* @return The opponent character.
|
||||
*/
|
||||
public function getOpponent(?pop:Bool = false):BaseCharacter
|
||||
public function getOpponent(pop:Bool = false):BaseCharacter
|
||||
{
|
||||
return getDad(pop);
|
||||
}
|
||||
|
|
|
@ -503,7 +503,7 @@ typedef StageDataCharacter =
|
|||
* Again, just like CSS.
|
||||
* @default 0
|
||||
*/
|
||||
zIndex:Null<Int>,
|
||||
?zIndex:Int,
|
||||
|
||||
/**
|
||||
* The position to render the character at.
|
||||
|
|
|
@ -225,7 +225,7 @@ class AddEventsCommand implements ChartEditorCommand
|
|||
var events:Array<SongEventData>;
|
||||
var appendToSelection:Bool;
|
||||
|
||||
public function new(events:Array<SongEventData>, ?appendToSelection:Bool = false)
|
||||
public function new(events:Array<SongEventData>, appendToSelection:Bool = false)
|
||||
{
|
||||
this.events = events;
|
||||
this.appendToSelection = appendToSelection;
|
||||
|
|
|
@ -258,7 +258,7 @@ class ChartEditorDialogHandler
|
|||
* @return The dialog that was opened.
|
||||
*/
|
||||
@:haxe.warning("-WVarInit")
|
||||
public static function openUploadInstDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
||||
public static function openUploadInstDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
||||
{
|
||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_UPLOAD_INST_LAYOUT, true, closable);
|
||||
|
||||
|
@ -578,7 +578,7 @@ class ChartEditorDialogHandler
|
|||
* @param closable Whether the dialog can be closed by the user.
|
||||
* @return The dialog that was opened.
|
||||
*/
|
||||
public static function openUploadVocalsDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
||||
public static function openUploadVocalsDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
||||
{
|
||||
var charIdsForVocals:Array<String> = [];
|
||||
|
||||
|
@ -692,7 +692,7 @@ class ChartEditorDialogHandler
|
|||
* @return The dialog that was opened.
|
||||
*/
|
||||
@:haxe.warning('-WVarInit')
|
||||
public static function openChartDialog(state:ChartEditorState, ?closable:Bool = true):Dialog
|
||||
public static function openChartDialog(state:ChartEditorState, closable:Bool = true):Dialog
|
||||
{
|
||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_OPEN_CHART_LAYOUT, true, closable);
|
||||
|
||||
|
@ -765,6 +765,19 @@ class ChartEditorDialogHandler
|
|||
var songMetadataVariation:SongMetadata = SongMigrator.migrateSongMetadata(songMetadataJson, 'import');
|
||||
songMetadataVariation = SongValidator.validateSongMetadata(songMetadataVariation, 'import');
|
||||
|
||||
if (songMetadataVariation == null)
|
||||
{
|
||||
// Tell the user the load was not successful.
|
||||
NotificationManager.instance.addNotification(
|
||||
{
|
||||
title: 'Failure',
|
||||
body: 'Could not load metadata file (${path.file}.${path.ext})',
|
||||
type: NotificationType.Error,
|
||||
expiryMs: ChartEditorState.NOTIFICATION_DISMISS_TIME
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
songMetadata.set(variation, songMetadataVariation);
|
||||
|
||||
// Tell the user the load was successful.
|
||||
|
@ -879,7 +892,7 @@ class ChartEditorDialogHandler
|
|||
* @param closable
|
||||
* @return Dialog
|
||||
*/
|
||||
public static function openImportChartDialog(state:ChartEditorState, format:String, ?closable:Bool = true):Dialog
|
||||
public static function openImportChartDialog(state:ChartEditorState, format:String, closable:Bool = true):Dialog
|
||||
{
|
||||
var dialog:Dialog = openDialog(state, CHART_EDITOR_DIALOG_IMPORT_CHART_LAYOUT, true, closable);
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@ class ChartEditorEventSprite extends FlxSprite
|
|||
* The note data that this sprite represents.
|
||||
* You can set this to null to kill the sprite and flag it for recycling.
|
||||
*/
|
||||
public var eventData(default, set):SongEventData;
|
||||
public var eventData(default, set):Null<SongEventData> = null;
|
||||
|
||||
/**
|
||||
* The image used for all song events. Cached for performance.
|
||||
*/
|
||||
static var eventSpriteBasic:BitmapData;
|
||||
static var eventSpriteBasic:Null<BitmapData> = null;
|
||||
|
||||
public function new(parent:ChartEditorState)
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ class ChartEditorEventSprite extends FlxSprite
|
|||
* Build a set of animations to allow displaying different types of chart events.
|
||||
* @param force `true` to force rebuilding the frames.
|
||||
*/
|
||||
static function buildFrames(?force:Bool = false):FlxFramesCollection
|
||||
static function buildFrames(force:Bool = false):FlxFramesCollection
|
||||
{
|
||||
static var eventFrames:FlxFramesCollection = null;
|
||||
|
||||
|
@ -112,7 +112,7 @@ class ChartEditorEventSprite extends FlxSprite
|
|||
this.updateHitbox();
|
||||
}
|
||||
|
||||
function set_eventData(value:SongEventData):SongEventData
|
||||
function set_eventData(value:Null<SongEventData>):Null<SongEventData>
|
||||
{
|
||||
this.eventData = value;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class ChartEditorNoteSprite extends FlxSprite
|
|||
* The note data that this sprite represents.
|
||||
* You can set this to null to kill the sprite and flag it for recycling.
|
||||
*/
|
||||
public var noteData(default, set):SongNoteData;
|
||||
public var noteData(default, set):Null<SongNoteData>;
|
||||
|
||||
/**
|
||||
* The name of the note style currently in use.
|
||||
|
@ -70,7 +70,7 @@ class ChartEditorNoteSprite extends FlxSprite
|
|||
this.animation.addByPrefix('tapRightPixel', 'pixel7');
|
||||
}
|
||||
|
||||
static var noteFrameCollection:FlxFramesCollection = null;
|
||||
static var noteFrameCollection:Null<FlxFramesCollection> = null;
|
||||
|
||||
/**
|
||||
* We load all the note frames once, then reuse them.
|
||||
|
@ -108,7 +108,7 @@ class ChartEditorNoteSprite extends FlxSprite
|
|||
}
|
||||
}
|
||||
|
||||
function set_noteData(value:SongNoteData):SongNoteData
|
||||
function set_noteData(value:Null<SongNoteData>):Null<SongNoteData>
|
||||
{
|
||||
this.noteData = value;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -168,9 +168,9 @@ class ChartEditorToolboxHandler
|
|||
case ChartEditorState.CHART_EDITOR_TOOLBOX_CHARACTERS_LAYOUT:
|
||||
toolbox = buildToolboxCharactersLayout(state);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_PLAYER_PREVIEW_LAYOUT:
|
||||
toolbox = null; // buildToolboxPlayerPreviewLayout(state);
|
||||
toolbox = buildToolboxPlayerPreviewLayout(state);
|
||||
case ChartEditorState.CHART_EDITOR_TOOLBOX_OPPONENT_PREVIEW_LAYOUT:
|
||||
toolbox = null; // buildToolboxOpponentPreviewLayout(state);
|
||||
toolbox = buildToolboxOpponentPreviewLayout(state);
|
||||
default:
|
||||
// This happens if you try to load an unknown layout.
|
||||
trace('ChartEditorToolboxHandler.initToolbox() - Unknown toolbox ID: $id');
|
||||
|
@ -200,6 +200,8 @@ class ChartEditorToolboxHandler
|
|||
// Initialize the toolbox without showing it.
|
||||
if (toolbox == null) toolbox = initToolbox(state, id);
|
||||
|
||||
if (toolbox == null) throw 'ChartEditorToolboxHandler.getToolbox() - Could not retrieve or build toolbox: $id';
|
||||
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ class CharacterPlayer extends Box
|
|||
{
|
||||
var character:BaseCharacter;
|
||||
|
||||
public function new(?defaultToBf:Bool = true)
|
||||
public function new(defaultToBf:Bool = true)
|
||||
{
|
||||
super();
|
||||
_overrideSkipTransformChildren = false;
|
||||
|
|
|
@ -21,7 +21,7 @@ class MovePropCommand implements StageEditorCommand
|
|||
var yDiff:Float;
|
||||
var realMove:Bool; // if needs a move!
|
||||
|
||||
public function new(xDiff:Float = 0, yDiff:Float = 0, ?realMove:Bool = true)
|
||||
public function new(xDiff:Float = 0, yDiff:Float = 0, realMove:Bool = true)
|
||||
{
|
||||
this.xDiff = xDiff;
|
||||
this.yDiff = yDiff;
|
||||
|
|
|
@ -3,17 +3,18 @@ package funkin.ui.stageBuildShit;
|
|||
import flixel.FlxSprite;
|
||||
import flixel.input.mouse.FlxMouseEvent;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.character.BaseCharacter;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.stage.StageData;
|
||||
import funkin.play.stage.StageProp;
|
||||
import funkin.shaderslmfao.StrokeShader;
|
||||
import funkin.ui.haxeui.HaxeUISubState;
|
||||
import funkin.ui.stageBuildShit.StageEditorCommand;
|
||||
import haxe.ui.RuntimeComponentBuilder;
|
||||
import funkin.util.SerializerUtil;
|
||||
import haxe.ui.containers.ListView;
|
||||
import haxe.ui.core.Component;
|
||||
import haxe.ui.events.UIEvent;
|
||||
import haxe.ui.RuntimeComponentBuilder;
|
||||
import openfl.events.Event;
|
||||
import openfl.events.IOErrorEvent;
|
||||
import openfl.net.FileReference;
|
||||
|
@ -376,6 +377,6 @@ class StageOffsetSubState extends HaxeUISubState
|
|||
stageLol.characters.gf.position[0] = Std.int(GF_FEET_SNIIIIIIIIIIIIIFFFF.x);
|
||||
stageLol.characters.gf.position[1] = Std.int(GF_FEET_SNIIIIIIIIIIIIIFFFF.y);
|
||||
|
||||
return CoolUtil.jsonStringify(stageLol);
|
||||
return SerializerUtil.toJSON(stageLol);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class ClipboardUtil
|
|||
* @param once If true, the callback will only execute once and then be deleted.
|
||||
* @param priority Set the priority at which the callback will be executed. Higher values execute first.
|
||||
*/
|
||||
public static function addListener(callback:Void->Void, ?once:Bool = false, ?priority:Int = 0):Void
|
||||
public static function addListener(callback:Void->Void, once:Bool = false, ?priority:Int = 0):Void
|
||||
{
|
||||
lime.system.Clipboard.onUpdate.add(callback, once, priority);
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ class FileUtil
|
|||
* @return Whether the file dialog was opened successfully.
|
||||
*/
|
||||
public static function saveMultipleFiles(resources:Array<Entry>, ?onSaveAll:Array<String>->Void, ?onCancel:Void->Void, ?defaultPath:String,
|
||||
?force:Bool = false):Bool
|
||||
force:Bool = false):Bool
|
||||
{
|
||||
#if desktop
|
||||
// Prompt the user for a directory, then write all of the files to there.
|
||||
|
@ -257,7 +257,7 @@ class FileUtil
|
|||
* Takes an array of file entries and prompts the user to save them as a ZIP file.
|
||||
*/
|
||||
public static function saveFilesAsZIP(resources:Array<Entry>, ?onSave:Array<String>->Void, ?onCancel:Void->Void, ?defaultPath:String,
|
||||
?force:Bool = false):Bool
|
||||
force:Bool = false):Bool
|
||||
{
|
||||
// Create a ZIP file.
|
||||
var zipBytes:Bytes = createZIPFromEntries(resources);
|
||||
|
@ -278,7 +278,7 @@ class FileUtil
|
|||
* Use `saveFilesAsZIP` instead.
|
||||
* @param force Whether to force overwrite an existing file.
|
||||
*/
|
||||
public static function saveFilesAsZIPToPath(resources:Array<Entry>, path:String, ?force:Bool = false):Bool
|
||||
public static function saveFilesAsZIPToPath(resources:Array<Entry>, path:String, force:Bool = false):Bool
|
||||
{
|
||||
#if desktop
|
||||
// Create a ZIP file.
|
||||
|
|
|
@ -21,7 +21,7 @@ class SerializerUtil
|
|||
/**
|
||||
* Convert a Haxe object to a JSON string.
|
||||
*/
|
||||
public static function toJSON(input:Dynamic, ?pretty:Bool = true):String
|
||||
public static function toJSON(input:Dynamic, pretty:Bool = true):String
|
||||
{
|
||||
return Json.stringify(input, replacer, pretty ? INDENT_CHAR : null);
|
||||
}
|
||||
|
|
143
source/funkin/util/logging/CrashHandler.hx
Normal file
143
source/funkin/util/logging/CrashHandler.hx
Normal file
|
@ -0,0 +1,143 @@
|
|||
package funkin.util.logging;
|
||||
|
||||
import openfl.Lib;
|
||||
import openfl.events.UncaughtErrorEvent;
|
||||
|
||||
/**
|
||||
* A custom crash handler that writes to a log file and displays a message box.
|
||||
*/
|
||||
@:nullSafety
|
||||
class CrashHandler
|
||||
{
|
||||
static final LOG_FOLDER = 'logs';
|
||||
|
||||
/**
|
||||
* Initializes
|
||||
*/
|
||||
public static function initialize():Void
|
||||
{
|
||||
trace('[LOG] Enabling standard uncaught error handler...');
|
||||
Lib.current.loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError);
|
||||
|
||||
#if cpp
|
||||
trace('[LOG] Enabling C++ critical error handler...');
|
||||
untyped __global__.__hxcpp_set_critical_error_handler(onCriticalError);
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an uncaught error occurs.
|
||||
* This handles most thrown errors, and is sufficient to handle everything alone on HTML5.
|
||||
* @param error Information on the error that was thrown.
|
||||
*/
|
||||
static function onUncaughtError(error:UncaughtErrorEvent):Void
|
||||
{
|
||||
try
|
||||
{
|
||||
#if sys
|
||||
logError(error);
|
||||
#end
|
||||
|
||||
displayError(error);
|
||||
}
|
||||
catch (e:Dynamic)
|
||||
{
|
||||
trace('Error while handling crash: ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
static function onCriticalError(message:String):Void
|
||||
{
|
||||
try
|
||||
{
|
||||
#if sys
|
||||
logErrorMessage(message, true);
|
||||
#end
|
||||
|
||||
displayErrorMessage(message);
|
||||
}
|
||||
catch (e:Dynamic)
|
||||
{
|
||||
trace('Error while handling crash: $e');
|
||||
|
||||
trace('Message: $message');
|
||||
}
|
||||
}
|
||||
|
||||
static function displayError(error:UncaughtErrorEvent):Void
|
||||
{
|
||||
displayErrorMessage(generateErrorMessage(error));
|
||||
}
|
||||
|
||||
static function displayErrorMessage(message:String):Void
|
||||
{
|
||||
lime.app.Application.current.window.alert(message, "Fatal Uncaught Exception");
|
||||
}
|
||||
|
||||
#if sys
|
||||
static function logError(error:UncaughtErrorEvent):Void
|
||||
{
|
||||
logErrorMessage(generateErrorMessage(error));
|
||||
}
|
||||
|
||||
static function logErrorMessage(message:String, critical:Bool = false):Void
|
||||
{
|
||||
FileUtil.createDirIfNotExists(LOG_FOLDER);
|
||||
|
||||
sys.io.File.saveContent('$LOG_FOLDER/crash${critical ? '-critical' : ''}-${DateUtil.generateTimestamp()}.log', message);
|
||||
}
|
||||
#end
|
||||
|
||||
static function generateErrorMessage(error:UncaughtErrorEvent):String
|
||||
{
|
||||
var errorMessage:String = "";
|
||||
var callStack:Array<haxe.CallStack.StackItem> = haxe.CallStack.exceptionStack(true);
|
||||
|
||||
errorMessage += '${error.error}\n';
|
||||
|
||||
for (stackItem in callStack)
|
||||
{
|
||||
switch (stackItem)
|
||||
{
|
||||
case FilePos(innerStackItem, file, line, column):
|
||||
errorMessage += ' in ${file}#${line}';
|
||||
if (column != null) errorMessage += ':${column}';
|
||||
case CFunction:
|
||||
errorMessage += '[Function] ';
|
||||
case Module(m):
|
||||
errorMessage += '[Module(${m})] ';
|
||||
case Method(classname, method):
|
||||
errorMessage += '[Function(${classname}.${method})] ';
|
||||
case LocalFunction(v):
|
||||
errorMessage += '[LocalFunction(${v})] ';
|
||||
}
|
||||
errorMessage += '\n';
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public static function queryStatus():Void
|
||||
{
|
||||
@:privateAccess
|
||||
var currentStatus = Lib.current.stage.__uncaughtErrorEvents.__enabled;
|
||||
trace('ERROR HANDLER STATUS: ' + currentStatus);
|
||||
|
||||
#if openfl_enable_handle_error
|
||||
trace('Define: openfl_enable_handle_error is enabled');
|
||||
#else
|
||||
trace('Define: openfl_enable_handle_error is disabled');
|
||||
#end
|
||||
|
||||
#if openfl_disable_handle_error
|
||||
trace('Define: openfl_disable_handle_error is enabled');
|
||||
#else
|
||||
trace('Define: openfl_disable_handle_error is disabled');
|
||||
#end
|
||||
}
|
||||
|
||||
public static function induceBasicCrash():Void
|
||||
{
|
||||
throw "This is an example of an uncaught exception.";
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ class ClassMacro
|
|||
* @param includeSubPackages Whether to include classes located in sub-packages of the target package.
|
||||
* @return A list of classes matching the specified criteria.
|
||||
*/
|
||||
public static macro function listClassesInPackage(targetPackage:String, ?includeSubPackages:Bool = true):ExprOf<Iterable<Class<Dynamic>>>
|
||||
public static macro function listClassesInPackage(targetPackage:String, includeSubPackages:Bool = true):ExprOf<Iterable<Class<Dynamic>>>
|
||||
{
|
||||
if (!onGenerateCallbackRegistered)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue