diff --git a/source/funkin/data/BaseRegistry.hx b/source/funkin/data/BaseRegistry.hx index 2df0c18f0..ad028fa94 100644 --- a/source/funkin/data/BaseRegistry.hx +++ b/source/funkin/data/BaseRegistry.hx @@ -1,6 +1,5 @@ package funkin.data; -import openfl.Assets; import funkin.util.assets.DataAssets; import funkin.util.VersionUtil; import haxe.Constraints.Constructible; @@ -19,12 +18,23 @@ typedef EntryConstructorFunction = String->Void; @:generic abstract class BaseRegistry & Constructible), J> { + /** + * The ID of the registry. Used when logging. + */ public final registryId:String; final dataFilePath:String; + /** + * A map of entry IDs to entries. + */ final entries:Map; + /** + * A map of entry IDs to scripted class names. + */ + final scriptedEntryIds:Map; + /** * The version rule to use when loading entries. * If the entry's version does not match this rule, migration is needed. @@ -37,17 +47,18 @@ abstract class BaseRegistry & Constructible(); + this.scriptedEntryIds = []; } /** - * TODO: Create a `loadEntriesAsync()` function. + * TODO: Create a `loadEntriesAsync(onProgress, onComplete)` function. */ public function loadEntries():Void { @@ -66,7 +77,7 @@ abstract class BaseRegistry & Constructible & Constructible & Constructible & Constructible & Constructible { var entryStr:String = loadEntryFile(id).contents; @@ -185,6 +232,8 @@ abstract class BaseRegistry & Constructible; @@ -194,6 +243,7 @@ abstract class BaseRegistry & Constructible; @@ -202,6 +252,9 @@ abstract class BaseRegistry & Constructible { @@ -220,12 +273,17 @@ abstract class BaseRegistry & Constructible & Constructible { log('Successfully created scripted entry (${entryCls} = ${entry.id})'); entries.set(entry.id, entry); + scriptedEntryIds.set(entry.id, entryCls); } else { diff --git a/source/funkin/graphics/FunkinSprite.hx b/source/funkin/graphics/FunkinSprite.hx index f47b4138a..03382f757 100644 --- a/source/funkin/graphics/FunkinSprite.hx +++ b/source/funkin/graphics/FunkinSprite.hx @@ -81,9 +81,10 @@ class FunkinSprite extends FlxSprite */ public function loadTexture(key:String):FunkinSprite { - if (!isTextureCached(key)) FlxG.log.warn('Texture not cached, may experience stuttering! $key'); + var graphicKey:String = Paths.image(key); + if (!isTextureCached(graphicKey)) FlxG.log.warn('Texture not cached, may experience stuttering! $graphicKey'); - loadGraphic(key); + loadGraphic(graphicKey); return this; } @@ -95,7 +96,7 @@ class FunkinSprite extends FlxSprite */ public function loadSparrow(key:String):FunkinSprite { - var graphicKey = Paths.image(key); + var graphicKey:String = Paths.image(key); if (!isTextureCached(graphicKey)) FlxG.log.warn('Texture not cached, may experience stuttering! $graphicKey'); this.frames = Paths.getSparrowAtlas(key); @@ -110,7 +111,7 @@ class FunkinSprite extends FlxSprite */ public function loadPacker(key:String):FunkinSprite { - var graphicKey = Paths.image(key); + var graphicKey:String = Paths.image(key); if (!isTextureCached(graphicKey)) FlxG.log.warn('Texture not cached, may experience stuttering! $graphicKey'); this.frames = Paths.getPackerAtlas(key); diff --git a/source/funkin/play/Countdown.hx b/source/funkin/play/Countdown.hx index 38e8986ef..747565100 100644 --- a/source/funkin/play/Countdown.hx +++ b/source/funkin/play/Countdown.hx @@ -215,7 +215,7 @@ class Countdown if (spritePath == null) return; - var countdownSprite:FunkinSprite = FunkinSprite.create(Paths.image(spritePath)); + var countdownSprite:FunkinSprite = FunkinSprite.create(spritePath); countdownSprite.scrollFactor.set(0, 0); if (isPixelStyle) countdownSprite.setGraphicSize(Std.int(countdownSprite.width * Constants.PIXEL_ART_SCALE)); diff --git a/source/funkin/play/GitarooPause.hx b/source/funkin/play/GitarooPause.hx index 1ed9dcf3b..eae56a9c3 100644 --- a/source/funkin/play/GitarooPause.hx +++ b/source/funkin/play/GitarooPause.hx @@ -28,7 +28,7 @@ class GitarooPause extends MusicBeatState { if (FlxG.sound.music != null) FlxG.sound.music.stop(); - var bg:FunkinSprite = FunkinSprite.create(Paths.image('pauseAlt/pauseBG')); + var bg:FunkinSprite = FunkinSprite.create('pauseAlt/pauseBG'); add(bg); var bf:FunkinSprite = FunkinSprite.createSparrow(0, 30, 'pauseAlt/bfLol'); diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index a6e4b4632..55c54e0fb 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1416,7 +1416,7 @@ class PlayState extends MusicBeatSubState function initHealthBar():Void { var healthBarYPos:Float = Preferences.downscroll ? FlxG.height * 0.1 : FlxG.height * 0.9; - healthBarBG = FunkinSprite.create(0, healthBarYPos, Paths.image('healthBar')); + healthBarBG = FunkinSprite.create(0, healthBarYPos, 'healthBar'); healthBarBG.screenCenter(X); healthBarBG.scrollFactor.set(0, 0); healthBarBG.zIndex = 800; @@ -1453,7 +1453,7 @@ class PlayState extends MusicBeatSubState function initMinimalMode():Void { // Create the green background. - var menuBG = FunkinSprite.create(Paths.image('menuDesat')); + var menuBG = FunkinSprite.create('menuDesat'); menuBG.color = 0xFF4CAF50; menuBG.setGraphicSize(Std.int(menuBG.width * 1.1)); menuBG.updateHitbox(); diff --git a/source/funkin/play/components/PopUpStuff.hx b/source/funkin/play/components/PopUpStuff.hx index 0fe50f513..105fce2b8 100644 --- a/source/funkin/play/components/PopUpStuff.hx +++ b/source/funkin/play/components/PopUpStuff.hx @@ -25,7 +25,7 @@ class PopUpStuff extends FlxTypedGroup if (PlayState.instance.currentStageId.startsWith('school')) ratingPath = "weeb/pixelUI/" + ratingPath + "-pixel"; - var rating:FunkinSprite = FunkinSprite.create(0, 0, Paths.image(ratingPath)); + var rating:FunkinSprite = FunkinSprite.create(0, 0, ratingPath); rating.scrollFactor.set(0.2, 0.2); rating.zIndex = 1000; @@ -76,7 +76,7 @@ class PopUpStuff extends FlxTypedGroup pixelShitPart1 = 'weeb/pixelUI/'; pixelShitPart2 = '-pixel'; } - var comboSpr:FunkinSprite = FunkinSprite.create(Paths.image(pixelShitPart1 + 'combo' + pixelShitPart2)); + var comboSpr:FunkinSprite = FunkinSprite.create(pixelShitPart1 + 'combo' + pixelShitPart2); comboSpr.y = FlxG.camera.height * 0.4 + 80; comboSpr.x = FlxG.width * 0.50; // comboSpr.x -= FlxG.camera.scroll.x * 0.2; @@ -124,7 +124,7 @@ class PopUpStuff extends FlxTypedGroup var daLoop:Int = 1; for (i in seperatedScore) { - var numScore:FunkinSprite = FunkinSprite.create(0, comboSpr.y, Paths.image(pixelShitPart1 + 'num' + Std.int(i) + pixelShitPart2)); + var numScore:FunkinSprite = FunkinSprite.create(0, comboSpr.y, pixelShitPart1 + 'num' + Std.int(i) + pixelShitPart2); if (PlayState.instance.currentStageId.startsWith('school')) { diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 3997692c2..1b7740408 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -1,6 +1,5 @@ package funkin.play.song; -import flixel.sound.FlxSound; import funkin.audio.VoicesGroup; import funkin.audio.FunkinSound; import funkin.data.IRegistryEntry; @@ -13,9 +12,8 @@ import funkin.data.song.SongData.SongOffsets; import funkin.data.song.SongData.SongTimeChange; import funkin.data.song.SongData.SongTimeFormat; import funkin.data.song.SongRegistry; -import funkin.data.song.SongRegistry; +import funkin.modding.IScriptedClass.IPlayStateScriptedClass; import funkin.modding.events.ScriptEvent; -import funkin.modding.IScriptedClass; import funkin.util.SortUtil; import openfl.utils.Assets; @@ -31,14 +29,44 @@ import openfl.utils.Assets; @:nullSafety class Song implements IPlayStateScriptedClass implements IRegistryEntry { - public static final DEFAULT_SONGNAME:String = "Unknown"; - public static final DEFAULT_ARTIST:String = "Unknown"; + /** + * The default value for the song's name + */ + public static final DEFAULT_SONGNAME:String = 'Unknown'; + + /** + * The default value for the song's artist + */ + public static final DEFAULT_ARTIST:String = 'Unknown'; + + /** + * The default value for the song's time format + */ public static final DEFAULT_TIMEFORMAT:SongTimeFormat = SongTimeFormat.MILLISECONDS; + + /** + * The default value for the song's divisions + */ public static final DEFAULT_DIVISIONS:Null = null; + + /** + * The default value for whether the song loops. + */ public static final DEFAULT_LOOPED:Bool = false; - public static final DEFAULT_STAGE:String = "mainStage"; + + /** + * The default value for the song's playable stage. + */ + public static final DEFAULT_STAGE:String = 'mainStage'; + + /** + * The default value for the song's scroll speed. + */ public static final DEFAULT_SCROLLSPEED:Float = 1.0; + /** + * The internal ID of the song. + */ public final id:String; /** @@ -53,6 +81,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry; final difficulties:Map; + /** + * The list of variations a song has. + */ public var variations(get, never):Array; function get_variations():Array @@ -65,6 +96,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry = fetchVariationMetadata(id, vari); if (variMeta != null) _metadata.set(variMeta.variation, variMeta); } } @@ -115,27 +152,62 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry, variations:Array, charts:Map, - validScore:Bool = false):Song + includeScript:Bool = true, validScore:Bool = false):Song { - var result:Song = new Song(songId); + @:privateAccess + var result:Null; + + if (includeScript && SongRegistry.instance.isScriptedEntry(songId)) + { + var songClassName:String = SongRegistry.instance.getScriptedEntryClassName(songId); + + @:privateAccess + result = SongRegistry.instance.createScriptedEntry(songClassName); + } + else + { + @:privateAccess + result = SongRegistry.instance.createEntry(songId); + } + + if (result == null) throw 'ERROR: Could not build Song instance ($songId), is the attached script bad?'; result._metadata.clear(); for (meta in metadata) + { result._metadata.set(meta.variation, meta); + } result.difficulties.clear(); result.populateDifficulties(); for (variation => chartData in charts) + { result.applyChartData(chartData, variation); + } result.validScore = validScore; return result; } + /** + * Retrieve a list of the raw metadata for the song. + * @return The metadata JSON objects for the song's variations. + */ public function getRawMetadata():Array { return _metadata.values(); @@ -192,6 +264,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry = toolbox.findComponent('playtestSongScriptsCheckbox', CheckBox); + + if (checkboxSongScripts == null) + throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find playtestSongScriptsCheckbox component.'; + + state.playtestSongScripts = checkboxSongScripts.selected; + + checkboxSongScripts.onClick = _ -> { + state.playtestSongScripts = checkboxSongScripts.selected; + }; + return toolbox; } diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 45f9a4d27..24008b19d 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -227,7 +227,7 @@ class FreeplayState extends MusicBeatSubState trace(FlxG.camera.initialZoom); trace(FlxCamera.defaultZoom); - var pinkBack:FunkinSprite = FunkinSprite.create(Paths.image('freeplay/pinkBack')); + var pinkBack:FunkinSprite = FunkinSprite.create('freeplay/pinkBack'); pinkBack.color = 0xFFffd4e9; // sets it to pink! pinkBack.x -= pinkBack.width; diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx index 5f755872f..e2f89a8b3 100644 --- a/source/funkin/ui/transition/LoadingState.hx +++ b/source/funkin/ui/transition/LoadingState.hx @@ -48,7 +48,7 @@ class LoadingState extends MusicBeatState var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, 0xFFcaff4d); add(bg); - funkay = FunkinSprite.create(Paths.image('funkay')); + funkay = FunkinSprite.create('funkay'); funkay.setGraphicSize(0, FlxG.height); funkay.updateHitbox(); add(funkay); @@ -389,9 +389,15 @@ class MultiCallback public function getUnfired():ArrayVoid> return unfired.array(); + /** + * Perform an FlxG.switchState with a nice transition + * @param state + * @param transitionTex + * @param time + */ public static function coolSwitchState(state:NextState, transitionTex:String = "shaderTransitionStuff/coolDots", time:Float = 2) { - var screenShit:FunkinSprite = FunkinSprite.create(Paths.image("shaderTransitionStuff/coolDots")); + var screenShit:FunkinSprite = FunkinSprite.create('shaderTransitionStuff/coolDots'); var screenWipeShit:ScreenWipeShader = new ScreenWipeShader(); screenWipeShit.funnyShit.input = screenShit.pixels; diff --git a/source/funkin/ui/transition/StickerSubState.hx b/source/funkin/ui/transition/StickerSubState.hx index 40fce6f7d..981a30e09 100644 --- a/source/funkin/ui/transition/StickerSubState.hx +++ b/source/funkin/ui/transition/StickerSubState.hx @@ -313,7 +313,7 @@ class StickerSprite extends FunkinSprite public function new(x:Float, y:Float, stickerSet:String, stickerName:String):Void { super(x, y); - loadTexture(Paths.image('transitionSwag/' + stickerSet + '/' + stickerName)); + loadTexture('transitionSwag/' + stickerSet + '/' + stickerName); updateHitbox(); scrollFactor.set(); } diff --git a/source/funkin/util/tools/StringTools.hx b/source/funkin/util/tools/StringTools.hx index 0585ffeae..b15808d00 100644 --- a/source/funkin/util/tools/StringTools.hx +++ b/source/funkin/util/tools/StringTools.hx @@ -13,15 +13,15 @@ class StringTools */ public static function toTitleCase(value:String):String { - var words:Array = value.split(" "); - var result:String = ""; + var words:Array = value.split(' '); + var result:String = ''; for (i in 0...words.length) { var word:String = words[i]; result += word.charAt(0).toUpperCase() + word.substr(1).toLowerCase(); if (i < words.length - 1) { - result += " "; + result += ' '; } } return result; @@ -35,7 +35,7 @@ class StringTools */ public static function toLowerKebabCase(value:String):String { - return value.toLowerCase().replace(' ', "-"); + return value.toLowerCase().replace(' ', '-'); } /** @@ -46,13 +46,30 @@ class StringTools */ public static function toUpperKebabCase(value:String):String { - return value.toUpperCase().replace(' ', "-"); + return value.toUpperCase().replace(' ', '-'); + } + + /** + * The regular expression to sanitize strings. + */ + static final SANTIZE_REGEX:EReg = ~/[^-a-zA-Z0-9]/g; + + /** + * Remove all instances of symbols other than alpha-numeric characters (and dashes)from a string. + * @param value The string to sanitize. + * @return The sanitized string. + */ + public static function sanitize(value:String):String + { + return SANTIZE_REGEX.replace(value, ''); } /** * Parses the string data as JSON and returns the resulting object. * This is here so you can use `string.parseJSON()` when `using StringTools`. * + * TODO: Remove this and replace with `json2object` + * @param value The * @return The parsed object. */ public static function parseJSON(value:String):Dynamic