public async UniTask <GameStateMap> SaveGameAsync(string slotId) { if (rollbackStack.Count == 0 || rollbackStack.Peek() is null) { PushRollbackSnapshot(false); } var quick = slotId.StartsWithFast(Configuration.QuickSaveSlotMask.GetBefore("{")); OnGameSaveStarted?.Invoke(new GameSaveLoadArgs(slotId, quick)); var state = new GameStateMap(rollbackStack.Peek()); state.SaveDateTime = DateTime.Now; state.Thumbnail = Engine.GetService <ICameraManager>().CaptureThumbnail(); var lastZero = rollbackStack.FirstOrDefault(s => s.PlaybackSpot.InlineIndex == 0); // Required when changing locale. bool filter(GameStateMap s) => (Configuration.EnableStateRollback && Configuration.SavedRollbackSteps > 0 && s.PlayerRollbackAllowed) || s == lastZero; state.RollbackStackJson = rollbackStack.ToJson(Configuration.SavedRollbackSteps, filter); await GameStateSlotManager.SaveAsync(slotId, state); // Also save global state on every game save. await SaveGlobalStateAsync(); OnGameSaveFinished?.Invoke(new GameSaveLoadArgs(slotId, quick)); return(state); }
public virtual async UniTask LoadServiceStateAsync(GameStateMap stateMap) { var state = stateMap.GetState <GameState>(); if (state is null) { RemoveAllActors(); return; } // Remove actors that doesn't exist in the serialized state. if (ManagedActors.Count > 0) { foreach (var actorId in ManagedActors.Keys.ToList()) { if (!state.ActorsMap.ContainsKey(actorId)) { RemoveActor(actorId); } } } foreach (var kv in state.ActorsMap) { var actor = await GetOrAddActorAsync(kv.Key); kv.Value.ApplyToActor(actor); } }
/// <summary> /// Saves current game state to the specified save slot. /// </summary> public async Task <GameStateMap> SaveGameAsync(string slotId) { if (rollbackStateStack.Count == 0 || rollbackStateStack.Peek() is null) { Debug.LogError("Failed to save game state: rollback stack is empty."); return(null); } var quick = slotId.StartsWithFast(config.QuickSaveSlotMask.GetBefore("{")); OnGameSaveStarted?.Invoke(new GameSaveLoadArgs(slotId, quick)); var state = new GameStateMap(rollbackStateStack.Peek()); state.SaveDateTime = DateTime.Now; state.Thumbnail = Engine.GetService <CameraManager>().CaptureThumbnail(); if (config.StateRollbackMode == StateRollbackMode.Full && config.SavedRollbackSteps > 0) { state.RollbackStackJson = rollbackStateStack.ToJson(config.SavedRollbackSteps); } await GameStateSlotManager.SaveAsync(slotId, state); // Also save global state on every game save. await SaveGlobalStateAsync(); OnGameSaveFinished?.Invoke(new GameSaveLoadArgs(slotId, quick)); return(state); }
protected virtual async UniTask PerformOnGameDeserializeTasksAsync(GameStateMap state) { for (int i = onGameDeserializeTasks.Count - 1; i >= 0; i--) { await onGameDeserializeTasks[i](state); } }
protected virtual void PerformOnGameSerializeTasks(GameStateMap state) { for (int i = onGameSerializeTasks.Count - 1; i >= 0; i--) { onGameSerializeTasks[i](state); } }
public override async Task LoadServiceStateAsync(GameStateMap stateMap) { await base.LoadServiceStateAsync(stateMap); var state = stateMap.GetState <GameState>(); if (state is null) { if (charIdToAvatarPathMap.Count > 0) { foreach (var charId in charIdToAvatarPathMap.Keys.ToList()) { RemoveAvatarTextureFor(charId); } } return; } // Remove non-existing avatar mappings. if (charIdToAvatarPathMap.Count > 0) { foreach (var charId in charIdToAvatarPathMap.Keys.ToList()) { if (!state.CharIdToAvatarPathMap.ContainsKey(charId)) { RemoveAvatarTextureFor(charId); } } } // Add new or changed avatar mappings. foreach (var kv in state.CharIdToAvatarPathMap) { SetAvatarTexturePathFor(kv.Key, kv.Value); } }
public virtual async Task LoadServiceStateAsync(GameStateMap stateMap) { var state = stateMap.GetState <GameState>(); if (state is null) { RemoveAllActors(); return; } // Remove actors that doesn't exist in the serialized state. if (ManagedActors.Count > 0) { foreach (var actorId in ManagedActors.Keys.ToList()) { if (!state.ActorState.Exists(s => s.Id.EqualsFast(actorId))) { RemoveActor(actorId); } } } foreach (var actorState in state.ActorState) { var actor = await GetOrAddActorAsync(actorState.Id); actorState.ApplyToActor(actor); } }
public virtual async UniTask <GameStateMap> SaveGameAsync(string slotId) { var quick = slotId.StartsWithFast(Configuration.QuickSaveSlotMask.GetBefore("{")); OnGameSaveStarted?.Invoke(new GameSaveLoadArgs(slotId, quick)); var state = new GameStateMap(); await scriptPlayer.SynchronizeAndDoAsync(DoSaveAfterSync); OnGameSaveFinished?.Invoke(new GameSaveLoadArgs(slotId, quick)); return(state); async UniTask DoSaveAfterSync() { state.SaveDateTime = DateTime.Now; state.Thumbnail = cameraManager.CaptureThumbnail(); SaveAllServicesToState <IStatefulService <GameStateMap>, GameStateMap>(state); PerformOnGameSerializeTasks(state); state.RollbackStackJson = SerializeRollbackStack(); await GameSlotManager.SaveAsync(slotId, state); // Also save global state on every game save. await SaveGlobalAsync(); } }
public override async UniTask LoadServiceStateAsync(GameStateMap stateMap) { await base.LoadServiceStateAsync(stateMap); var state = stateMap.GetState <GameState>() ?? new GameState(); DefaultPrinterId = state.DefaultPrinterId ?? Configuration.DefaultPrinterId; }
public void Push(GameStateMap item) { rollbackList.AddFirst(item); if (rollbackList.Count > Capacity) { rollbackList.RemoveLast(); } }
public override void SaveServiceState(GameStateMap stateMap) { base.SaveServiceState(stateMap); var gameState = new GameState { DefaultPrinterId = DefaultPrinterId ?? Configuration.DefaultPrinterId }; stateMap.SetState(gameState); }
public override void SaveServiceState(GameStateMap stateMap) { base.SaveServiceState(stateMap); var gameState = new GameState { CharIdToAvatarPathMap = new SerializableLiteralStringMap(charIdToAvatarPathMap) }; stateMap.SetState(gameState); }
public override async Task SaveServiceStateAsync(GameStateMap stateMap) { await base.SaveServiceStateAsync(stateMap); var gameState = new GameState() { DefaultPrinterId = DefaultPrinterId ?? Configuration.DefaultPrinterId }; stateMap.SetState(gameState); }
public override async Task SaveServiceStateAsync(GameStateMap stateMap) { await base.SaveServiceStateAsync(stateMap); var gameState = new GameState() { CharIdToAvatarPathMap = new SerializableLiteralStringMap(charIdToAvatarPathMap) }; stateMap.SetState(gameState); }
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); } }
public void SaveServiceState(GameStateMap stateMap) { var gameState = new GameState() { Playing = Playing, WaitingForInput = WaitingForInput, GosubReturnSpots = GosubReturnSpots.Count > 0 ? GosubReturnSpots.Reverse().ToList() : null // Stack is reversed on enum. }; stateMap.PlaybackSpot = PlaybackSpot; stateMap.SetState(gameState); }
public virtual void SaveServiceState(GameStateMap stateMap) { var state = new GameState(); foreach (var kv in ManagedActors) { var actorState = new TState(); actorState.OverwriteFromActor(kv.Value); state.ActorsMap.Add(kv.Key, actorState); } stateMap.SetState(state); }
public virtual Task SaveServiceStateAsync(GameStateMap stateMap) { var state = new GameState(); foreach (var kv in ManagedActors) { var actorState = new TState(); actorState.OverwriteFromActor(kv.Value); state.ActorState.Add(actorState); } stateMap.SetState(state); return(Task.CompletedTask); }
public Task SaveServiceStateAsync(GameStateMap stateMap) { var gameState = new GameState() { PlayedScriptName = PlayedScript?.Name, PlayedIndex = PlayedIndex, IsWaitingForInput = IsWaitingForInput, LastGosubReturnSpots = LastGosubReturnSpots.Count > 0 ? LastGosubReturnSpots.Reverse().ToList() : null // Stack is reversed on enum. }; stateMap.PlaybackSpot = PlaybackSpot; stateMap.SetState(gameState); return(Task.CompletedTask); }
private async Task PushRollbackSnapshotAsync(Commands.Command executedCommand) { var state = new GameStateMap(); state.SaveDateTime = DateTime.Now; await SaveAllServicesToStateAsync <IStatefulService <GameStateMap>, GameStateMap>(state); foreach (var task in onGameSerializeTasks) { await task(state); } rollbackStateStack.Push(state); }
public async Task LoadServiceStateAsync(GameStateMap stateMap) { var state = stateMap.GetState <GameState>(); if (state is null) { ResetService(); return; } Stop(true); PlayedIndex = state.PlayedIndex; SetWaitingForInputActive(state.IsWaitingForInput); if (state.LastGosubReturnSpots != null && state.LastGosubReturnSpots.Count > 0) { LastGosubReturnSpots = new Stack <PlaybackSpot>(state.LastGosubReturnSpots); } else { LastGosubReturnSpots.Clear(); } if (!string.IsNullOrEmpty(state.PlayedScriptName)) { if (PlayedScript is null || !state.PlayedScriptName.EqualsFast(PlayedScript.Name)) { PlayedScript = await scriptManager.LoadScriptAsync(state.PlayedScriptName); Playlist = new ScriptPlaylist(PlayedScript); var endIndex = providerManager.ResourcePolicy == ResourcePolicy.Static ? Playlist.Count - 1 : Mathf.Min(PlayedIndex + providerManager.DynamicPolicySteps, Playlist.Count - 1); await Playlist.HoldResourcesAsync(PlayedIndex, endIndex); } // Start playback and force waiting for input to prevent looping same command when performing state rollback. if (stateManager.RollbackInProgress) { SetWaitingForInputActive(true); Play(); } } else { Playlist.Clear(); PlayedScript = null; } }
public void PushRollbackSnapshot(bool allowPlayerRollback) { var state = new GameStateMap(); state.SaveDateTime = DateTime.Now; state.PlayerRollbackAllowed = allowPlayerRollback; SaveAllServicesToState <IStatefulService <GameStateMap>, GameStateMap>(state); for (int i = onGameSerializeTasks.Count - 1; i >= 0; i--) { onGameSerializeTasks[i](state); } rollbackStack.Push(state); }
public virtual void PushRollbackSnapshot(bool allowPlayerRollback) { if (RollbackStack is null) { return; } var state = new GameStateMap(); state.SaveDateTime = DateTime.Now; state.PlayerRollbackAllowed = allowPlayerRollback; SaveAllServicesToState <IStatefulService <GameStateMap>, GameStateMap>(state); PerformOnGameSerializeTasks(state); RollbackStack.Push(state); }
protected virtual async UniTask RollbackToStateAsync(GameStateMap state) { rollbackTaskQueue.Enqueue(state); OnRollbackStarted?.Invoke(); while (rollbackTaskQueue.Peek() != state) { await AsyncUtils.WaitEndOfFrame; } await LoadAllServicesFromStateAsync <IStatefulService <GameStateMap>, GameStateMap>(state); await PerformOnGameDeserializeTasksAsync(state); rollbackTaskQueue.Dequeue(); OnRollbackFinished?.Invoke(); }
private async UniTask RollbackToStateAsync(GameStateMap state) { rollbackTaskQueue.Enqueue(state); OnRollbackStarted?.Invoke(); while (rollbackTaskQueue.Peek() != state) { await AsyncUtils.WaitEndOfFrame; } await LoadAllServicesFromStateAsync <IStatefulService <GameStateMap>, GameStateMap>(state); for (int i = onGameDeserializeTasks.Count - 1; i >= 0; i--) { await onGameDeserializeTasks[i](state); } rollbackTaskQueue.Dequeue(); OnRollbackFinished?.Invoke(); }
private async Task RollbackToStateAsync(GameStateMap state) { rollbackTaskQueue.Enqueue(state); OnRollbackStarted?.Invoke(); while (rollbackTaskQueue.Peek() != state) { await waitForFrame; } await LoadAllServicesFromStateAsync <IStatefulService <GameStateMap>, GameStateMap>(state); foreach (var task in onGameDeserializeTasks) { await task(state); } rollbackTaskQueue.Dequeue(); OnRollbackFinished?.Invoke(); }
public virtual async UniTask <GameStateMap> SaveGameAsync(string slotId) { var quick = slotId.StartsWithFast(Configuration.QuickSaveSlotMask.GetBefore("{")); OnGameSaveStarted?.Invoke(new GameSaveLoadArgs(slotId, quick)); var state = new GameStateMap(); await scriptPlayer.SynchronizeAndDoAsync(DoSaveAfterSync); OnGameSaveFinished?.Invoke(new GameSaveLoadArgs(slotId, quick)); return(state); async UniTask DoSaveAfterSync() { state.SaveDateTime = DateTime.Now; state.Thumbnail = cameraManager.CaptureThumbnail(); SaveAllServicesToState <IStatefulService <GameStateMap>, GameStateMap>(state); for (int i = onGameSerializeTasks.Count - 1; i >= 0; i--) { onGameSerializeTasks[i](state); } if (RollbackStack != null) { // Closest spot with zero inline index is used when changing locale (UI/GameSettings/LanguageDropdown.cs). var nearestStartLineSpot = RollbackStack.FirstOrDefault(s => s.PlaybackSpot.InlineIndex == 0); bool SelectSerializedSnapshots(GameStateMap s) => s.PlayerRollbackAllowed || s == nearestStartLineSpot; state.RollbackStackJson = RollbackStack.ToJson(Configuration.SavedRollbackSteps, SelectSerializedSnapshots); } await GameStateSlotManager.SaveAsync(slotId, state); // Also save global state on every game save. await SaveGlobalStateAsync(); } }