예제 #1
0
        public virtual async UniTask LoadServiceStateAsync(GameStateMap stateMap)
        {
            var state = stateMap.GetState <GameState>();

            if (state is null)
            {
                ResetService();
                return;
            }

            // Force stop and cancel all running commands to prevent state mutation while loading other services.
            Stop(); CancelCommands();

            executedPlayedCommand = state.ExecutedPlayedCommand;

            if (state.Playing) // The playback is resumed (when necessary) after other services are loaded.
            {
                if (stateManager.RollbackInProgress)
                {
                    stateManager.OnRollbackFinished += PlayAfterRollback;
                }
                else
                {
                    stateManager.OnGameLoadFinished += PlayAfterLoad;
                }
            }

            if (state.GosubReturnSpots != null && state.GosubReturnSpots.Count > 0)
            {
                GosubReturnSpots = new Stack <PlaybackSpot>(state.GosubReturnSpots);
            }
            else
            {
                GosubReturnSpots.Clear();
            }

            if (!string.IsNullOrEmpty(stateMap.PlaybackSpot.ScriptName))
            {
                if (PlayedScript is null || !stateMap.PlaybackSpot.ScriptName.EqualsFast(PlayedScript.Name))
                {
                    PlayedScript = await scriptManager.LoadScriptAsync(stateMap.PlaybackSpot.ScriptName);

                    Playlist    = new ScriptPlaylist(PlayedScript, scriptManager);
                    PlayedIndex = Playlist.IndexOf(stateMap.PlaybackSpot);
                    Debug.Assert(PlayedIndex >= 0, $"Failed to load script player state: `{stateMap.PlaybackSpot}` doesn't exist in the current playlist.");
                    var endIndex = providerConfig.ResourcePolicy == ResourcePolicy.Static ? Playlist.Count - 1 :
                                   Mathf.Min(PlayedIndex + providerConfig.DynamicPolicySteps, Playlist.Count - 1);
                    await Playlist.PreloadResourcesAsync(PlayedIndex, endIndex);
                }
                else
                {
                    PlayedIndex = Playlist.IndexOf(stateMap.PlaybackSpot);
                }
            }
예제 #2
0
        /// <summary>
        /// Performs hot-reload of the currently played script.
        /// </summary>
        public static async UniTask ReloadPlayedScriptAsync()
        {
            if (player?.Playlist is null || player.Playlist.Count == 0 || !player.PlayedScript)
            {
                Debug.LogError("Failed to perform hot reload: script player is not available or no script is currently played.");
                return;
            }

            var requireReload = string.IsNullOrEmpty(AssetDatabase.GetAssetPath(player.PlayedScript));

            if (requireReload)                         // In case the played script is stored outside of Unity project, force reload it.
            {
                var prevLineHashes = playedLineHashes; // Otherwise they're overridden when playing the loaded script below.
                var scriptName     = player.PlayedScript.Name;
                scriptManager.UnloadScript(scriptName);
                var script = await scriptManager.LoadScriptAsync(scriptName);

                player.Play(script, player.PlaybackSpot.LineIndex, player.PlaybackSpot.InlineIndex);
                playedLineHashes = prevLineHashes;
            }

            var lastPlayedLineIndex = (player.PlayedCommand ?? player.Playlist.Last()).PlaybackSpot.LineIndex;

            // Find the first modified line in the updated script (before the played line).
            var rollbackIndex = -1;

            for (int i = 0; i < lastPlayedLineIndex; i++)
            {
                if (!player.PlayedScript.Lines.IsIndexValid(i)) // The updated script ends before the currently played line.
                {
                    rollbackIndex = player.Playlist.GetCommandBeforeLine(i - 1, 0)?.PlaybackSpot.LineIndex ?? 0;
                    break;
                }

                if (playedLineHashes?.IsIndexValid(i) ?? false)
                {
                    var oldLineHash = playedLineHashes[i];
                    var newLine     = player.PlayedScript.Lines[i];
                    if (oldLineHash.EqualsFast(newLine.LineHash))
                    {
                        continue;
                    }
                }

                rollbackIndex = player.Playlist.GetCommandBeforeLine(i, 0)?.PlaybackSpot.LineIndex ?? 0;
                break;
            }

            if (rollbackIndex > -1) // Script has changed before the played line.
            // Rollback to the line before the first modified one.
            {
                await stateManager.RollbackAsync(s => s.PlaybackSpot.LineIndex == rollbackIndex);
            }

            // Update the playlist and play.
            var resumeLineIndex = rollbackIndex > -1 ? rollbackIndex : lastPlayedLineIndex;
            var playlist        = new ScriptPlaylist(player.PlayedScript, scriptManager);
            var playlistIndex   = player.Playlist.FindIndex(c => c.PlaybackSpot.LineIndex == resumeLineIndex);

            if (playlistIndex < 0)
            {
                playlistIndex = 0;
            }
            await playlist.PreloadResourcesAsync(playlistIndex, playlist.Count - 1);

            player.Play(playlist, playlistIndex);

            if (player.WaitingForInput)
            {
                player.SetWaitingForInputEnabled(false);
            }
        }