diff --git a/.github/workflows/build-shit.yml b/.github/workflows/build-shit.yml index 49bab1ac1..e217d1f18 100644 --- a/.github/workflows/build-shit.yml +++ b/.github/workflows/build-shit.yml @@ -13,8 +13,9 @@ jobs: apt update apt install -y sudo git curl unzip - name: Fix git config on posix runner + # this can't be {{ github.workspace }} because that's not docker-aware run: | - git config --global --add safe.directory ${{ github.workspace }} + git config --global --add safe.directory $GITHUB_WORKSPACE - name: Get checkout token uses: actions/create-github-app-token@v1 id: app_token @@ -90,8 +91,9 @@ jobs: runs-on: [self-hosted, macos] steps: - name: Fix git config on posix runner + # this can't be {{ github.workspace }} because that's not docker-aware run: | - git config --global --add safe.directory ${{ github.workspace }} + git config --global --add safe.directory $GITHUB_WORKSPACE - name: Get checkout token uses: actions/create-github-app-token@v1 id: app_token diff --git a/source/funkin/Conductor.hx b/source/funkin/Conductor.hx index 01147ce31..7ac6382f2 100644 --- a/source/funkin/Conductor.hx +++ b/source/funkin/Conductor.hx @@ -35,7 +35,15 @@ class Conductor * You can also do stuff like store a reference to the Conductor and pass it around or temporarily replace it, * or have a second Conductor running at the same time, or other weird stuff like that if you need to. */ - public static var instance:Conductor = new Conductor(); + public static var instance(get, never):Conductor; + + static var _instance:Null<Conductor> = null; + + static function get_instance():Conductor + { + if (_instance == null) _instance = new Conductor(); + return _instance; + } /** * Signal fired when the current Conductor instance advances to a new measure. @@ -523,6 +531,6 @@ class Conductor */ public static function reset():Void { - Conductor.instance = new Conductor(); + _instance = new Conductor(); } } diff --git a/source/funkin/data/BaseRegistry.hx b/source/funkin/data/BaseRegistry.hx index ad028fa94..7419d9425 100644 --- a/source/funkin/data/BaseRegistry.hx +++ b/source/funkin/data/BaseRegistry.hx @@ -55,6 +55,13 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo this.entries = new Map<String, T>(); this.scriptedEntryIds = []; + + // Lazy initialization of singletons should let this get called, + // but we have this check just in case. + if (FlxG.game != null) + { + FlxG.console.registerObject('registry$registryId', this); + } } /** diff --git a/source/funkin/data/dialogue/ConversationRegistry.hx b/source/funkin/data/dialogue/ConversationRegistry.hx index 9186ef786..4a8af2162 100644 --- a/source/funkin/data/dialogue/ConversationRegistry.hx +++ b/source/funkin/data/dialogue/ConversationRegistry.hx @@ -15,7 +15,14 @@ class ConversationRegistry extends BaseRegistry<Conversation, ConversationData> public static final CONVERSATION_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x"; - public static final instance:ConversationRegistry = new ConversationRegistry(); + public static var instance(get, never):ConversationRegistry; + static var _instance:Null<ConversationRegistry> = null; + + static function get_instance():ConversationRegistry + { + if (_instance == null) _instance = new ConversationRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/data/dialogue/DialogueBoxRegistry.hx b/source/funkin/data/dialogue/DialogueBoxRegistry.hx index 87205d96c..d07ea6da2 100644 --- a/source/funkin/data/dialogue/DialogueBoxRegistry.hx +++ b/source/funkin/data/dialogue/DialogueBoxRegistry.hx @@ -15,7 +15,14 @@ class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData> public static final DIALOGUEBOX_DATA_VERSION_RULE:thx.semver.VersionRule = "1.1.x"; - public static final instance:DialogueBoxRegistry = new DialogueBoxRegistry(); + public static var instance(get, never):DialogueBoxRegistry; + static var _instance:Null<DialogueBoxRegistry> = null; + + static function get_instance():DialogueBoxRegistry + { + if (_instance == null) _instance = new DialogueBoxRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/data/dialogue/SpeakerRegistry.hx b/source/funkin/data/dialogue/SpeakerRegistry.hx index 6bd301dd7..c76c6d766 100644 --- a/source/funkin/data/dialogue/SpeakerRegistry.hx +++ b/source/funkin/data/dialogue/SpeakerRegistry.hx @@ -15,7 +15,14 @@ class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData> public static final SPEAKER_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x"; - public static final instance:SpeakerRegistry = new SpeakerRegistry(); + public static var instance(get, never):SpeakerRegistry; + static var _instance:Null<SpeakerRegistry> = null; + + static function get_instance():SpeakerRegistry + { + if (_instance == null) _instance = new SpeakerRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/data/level/LevelRegistry.hx b/source/funkin/data/level/LevelRegistry.hx index 96712cba5..e37e78d8c 100644 --- a/source/funkin/data/level/LevelRegistry.hx +++ b/source/funkin/data/level/LevelRegistry.hx @@ -15,7 +15,14 @@ class LevelRegistry extends BaseRegistry<Level, LevelData> public static final LEVEL_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x"; - public static final instance:LevelRegistry = new LevelRegistry(); + public static var instance(get, never):LevelRegistry; + static var _instance:Null<LevelRegistry> = null; + + static function get_instance():LevelRegistry + { + if (_instance == null) _instance = new LevelRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/data/notestyle/NoteStyleRegistry.hx b/source/funkin/data/notestyle/NoteStyleRegistry.hx index ffb9bf490..5e9fa9a3d 100644 --- a/source/funkin/data/notestyle/NoteStyleRegistry.hx +++ b/source/funkin/data/notestyle/NoteStyleRegistry.hx @@ -15,7 +15,14 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData> public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x"; - public static final instance:NoteStyleRegistry = new NoteStyleRegistry(); + public static var instance(get, never):NoteStyleRegistry; + static var _instance:Null<NoteStyleRegistry> = null; + + static function get_instance():NoteStyleRegistry + { + if (_instance == null) _instance = new NoteStyleRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/data/song/SongRegistry.hx b/source/funkin/data/song/SongRegistry.hx index e7f74569c..d82e184a5 100644 --- a/source/funkin/data/song/SongRegistry.hx +++ b/source/funkin/data/song/SongRegistry.hx @@ -40,10 +40,17 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata> } /** - * TODO: What if there was a Singleton macro which created static functions - * that redirected to the instance? + * TODO: What if there was a Singleton macro which automatically created the property for us? */ - public static final instance:SongRegistry = new SongRegistry(); + public static var instance(get, never):SongRegistry; + + static var _instance:Null<SongRegistry> = null; + + static function get_instance():SongRegistry + { + if (_instance == null) _instance = new SongRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/data/stage/StageRegistry.hx b/source/funkin/data/stage/StageRegistry.hx index b78292e5b..13a5afb8d 100644 --- a/source/funkin/data/stage/StageRegistry.hx +++ b/source/funkin/data/stage/StageRegistry.hx @@ -15,7 +15,14 @@ class StageRegistry extends BaseRegistry<Stage, StageData> public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x"; - public static final instance:StageRegistry = new StageRegistry(); + public static var instance(get, never):StageRegistry; + static var _instance:Null<StageRegistry> = null; + + static function get_instance():StageRegistry + { + if (_instance == null) _instance = new StageRegistry(); + return _instance; + } public function new() { diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 8734d0c1d..a8cb879a3 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1364,7 +1364,10 @@ class PlayState extends MusicBeatSubState } // Only zoom camera if we are zoomed by less than 35%. - if (FlxG.camera.zoom < (1.35 * defaultCameraZoom) && cameraZoomRate > 0 && Conductor.instance.currentBeat % cameraZoomRate == 0) + if (Preferences.zoomCamera + && FlxG.camera.zoom < (1.35 * defaultCameraZoom) + && cameraZoomRate > 0 + && Conductor.instance.currentBeat % cameraZoomRate == 0) { // Zoom camera in (1.5%) currentCameraZoom += cameraZoomIntensity * defaultCameraZoom; @@ -2106,8 +2109,7 @@ class PlayState extends MusicBeatSubState holdNote.handledMiss = true; // We dropped a hold note. - // Mute vocals and play miss animation, but don't penalize. - vocals.opponentVolume = 0; + // Play miss animation, but don't penalize. currentStage.getOpponent().playSingAnimation(holdNote.noteData.getDirection(), true); } } diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx index ff56e0919..3da51185f 100644 --- a/source/funkin/play/cutscene/VideoCutscene.hx +++ b/source/funkin/play/cutscene/VideoCutscene.hx @@ -5,6 +5,7 @@ import flixel.FlxSprite; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.util.FlxColor; +import flixel.util.FlxSignal; import flixel.util.FlxTimer; #if html5 import funkin.graphics.video.FlxVideo; @@ -28,6 +29,31 @@ class VideoCutscene static var vid:FlxVideoSprite; #end + /** + * Called when the video is started. + */ + public static final onVideoStarted:FlxSignal = new FlxSignal(); + + /** + * Called if the video is paused. + */ + public static final onVideoPaused:FlxSignal = new FlxSignal(); + + /** + * Called if the video is resumed. + */ + public static final onVideoResumed:FlxSignal = new FlxSignal(); + + /** + * Called if the video is restarted. onVideoStarted is not called. + */ + public static final onVideoRestarted:FlxSignal = new FlxSignal(); + + /** + * Called when the video is ended or skipped. + */ + public static final onVideoEnded:FlxSignal = new FlxSignal(); + /** * Play a video cutscene. * TODO: Currently this is hardcoded to start the countdown after the video is done. @@ -94,6 +120,8 @@ class VideoCutscene PlayState.instance.add(vid); PlayState.instance.refresh(); + + onVideoStarted.dispatch(); } else { @@ -129,6 +157,8 @@ class VideoCutscene vid.y = 0; // vid.scale.set(0.5, 0.5); }); + + onVideoStarted.dispatch(); } else { @@ -143,6 +173,7 @@ class VideoCutscene if (vid != null) { vid.restartVideo(); + onVideoRestarted.dispatch(); } #end @@ -156,6 +187,8 @@ class VideoCutscene // Resume the video if it was paused. vid.resume(); } + + onVideoRestarted.dispatch(); } #end } @@ -166,6 +199,7 @@ class VideoCutscene if (vid != null) { vid.pauseVideo(); + onVideoPaused.dispatch(); } #end @@ -173,6 +207,45 @@ class VideoCutscene if (vid != null) { vid.pause(); + onVideoPaused.dispatch(); + } + #end + } + + public static function hideVideo():Void + { + #if html5 + if (vid != null) + { + vid.visible = false; + blackScreen.visible = false; + } + #end + + #if hxCodec + if (vid != null) + { + vid.visible = false; + blackScreen.visible = false; + } + #end + } + + public static function showVideo():Void + { + #if html5 + if (vid != null) + { + vid.visible = true; + blackScreen.visible = false; + } + #end + + #if hxCodec + if (vid != null) + { + vid.visible = true; + blackScreen.visible = false; } #end } @@ -183,6 +256,7 @@ class VideoCutscene if (vid != null) { vid.resumeVideo(); + onVideoResumed.dispatch(); } #end @@ -190,6 +264,7 @@ class VideoCutscene if (vid != null) { vid.resume(); + onVideoResumed.dispatch(); } #end } @@ -240,6 +315,7 @@ class VideoCutscene { ease: FlxEase.quadInOut, onComplete: function(twn:FlxTween) { + onVideoEnded.dispatch(); onCutsceneFinish(cutsceneType); } }); diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 567c388c7..0248e09ee 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -139,7 +139,16 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta for (vari in _data.playData.songVariations) { var variMeta:Null<SongMetadata> = fetchVariationMetadata(id, vari); - if (variMeta != null) _metadata.set(variMeta.variation, variMeta); + if (variMeta != null) + { + _metadata.set(variMeta.variation, variMeta); + trace(' Loaded variation: $vari'); + } + else + { + FlxG.log.warn('[SONG] Failed to load variation metadata (${id}:${vari}), is the path correct?'); + trace(' FAILED to load variation: $vari'); + } } } @@ -374,12 +383,17 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta public function getFirstValidVariation(?diffId:String, ?possibleVariations:Array<String>):Null<String> { - if (variations == null) possibleVariations = variations; + if (possibleVariations == null) + { + possibleVariations = variations; + possibleVariations.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_VARIATION_LIST)); + } if (diffId == null) diffId = listDifficulties(null, possibleVariations)[0]; - for (variation in variations) + for (variationId in possibleVariations) { - if (difficulties.exists('$diffId-$variation')) return variation; + var variationSuffix = (variationId != Constants.DEFAULT_VARIATION) ? '-$variationId' : ''; + if (difficulties.exists('$diffId$variationSuffix')) return variationId; } return null; diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 8e82c0fd8..888398f34 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -4948,7 +4948,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState playbarNoteSnap.text = '1/${noteSnapQuant}'; playbarDifficulty.text = '${selectedDifficulty.toTitleCase()}'; - // playbarBPM.text = 'BPM: ${(Conductor.currentTimeChange?.bpm ?? 0.0)}'; + playbarBPM.text = 'BPM: ${(Conductor.instance.bpm ?? 0.0)}'; } function handlePlayhead():Void diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx index 249c7ffae..f7554197f 100644 --- a/source/funkin/ui/freeplay/FreeplayState.hx +++ b/source/funkin/ui/freeplay/FreeplayState.hx @@ -1017,7 +1017,14 @@ class FreeplayState extends MusicBeatSubState // Set the difficulty star count on the right. albumRoll.setDifficultyStars(daSong?.songRating); - albumRoll.albumId = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID; + + // Set the album graphic and play the animation if relevant. + var newAlbumId:String = daSong?.albumId ?? Constants.DEFAULT_ALBUM_ID; + if (albumRoll.albumId != newAlbumId) + { + albumRoll.albumId = newAlbumId; + albumRoll.playIntro(); + } } // Clears the cache of songs, frees up memory, they' ll have to be loaded in later tho function clearDaCache(actualSongTho:String) diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx index 315444fb0..d3aa68c49 100644 --- a/source/funkin/ui/story/StoryMenuState.hx +++ b/source/funkin/ui/story/StoryMenuState.hx @@ -450,7 +450,11 @@ class StoryMenuState extends MusicBeatState */ function changeDifficulty(change:Int = 0):Void { - var difficultyList:Array<String> = currentLevel.getDifficulties(); + // "For now, NO erect in story mode" -Dave + + var difficultyList:Array<String> = Constants.DEFAULT_DIFFICULTY_LIST; + // Use this line to displays all difficulties + // var difficultyList:Array<String> = currentLevel.getDifficulties(); var currentIndex:Int = difficultyList.indexOf(currentDifficultyId); currentIndex += change; diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index c9b99ed46..c7bc03139 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -157,6 +157,11 @@ class Constants */ public static final DEFAULT_VARIATION:String = 'default'; + /** + * Standard variations used by the game. + */ + public static final DEFAULT_VARIATION_LIST:Array<String> = ['default', 'erect', 'pico']; + /** * The default intensity for camera zooms. */