using System;
using System.Collections.Generic;
using UnityEngine;
using Framework.Services;
using Framework.Storage.Containers;
namespace Framework.Storage {
/// Manages all persistent data of the game
///
///
/// This service remain in existence for as long as the game runs and manages
/// settings that apply to the whole game. Before accessing it for the first
/// time, the specific classes used to store the game's settings need to be
/// made known to the service by calling the method.
///
///
/// It is recommended that you access the service through a game-specific
/// wrapper which makes sure that the method is
/// always called before accessing the settings, even when a scene is started
/// inside the editor, skipping the startup, main menu and other scenes.
///
///
/// Shared modules which do not have access to the game specific classes used
/// to store settings can wait for the game to initialize the settings manager
/// by subscribing to the event. If the settings
/// manager has already been initialized at the time of subscription,
/// the event handler will be called while subscribing.
///
///
[
ServiceScope(Scope.Global)
]
public class PersistentSettingsManager : Service, IPersistentSettingsStore {
/// Filename for the machine settings file
public static readonly string MachineSettingsFilename = "Settings.xml";
/// Filename for the user settings file
public static readonly string UserSettingsFilename = "UserSettings.xml";
/// Filename for the achievements and global unlocks file
public static readonly string AchievementsFilename = "Achievements.xml";
/// Called when the persistent state store has been initialized
public event Action Initialized {
add {
if(IsInitialized) {
value();
} else {
if(this.initializedEventSubscribers == null) {
this.initializedEventSubscribers = new List();
this.initializedEventSubscribers.Add(value);
} else if(!this.initializedEventSubscribers.Contains(value)) {
this.initializedEventSubscribers.Add(value);
}
}
}
remove {
this.initializedEventSubscribers.Remove(value);
}
}
/// Initializes the types that will be used by the persistent data store
///
/// Type that will be used to store user-specific settings such as key bindings,
/// mouse speed or language.
///
///
/// Type that will be used to store machine-specific settings such as resolution,
/// monitor and detail levels.
///
///
/// Type that will be used to store global unlocks and achievements
///
///
/// The default implementation of the persistent store requires this method to be called
/// before any of the other properties and methods of the persistent store will work.
/// It will load the game's current settings from their default locations if available
/// and create new default instances of no saved settings exist.
///
public void Initialize<
TMachineSettings,
TUserSettings,
TAchievements
>(
IPersistentStateSerializer machineSettingsSerializer = null,
IPersistentStateSerializer userSettingsSerializer = null,
IPersistentStateSerializer achievementSerializer = null
)
where TMachineSettings : class, IMachineSettings, new()
where TUserSettings : class, IUserSettings, new()
where TAchievements : class, IAchievements, new() {
if(IsInitialized) {
Debug.LogError("Persistent data manager was initialized a second time.");
return;
}
{
var machineSettingsContainer = new XmlBackedContainer(
StandardDirectories.UserDataPath, MachineSettingsFilename
);
machineSettingsContainer.CustomSerializer = machineSettingsSerializer;
this.machineSettings = machineSettingsContainer;
}
{
var userSettingsContainer = new XmlBackedContainer(
StandardDirectories.UserDataPath, UserSettingsFilename
);
userSettingsContainer.CustomSerializer = userSettingsSerializer;
this.userSettings = userSettingsContainer;
}
{
var achievementContainer = new XmlBackedContainer(
StandardDirectories.UserDataPath, AchievementsFilename
);
achievementContainer.CustomSerializer = achievementSerializer;
this.achievements = achievementContainer;
}
Debug.Log("Persistent settings manager initialized");
OnInitialized();
}
/// Whether the persistent data store has been initialized already
public bool IsInitialized {
get {
return (
(this.userSettings != null) &&
(this.machineSettings != null) &&
(this.achievements != null)
);
}
}
/// Container for machine-specific settings such as display parameters
public IPersistentContainer MachineSettings {
get {
if(!IsInitialized) {
throw new InvalidOperationException(
"Can't access machine settings; persistent settings manager not initialized uet"
);
}
return this.machineSettings;
}
}
/// Container for user-specific settings such as key bindings
public IPersistentContainer UserSettings {
get {
if(!IsInitialized) {
throw new InvalidOperationException(
"Can't access user settings; persistent settings manager not initialized uet"
);
}
return this.userSettings;
}
}
/// Container for global unlocks and achievements
public IVerifiedPersistentContainer Achievements {
get {
if(!IsInitialized) {
throw new InvalidOperationException(
"Can't access achievements; persistent settings manager not initialized uet"
);
}
return this.achievements;
}
}
/// Loads all persistent settings from the current serialized state
public void LoadAllSettings() {
if(!IsInitialized) {
throw new InvalidOperationException(
"Can't load settings; persistent game state manager not initialized uet"
);
}
this.machineSettings.Load();
this.userSettings.Load();
}
/// Saves all persistent settings into their respective files
public void SaveAllSettings() {
if(!IsInitialized) {
throw new InvalidOperationException(
"Can't save settings; persistent game state manager not initialized uet"
);
}
this.machineSettings.Save();
this.userSettings.Save();
}
/// Fires the OnInitialized() event
/// >
/// We auto-clear the subscribers after firing since the event is supposed to
/// only happen once per game and we don't want to keep a bunch of objects hanging
/// by their subscription to the event list.
///
protected virtual void OnInitialized() {
if(this.initializedEventSubscribers != null) {
IList subscribers = this.initializedEventSubscribers;
this.initializedEventSubscribers = null;
int subscriberCount = subscribers.Count;
for(int index = 0; index < subscriberCount; ++index) {
subscribers[index]();
}
}
}
/// Container for machine-specific settings such as display parameters
private IPersistentContainer machineSettings;
/// Container for user-specific settings such as key bindings
private IPersistentContainer userSettings;
/// Container for global unlocks and achievements
private IVerifiedPersistentContainer achievements;
/// List of subscribers for the event
private IList initializedEventSubscribers;
}
} // namespace Framework.Storage