using System;
using System.IO;
namespace Framework.Storage.Containers {
/// XML-backed persistent state container
/// Type of state the persistent container stores
internal class XmlBackedContainer :
IVerifiedPersistentContainer
where TState : class, TInterface, new()
where TInterface : class {
#if false
/// Triggered when the settings should be reapplied
///
///
/// Typically, you don't want to tightly integrate all your character controllers
/// and other game logic with the persistent state saving system and instead
/// create 'glue' objects which take the settings from a persistent container
/// and apply them at will.
///
///
/// This event can be used to signal to those 'glue' objects that they should
/// apply the current settings to the game's controllers again.
///
///
/// One danger of this event is that dead objects may keep hanging on to it.
/// Any 'glue' component needs to cleanly unsubscribe when it is being destroyed!
///
///
public event Action Apply;
#endif
/// Initializes a new XML-backed persistent state container
/// Directory in which state file will be stored
/// Default name of the state file
public XmlBackedContainer(string directory, string defaultFilename) {
this.state = new TState();
this.directory = directory;
this.defaultFilename = defaultFilename;
this.isGenuine = true;
}
/// Accesses the informations stored in the state
public TInterface Access() {
return this.state;
}
/// Accesses the game-specific state
///
/// Game-specific type of state the game is storing
///
/// The game-specific state
public TSpecificState Access() where TSpecificState : TInterface {
object stateAsObject = (object)this.state;
return (TSpecificState)stateAsObject;
// return default(TSpecificState); // This should work. Cast unknown class X to Y...
}
/// Optional custom serializer for the state, null to use default
public IPersistentStateSerializer CustomSerializer {
get { return this.customSerializer; }
set { this.customSerializer = value; }
}
/// Loads the saved state of the container from disk
public void Load() {
// If we don't do this and a future version of the game adds new attributes
// or properties, the player could mix things up by playing a save with
// the desired attributes, then loading an old-version save (leaving those
// attributes in their previous states).
Reset();
if(this.customSerializer == null) {
loadUsingDefaultSerializer();
this.isGenuine = true;
} else {
this.isGenuine = loadUsingCustomSerializer();
}
}
/// Saves the current state of the container to disk
public void Save() {
if(this.customSerializer == null) {
saveUsingDefaultSerializer();
} else {
saveUsingCustomSerializer();
}
}
/// Resets the container to its default settings
public void Reset() {
// Would like to replace this with create-instance-and-copy-into-existing
this.state = new TState();
}
/// Whether the container's state is tamper-free
/// >
/// If the user tries to edit the save file, a verified container will
/// detect this and report its state as non-genuine.
///
public bool IsGenuine { get { return this.isGenuine; } }
/// Updates the Directory in which the XML file will be stored
/// New directory to use for the XML file
public void ChangeDirectory(string newDirectory) {
this.directory = newDirectory;
}
/// Loads the state using a custom serializer
private bool loadUsingCustomSerializer() {
string path = this.customSerializer.DefaultFilename;
if(string.IsNullOrEmpty(path)) {
path = Path.Combine(this.directory, this.defaultFilename);
} else {
path = Path.Combine(this.directory, path);
}
if(File.Exists(path)) {
return this.customSerializer.Load(this.state, path);
} else {
Reset();
return true;
}
}
/// Loads the state using the default XML serializer
private void loadUsingDefaultSerializer() {
if(!Directory.Exists(this.directory)) {
Directory.CreateDirectory(this.directory);
}
string path = Path.Combine(this.directory, this.defaultFilename);
if(File.Exists(path)) {
SimpleXmlSerializer.Load(this.state, path);
} else {
Reset();
}
}
/// Saves the state using a custom serializer
private void saveUsingCustomSerializer() {
if(!Directory.Exists(this.directory)) {
Directory.CreateDirectory(this.directory);
}
string path = this.customSerializer.DefaultFilename;
if(string.IsNullOrEmpty(path)) {
path = Path.Combine(this.directory, this.defaultFilename);
} else {
path = Path.Combine(this.directory, path);
}
this.customSerializer.Save(this.state, path);
}
/// Saves the state using the default XML serializer
private void saveUsingDefaultSerializer() {
if(!Directory.Exists(this.directory)) {
Directory.CreateDirectory(this.directory);
}
string path = Path.Combine(this.directory, this.defaultFilename);
SimpleXmlSerializer.Save(this.state, path);
}
/// Custom serializer that will be used to persist the container
private IPersistentStateSerializer customSerializer;
/// Informations stored in this container
private TState state;
/// Directory in which the state file will be saved
private string directory;
/// Default filename that will be used for the state file
///
/// This can be overriden if a custom serializer is assigned
///
private string defaultFilename;
/// Whether the current state is tamper-free
private bool isGenuine;
}
} // namespace Framework.Storage.Containers