Skip to content

Commit

Permalink
More features & fixes
Browse files Browse the repository at this point in the history
* Save Instance Managers now only get created if there is data present for them.
Or when a new saved prefab gets spawned.
* Fixed issue in initialization of Saveables, hasIdentification now gets lazy initialization upon first load.
* Added support for spawning Saved Instances in duplicated scenes. You are required to create a Save Instance Manager with
a custom ID for a duplicate scene.
  • Loading branch information
AlexMeesters committed Feb 17, 2020
1 parent afed1f0 commit 721fc90
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,6 @@ private void Awake()
{
SaveMaster.AddListener(this);
}

hasIdentification = !string.IsNullOrEmpty(saveIdentification);
}

private void OnDestroy()
Expand Down Expand Up @@ -408,12 +406,6 @@ public void OnSaveRequest(SaveGame saveGame)
// Request is sent by the Save System
public void OnLoadRequest(SaveGame saveGame)
{
if (!hasIdentification)
{
Debug.Log("No identification!");
return;
}

if (loadOnce && hasLoaded)
{
return;
Expand All @@ -423,6 +415,13 @@ public void OnLoadRequest(SaveGame saveGame)
// Ensure it only loads once with the loadOnce
// Parameter
hasLoaded = true;
hasIdentification = !string.IsNullOrEmpty(saveIdentification);
}

if (!hasIdentification)
{
Debug.Log("No identification!");
return;
}

int componentCount = saveableComponentIDs.Count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Lowscope.Saving.Enums;
using Lowscope.Saving.Data;
using UnityEngine.SceneManagement;
using System;

namespace Lowscope.Saving.Core
{
Expand All @@ -21,6 +22,10 @@ public class SaveInstanceManager : MonoBehaviour, ISaveable
private int spawnCountHistory;
private int changesMade;

public string SceneID { set; get; }
public Saveable Saveable { set; get; }
public int LoadedIDCount { get { return loadedIDs.Count; } }

[System.Serializable]
public class SaveData
{
Expand Down Expand Up @@ -123,7 +128,7 @@ public SavedInstance SpawnObject(InstanceSource source, string filePath, string
// Then we give it a new identification, and we store it into our spawninfo array so we know to spawn it again.
if (string.IsNullOrEmpty(saveIdentification))
{
saveable.SaveIdentification = string.Format("{0}-{1}-{2}", this.gameObject.scene.name, saveable.name, spawnCountHistory);
saveable.SaveIdentification = string.Format("{0}-{1}-{2}", SceneID, saveable.name, spawnCountHistory);

spawnInfo.Add(savedInstance, new SpawnInfo()
{
Expand Down
88 changes: 77 additions & 11 deletions Assets/Plugins/Lowscope/ComponentSaveSystem/SaveMaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ public class SaveMaster : MonoBehaviour
private static SaveMaster instance;

private static GameObject saveMasterTemplate;
private static Dictionary<string, SaveInstanceManager> saveInstanceManagers
= new Dictionary<string, SaveInstanceManager>();

// Used to track duplicate scenes.
private static Dictionary<string, int> loadedSceneNames = new Dictionary<string, int>();
private static HashSet<int> duplicatedSceneHandles = new HashSet<int>();

private static Dictionary<int, SaveInstanceManager> saveInstanceManagers
= new Dictionary<int, SaveInstanceManager>();

private static bool isQuittingGame;

Expand Down Expand Up @@ -53,22 +58,71 @@ private static void CreateInstance()

private static void OnSceneUnloaded(Scene scene)
{
if (saveInstanceManagers.ContainsKey(scene.name))
// If it is a duplicate scene, we just remove this handle.
if (duplicatedSceneHandles.Contains(scene.handle))
{
duplicatedSceneHandles.Remove(scene.handle);
}
else
{
if (loadedSceneNames.ContainsKey(scene.name))
{
loadedSceneNames.Remove(scene.name);
}
}

if (saveInstanceManagers.ContainsKey(scene.handle))
{
saveInstanceManagers.Remove(scene.name);
saveInstanceManagers.Remove(scene.handle);
}
}

private static void OnSceneLoaded(Scene scene, LoadSceneMode arg1)
{
if (!saveInstanceManagers.ContainsKey(scene.name))
// Store a refeference to a non-duplicate scene
if (!loadedSceneNames.ContainsKey(scene.name))
{
SpawnInstanceManager(scene);
loadedSceneNames.Add(scene.name, scene.handle);
}
else
{
// These scenes are marked as duplicates. They need special treatment for saving.
duplicatedSceneHandles.Add(scene.handle);
}

// Dont create save instance manager if there are no saved instances in the scene.
if (string.IsNullOrEmpty(activeSaveGame.Get(string.Format("SaveMaster-{0}-IM", scene.name))))
{
return;
}

if (!saveInstanceManagers.ContainsKey(scene.handle))
{
var instanceManager = SpawnInstanceManager(scene);
}
}

private static SaveInstanceManager SpawnInstanceManager(Scene scene)
/// <summary>
/// You only need to call this for scenes with a duplicate name. If you have a duplicate ID, you can then
/// assign a ID to it. And it will save the data of the saveable to that ID instead.
/// </summary>
/// <param name="scene"> </param>
/// <param name="id"> Add a extra indentification for the scene. Useful for duplicated scenes. </param>
/// <returns></returns>
public static SaveInstanceManager SpawnInstanceManager(Scene scene, string id = "")
{
// Safety precautions.
if (!string.IsNullOrEmpty(id) && duplicatedSceneHandles.Contains(scene.handle))
{
duplicatedSceneHandles.Remove(scene.handle);
}

// Already exists
if (saveInstanceManagers.ContainsKey(scene.handle))
{
return null;
}

// We spawn a game object seperately, so we can keep it disabled during configuration.
// This prevents any UnityEngine calls such as Awake or Start
var go = new GameObject("Save Instance Manager");
Expand All @@ -78,9 +132,14 @@ private static SaveInstanceManager SpawnInstanceManager(Scene scene)
var saveable = go.AddComponent<Saveable>();
SceneManager.MoveGameObjectToScene(go, scene);

saveable.SaveIdentification = string.Format("{0}-{1}", "SaveMaster", scene.name);
string saveID = string.IsNullOrEmpty(id) ? scene.name : string.Format("{0}-{1}", scene.name, id);

saveable.SaveIdentification = string.Format("{0}-{1}", "SaveMaster", saveID);
saveable.AddSaveableComponent("IM", instanceManager, true);
saveInstanceManagers.Add(scene.name, instanceManager);
saveInstanceManagers.Add(scene.handle, instanceManager);

instanceManager.SceneID = saveID;
instanceManager.Saveable = saveable;

go.gameObject.SetActive(true);
return instanceManager;
Expand Down Expand Up @@ -582,10 +641,17 @@ public static GameObject SpawnSavedPrefab(InstanceSource source, string filePath
if (scene == default(Scene))
{
scene = SceneManager.GetActiveScene();
}

if (duplicatedSceneHandles.Contains(scene.handle))
{
Debug.Log(string.Format("Following scene has a duplicate name: {0}. " +
"Ensure to call SaveMaster.SpawnInstanceManager(scene, id) with a custom ID after spawning the scene.", scene.name));
scene = SceneManager.GetActiveScene();
}

SaveInstanceManager saveIM;
if (!saveInstanceManagers.TryGetValue(scene.name, out saveIM))
if (!saveInstanceManagers.TryGetValue(scene.handle, out saveIM))
{
saveIM = SpawnInstanceManager(scene);
}
Expand Down Expand Up @@ -748,7 +814,7 @@ private static void ClearActiveSavedPrefabs()
Scene scene = SceneManager.GetSceneAt(i);
SaveInstanceManager saveIM;

if (saveInstanceManagers.TryGetValue(scene.name, out saveIM))
if (saveInstanceManagers.TryGetValue(scene.handle, out saveIM))
{
saveIM.DestroyAllObjects();
}
Expand Down

0 comments on commit 721fc90

Please sign in to comment.