public LevelOptionsInfo(BeatmapDifficulty difficulty, GameplayModifiers modifiers, string characteristicName) { this.difficulty = difficulty; this.modifiers = new GameplayModifiersStruct(modifiers); this.characteristicName = characteristicName; }
private void CleanUpSong() { statusManager.gameStatus.ResetMapInfo(); statusManager.gameStatus.ResetPerformance(); // Release references for AfterCutScoreBuffers that don't resolve due to player leaving the map before finishing. noteCutMapping.Clear(); // Clear note id mappings. noteToIdMapping = null; if (pauseController != null) { pauseController.didPauseEvent -= OnGamePause; pauseController.didResumeEvent -= OnGameResume; pauseController = null; } if (scoreController != null) { scoreController.noteWasCutEvent -= OnNoteWasCut; scoreController.noteWasMissedEvent -= OnNoteWasMissed; scoreController.scoreDidChangeEvent -= OnScoreDidChange; scoreController.comboDidChangeEvent -= OnComboDidChange; scoreController.multiplierDidChangeEvent -= OnMultiplierDidChange; scoreController = null; } if (gameplayManager != null) { if (gameplayManager is ILevelEndActions levelEndActions) { // event Action levelFailedEvent; levelEndActions.levelFailedEvent += OnLevelFailed; } gameplayManager = null; } if (beatmapObjectCallbackController != null) { beatmapObjectCallbackController.beatmapEventDidTriggerEvent -= OnBeatmapEventDidTrigger; beatmapObjectCallbackController = null; } if (gameplayModifiersSO != null) { gameplayModifiersSO = null; } if (audioTimeSyncController != null) { audioTimeSyncController = null; } if (playerHeadAndObstacleInteraction != null) { playerHeadAndObstacleInteraction = null; } if (gameSongController != null) { gameSongController.songDidFinishEvent -= OnLevelFinished; gameSongController = null; } if (gameEnergyCounter != null) { gameEnergyCounter.gameEnergyDidReach0Event -= OnEnergyDidReach0Event; gameEnergyCounter = null; } if (gameplayCoreSceneSetupData != null) { gameplayCoreSceneSetupData = null; } if (gameplayModifiers != null) { gameplayModifiers = null; } }
private void Client_PacketRecieved(Packet packet) { if (packet.Type == PacketType.PlaySong) { PlaySong playSong = packet.SpecificPacket as PlaySong; var desiredLevel = Plugin.masterLevelList.First(x => x.levelID == playSong.levelId); var desiredCharacteristic = desiredLevel.beatmapCharacteristics.First(x => x.serializedName == playSong.characteristic.SerializedName); var desiredDifficulty = (BeatmapDifficulty)playSong.difficulty; var playerSpecificSettings = new PlayerSpecificSettings(); playerSpecificSettings.advancedHud = playSong.playerSettings.advancedHud; playerSpecificSettings.leftHanded = playSong.playerSettings.leftHanded; playerSpecificSettings.noTextsAndHuds = playSong.playerSettings.noTextsAndHuds; playerSpecificSettings.reduceDebris = playSong.playerSettings.reduceDebris; playerSpecificSettings.staticLights = playSong.playerSettings.staticLights; var gameplayModifiers = new GameplayModifiers(); gameplayModifiers.batteryEnergy = playSong.gameplayModifiers.batteryEnergy; gameplayModifiers.disappearingArrows = playSong.gameplayModifiers.disappearingArrows; gameplayModifiers.failOnSaberClash = playSong.gameplayModifiers.failOnSaberClash; gameplayModifiers.fastNotes = playSong.gameplayModifiers.fastNotes; gameplayModifiers.ghostNotes = playSong.gameplayModifiers.ghostNotes; gameplayModifiers.instaFail = playSong.gameplayModifiers.instaFail; gameplayModifiers.noBombs = playSong.gameplayModifiers.noBombs; gameplayModifiers.noFail = playSong.gameplayModifiers.noFail; gameplayModifiers.noObstacles = playSong.gameplayModifiers.noObstacles; gameplayModifiers.songSpeed = (GameplayModifiers.SongSpeed)playSong.gameplayModifiers.songSpeed; SaberUtilities.PlaySong(desiredLevel, desiredCharacteristic, desiredDifficulty, gameplayModifiers, playerSpecificSettings); } else if (packet.Type == PacketType.LoadSong) { LoadSong loadSong = packet.SpecificPacket as LoadSong; Action <IBeatmapLevel> SongLoaded = (loadedLevel) => { var loadedSong = new LoadedSong(); var beatmapLevel = new PreviewBeatmapLevel(); beatmapLevel.Characteristics = loadedLevel.beatmapCharacteristics.ToList().Select(x => { var characteristic = new Characteristic(); characteristic.SerializedName = x.serializedName; characteristic.difficulties = loadedLevel.beatmapLevelData.difficultyBeatmapSets .First(y => y.beatmapCharacteristic.serializedName == x.serializedName) .difficultyBeatmaps.Select(y => (Characteristic.BeatmapDifficulty)y.difficulty).ToArray(); return(characteristic); }).ToArray(); beatmapLevel.LevelId = loadedLevel.levelID; beatmapLevel.Name = loadedLevel.songName; beatmapLevel.Loaded = true; loadedSong.level = beatmapLevel; client.Send(new Packet(loadedSong).ToBytes()); }; LoadSong(loadSong.levelId, SongLoaded); } else if (packet.Type == PacketType.Command) { Command command = packet.SpecificPacket as Command; if (command.commandType == Command.CommandType.ReturnToMenu) { SaberUtilities.ReturnToMenu(); } } }
static void Prefix(MissionLevelScenesTransitionSetupDataSO __instance, IDifficultyBeatmap difficultyBeatmap, MissionObjective[] missionObjectives, GameplayModifiers gameplayModifiers, PlayerSpecificSettings playerSpecificSettings) { Plugin.LevelData.GameplayCoreSceneSetupData = new GameplayCoreSceneSetupData(difficultyBeatmap, gameplayModifiers, playerSpecificSettings, PracticeSettings.defaultPracticeSettings, false); Plugin.LevelData.IsSet = true; __instance.didFinishEvent -= __instance_didFinishEvent; __instance.didFinishEvent += __instance_didFinishEvent; }
//private BeatmapObjectCallbackController beatmapObjectCallbackController; public void SceneManagerOnActiveSceneChanged(Scene oldScene, Scene newScene) { if (newScene.name == "GameCore") { gameStatus = new GameStatus(); levelSceneSetupData = FindFirstOrDefault <StandardLevelSceneSetupDataSO>(); //gamePauseManager = FindFirstOrDefault<GamePauseManager>(); scoreController = FindFirstOrDefault <ScoreController>(); gameplayModifiersSO = FindFirstOrDefault <GameplayModifiersModelSO>(); audioTimeSyncController = FindFirstOrDefault <AudioTimeSyncController>(); //playerHeadAndObstacleInteraction = FindFirstOrDefault<PlayerHeadAndObstacleInteraction>(); gameEnergyCounter = FindFirstOrDefault <GameEnergyCounter>(); gameplayManager = FindFirstOrDefault <StandardLevelGameplayManager>(); //beatmapObjectCallbackController = FindFirstOrDefault<BeatmapObjectCallbackController>(); // Register event listeners // private GameEvent GamePauseManager#_gameDidPauseSignal //AddSubscriber(gamePauseManager, "_gameDidPauseSignal", OnGamePause); // private GameEvent GamePauseManager#_gameDidResumeSignal //AddSubscriber(gamePauseManager, "_gameDidResumeSignal", OnGameResume); // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after AfterCutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; // private GameEvent GameplayManager#_levelFinishedSignal AddSubscriber(gameplayManager, "_levelFinishedSignal", OnLevelFinished); // private GameEvent GameplayManager#_levelFailedSignal AddSubscriber(gameplayManager, "_levelFailedSignal", OnLevelFailed); // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent //beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; IDifficultyBeatmap diff = levelSceneSetupData.difficultyBeatmap; IBeatmapLevel level = diff.level; GameplayModifiers gameplayModifiers = levelSceneSetupData.gameplayCoreSetupData.gameplayModifiers; PlayerSpecificSettings playerSettings = levelSceneSetupData.gameplayCoreSetupData.playerSpecificSettings; PracticeSettings practiceSettings = levelSceneSetupData.gameplayCoreSetupData.practiceSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; if (practiceSettings != null) { songSpeedMul = practiceSettings.songSpeedMul; } float modifierMultiplier = gameplayModifiersSO.GetTotalMultiplier(gameplayModifiers); var songInfo = FindLevelInfancyWay(levelSceneSetupData.difficultyBeatmap.level.levelID); gameStatus.songHash = level.levelID.Substring(0, Math.Max(0, level.levelID.IndexOf('∎'))); gameStatus.songBeatSaverID = songInfo == null ? null : ParseIdFromSongPath(songInfo); gameStatus.songFilePath = songInfo?.path; gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.noteJumpSpeed = diff.noteJumpMovementSpeed; gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f / songSpeedMul); gameStatus.length = (long)(level.audioClip.length * 1000f / songSpeedMul); gameStatus.start = GetCurrentTime() - (long)(audioTimeSyncController.songTime * 1000f / songSpeedMul); if (practiceSettings != null) { gameStatus.start -= (long)(practiceSettings.startSongTime * 1000f / songSpeedMul); } gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.notesCount = diff.beatmapData.notesCount; gameStatus.bombsCount = diff.beatmapData.bombsCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.maxScore = ScoreController.GetScoreForGameplayModifiersScoreMultiplier(ScoreController.MaxScoreForNumberOfNotes(diff.beatmapData.notesCount), modifierMultiplier); gameStatus.maxPossibleScore = ScoreController.MaxScoreForNumberOfNotes(diff.beatmapData.notesCount); gameStatus.maxRank = RankModel.MaxRankForGameplayModifiers(gameplayModifiers, gameplayModifiersSO).ToString(); gameStatus.ResetPerformance(); gameStatus.modifierMultiplier = modifierMultiplier; gameStatus.songSpeedMultiplier = songSpeedMul; gameStatus.batteryLives = gameEnergyCounter.batteryLives; gameStatus.modObstacles = gameplayModifiers.enabledObstacleType.ToString(); gameStatus.modInstaFail = gameplayModifiers.instaFail; gameStatus.modNoFail = gameplayModifiers.noFail; gameStatus.modBatteryEnergy = gameplayModifiers.batteryEnergy; gameStatus.modDisappearingArrows = gameplayModifiers.disappearingArrows; gameStatus.modNoBombs = gameplayModifiers.noBombs; gameStatus.modSongSpeed = gameplayModifiers.songSpeed.ToString(); gameStatus.modFailOnSaberClash = gameplayModifiers.failOnSaberClash; gameStatus.modStrictAngles = gameplayModifiers.strictAngles; } }
// Yoinked from TournamentAssistant 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( loadedLevel.beatmapLevelData.GetDifficultyBeatmap(characteristic, difficulty), overrideEnvironmentSettings, colorScheme, gameplayModifiers ?? new GameplayModifiers(), playerSettings ?? new PlayerSpecificSettings(), null, "Menu", false, null, (standardLevelScenesTransitionSetupData, results) => songFinishedCallback?.Invoke(standardLevelScenesTransitionSetupData, results) ); }; BeatmapLevelsModel beatmapLevelsModel = Resources.FindObjectsOfTypeAll <BeatmapLevelsModel>().FirstOrDefault(); 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("_coverImageTexture2D", level.GetField <Texture2D>("_coverImageTexture2D")); SongLoaded(loadedLevel); } }
static void Postfix(MissionLevelScenesTransitionSetupDataSO __instance, IPreviewBeatmapLevel previewBeatmapLevel, string missionId, IDifficultyBeatmap difficultyBeatmap, MissionObjective[] missionObjectives, ColorScheme overrideColorScheme, GameplayModifiers gameplayModifiers, PlayerSpecificSettings playerSpecificSettings, string backButtonText) { EnvironmentInfoSO environmentInfoSO = difficultyBeatmap.GetEnvironmentInfo(); ScoreSubmission._wasDisabled = false; ScoreSubmission.LastDisablers = Array.Empty <string>(); Plugin.LevelData.GameplayCoreSceneSetupData = new GameplayCoreSceneSetupData(difficultyBeatmap, previewBeatmapLevel, gameplayModifiers, playerSpecificSettings, PracticeSettings.defaultPracticeSettings, false, environmentInfoSO, overrideColorScheme); Plugin.LevelData.IsSet = true; Plugin.LevelData.Mode = Mode.Mission; Utilities.Logger.log.Debug("Level Data set"); __instance.didFinishEvent -= __instance_didFinishEvent; __instance.didFinishEvent += __instance_didFinishEvent; }
public override void HandleMenuRpcManagerSelectedGameplayModifiers(string userId, GameplayModifiers gameplayModifiers) { ExtendedPlayer?player = _playerManager.GetExtendedPlayer(userId); if (player != null) { player.lastModifiers = gameplayModifiers; } base.HandleMenuRpcManagerSelectedGameplayModifiers(userId, gameplayModifiers); if (userId == hostUserId && MPState.FreeModEnabled) { GameplayModifiers localModifiers = GetPlayerGameplayModifiers(localUserId); if (localModifiers.songSpeed != gameplayModifiers.songSpeed) { base.SetLocalPlayerGameplayModifiers(localModifiers.CopyWith(songSpeed: gameplayModifiers.songSpeed)); } } }
static void Prefix(string gameMode, IDifficultyBeatmap difficultyBeatmap, OverrideEnvironmentSettings overrideEnvironmentSettings, ref ColorScheme overrideColorScheme, GameplayModifiers gameplayModifiers, PlayerSpecificSettings playerSpecificSettings, PracticeSettings practiceSettings, string backButtonText, bool useTestNoteCutSoundEffects, Action beforeSceneSwitchCallback, Action <DiContainer> afterSceneSwitchCallback, Action <StandardLevelScenesTransitionSetupDataSO, LevelCompletionResults> levelFinishedCallback) { Plugin.Log.Info($"Starting ({difficultyBeatmap.GetType().FullName}) {difficultyBeatmap.SerializedName()} {gameMode} {difficultyBeatmap.difficulty} {difficultyBeatmap.level.songName}"); string startingGameModeName = difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName; if (startingGameModeName == GameModeHelper.GENERATED_360DEGREE_MODE || startingGameModeName == GameModeHelper.GENERATED_90DEGREE_MODE) { Plugin.Log.Info($"Generating rotation events for {startingGameModeName}..."); // Colors are not copied from standard mode for some reason? Enforce it here var mapCustomColors = difficultyBeatmap.level.environmentInfo?.colorScheme?.colorScheme; if (mapCustomColors != null && overrideColorScheme == null) { Plugin.Log.Info($"Overriding custom colors with {mapCustomColors.environmentColor0} {mapCustomColors.environmentColor1}"); overrideColorScheme = mapCustomColors; } if (!generated.Contains(difficultyBeatmap)) { generated.Add(difficultyBeatmap); Generator360 gen = new Generator360(); gen.WallGenerator = Config.Instance.EnableWallGenerator; gen.OnlyOneSaber = Config.Instance.OnlyOneSaber; if (startingGameModeName == GameModeHelper.GENERATED_90DEGREE_MODE) { gen.LimitRotations = Config.Instance.LimitRotations90; gen.BottleneckRotations = Config.Instance.LimitRotations90 / 2; } else if (startingGameModeName == GameModeHelper.GENERATED_360DEGREE_MODE) { gen.LimitRotations = Config.Instance.LimitRotations360; gen.BottleneckRotations = Config.Instance.LimitRotations360 / 2; } gen.Generate(difficultyBeatmap); } else { Plugin.Log.Info("Already generated rotation events"); } } }
public void SongFinished(StandardLevelScenesTransitionSetupDataSO sender, LevelCompletionResults levelCompletionResults, IDifficultyBeatmap difficultyBeatmap, GameplayModifiers gameplayModifiers, bool practice) { if (Client.Instance.InRadioMode) { PluginUI.instance.radioFlowCoordinator.lastDifficulty = difficultyBeatmap; PluginUI.instance.radioFlowCoordinator.lastResults = levelCompletionResults; } if (Config.Instance.SpectatorMode || Client.disableScoreSubmission || ScoreSubmission.Disabled || ScoreSubmission.ProlongedDisabled) { return; } PlayerDataModelSO _playerDataModel = Resources.FindObjectsOfTypeAll <PlayerDataModelSO>().First(); _playerDataModel.currentLocalPlayer.playerAllOverallStatsData.soloFreePlayOverallStatsData.UpdateWithLevelCompletionResults(levelCompletionResults); _playerDataModel.Save(); if (levelCompletionResults.levelEndStateType != LevelCompletionResults.LevelEndStateType.Failed && levelCompletionResults.levelEndStateType != LevelCompletionResults.LevelEndStateType.Cleared) { return; } PlayerDataModelSO.LocalPlayer currentLocalPlayer = _playerDataModel.currentLocalPlayer; bool cleared = levelCompletionResults.levelEndStateType == LevelCompletionResults.LevelEndStateType.Cleared; string levelID = difficultyBeatmap.level.levelID; BeatmapDifficulty difficulty = difficultyBeatmap.difficulty; BeatmapCharacteristicSO beatmapCharacteristic = difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic; PlayerLevelStatsData playerLevelStatsData = currentLocalPlayer.GetPlayerLevelStatsData(levelID, difficulty, beatmapCharacteristic); bool newHighScore = playerLevelStatsData.highScore < levelCompletionResults.score; playerLevelStatsData.IncreaseNumberOfGameplays(); if (cleared) { playerLevelStatsData.UpdateScoreData(levelCompletionResults.score, levelCompletionResults.maxCombo, levelCompletionResults.fullCombo, levelCompletionResults.rank); Resources.FindObjectsOfTypeAll <PlatformLeaderboardsModel>().First().AddScore(difficultyBeatmap, levelCompletionResults.unmodifiedScore, gameplayModifiers); } }
private void SongDetail_didPressPlayButtonEvent(IBeatmapLevel level, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty) { _lastPlayedBeatmapLevel = level; _lastPlayedCharacteristic = characteristic; _lastPlayedDifficulty = difficulty; var playerData = Resources.FindObjectsOfTypeAll <PlayerDataModel>().First().playerData; var playerSettings = playerData.playerSpecificSettings; //Override defaults if we have forced options enabled if (_currentParameters.PlayerSettings.Options != PlayerOptions.None) { playerSettings = new PlayerSpecificSettings( _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.LeftHanded), _currentParameters.PlayerSettings.PlayerHeight, _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AutoPlayerHeight), _currentParameters.PlayerSettings.SfxVolume, _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.ReduceDebris), _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.NoHud), _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.NoFailEffects), _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AdvancedHud), _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AutoRestart), _currentParameters.PlayerSettings.SaberTrailIntensity, _currentParameters.PlayerSettings.NoteJumpStartBeatOffset, _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.HideNoteSpawnEffect), _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.AdaptiveSfx), _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.StaticLights) ? EnvironmentEffectsFilterPreset.NoEffects : EnvironmentEffectsFilterPreset.AllEffects, _currentParameters.PlayerSettings.Options.HasFlag(PlayerOptions.StaticLights) ? EnvironmentEffectsFilterPreset.NoEffects : EnvironmentEffectsFilterPreset.AllEffects ); } var songSpeed = GameplayModifiers.SongSpeed.Normal; if (_currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.SlowSong)) { songSpeed = GameplayModifiers.SongSpeed.Slower; } if (_currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.FastSong)) { songSpeed = GameplayModifiers.SongSpeed.Faster; } if (_currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.SuperFastSong)) { songSpeed = GameplayModifiers.SongSpeed.SuperFast; } var gameplayModifiers = new GameplayModifiers( _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.DemoNoFail), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.DemoNoObstacles), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.BatteryEnergy) ? GameplayModifiers.EnergyType.Battery : GameplayModifiers.EnergyType.Bar, _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoFail), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.InstaFail), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.FailOnClash), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoObstacles) ? GameplayModifiers.EnabledObstacleType.NoObstacles : GameplayModifiers.EnabledObstacleType.All, _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoBombs), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.FastNotes), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.StrictAngles), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.DisappearingArrows), songSpeed, _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.NoArrows), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.GhostNotes), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.ProMode), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.ZenMode), _currentParameters.GameplayModifiers.Options.HasFlag(GameOptions.SmallCubes) ); var colorScheme = playerData.colorSchemesSettings.overrideDefaultColors ? playerData.colorSchemesSettings.GetSelectedColorScheme() : null; //Disable scores if we need to if (((QualifierEvent.EventSettings)Event.Flags).HasFlag(QualifierEvent.EventSettings.DisableScoresaberSubmission)) { BS_Utils.Gameplay.ScoreSubmission.DisableSubmission(SharedConstructs.Name); } SongUtils.PlaySong(level, characteristic, difficulty, playerData.overrideEnvironmentSettings, colorScheme, gameplayModifiers, playerSettings, SongFinished); }
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})"); } }
public void StartLevel(BeatmapLevelSO song, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty, GameplayModifiers modifiers) { if (Connected && NetworkClient != null) { #if DEBUG Misc.Logger.Info("Starting level..."); #endif NetOutgoingMessage outMsg = NetworkClient.CreateMessage(); outMsg.Write((byte)CommandType.StartLevel); new StartLevelInfo(difficulty, modifiers, characteristic.serializedName).AddToMessage(outMsg); SongInfo selectedSong = new SongInfo(song); selectedSong.songDuration = selectedSong.songDuration / modifiers.songSpeedMul; selectedSong.AddToMessage(outMsg); NetworkClient.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0); } }
public void StartLevel(IBeatmapLevel level, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty, GameplayModifiers modifiers, float startTime = 0f) { Client.Instance.playerInfo.updateInfo.playerComboBlocks = 0; Client.Instance.playerInfo.updateInfo.playerCutBlocks = 0; Client.Instance.playerInfo.updateInfo.playerEnergy = 0f; Client.Instance.playerInfo.updateInfo.playerScore = 0; MenuTransitionsHelperSO menuSceneSetupData = Resources.FindObjectsOfTypeAll <MenuTransitionsHelperSO>().FirstOrDefault(); if (menuSceneSetupData != null) { PlayerData playerData = Resources.FindObjectsOfTypeAll <PlayerDataModelSO>().FirstOrDefault().playerData; PlayerSpecificSettings playerSettings = playerData.playerSpecificSettings; channelInfo.state = ChannelState.InGame; Client.Instance.playerInfo.updateInfo.playerState = PlayerState.Game; IDifficultyBeatmap difficultyBeatmap = level.GetDifficultyBeatmap(characteristic, difficulty, false); #if DEBUG Plugin.log.Info($"Starting song: name={level.songName}, levelId={level.levelID}, difficulty={difficulty}"); #endif PracticeSettings practiceSettings = new PracticeSettings(PracticeSettings.defaultPracticeSettings); practiceSettings.startSongTime = startTime + 1.5f; practiceSettings.songSpeedMul = modifiers.songSpeedMul; practiceSettings.startInAdvanceAndClearNotes = true; Client.Instance.MessageReceived -= MessageReceived; try { BS_Utils.Gameplay.Gamemode.NextLevelIsIsolated("Beat Saber Multiplayer"); } catch { } OverrideEnvironmentSettings overrideEnvironmentSettings = new OverrideEnvironmentSettings(); menuSceneSetupData.StartStandardLevel(difficultyBeatmap, overrideEnvironmentSettings, playerData.colorSchemesSettings.GetSelectedColorScheme(), modifiers, playerSettings, (startTime > 1f ? practiceSettings : null), "Lobby", false, () => {}, (StandardLevelScenesTransitionSetupDataSO sender, LevelCompletionResults levelCompletionResults) => { InGameOnlineController.Instance.SongFinished(sender, levelCompletionResults, difficultyBeatmap, modifiers, (startTime > 1f)); }); } else { Plugin.log.Error("SceneSetupData is null!"); } }
protected override void Client_PlaySong(IPreviewBeatmapLevel desiredLevel, BeatmapCharacteristicSO desiredCharacteristic, BeatmapDifficulty desiredDifficulty, GameplayModifiers gameplayModifiers, PlayerSpecificSettings playerSpecificSettings, OverrideEnvironmentSettings overrideEnvironmentSettings, ColorScheme colorScheme, bool useFloatingScoreboard = false, bool useSync = false, bool disablePause = false) { base.Client_PlaySong(desiredLevel, desiredCharacteristic, desiredDifficulty, gameplayModifiers, playerSpecificSettings, overrideEnvironmentSettings, colorScheme, useFloatingScoreboard, useSync, disablePause); //Set up per-play settings Plugin.UseSync = useSync; Plugin.UseFloatingScoreboard = useFloatingScoreboard; Plugin.DisablePause = disablePause; //Reset score (Plugin.client.SelfObject as Player).Score = 0; (Plugin.client.SelfObject as Player).Accuracy = 0; var playerUpdate = new Event { Type = Event.Types.EventType.PlayerUpdated, ChangedObject = Google.Protobuf.WellKnownTypes.Any.Pack(Plugin.client.SelfObject as IMessage) }; Plugin.client.Send(new Packet(playerUpdate)); UnityMainThreadDispatcher.Instance().Enqueue(() => { //If the player is still on the results screen, go ahead and boot them out if (_resultsViewController.isInViewControllerHierarchy) { resultsViewController_continueButtonPressedEvent(null); } SongUtils.PlaySong(desiredLevel, desiredCharacteristic, desiredDifficulty, overrideEnvironmentSettings, colorScheme, gameplayModifiers, playerSpecificSettings, SongFinished); }); }
private void PacketReceived(NetIncomingMessage msg) { CommandType commandType = (CommandType)msg.ReadByte(); if (!joined) { if (commandType == CommandType.JoinRoom) { switch (msg.ReadByte()) { case 0: { Client.Instance.playerInfo.playerState = PlayerState.DownloadingSongs; Client.Instance.RequestRoomInfo(); Client.Instance.SendPlayerInfo(); joined = true; InGameOnlineController.Instance.needToSendUpdates = true; } break; case 1: { _roomNavigationController.DisplayError("Unable to join room!\nRoom not found"); } break; case 2: { _roomNavigationController.DisplayError("Unable to join room!\nIncorrect password"); } break; case 3: { _roomNavigationController.DisplayError("Unable to join room!\nToo much players"); } break; default: { _roomNavigationController.DisplayError("Unable to join room!\nUnknown error"); } break; } } } else { try { switch (commandType) { case CommandType.GetRoomInfo: { Client.Instance.playerInfo.playerState = PlayerState.Room; roomInfo = new RoomInfo(msg); Client.Instance.isHost = Client.Instance.playerInfo.Equals(roomInfo.roomHost); UpdateUI(roomInfo.roomState); } break; case CommandType.SetSelectedSong: { if (msg.LengthBytes < 16) { roomInfo.roomState = RoomState.SelectingSong; roomInfo.selectedSong = null; PreviewPlayer.CrossfadeToDefault(); UpdateUI(roomInfo.roomState); if (songToDownload != null) { songToDownload.songQueueState = SongQueueState.Error; Client.Instance.playerInfo.playerState = PlayerState.Room; } } else { roomInfo.roomState = RoomState.Preparing; SongInfo selectedSong = new SongInfo(msg); roomInfo.selectedSong = selectedSong; if (songToDownload != null) { songToDownload.songQueueState = SongQueueState.Error; } UpdateUI(roomInfo.roomState); } } break; case CommandType.TransferHost: { roomInfo.roomHost = new PlayerInfo(msg); Client.Instance.isHost = Client.Instance.playerInfo.Equals(roomInfo.roomHost); if (Client.Instance.playerInfo.playerState == PlayerState.DownloadingSongs) { return; } UpdateUI(roomInfo.roomState); } break; case CommandType.StartLevel: { if (Client.Instance.playerInfo.playerState == PlayerState.DownloadingSongs) { return; } lastSelectedSong = ""; Client.Instance.playerInfo.playerComboBlocks = 0; Client.Instance.playerInfo.playerCutBlocks = 0; Client.Instance.playerInfo.playerEnergy = 0f; Client.Instance.playerInfo.playerScore = 0; byte difficulty = msg.ReadByte(); SongInfo songInfo = new SongInfo(msg); MenuSceneSetupDataSO menuSceneSetupData = Resources.FindObjectsOfTypeAll <MenuSceneSetupDataSO>().FirstOrDefault(); if (menuSceneSetupData != null) { GameplayModifiers gameplayModifiers = new GameplayModifiers(); if (Config.Instance.SpectatorMode) { Client.Instance.playerInfo.playerState = PlayerState.Spectating; gameplayModifiers.noFail = true; } else { Client.Instance.playerInfo.playerState = PlayerState.Game; gameplayModifiers.noFail = roomInfo.noFail; } PlayerSpecificSettings playerSettings = Resources.FindObjectsOfTypeAll <PlayerDataModelSO>().FirstOrDefault().currentLocalPlayer.playerSpecificSettings; roomInfo.roomState = RoomState.InGame; Client.Instance.MessageReceived -= PacketReceived; LevelSO level = _levelCollection.levels.First(x => x.levelID.StartsWith(songInfo.levelId)); IDifficultyBeatmap difficultyBeatmap = level.GetDifficultyBeatmap((BeatmapDifficulty)difficulty); Logger.Info($"Starting song: name={level.songName}, levelId={level.levelID}, difficulty={(BeatmapDifficulty)difficulty}"); Client.Instance.MessageReceived -= PacketReceived; menuSceneSetupData.StartStandardLevel(difficultyBeatmap, gameplayModifiers, playerSettings, null, null, (StandardLevelSceneSetupDataSO sender, LevelCompletionResults levelCompletionResults) => { InGameOnlineController.Instance.SongFinished(sender, levelCompletionResults, difficultyBeatmap, gameplayModifiers, false); }); return; } else { Logger.Error("SceneSetupData is null!"); } } break; case CommandType.LeaveRoom: { LeaveRoom(); } break; case CommandType.UpdatePlayerInfo: { if (roomInfo != null) { if (roomInfo.roomState != RoomState.SelectingSong) { float currentTime = msg.ReadFloat(); float totalTime = msg.ReadFloat(); int playersCount = msg.ReadInt32(); List <PlayerInfo> playerInfos = new List <PlayerInfo>(); for (int j = 0; j < playersCount; j++) { try { playerInfos.Add(new PlayerInfo(msg)); } catch (Exception e) { #if DEBUG Misc.Logger.Exception($"Unable to parse PlayerInfo! Excpetion: {e}"); #endif } } switch (roomInfo.roomState) { case RoomState.InGame: playerInfos = playerInfos.Where(x => x.playerScore > 0 && x.playerState == PlayerState.Game).ToList(); UpdateLeaderboard(playerInfos, currentTime, totalTime, false); break; case RoomState.Results: playerInfos = playerInfos.Where(x => x.playerScore > 0 && (x.playerState == PlayerState.Game || x.playerState == PlayerState.Room)).ToList(); UpdateLeaderboard(playerInfos, currentTime, totalTime, true); break; case RoomState.Preparing: _roomManagementViewController.UpdatePlayerList(playerInfos); break; } } } } break; case CommandType.PlayerReady: { int playersReady = msg.ReadInt32(); int playersTotal = msg.ReadInt32(); if (roomInfo.roomState == RoomState.Preparing && _difficultySelectionViewController != null) { _difficultySelectionViewController.SetPlayersReady(playersReady, playersTotal); } } break; case CommandType.Disconnect: { InGameOnlineController.Instance.needToSendUpdates = false; if (msg.LengthBytes > 3) { string reason = msg.ReadString(); PopAllViewControllers(_roomNavigationController); InGameOnlineController.Instance.DestroyAvatars(); PreviewPlayer.CrossfadeToDefault(); joined = false; lastSelectedSong = ""; _roomNavigationController.DisplayError(reason); } else { _roomNavigationController.DisplayError("ServerHub refused connection!"); } } break; } }catch (Exception e) { Logger.Exception("Unable to parse packet!"); if (msg != null) { Logger.Exception($"Packet={commandType}, DataLength={msg.LengthBytes}"); } Logger.Exception(e.ToString()); } } }
public void StartLevel(IPreviewBeatmapLevel song, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty, GameplayModifiers modifiers) { if (connected && networkClient != null) { Plugin.log.Debug("Starting level..."); NetOutgoingMessage outMsg = networkClient.CreateMessage(); outMsg.Write((byte)CommandType.StartLevel); new LevelOptionsInfo(difficulty, modifiers, characteristic.serializedName).AddToMessage(outMsg); SongInfo selectedSong = new SongInfo(song); selectedSong.songDuration = selectedSong.songDuration / modifiers.songSpeedMul; selectedSong.AddToMessage(outMsg); networkClient.SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered, 0); } }
private static void StartLevel(IBeatmapLevel beatmapLevel, CustomPreviewBeatmapLevel beatmap, BeatmapDifficulty difficulty) { Logger.log.Info("Starting level"); MenuTransitionsHelper menuSceneSetupData = Resources.FindObjectsOfTypeAll <MenuTransitionsHelper>().FirstOrDefault(); PlayerData playerSettings = Resources.FindObjectsOfTypeAll <PlayerDataModel>().FirstOrDefault().playerData; var gamePlayModifiers = new GameplayModifiers(); gamePlayModifiers.IsWithoutModifiers(); IBeatmapLevel level = beatmapLevel; BeatmapCharacteristicSO characteristics = beatmap.previewDifficultyBeatmapSets[0].beatmapCharacteristic; IDifficultyBeatmap levelDifficulty = BeatmapLevelDataExtensions.GetDifficultyBeatmap(level.beatmapLevelData, characteristics, difficulty); menuSceneSetupData.StartStandardLevel( "Random", levelDifficulty, playerSettings.overrideEnvironmentSettings.overrideEnvironments ? playerSettings.overrideEnvironmentSettings : null, playerSettings.colorSchemesSettings.overrideDefaultColors ? playerSettings.colorSchemesSettings.GetSelectedColorScheme() : null, gamePlayModifiers, playerSettings.playerSpecificSettings, playerSettings.practiceSettings, "Exit", false, () => { }, (StandardLevelScenesTransitionSetupDataSO sceneTransition, LevelCompletionResults results) => { bool newHighScore = false; var mainFlowCoordinator = Resources.FindObjectsOfTypeAll <MainFlowCoordinator>().First(); RandomSongMenu randomSongMenu = BeatSaberUI.CreateFlowCoordinator <RandomSongMenu>(); if (results.levelEndAction == LevelCompletionResults.LevelEndAction.Restart) { Logger.log.Info("Restarting level"); return; } switch (results.levelEndStateType) { case LevelCompletionResults.LevelEndStateType.None: break; case LevelCompletionResults.LevelEndStateType.Cleared: UploadScore(levelDifficulty, results, out newHighScore); randomSongMenu.Show(beatmap, difficulty, levelDifficulty, results, newHighScore); Logger.log.Info("Showing menu"); break; case LevelCompletionResults.LevelEndStateType.Failed: Logger.log.Info("Showing menu"); randomSongMenu.Show(beatmap, difficulty, levelDifficulty, results, newHighScore); break; default: break; } }); }
public GameplayModifiersWrapper(GameplayModifiers modifiers) { _modifiers = modifiers; }
public static void HandleSongSelected(IPreviewBeatmapLevel previewBeatmapLevel, BeatmapDifficulty beatmapDifficulty, BeatmapCharacteristicSO beatmapCharacteristic, GameplayModifiers gameplayModifiers) { if (!MpLobbyConnectionTypePatch.IsPartyHost) { return; } _level = previewBeatmapLevel; _difficulty = beatmapDifficulty; HandleUpdate(); }
public void OnActiveSceneChanged(Scene oldScene, Scene newScene) { GameStatus gameStatus = statusManager.gameStatus; gameStatus.scene = newScene.name; if (newScene.name == "MenuCore") { // Menu gameStatus.scene = "Menu"; Gamemode.Init(); // TODO: get the current song, mode and mods while in menu gameStatus.ResetMapInfo(); gameStatus.ResetPerformance(); // Release references for AfterCutScoreBuffers that don't resolve due to player leaving the map before finishing. noteCutMapping.Clear(); statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "menu"); } else if (newScene.name == "GameCore") { // In game gameStatus.scene = "Song"; gamePause = FindFirstOrDefault <GamePause>(); scoreController = FindFirstOrDefault <ScoreController>(); gameplayManager = Resources.FindObjectsOfTypeAll <StandardLevelGameplayManager>().FirstOrDefault() as MonoBehaviour ?? Resources.FindObjectsOfTypeAll <MissionLevelGameplayManager>().FirstOrDefault(); beatmapObjectCallbackController = FindFirstOrDefault <BeatmapObjectCallbackController>(); gameplayModifiersSO = FindFirstOrDefault <GameplayModifiersModelSO>(); audioTimeSyncController = FindFirstOrDefault <AudioTimeSyncController>(); playerHeadAndObstacleInteraction = FindFirstOrDefault <PlayerHeadAndObstacleInteraction>(); gameEnergyCounter = FindFirstOrDefault <GameEnergyCounter>(); if (gameplayManager.GetType() == typeof(StandardLevelGameplayManager)) { Plugin.log.Info("Standard Level loaded"); standardLevelGameplayManager = FindFirstOrDefault <StandardLevelGameplayManager>(); // public event Action StandardLevelGameplayManager#levelFailedEvent; standardLevelGameplayManager.levelFailedEvent += OnLevelFailed; // public event Action StandardLevelGameplayManager#levelFinishedEvent; standardLevelGameplayManager.levelFinishedEvent += OnLevelFinished; } else if (gameplayManager.GetType() == typeof(MissionLevelGameplayManager)) { Plugin.log.Info("Mission Level loaded"); missionLevelGameplayManager = FindFirstOrDefault <MissionLevelGameplayManager>(); // public event Action StandardLevelGameplayManager#levelFailedEvent; missionLevelGameplayManager.levelFailedEvent += OnLevelFailed; // public event Action StandardLevelGameplayManager#levelFinishedEvent; missionLevelGameplayManager.levelFinishedEvent += OnLevelFinished; } gameplayCoreSceneSetupData = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData; // Register event listeners // public event Action GamePause#didPauseEvent; gamePause.didPauseEvent += OnGamePause; // public event Action GamePause#didResumeEvent; gamePause.didResumeEvent += OnGameResume; // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after AfterCutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int, int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; IDifficultyBeatmap diff = gameplayCoreSceneSetupData.difficultyBeatmap; IBeatmapLevel level = diff.level; gameStatus.partyMode = Gamemode.IsPartyActive; gameStatus.mode = Gamemode.GameMode; gameplayModifiers = gameplayCoreSceneSetupData.gameplayModifiers; PlayerSpecificSettings playerSettings = gameplayCoreSceneSetupData.playerSpecificSettings; PracticeSettings practiceSettings = gameplayCoreSceneSetupData.practiceSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; if (practiceSettings != null) { songSpeedMul = practiceSettings.songSpeedMul; } float modifierMultiplier = gameplayModifiersSO.GetTotalMultiplier(gameplayModifiers); gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.levelAuthorName = level.levelAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.noteJumpSpeed = diff.noteJumpMovementSpeed; // 13 is a magical number for the length of "custom_level_" gameStatus.songHash = level.levelID.StartsWith("custom_level_") && !level.levelID.EndsWith(" WIP") ? level.levelID.Substring(13) : null; gameStatus.levelId = level.levelID; gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f / songSpeedMul); gameStatus.length = (long)(level.beatmapLevelData.audioClip.length * 1000f / songSpeedMul); gameStatus.start = GetCurrentTime() - (long)(audioTimeSyncController.songTime * 1000f / songSpeedMul); if (practiceSettings != null) { gameStatus.start -= (long)(practiceSettings.startSongTime * 1000f / songSpeedMul); } gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.notesCount = diff.beatmapData.notesCount; gameStatus.bombsCount = diff.beatmapData.bombsCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.environmentName = level.environmentInfo.sceneInfo.sceneName; gameStatus.maxScore = gameplayModifiersSO.MaxModifiedScoreForMaxRawScore(ScoreModel.MaxRawScoreForNumberOfNotes(diff.beatmapData.notesCount), gameplayModifiers, gameplayModifiersSO); gameStatus.maxRank = RankModel.MaxRankForGameplayModifiers(gameplayModifiers, gameplayModifiersSO).ToString(); try { // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- var texture = level.GetCoverImageTexture2DAsync(CancellationToken.None).Result; var active = RenderTexture.active; var temporary = RenderTexture.GetTemporary( texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear ); Graphics.Blit(texture, temporary); RenderTexture.active = temporary; var cover = new Texture2D(texture.width, texture.height); cover.ReadPixels(new Rect(0, 0, temporary.width, temporary.height), 0, 0); cover.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); gameStatus.songCover = System.Convert.ToBase64String( ImageConversion.EncodeToPNG(cover) ); } catch { gameStatus.songCover = null; } gameStatus.ResetPerformance(); gameStatus.modifierMultiplier = modifierMultiplier; gameStatus.songSpeedMultiplier = songSpeedMul; gameStatus.batteryLives = gameEnergyCounter.batteryLives; gameStatus.modObstacles = gameplayModifiers.enabledObstacleType.ToString(); gameStatus.modInstaFail = gameplayModifiers.instaFail; gameStatus.modNoFail = gameplayModifiers.noFail; gameStatus.modBatteryEnergy = gameplayModifiers.batteryEnergy; gameStatus.modDisappearingArrows = gameplayModifiers.disappearingArrows; gameStatus.modNoBombs = gameplayModifiers.noBombs; gameStatus.modSongSpeed = gameplayModifiers.songSpeed.ToString(); gameStatus.modNoArrows = gameplayModifiers.noArrows; gameStatus.modGhostNotes = gameplayModifiers.ghostNotes; gameStatus.modFailOnSaberClash = gameplayModifiers.failOnSaberClash; gameStatus.modStrictAngles = gameplayModifiers.strictAngles; gameStatus.modFastNotes = gameplayModifiers.fastNotes; gameStatus.staticLights = playerSettings.staticLights; gameStatus.leftHanded = playerSettings.leftHanded; gameStatus.playerHeight = playerSettings.playerHeight; gameStatus.sfxVolume = playerSettings.sfxVolume; gameStatus.reduceDebris = playerSettings.reduceDebris; gameStatus.noHUD = playerSettings.noTextsAndHuds; gameStatus.advancedHUD = playerSettings.advancedHud; gameStatus.autoRestart = playerSettings.autoRestart; statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "songStart"); } }
protected virtual void Client_PlaySong(IPreviewBeatmapLevel level, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty, GameplayModifiers gameOptions, PlayerSpecificSettings playerOptions, OverrideEnvironmentSettings environmentSettings, ColorScheme colors, bool floatingScoreboard, bool streamSync, bool disablePause) { }
static void Prefix(StandardLevelScenesTransitionSetupDataSO __instance, IDifficultyBeatmap difficultyBeatmap, GameplayModifiers gameplayModifiers, PlayerSpecificSettings playerSpecificSettings, PracticeSettings practiceSettings, string backButtonText, bool useTestNoteCutSoundEffects) { Plugin.LevelData.GameplayCoreSceneSetupData = new GameplayCoreSceneSetupData(difficultyBeatmap, gameplayModifiers, playerSpecificSettings, practiceSettings, useTestNoteCutSoundEffects); Plugin.LevelData.IsSet = true; __instance.didFinishEvent -= __instance_didFinishEvent; __instance.didFinishEvent += __instance_didFinishEvent; }
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 })); } }
public void StartLevel(BeatmapLevelSO level, BeatmapCharacteristicSO characteristic, BeatmapDifficulty difficulty, GameplayModifiers modifiers, float startTime = 0f) { Client.Instance.playerInfo.playerComboBlocks = 0; Client.Instance.playerInfo.playerCutBlocks = 0; Client.Instance.playerInfo.playerEnergy = 0f; Client.Instance.playerInfo.playerScore = 0; MenuTransitionsHelperSO menuSceneSetupData = Resources.FindObjectsOfTypeAll <MenuTransitionsHelperSO>().FirstOrDefault(); if (menuSceneSetupData != null) { PlayerSpecificSettings playerSettings = Resources.FindObjectsOfTypeAll <PlayerDataModelSO>().FirstOrDefault().currentLocalPlayer.playerSpecificSettings; channelInfo.state = ChannelState.InGame; Client.Instance.playerInfo.playerState = PlayerState.Game; IDifficultyBeatmap difficultyBeatmap = level.GetDifficultyBeatmap(characteristic, difficulty, false); #if DEBUG Misc.Logger.Info($"Starting song: name={level.songName}, levelId={level.levelID}, difficulty={difficulty}"); #endif PracticeSettings practiceSettings = new PracticeSettings(PracticeSettings.defaultPracticeSettings); practiceSettings.songSpeedMul = modifiers.songSpeedMul; if (startTime > 1.5f) { practiceSettings.startSongTime = startTime + 1.5f; } Client.Instance.MessageReceived -= MessageReceived; try { BS_Utils.Gameplay.Gamemode.NextLevelIsIsolated("Beat Saber Multiplayer"); } catch { } menuSceneSetupData.StartStandardLevel(difficultyBeatmap, modifiers, playerSettings, (startTime > 1.5f ? practiceSettings : null), false, () => {}, (StandardLevelScenesTransitionSetupDataSO sender, LevelCompletionResults levelCompletionResults) => { InGameOnlineController.Instance.SongFinished(sender, levelCompletionResults, difficultyBeatmap, modifiers, (practiceSettings != null)); }); return; } else { Misc.Logger.Error("SceneSetupData is null!"); } }
public static bool HasPositiveModifiers(GameplayModifiers modifiers) { return(modifiers.disappearingArrows || modifiers.ghostNotes || modifiers.songSpeed == GameplayModifiers.SongSpeed.Faster); }
public async void HandleSongStart() { GameStatus gameStatus = statusManager.gameStatus; // Check for multiplayer early to abort if needed: gameplay controllers don't exist in multiplayer until later multiplayerSessionManager = FindFirstOrDefaultOptional <MultiplayerSessionManager>(); multiplayerController = FindFirstOrDefaultOptional <MultiplayerController>(); if (multiplayerSessionManager && multiplayerController) { Plugin.log.Debug("Multiplayer Level loaded"); // public event Action<DisconnectedReason> MultiplayerSessionManager#disconnectedEvent; multiplayerSessionManager.disconnectedEvent += OnMultiplayerDisconnected; // public event Action<State> MultiplayerController#stateChangedEvent; multiplayerController.stateChangedEvent += OnMultiplayerStateChanged; // Do nothing until the next state change to Gameplay. if (multiplayerController.state != MultiplayerController.State.Gameplay) { return; } multiplayerLocalActivePlayerFacade = FindFirstOrDefaultOptional <MultiplayerLocalActivePlayerFacade>(); if (multiplayerLocalActivePlayerFacade != null) { multiplayerLocalActivePlayerFacade.playerDidFinishEvent += OnMultiplayerLevelFinished; } } else if (!doDelayedSongStart) { doDelayedSongStart = true; return; } // `wants_to_play_next_level` is set for players who don't want to play the song aka want to spectate aka are not "active". `isSpectating` is apparently not spectating. gameStatus.scene = multiplayerSessionManager.isSpectating || !multiplayerSessionManager.LocalPlayerHasState(NetworkConstants.wantsToPlayNextLevel) ? "Spectator" : "Song"; gameStatus.multiplayer = multiplayerSessionManager.isConnectingOrConnected; pauseController = FindFirstOrDefaultOptional <PauseController>(); scoreController = FindFirstOrDefault <ScoreController>(); gameplayManager = FindFirstOrDefaultOptional <StandardLevelGameplayManager>() as MonoBehaviour ?? FindFirstOrDefaultOptional <MissionLevelGameplayManager>(); beatmapObjectCallbackController = FindFirstOrDefault <BeatmapObjectCallbackController>(); gameplayModifiersSO = FindFirstOrDefault <GameplayModifiersModelSO>(); audioTimeSyncController = FindFirstOrDefault <AudioTimeSyncController>(); playerHeadAndObstacleInteraction = (PlayerHeadAndObstacleInteraction)scoreControllerHeadAndObstacleInteractionField.GetValue(scoreController); gameSongController = FindFirstOrDefault <GameSongController>(); gameEnergyCounter = FindFirstOrDefault <GameEnergyCounter>(); if (multiplayerController) { // NOOP } else if (gameplayManager is StandardLevelGameplayManager) { Plugin.log.Debug("Standard Level loaded"); } else if (gameplayManager is MissionLevelGameplayManager) { Plugin.log.Debug("Mission Level loaded"); } gameplayCoreSceneSetupData = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData; // Register event listeners // PauseController doesn't exist in multiplayer if (pauseController != null) { // public event Action PauseController#didPauseEvent; pauseController.didPauseEvent += OnGamePause; // public event Action PauseController#didResumeEvent; pauseController.didResumeEvent += OnGameResume; } // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after AfterCutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int, int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; // public event Action GameSongController#songDidFinishEvent; gameSongController.songDidFinishEvent += OnLevelFinished; // public event Action GameEnergyCounter#gameEnergyDidReach0Event; gameEnergyCounter.gameEnergyDidReach0Event += OnEnergyDidReach0Event; if (gameplayManager is ILevelEndActions levelEndActions) { // event Action levelFailedEvent; levelEndActions.levelFailedEvent += OnLevelFailed; } IDifficultyBeatmap diff = gameplayCoreSceneSetupData.difficultyBeatmap; IBeatmapLevel level = diff.level; gameStatus.partyMode = Gamemode.IsPartyActive; gameStatus.mode = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName; gameplayModifiers = gameplayCoreSceneSetupData.gameplayModifiers; PlayerSpecificSettings playerSettings = gameplayCoreSceneSetupData.playerSpecificSettings; PracticeSettings practiceSettings = gameplayCoreSceneSetupData.practiceSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; if (practiceSettings != null) { songSpeedMul = practiceSettings.songSpeedMul; } // Generate NoteData to id mappings for backwards compatiblity with <1.12.1 noteToIdMapping = new NoteData[diff.beatmapData.cuttableNotesType + diff.beatmapData.bombsCount]; lastNoteId = 0; int beatmapObjectId = 0; var beatmapObjectsData = diff.beatmapData.beatmapObjectsData; foreach (BeatmapObjectData beatmapObjectData in beatmapObjectsData) { if (beatmapObjectData is NoteData noteData) { noteToIdMapping[beatmapObjectId++] = noteData; } } gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.levelAuthorName = level.levelAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.noteJumpSpeed = diff.noteJumpMovementSpeed; // 13 is "custom_level_" and 40 is the magic number for the length of the SHA-1 hash gameStatus.songHash = level.levelID.StartsWith("custom_level_") && !level.levelID.EndsWith(" WIP") ? level.levelID.Substring(13, 40) : null; gameStatus.levelId = level.levelID; gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f / songSpeedMul); gameStatus.length = (long)(level.beatmapLevelData.audioClip.length * 1000f / songSpeedMul); gameStatus.start = GetCurrentTime() - (long)(audioTimeSyncController.songTime * 1000f / songSpeedMul); if (practiceSettings != null) { gameStatus.start -= (long)(practiceSettings.startSongTime * 1000f / songSpeedMul); } gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.notesCount = diff.beatmapData.cuttableNotesType; gameStatus.bombsCount = diff.beatmapData.bombsCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.environmentName = level.environmentInfo.sceneInfo.sceneName; try { // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- var texture = (await level.GetCoverImageAsync(CancellationToken.None)).texture; var active = RenderTexture.active; var temporary = RenderTexture.GetTemporary( texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear ); Graphics.Blit(texture, temporary); RenderTexture.active = temporary; var cover = new Texture2D(texture.width, texture.height); cover.ReadPixels(new Rect(0, 0, temporary.width, temporary.height), 0, 0); cover.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); gameStatus.songCover = System.Convert.ToBase64String( ImageConversion.EncodeToPNG(cover) ); } catch { gameStatus.songCover = null; } gameStatus.ResetPerformance(); UpdateModMultiplier(); gameStatus.songSpeedMultiplier = songSpeedMul; gameStatus.batteryLives = gameEnergyCounter.batteryLives; gameStatus.modObstacles = gameplayModifiers.enabledObstacleType.ToString(); gameStatus.modInstaFail = gameplayModifiers.instaFail; gameStatus.modNoFail = gameplayModifiers.noFailOn0Energy; gameStatus.modBatteryEnergy = gameplayModifiers.energyType == GameplayModifiers.EnergyType.Battery; gameStatus.modDisappearingArrows = gameplayModifiers.disappearingArrows; gameStatus.modNoBombs = gameplayModifiers.noBombs; gameStatus.modSongSpeed = gameplayModifiers.songSpeed.ToString(); gameStatus.modNoArrows = gameplayModifiers.noArrows; gameStatus.modGhostNotes = gameplayModifiers.ghostNotes; gameStatus.modFailOnSaberClash = gameplayModifiers.failOnSaberClash; gameStatus.modStrictAngles = gameplayModifiers.strictAngles; gameStatus.modFastNotes = gameplayModifiers.fastNotes; gameStatus.staticLights = playerSettings.staticLights; gameStatus.leftHanded = playerSettings.leftHanded; gameStatus.playerHeight = playerSettings.playerHeight; gameStatus.sfxVolume = playerSettings.sfxVolume; gameStatus.reduceDebris = playerSettings.reduceDebris; gameStatus.noHUD = playerSettings.noTextsAndHuds; gameStatus.advancedHUD = playerSettings.advancedHud; gameStatus.autoRestart = playerSettings.autoRestart; statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "songStart"); }
public static float GetModifiedAcc(float accuracy, GameplayModifiersModelSO modifiersModel, GameplayModifiers modifiers) { return(modifiersModel.GetTotalMultiplier(modifiers) * accuracy); }
static bool Prefix(ref string userId, ref BeatmapIdentifierNetSerializable beatmapId, ref GameplayModifiers gameplayModifiers, ref float startTime, LobbyGameStateController __instance) { Plugin.Log?.Debug($"LobbyGameStateController.HandleMenuRpcManagerStartedLevel"); if (SongCore.Loader.GetLevelById(beatmapId.levelID) != null) { Plugin.Log?.Debug($"Level is loaded."); } LobbyGameStateController = __instance; LastUserId = userId; return(true); }
public CustomGameplayModifiers(GameplayModifiers gameplayModifiers) : base(gameplayModifiers.demoNoFail, gameplayModifiers.demoNoObstacles, gameplayModifiers.energyType, gameplayModifiers.noFail, gameplayModifiers.instaFail, gameplayModifiers.failOnSaberClash, gameplayModifiers.enabledObstacleType, gameplayModifiers.noBombs, gameplayModifiers.fastNotes, gameplayModifiers.strictAngles, gameplayModifiers.disappearingArrows, gameplayModifiers.songSpeed, gameplayModifiers.noArrows, gameplayModifiers.ghostNotes) { }