public static async void PlaySong(IPreviewBeatmapLevel level, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty, OverrideEnvironmentSettings overrideEnvironmentSettings = null, ColorScheme colorScheme = null, GameplayModifiers gameplayModifiers = null, PlayerSpecificSettings playerSettings = null, Action <StandardLevelScenesTransitionSetupDataSO, LevelCompletionResults> songFinishedCallback = null) { Action <IBeatmapLevel> SongLoaded = (loadedLevel) => { MenuTransitionsHelper _menuSceneSetupData = Resources.FindObjectsOfTypeAll <MenuTransitionsHelper>().First(); _menuSceneSetupData.StartStandardLevel( "Solo", loadedLevel.beatmapLevelData.GetDifficultyBeatmap(characteristic, difficulty), loadedLevel, overrideEnvironmentSettings, colorScheme, gameplayModifiers ?? new GameplayModifiers(), playerSettings ?? new PlayerSpecificSettings(), null, "Menu", false, null, (standardLevelScenesTransitionSetupData, results) => songFinishedCallback?.Invoke(standardLevelScenesTransitionSetupData, results) ); }; if ((level is PreviewBeatmapLevelSO && await HasDLCLevel(level.levelID)) || level is CustomPreviewBeatmapLevel) { Logger.Debug("Loading DLC/Custom level..."); var result = await GetLevelFromPreview(level); if (result != null && !(result?.isError == true)) { //HTTPstatus requires cover texture to be applied in here, and due to a fluke //of beat saber, it's not applied when the level is loaded, but it *is* //applied to the previewlevel it's loaded from var loadedLevel = result?.beatmapLevel; loadedLevel.SetField("_coverImage", level.GetField <Sprite>("_coverImage")); SongLoaded(loadedLevel); } } else if (level is BeatmapLevelSO) { Logger.Debug("Reading OST data without songloader..."); SongLoaded(level as IBeatmapLevel); } else { Logger.Debug($"Skipping unowned DLC ({level.songName})"); } }
//Returns the closest difficulty to the one provided, preferring lower difficulties first if any exist public static IDifficultyBeatmap GetClosestDifficultyPreferLower(IBeatmapLevel level, BeatmapDifficulty difficulty, string characteristic) { //First, look at the characteristic parameter. If there's something useful in there, we try to use it, but fall back to Standard var desiredCharacteristic = level.previewDifficultyBeatmapSets.FirstOrDefault(x => x.beatmapCharacteristic.serializedName == characteristic).beatmapCharacteristic ?? level.previewDifficultyBeatmapSets.First().beatmapCharacteristic; IDifficultyBeatmap[] availableMaps = level .beatmapLevelData .difficultyBeatmapSets .FirstOrDefault(x => x.beatmapCharacteristic.serializedName == desiredCharacteristic.serializedName) .difficultyBeatmaps .OrderBy(x => x.difficulty) .ToArray(); IDifficultyBeatmap ret = availableMaps.FirstOrDefault(x => x.difficulty == difficulty); if (ret is CustomDifficultyBeatmap) { var extras = Collections.RetrieveExtraSongData(ret.level.levelID); var requirements = extras?._difficulties.First(x => x._difficulty == ret.difficulty).additionalDifficultyData._requirements; Logger.Debug($"{ret.level.songName} is a custom level, checking for requirements on {ret.difficulty}..."); if ( (requirements?.Count() > 0) && (!requirements?.ToList().All(x => Collections.capabilities.Contains(x)) ?? false) ) { ret = null; } Logger.Debug((ret == null ? "Requirement not met." : "Requirement met!")); } if (ret == null) { ret = GetLowerDifficulty(availableMaps, difficulty, desiredCharacteristic); } if (ret == null) { ret = GetHigherDifficulty(availableMaps, difficulty, desiredCharacteristic); } return(ret); }
//Returns the next-lowest difficulty to the one provided private static IDifficultyBeatmap GetLowerDifficulty(IDifficultyBeatmap[] availableMaps, BeatmapDifficulty difficulty, BeatmapCharacteristicSO characteristic) { var ret = availableMaps.TakeWhile(x => x.difficulty < difficulty).LastOrDefault(); if (ret is CustomDifficultyBeatmap) { var extras = Collections.RetrieveExtraSongData(ret.level.levelID); var requirements = extras?._difficulties.First(x => x._difficulty == ret.difficulty).additionalDifficultyData._requirements; Logger.Debug($"{ret.level.songName} is a custom level, checking for requirements on {ret.difficulty}..."); if ( (requirements?.Count() > 0) && (!requirements?.ToList().All(x => Collections.capabilities.Contains(x)) ?? false) ) { ret = null; } Logger.Debug((ret == null ? "Requirement not met." : "Requirement met!")); } return(ret); }
protected override void Client_PacketReceived(Packet packet) { base.Client_PacketReceived(packet); if (packet.Type == PacketType.PlaySong) { PlaySong playSong = packet.SpecificPacket as PlaySong; var desiredLevel = SongUtils.masterLevelList.First(x => x.levelID == playSong.GameplayParameters.Beatmap.LevelId); var desiredCharacteristic = desiredLevel.previewDifficultyBeatmapSets.FirstOrDefault(x => x.beatmapCharacteristic.serializedName == playSong.GameplayParameters.Beatmap.Characteristic.SerializedName).beatmapCharacteristic ?? desiredLevel.previewDifficultyBeatmapSets.First().beatmapCharacteristic; var desiredDifficulty = (BeatmapDifficulty)playSong.GameplayParameters.Beatmap.Difficulty; var playerData = Resources.FindObjectsOfTypeAll <PlayerDataModel>().First().playerData; var playerSettings = playerData.playerSpecificSettings; //Override defaults if we have forced options enabled if (playSong.GameplayParameters.PlayerSettings.Options != PlayerOptions.None) { playerSettings = new PlayerSpecificSettings( playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.StaticLights), playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.LeftHanded), playSong.GameplayParameters.PlayerSettings.PlayerHeight, playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AutoPlayerHeight), playSong.GameplayParameters.PlayerSettings.SfxVolume, playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.ReduceDebris), playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.NoHud), playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.NoFailEffects), playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AdvancedHud), playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AutoRestart), playSong.GameplayParameters.PlayerSettings.SaberTrailIntensity, playSong.GameplayParameters.PlayerSettings.NoteJumpStartBeatOffset, playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.HideNoteSpawnEffect), playSong.GameplayParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AdaptiveSfx) ); } var songSpeed = GameplayModifiers.SongSpeed.Normal; if (playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.SlowSong)) { songSpeed = GameplayModifiers.SongSpeed.Slower; } if (playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.FastSong)) { songSpeed = GameplayModifiers.SongSpeed.Faster; } var gameplayModifiers = new GameplayModifiers( playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.DemoNoFail), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.DemoNoObstacles), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.BatteryEnergy) ? GameplayModifiers.EnergyType.Battery : GameplayModifiers.EnergyType.Bar, playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoFail), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.InstaFail), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.FailOnClash), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoObstacles) ? GameplayModifiers.EnabledObstacleType.NoObstacles : GameplayModifiers.EnabledObstacleType.All, playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoBombs), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.FastNotes), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.StrictAngles), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.DisappearingArrows), songSpeed, playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoArrows), playSong.GameplayParameters.GameplayModifiers.Options.HasFlag(GameOptions.GhostNotes) ); var colorScheme = playerData.colorSchemesSettings.overrideDefaultColors ? playerData.colorSchemesSettings.GetSelectedColorScheme() : null; //Disable score submission if nofail is on. This is specifically for Hidden Sabers, though it may stay longer if (playSong.DisableScoresaberSubmission) { BS_Utils.Gameplay.ScoreSubmission.DisableSubmission(SharedConstructs.Name); } if (playSong.ShowNormalNotesOnStream) { var customNotes = IPA.Loader.PluginManager.GetPluginFromId("CustomNotes"); if (customNotes != null) { EnableHMDOnly(); } } PlaySong?.Invoke(desiredLevel, desiredCharacteristic, desiredDifficulty, gameplayModifiers, playerSettings, playerData.overrideEnvironmentSettings, colorScheme, playSong.FloatingScoreboard, playSong.StreamSync, playSong.DisablePause, playSong.DisableFail); } else if (packet.Type == PacketType.Command) { Command command = packet.SpecificPacket as Command; if (command.CommandType == Command.CommandTypes.ReturnToMenu) { if (SyncHandler.Instance != null) { ScreenOverlay.Instance.Clear(); } if ((Self as Player).PlayState == Player.PlayStates.InGame) { PlayerUtils.ReturnToMenu(); } } else if (command.CommandType == Command.CommandTypes.ScreenOverlay_ShowPng) { ScreenOverlay.Instance.ShowPng(); } else if (command.CommandType == Command.CommandTypes.DelayTest_Finish) { UnityMainThreadDispatcher.Instance().Enqueue(() => { ScreenOverlay.Instance.Clear(); SyncHandler.Instance.Resume(); SyncHandler.Destroy(); }); } } else if (packet.Type == PacketType.LoadSong) { LoadSong loadSong = packet.SpecificPacket as LoadSong; Action <IBeatmapLevel> SongLoaded = (loadedLevel) => { //Send updated download status (Self as Player).DownloadState = Player.DownloadStates.Downloaded; var playerUpdate = new Event(); playerUpdate.Type = Event.EventType.PlayerUpdated; playerUpdate.ChangedObject = Self; Send(new Packet(playerUpdate)); //Notify any listeners of the client that a song has been loaded LoadedSong?.Invoke(loadedLevel); }; if (OstHelper.IsOst(loadSong.LevelId)) { SongLoaded?.Invoke(SongUtils.masterLevelList.First(x => x.levelID == loadSong.LevelId) as BeatmapLevelSO); } else { if (SongUtils.masterLevelList.Any(x => x.levelID == loadSong.LevelId)) { SongUtils.LoadSong(loadSong.LevelId, SongLoaded); } else { Action <string, bool> loadSongAction = (hash, succeeded) => { if (succeeded) { SongUtils.LoadSong(loadSong.LevelId, SongLoaded); } else { (Self as Player).DownloadState = Player.DownloadStates.DownloadError; var playerUpdated = new Event(); playerUpdated.Type = Event.EventType.PlayerUpdated; playerUpdated.ChangedObject = Self; Send(new Packet(playerUpdated)); } }; (Self as Player).DownloadState = Player.DownloadStates.Downloading; var playerUpdate = new Event(); playerUpdate.Type = Event.EventType.PlayerUpdated; playerUpdate.ChangedObject = Self; Send(new Packet(playerUpdate)); SongDownloader.DownloadSong(loadSong.LevelId, songDownloaded: loadSongAction, downloadProgressChanged: (hash, progress) => Logger.Debug($"DOWNLOAD PROGRESS ({hash}): {progress}"), customHostUrl: loadSong.CustomHostUrl); } } } else if (packet.Type == PacketType.File) { File file = packet.SpecificPacket as File; if (file.Intent == File.Intentions.SetPngToShowWhenTriggered) { var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data; ScreenOverlay.Instance.SetPngBytes(pngBytes); } else if (file.Intent == File.Intentions.ShowPngImmediately) { var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data; ScreenOverlay.Instance.SetPngBytes(pngBytes); ScreenOverlay.Instance.ShowPng(); } Send(packet.From, new Packet(new Acknowledgement() { PacketId = packet.Id, Type = Acknowledgement.AcknowledgementType.FileDownloaded })); } }
public void SongFinished(StandardLevelScenesTransitionSetupDataSO standardLevelScenesTransitionSetupData, LevelCompletionResults results) { standardLevelScenesTransitionSetupData.didFinishEvent -= SongFinished; var map = (standardLevelScenesTransitionSetupData.sceneSetupDataArray.First(x => x is GameplayCoreSceneSetupData) as GameplayCoreSceneSetupData).difficultyBeatmap; var localPlayer = _playerDataModel.playerData; var localResults = localPlayer.GetPlayerLevelStatsData(map.level.levelID, map.difficulty, map.parentDifficultyBeatmapSet.beatmapCharacteristic); var highScore = localResults.highScore < results.modifiedScore; //Send final score to Host if (Plugin.client.Connected) { Logger.Debug($"SENDING RESULTS: {results.modifiedScore}"); var songFinished = new SongFinished(); if (results.levelEndStateType == LevelCompletionResults.LevelEndStateType.Cleared) { songFinished.Type = TournamentAssistantShared.Models.Packets.SongFinished.CompletionType.Passed; } if (results.levelEndStateType == LevelCompletionResults.LevelEndStateType.Failed) { songFinished.Type = TournamentAssistantShared.Models.Packets.SongFinished.CompletionType.Failed; } if (results.levelEndAction == LevelCompletionResults.LevelEndAction.Quit) { songFinished.Type = TournamentAssistantShared.Models.Packets.SongFinished.CompletionType.Quit; } songFinished.User = Plugin.client.Self as Player; songFinished.Beatmap = new Beatmap(); songFinished.Beatmap.LevelId = map.level.levelID; songFinished.Beatmap.Difficulty = (SharedConstructs.BeatmapDifficulty)map.difficulty; songFinished.Beatmap.Characteristic = new Characteristic(); songFinished.Beatmap.Characteristic.SerializedName = map.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName; songFinished.Beatmap.Characteristic.Difficulties = map.parentDifficultyBeatmapSet.difficultyBeatmaps.Select(x => (SharedConstructs.BeatmapDifficulty)x.difficulty).ToArray(); songFinished.Score = results.modifiedScore; Plugin.client.Send(new Packet(songFinished)); } if (results.levelEndStateType != LevelCompletionResults.LevelEndStateType.None) { _menuLightsManager.SetColorPreset(_scoreLights, true); _resultsViewController.Init(results, map, false, highScore); _resultsViewController.GetField <Button>("_restartButton").gameObject.SetActive(false); _resultsViewController.continueButtonPressedEvent += resultsViewController_continueButtonPressedEvent; PresentViewController(_resultsViewController, null, true); } else if (ShouldDismissOnReturnToMenu) { Dismiss(); } else if (!Plugin.client.State.Matches.Contains(Match)) { if (tournamentMode) { SwitchToWaitingForCoordinatorMode(); } else { Dismiss(); } } }
private static IEnumerator DownloadSong_internal(string hash, bool refreshWhenDownloaded = true, Action <string, bool> songDownloaded = null, Action <string, float> downloadProgressChanged = null, string customHostUrl = null) { var songUrl = $"{beatSaverDownloadUrl}{hash}.zip"; if (!string.IsNullOrEmpty(customHostUrl)) { songUrl = $"{customHostUrl}{hash.ToUpper()}.zip"; } UnityWebRequest www = UnityWebRequest.Get(songUrl); bool timeout = false; float time = 0f; float lastProgress = 0f; www.SetRequestHeader("user-agent", SharedConstructs.Name); UnityWebRequestAsyncOperation asyncRequest = www.SendWebRequest(); while (!asyncRequest.isDone || asyncRequest.progress < 1f) { yield return(null); time += Time.deltaTime; if (time >= 15f && asyncRequest.progress == 0f) { www.Abort(); timeout = true; } if (lastProgress != asyncRequest.progress) { lastProgress = asyncRequest.progress; downloadProgressChanged?.Invoke($"custom_level_{hash.ToUpper()}", asyncRequest.progress); } } if (www.isNetworkError || www.isHttpError || timeout) { Logger.Error($"Error downloading song {hash}: {www.error}"); songDownloaded?.Invoke($"custom_level_{hash.ToUpper()}", false); } else { string zipPath = ""; string customSongsPath = CustomLevelPathHelper.customLevelsDirectoryPath; string customSongPath = ""; byte[] data = www.downloadHandler.data; try { customSongPath = customSongsPath + "/" + hash + "/"; zipPath = customSongPath + hash + ".zip"; if (!Directory.Exists(customSongPath)) { Directory.CreateDirectory(customSongPath); } File.WriteAllBytes(zipPath, data); } catch (Exception e) { Logger.Error($"Error writing zip: {e}"); songDownloaded?.Invoke($"custom_level_{hash.ToUpper()}", false); yield break; } try { ZipFile.ExtractToDirectory(zipPath, customSongPath); } catch (Exception e) { Logger.Error($"Unable to extract ZIP! Exception: {e}"); songDownloaded?.Invoke($"custom_level_{hash.ToUpper()}", false); yield break; } try { File.Delete(zipPath); } catch (IOException e) { Logger.Warning($"Unable to delete zip! Exception: {e}"); yield break; } Logger.Success($"Downloaded!"); if (refreshWhenDownloaded) { Action <Loader, ConcurrentDictionary <string, CustomPreviewBeatmapLevel> > songsLoaded = null; songsLoaded = (_, __) => { Loader.SongsLoadedEvent -= songsLoaded; songDownloaded?.Invoke($"custom_level_{hash.ToUpper()}", true); }; Loader.SongsLoadedEvent += songsLoaded; Loader.Instance.RefreshSongs(false); } else { songDownloaded?.Invoke($"custom_level_{hash.ToUpper()}", true); } } }
protected override void Client_PacketRecieved(Packet packet) { base.Client_PacketRecieved(packet); if (packet.Type == PacketType.PlaySong) { PlaySong playSong = packet.SpecificPacket as PlaySong; var desiredLevel = SongUtils.masterLevelList.First(x => x.levelID == playSong.Beatmap.LevelId); var desiredCharacteristic = desiredLevel.previewDifficultyBeatmapSets.FirstOrDefault(x => x.beatmapCharacteristic.serializedName == playSong.Beatmap.Characteristic.SerializedName).beatmapCharacteristic ?? desiredLevel.previewDifficultyBeatmapSets.First().beatmapCharacteristic; var desiredDifficulty = (BeatmapDifficulty)playSong.Beatmap.Difficulty; var playerData = Resources.FindObjectsOfTypeAll <PlayerDataModel>().First().playerData; var playerSettings = playerData.playerSpecificSettings; //Override defaults if we have forced options enabled if (playSong.PlayerSettings.Options != PlayerOptions.None) { playerSettings = new PlayerSpecificSettings(); playerSettings.leftHanded = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.LeftHanded); playerSettings.staticLights = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.StaticLights); playerSettings.noTextsAndHuds = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.NoHud); playerSettings.advancedHud = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.AdvancedHud); playerSettings.reduceDebris = playSong.PlayerSettings.Options.HasFlag(PlayerOptions.ReduceDebris); } var gameplayModifiers = new GameplayModifiers(); gameplayModifiers.batteryEnergy = playSong.GameplayModifiers.Options.HasFlag(GameOptions.BatteryEnergy); gameplayModifiers.disappearingArrows = playSong.GameplayModifiers.Options.HasFlag(GameOptions.DisappearingArrows); gameplayModifiers.failOnSaberClash = playSong.GameplayModifiers.Options.HasFlag(GameOptions.FailOnClash); gameplayModifiers.fastNotes = playSong.GameplayModifiers.Options.HasFlag(GameOptions.FastNotes); gameplayModifiers.ghostNotes = playSong.GameplayModifiers.Options.HasFlag(GameOptions.GhostNotes); gameplayModifiers.instaFail = playSong.GameplayModifiers.Options.HasFlag(GameOptions.InstaFail); gameplayModifiers.noBombs = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoBombs); gameplayModifiers.noFail = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoFail); gameplayModifiers.noObstacles = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoObstacles); gameplayModifiers.noArrows = playSong.GameplayModifiers.Options.HasFlag(GameOptions.NoArrows); if (playSong.GameplayModifiers.Options.HasFlag(GameOptions.SlowSong)) { gameplayModifiers.songSpeed = GameplayModifiers.SongSpeed.Slower; } if (playSong.GameplayModifiers.Options.HasFlag(GameOptions.FastSong)) { gameplayModifiers.songSpeed = GameplayModifiers.SongSpeed.Faster; } var colorScheme = playerData.colorSchemesSettings.overrideDefaultColors ? playerData.colorSchemesSettings.GetSelectedColorScheme() : null; PlaySong?.Invoke(desiredLevel, desiredCharacteristic, desiredDifficulty, gameplayModifiers, playerSettings, playerData.overrideEnvironmentSettings, colorScheme, playSong.FloatingScoreboard, playSong.StreamSync, playSong.DisablePause, playSong.DisableFail); } else if (packet.Type == PacketType.Command) { Command command = packet.SpecificPacket as Command; if (command.CommandType == Command.CommandTypes.ReturnToMenu) { if (SyncHandler.Instance != null) { ScreenOverlay.Instance.Clear(); } if ((Self as Player).PlayState == Player.PlayStates.InGame) { PlayerUtils.ReturnToMenu(); } } else if (command.CommandType == Command.CommandTypes.ScreenOverlay_ShowPng) { ScreenOverlay.Instance.ShowPng(); } else if (command.CommandType == Command.CommandTypes.DelayTest_Finish) { UnityMainThreadDispatcher.Instance().Enqueue(() => { ScreenOverlay.Instance.Clear(); SyncHandler.Instance.Resume(); SyncHandler.Destroy(); }); } } else if (packet.Type == PacketType.LoadSong) { LoadSong loadSong = packet.SpecificPacket as LoadSong; Action <IBeatmapLevel> SongLoaded = (loadedLevel) => { //Send updated download status (Self as Player).DownloadState = Player.DownloadStates.Downloaded; var playerUpdate = new Event(); playerUpdate.Type = Event.EventType.PlayerUpdated; playerUpdate.ChangedObject = Self; Send(new Packet(playerUpdate)); //Notify any listeners of the client that a song has been loaded LoadedSong?.Invoke(loadedLevel); Logger.Debug($"SENT DOWNLOADED SIGNAL {(playerUpdate.ChangedObject as Player).DownloadState}"); }; if (OstHelper.IsOst(loadSong.LevelId)) { SongLoaded?.Invoke(SongUtils.masterLevelList.First(x => x.levelID == loadSong.LevelId) as BeatmapLevelSO); } else { if (SongUtils.masterLevelList.Any(x => x.levelID == loadSong.LevelId)) { SongUtils.LoadSong(loadSong.LevelId, SongLoaded); } else { Action <bool> loadSongAction = (succeeded) => { if (succeeded) { SongUtils.LoadSong(loadSong.LevelId, SongLoaded); } else { (Self as Player).DownloadState = Player.DownloadStates.DownloadError; var playerUpdated = new Event(); playerUpdated.Type = Event.EventType.PlayerUpdated; playerUpdated.ChangedObject = Self; Send(new Packet(playerUpdated)); Logger.Debug($"SENT DOWNLOADED SIGNAL {(playerUpdated.ChangedObject as Player).DownloadState}"); } }; (Self as Player).DownloadState = Player.DownloadStates.Downloading; var playerUpdate = new Event(); playerUpdate.Type = Event.EventType.PlayerUpdated; playerUpdate.ChangedObject = Self; Send(new Packet(playerUpdate)); Logger.Debug($"SENT DOWNLOAD SIGNAL {(playerUpdate.ChangedObject as Player).DownloadState}"); SongDownloader.DownloadSong(loadSong.LevelId, songDownloaded: loadSongAction, downloadProgressChanged: (progress) => Logger.Debug($"DOWNLOAD PROGRESS: {progress}")); } } } else if (packet.Type == PacketType.File) { File file = packet.SpecificPacket as File; if (file.Intention == File.Intentions.SetPngToShowWhenTriggered) { var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data; ScreenOverlay.Instance.SetPngBytes(pngBytes); } else if (file.Intention == File.Intentions.ShowPngImmediately) { var pngBytes = file.Compressed ? CompressionUtils.Decompress(file.Data) : file.Data; ScreenOverlay.Instance.SetPngBytes(pngBytes); ScreenOverlay.Instance.ShowPng(); } Send(packet.From, new Packet(new Acknowledgement() { PacketId = packet.Id, Type = Acknowledgement.AcknowledgementType.FileDownloaded })); } }