An Example or Tutorial Request: Multi Profiles/Save Slots

Easy Save 2 has been replaced by Easy Save 3, so is no longer supported.
Locked
Shockwolf
Posts: 14
Joined: Thu Feb 09, 2017 7:09 am

An Example or Tutorial Request: Multi Profiles/Save Slots

Post by Shockwolf »

Hi,

I was going to request this under the Examples and Tutorials section, but alas it appears to be locked with no sign on the door. :roll:

Anyway, is there any chance of an example or tutorial on how to set up multiple user profiles that save seperate instances of the game/variables for each user, please? Or just at least a list of multiple Game Save Slots that do more or less the same thing?

Its a pretty standard feature for most games, so I'm very surprised not to have seen an example or tutorial for this already. :?

Cheers!
Regards, SW.
User avatar
Joel
Moodkie Staff
Posts: 4826
Joined: Wed Nov 07, 2012 10:32 pm

Re: An Example or Tutorial Request: Multi Profiles/Save Slo

Post by Joel »

Hi there,

There's a thread at the top of the forums where you can request examples that you would like to see. However, I'll respond to this request here.

We've not created an example for this because there's not much to explain aside from the GUI side of things (which is outside the scope of Easy Save).

To create a profile system you simply need to save each piece of save data to a different filename (or even a different folder if you prefer). Then you can use ES2.GetFiles or ES2.GetFolders to get an array of profiles.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Shockwolf
Posts: 14
Joined: Thu Feb 09, 2017 7:09 am

Re: An Example or Tutorial Request: Multi Profiles/Save Slo

Post by Shockwolf »

Hi Joel,

And thanks for the reply.

I guess instead of using a metaphore, I should have just outright said that your forum will not let me post in that section for some reason. No reply or post buttons are there when I log in, they disappear. I figured you must of locked it for some reason, but perhaps you don't realise there is a problem? :roll:

I can figure out how to make a menu/GUI for multiple saves and I already figured out that saving to different file names and locations would be one way, but that would need to be at the press of a button, correct?
But what about saving things on the fly during gameplay? How is EasySave going to know which player is playing and in which world for example? Like a smart Auto Save that knows which Game World and Player is which.

I'm building a Survival Game that I intend will have some simularities to Minecraft and 7 Days to Die. I want the way my game saves and loads to be the same as those titles. So I will want the player to be able create multiple saves/worlds. When they play it saves data on the fly as things change without actually pressing any save buttons. When they quit the game, everything is saved automatically, so when they select that game again, its all loaded back up and a way they go. And then they could still keep that game but start a new one or many more and they are all saved independant of each other, again without any press of a save button, only a load button for each world/save created.

Can this be done with EasySave?

Cheers.
Regards, SW.
User avatar
Joel
Moodkie Staff
Posts: 4826
Joined: Wed Nov 07, 2012 10:32 pm

Re: An Example or Tutorial Request: Multi Profiles/Save Slo

Post by Joel »

Hi there,

Thanks for the clarification. For some reason you weren't granted the forum permissions when your account was confirmed, but I've manually applied the permissions so you should be able to post in the Examples forum now.

When your user selects the profile which they want to use, you can put the profile name into a static variable and use this whenever you save/load. i.e. something along the lines of:
// When your user selects a profile, put the profile name into this variable.
// Static variables are not reset when you change scenes, so it doesn't matter if you set this in a different scene.
public static string profile = null;

public void Save()
{
    if(profile == null)
        Debug.LogError("Profile has not been set");
    // Your save calls here.
    ES2.Save(123, profile+"?tag=myInt");
}

public void Load()
{
    if(profile == null)
        Debug.LogError("Profile has not been set");
    if(ES2.Exists(profile))
    {
        // Your Load calls here.
        myData = ES2.Load<int>(profile+"?tag=myInt");
    }
}
Hope this helps!

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Shockwolf
Posts: 14
Joined: Thu Feb 09, 2017 7:09 am

Re: An Example or Tutorial Request: Multi Profiles/Save Slo

Post by Shockwolf »

I was hoping for something a lot more elaborate to be honest, however your script example did get my noggin rolling with ideas, so thanks for that. "Ideas" that I would like to share with other Programming N00bs like myself. And it's a lot more to do with coding than the GUI side of things. Feel free to add this to your Tutorials Section. :geek:

So here's basically what I did...

The idea I had was to have a Script that manages Everything to do with Player Profiles and then use it to communicate with other scripts that use EasySave to help them determine the Save Path they need to use. The Players name a Profile and then either Create a New Game(Which deletes any active profile's folder and starts a fresh game) or Load the Saved Game and then Sets this Profile as active.

Having a total of 6 Profiles available, after the player chooses one by naming and choosing a launch option, the script would then set that Profile as active using an Integer and save it to a file with EasySave. It would then Create a folder for that Profile e.g: "Profile1" and inside it would save the name of the profile, typed by the player to another file using EasySave. That way this information could be recalled at runtime and loaded and shared publicly with other scripts.

In a Start Scene that's loaded first before the main game Scene, I created a menu with a button Labelled: "Create or Load Game". Pressing this fires a function named "ToggleProfileGUI" in a Script I named "ProfileMenuManagement"(The script that manages Profiles and Some Loading and Saving Commands). "ToggleProfileGUI" just basically shows up the OnGUI functionality for players to Create a User Name, Create New Game or Load a Saved Game. This is only accessed from the Start Scene or Main Menu before the main game scene starts. The Game is Automatically saved by the ProfileMenuManagement script every time the player Presses the Escape key or Pause in the main Game scene. But to load a game or start a new game they must exit back out to the main menu/Start Scene.

Every time the Escape or Paused Key is pressed during game play, the ProfileMenuManagement script tells all other scripts that Save data to save their data. Those other scripts then pull the public Active profileName integer from the ProfileMenuManagement script and add that integer to the save folder name, thus making sure it is saved to the correct folder linked to the appropriate Player Profile.
When loading a game, all Saved Data is called on the OnStart() function of every script that loads data when the Main Scene is loaded. Before doing this they look up which Active Profile it is, then apply that to the path and load it from the corresponding folder of that profile. Of course this Saved Data will no longer be available if the Profile folder has been deleted by pressing "Create New Game", so the Scene will start as normal, thus creating a new game.

Here is my Script for you to use as a Reference...


Code: Select all

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using SmartFPController;
using Devdog.General;
using Devdog.InventoryPro;
using Devdog.InventoryPro.Integration.EasySave2;

//Myk Created this Script to manage the Player Profiles.

public class ProfileMenuManagement : MonoBehaviour

{
	//GUI Profile Menu Manager (Open/Close)
	private bool OpenProfileUI;

	//The 6 Profiles
	public static string profileName1 = "Profile 1";
	public static string profileName2 = "Profile 2";
	public static string profileName3 = "Profile 3";
	public static string profileName4 = "Profile 4";
	public static string profileName5 = "Profile 5";
	public static string profileName6 = "Profile 6";

	//Which profile is Active
	public int activeProfile = 1;
	//What is the Name of this Scene?
	private string sceneName;

	void Start ()
	{
		//GUI Starts Off
		OpenProfileUI = false;

		//Get the Current Scene Running, so we can tell if its appropriate to do certain things.
		Scene currentScene = SceneManager.GetActiveScene ();
		sceneName = currentScene.name;

		//Get the Profiles if any.
		if (ES2.Exists ("ActiveProfile.ini")) 
		{
			activeProfile = ES2.Load<int> ("ActiveProfile.ini");
			Debug.Log ("Profile " + activeProfile + " is active.");
		}
		if (ES2.Exists ("Profile1/User.ini")) 
		{
			profileName1 = ES2.Load<string> ("Profile1/User.ini");
		}
		if (ES2.Exists ("Profile2/User.ini")) 
		{
			profileName2 = ES2.Load<string> ("Profile2/User.ini");
		}
		if (ES2.Exists ("Profile3/User.ini")) 
		{
			profileName3 = ES2.Load<string> ("Profile3/User.ini");
		}
		if (ES2.Exists ("Profile4/User.ini")) 
		{
			profileName4 = ES2.Load<string> ("Profile4/User.ini");
		}
		if (ES2.Exists ("Profile5/User.ini")) 
		{
			profileName5 = ES2.Load<string> ("Profile5/User.ini");
		}
		if (ES2.Exists ("Profile6/User.ini")) 
		{
			profileName6 = ES2.Load<string> ("Profile6/User.ini");
		}


	}
	
	// Update is called once per frame
	void Update () 
	{
		//Close the UI on Escape Press.
		if (Input.GetKeyDown (KeyCode.Escape)) 
		{
			OpenProfileUI = false;
		}

		/*If we are in the main Game Scene and Escape or Pause are pressed, 
		 * then Auto-Save the Active Profile.*/
		if (sceneName == "TestScene01") 
		{
			if (Input.GetKeyUp (KeyCode.Escape) ||
			   Input.GetKeyUp (KeyCode.Pause)) 
			{
			
				if (activeProfile == 1) {
					SaveProfile1 ();
				}
				if (activeProfile == 2) {
					SaveProfile2 ();
				}
				if (activeProfile == 3) {
					SaveProfile3 ();
				}
				if (activeProfile == 4) {
					SaveProfile4 ();
				}
				if (activeProfile == 5) {
					SaveProfile5 ();
				}
				if (activeProfile == 6) {
					SaveProfile6 ();
				}


			}
		}


	}

	void OnGUI()
	{
		//If the Profile Manager GUI isn't meant to be displayed then for heavens sake don't display it.
		if (OpenProfileUI == false) 
		{
			return;
		}

		//Otherwise let's see it.  Show us your profiles baby!
		if (OpenProfileUI == true) 
		{
			//PROFILE 1
			profileName1 = GUILayout.TextArea (profileName1, 9);
				
			if (GUILayout.Button ("Create New Game")) 
			{
				DeleteProfile1 ();
			}
			if (GUILayout.Button ("Load " + profileName1 + "'s Game")) 
			{
				LoadProfile1 ();
			}
		
			//PROFILE 2
			profileName2 = GUILayout.TextArea (profileName2, 9);

			if (GUILayout.Button ("Create New Game")) 
			{
				DeleteProfile2 ();
			}
			if (GUILayout.Button ("Load " + profileName2 + "'s Game")) 
			{
				LoadProfile2 ();
			}

			//PROFILE 3
			profileName3 = GUILayout.TextArea (profileName3, 9);

			if (GUILayout.Button ("Create New Game")) 
			{
				DeleteProfile3 ();
			}
			if (GUILayout.Button ("Load " + profileName3 + "'s Game")) 
			{
				LoadProfile3 ();
			}

			//PROFILE 4
			profileName4 = GUILayout.TextArea (profileName4, 9);

			if (GUILayout.Button ("Create New Game")) 
			{
				DeleteProfile4 ();
			}
			if (GUILayout.Button ("Load " + profileName4 + "'s Game")) 
			{
				LoadProfile4 ();
			}

			//PROFILE 5
			profileName5 = GUILayout.TextArea (profileName5, 9);

			if (GUILayout.Button ("Create New Game")) 
			{
				DeleteProfile5 ();
			}
			if (GUILayout.Button ("Load " + profileName5 + "'s Game")) 
			{
				LoadProfile5 ();
			}

			//PROFILE 6
			profileName6 = GUILayout.TextArea (profileName6, 9);

			if (GUILayout.Button ("Create New Game")) 
			{
				DeleteProfile6 ();
			}
			if (GUILayout.Button ("Load " + profileName6 + "'s Game")) 
			{
				LoadProfile6 ();
			}
		}


	}

	//GUI Switch it on, Switch it Off.
	public void ToggleProfileGUI()
	{
		if (OpenProfileUI == false) 
		{
			OpenProfileUI = true;
		} 
		else if (OpenProfileUI == true) 
		{
			OpenProfileUI = false;
		}
	}


	//SAVERS AND LOADERS.
	public void SaveProfile1()
	{
		activeProfile = 1;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName1, "Profile1/User.ini");
		//Activate Functions on outside Scripts.
		SmartInputManager.Instance.Save ();
		PlayerStats.Instance.SaveStats ();

		//Tell All Inventory Pro Collections and Containers to Save.
		var serializers1 = FindObjectsOfType<EasySave2CollectionSaverLoader>();
		foreach(var s in serializers1)
		{
			s.Save(); // Save the serializer one by one.
		}
		var serializers2 = FindObjectsOfType<EasySave2ContainerSaverLoader>();
		foreach(var s in serializers2)
		{
			s.Save(); // Save the serializer one by one.
		}
	}

	public void LoadProfile1()
	{
		activeProfile = 1;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName1, "Profile1/User.ini");
		//Load The Main Game Scene.
		SceneManager.LoadScene (1);
	}

	public void SaveProfile2()
	{
		activeProfile = 2;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName2, "Profile2/User.ini");
		//Activate Functions on outside Scripts.
		SmartInputManager.Instance.Save ();
		PlayerStats.Instance.SaveStats ();

		//Tell All Inventory Pro Collections and Containers to Save.
		var serializers1 = FindObjectsOfType<EasySave2CollectionSaverLoader>();
		foreach(var s in serializers1)
		{
			s.Save(); // Save the serializer one by one.
		}
		var serializers2 = FindObjectsOfType<EasySave2ContainerSaverLoader>();
		foreach(var s in serializers2)
		{
			s.Save(); // Save the serializer one by one.
		}
	}

	public void LoadProfile2()
	{
		activeProfile = 2;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName2, "Profile2/User.ini");
		//Load The Main Game Scene.
		SceneManager.LoadScene (1);
	}


	public void SaveProfile3()
	{
		activeProfile = 3;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName3, "Profile3/User.ini");
		//Activate Functions on outside Scripts.
		SmartInputManager.Instance.Save ();
		PlayerStats.Instance.SaveStats ();

		//Tell All Inventory Pro Collections and Containers to Save.
		var serializers1 = FindObjectsOfType<EasySave2CollectionSaverLoader>();
		foreach(var s in serializers1)
		{
			s.Save(); // Save the serializer one by one.
		}
		var serializers2 = FindObjectsOfType<EasySave2ContainerSaverLoader>();
		foreach(var s in serializers2)
		{
			s.Save(); // Save the serializer one by one.
		}
	}

	public void LoadProfile3()
	{
		activeProfile = 3;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName3, "Profile3/User.ini");
		//Load The Main Game Scene.
		SceneManager.LoadScene (1);
	}

	public void SaveProfile4()
	{
		activeProfile = 4;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName4, "Profile4/User.ini");
		//Activate Functions on outside Scripts.
		SmartInputManager.Instance.Save ();
		PlayerStats.Instance.SaveStats ();

		//Tell All Inventory Pro Collections and Containers to Save.
		var serializers1 = FindObjectsOfType<EasySave2CollectionSaverLoader>();
		foreach(var s in serializers1)
		{
			s.Save(); // Save the serializer one by one.
		}
		var serializers2 = FindObjectsOfType<EasySave2ContainerSaverLoader>();
		foreach(var s in serializers2)
		{
			s.Save(); // Save the serializer one by one.
		}
	}

	public void LoadProfile4()
	{
		activeProfile = 4;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName4, "Profile4/User.ini");
		//Load The Main Game Scene.
		SceneManager.LoadScene (1);
	}

	public void SaveProfile5()
	{
		activeProfile = 5;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName5, "Profile5/User.ini");
		//Activate Functions on outside Scripts.
		SmartInputManager.Instance.Save ();
		PlayerStats.Instance.SaveStats ();

		//Tell All Inventory Pro Collections and Containers to Save.
		var serializers1 = FindObjectsOfType<EasySave2CollectionSaverLoader>();
		foreach(var s in serializers1)
		{
			s.Save(); // Save the serializer one by one.
		}
		var serializers2 = FindObjectsOfType<EasySave2ContainerSaverLoader>();
		foreach(var s in serializers2)
		{
			s.Save(); // Save the serializer one by one.
		}
	}

	public void LoadProfile5()
	{
		activeProfile = 5;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName5, "Profile5/User.ini");
		//Load The Main Game Scene.
		SceneManager.LoadScene (1);
	}

	public void SaveProfile6()
	{
		activeProfile = 6;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName6, "Profile6/User.ini");
		//Activate Functions on outside Scripts.
		SmartInputManager.Instance.Save ();
		PlayerStats.Instance.SaveStats ();

		//Tell All Inventory Pro Collections and Containers to Save.
		var serializers1 = FindObjectsOfType<EasySave2CollectionSaverLoader>();
		foreach(var s in serializers1)
		{
			s.Save(); // Save the serializer one by one.
		}
		var serializers2 = FindObjectsOfType<EasySave2ContainerSaverLoader>();
		foreach(var s in serializers2)
		{
			s.Save(); // Save the serializer one by one.
		}
	}

	public void LoadProfile6()
	{
		activeProfile = 6;
		//Setting the Profile regardless of Save or Load.
		ES2.Save (activeProfile, "ActiveProfile.ini");
		ES2.Save (profileName6, "Profile6/User.ini");
		//Load The Main Game Scene.
		SceneManager.LoadScene (1);
	}


	//DELETERS
	public void DeleteProfile1()

	{
			ES2.Delete("Profile1/");
			activeProfile = 1;
			//Setting the Profile regardless of Save or Load.
			ES2.Save (activeProfile, "ActiveProfile.ini");
			ES2.Save (profileName1, "Profile1/User.ini");
			//Load The Main Game Scene.
			SceneManager.LoadScene (1);
	}

	public void DeleteProfile2()

	{
			ES2.Delete("Profile2/");
			activeProfile = 2;
			//Setting the Profile regardless of Save or Load.
			ES2.Save (activeProfile, "ActiveProfile.ini");
			ES2.Save (profileName2, "Profile2/User.ini");
			//Load The Main Game Scene.
			SceneManager.LoadScene (1);
	}

	public void DeleteProfile3()

	{
			ES2.Delete("Profile3/");
			activeProfile = 3;
			//Setting the Profile regardless of Save or Load.
			ES2.Save (activeProfile, "ActiveProfile.ini");
			ES2.Save (profileName3, "Profile3/User.ini");
			//Load The Main Game Scene.
			SceneManager.LoadScene (1);
	}

	public void DeleteProfile4()

	{
			ES2.Delete("Profile4/");
			activeProfile = 4;
			//Setting the Profile regardless of Save or Load.
			ES2.Save (activeProfile, "ActiveProfile.ini");
			ES2.Save (profileName4, "Profile4/User.ini");
			//Load The Main Game Scene.
			SceneManager.LoadScene (1);
	}

	public void DeleteProfile5()

	{
			ES2.Delete("Profile5/");
			activeProfile = 5;
			//Setting the Profile regardless of Save or Load.
			ES2.Save (activeProfile, "ActiveProfile.ini");
			ES2.Save (profileName5, "Profile5/User.ini");
			//Load The Main Game Scene.
			SceneManager.LoadScene (1);
	}

	public void DeleteProfile6()

	{
			ES2.Delete("Profile6/");
			activeProfile = 6;
			//Setting the Profile regardless of Save or Load.
			ES2.Save (activeProfile, "ActiveProfile.ini");
			ES2.Save (profileName6, "Profile6/User.ini");
			//Load The Main Game Scene.
			SceneManager.LoadScene (1);
	}



}

And just a little example code you might use in other scripts to access it would be something like:

Code: Select all

//Player Profile Reference
public string activeProfile; 

/*Grabs the Active Profile int from the ProfileMenuManagement Script placed on an object named _Managers and makes it a String.*/
activeProfile = GameObject.Find("_Managers").GetComponent<ProfileMenuManagement>().activeProfile.ToString(); 

/*Saves the Variable to a Profile folder numbered by the String created from the Profile Integer taken from the ProfileMenuManagement Script.*/
ES2.Save(this.transform, "Profile" + activeProfile + "/Player.Bin"); 

/*Loads that data using the same references.
if (ES2.Exists ("Profile" + activeProfile + "/Player.Bin")) 
   {
         ES2.Load<Transform> ("Profile" + activeProfile + "/Player.Bin", this.transform);
   }

I am sure there are probably better ways a Skilled Programmer could figure out how to do this and if there are any of you out there willing, please feel free to share here. :)
Regards, SW.
User avatar
Joel
Moodkie Staff
Posts: 4826
Joined: Wed Nov 07, 2012 10:32 pm

Re: An Example or Tutorial Request: Multi Profiles/Save Slo

Post by Joel »

Thanks for posting up the steps you took to implement your save profiles, looking over the code it certainly looks like a valid way to do things so it should be useful to quite a few people.

If anyone reading this would like to see a formal save slots/profile tutorial, leave a message below, and include any comments about what features you would expect to see in the tutorial. If there's enough demand for it we'll be happy to put an example project on our To Do list.

- Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Shockwolf
Posts: 14
Joined: Thu Feb 09, 2017 7:09 am

Re: An Example or Tutorial Request: Multi Profiles/Save Slo

Post by Shockwolf »

Thanks Joel,

And you're welcome. :D I'm glad you're okay with it. Hopefully it will pull enough interest to get a really good Tutorial for a really Snazzy Slots/Profile System. I'd be very surprised if this isn't something most developers would want in their games at some point. Personally I think it would be a nice bit of Icing on the Cake for what is already a pretty good Asset you have here. ;)
Regards, SW.
Locked