Files
modular-vr/Assets/Engine/Runtime/Measurements/PuzzleStorage.cs

149 lines
5.0 KiB
C#

using EscapeRoomEngine.Engine.Runtime.Modules.Description;
using EscapeRoomEngine.Engine.Runtime.UI;
using Realms;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
/// <summary>
/// The storage engine that manages the data in a realm database.
/// </summary>
public class PuzzleStorage : MonoBehaviour
{
/// <summary>
/// The schema version must be updated whenever the schema in the database changed.
/// </summary>
private const int SchemaVersion = 2;
/// <summary>
/// The active instance of the storage engine.
/// </summary>
public static PuzzleStorage Instance { get; private set; }
[Tooltip("The path of the database relative to where the engine stores persistent data.")]
[SerializeField]
private string databasePath = "measurements.realm";
private Realm _realm;
private void OnEnable()
{
// configure special actions during specific migrations of the database
var config = new RealmConfiguration
{
SchemaVersion = SchemaVersion,
MigrationCallback = (migration, oldSchemaVersion) =>
{
if (oldSchemaVersion < 1)
{
// migration from version 0 to 1
// nothing to do
}
if (oldSchemaVersion < 2)
{
// migration from version 1 to 2
// nothing to do
}
Logger.Log($"Migrated database to version {SchemaVersion}", LogType.Measuring);
}
};
_realm = Realm.GetInstance(config.ConfigWithPath(databasePath));
}
private void Awake()
{
Instance = this;
}
private void Start()
{
Logger.Log($"Using realm database at {_realm.Config.DatabasePath}", LogType.Measuring);
}
private void OnDisable()
{
_realm?.Dispose();
}
#region Session
/// <summary>
/// End a session and store it to the database.
/// </summary>
public void EndSession(Session session, float time)
{
session.Time = time;
_realm.Write(() => _realm.Add(session));
}
#endregion
#region Puzzles
/// <summary>
/// Create a new puzzle for a specific description and store it in the database.
/// </summary>
/// <remarks>This requires that the puzzle does not yet exist in the database.</remarks>
public Puzzle New(PuzzleModuleDescription puzzle)
{
Puzzle created = null;
_realm.Write(() => created = _realm.Add(new Puzzle(puzzle)));
return created;
}
/// <summary>
/// Load a specific puzzle from the database or create it if it wasn't found.
/// </summary>
public Puzzle LoadOrNew(PuzzleModuleDescription puzzle) => _realm.Find<Puzzle>(puzzle.Id) ?? New(puzzle);
/// <summary>
/// Load a specific puzzle from the database.
/// </summary>
/// <returns>The puzzle or null if it wasn't found in the database.</returns>
public Puzzle Load(PuzzleModuleDescription puzzle) => _realm.Find<Puzzle>(puzzle.Id);
/// <summary>
/// Delete all records concerning a specific puzzle from the database irreversibly.
/// </summary>
public void Delete(PuzzleModuleDescription puzzle)
{
var found = Load(puzzle);
if (found != null)
{
_realm.Write(() => _realm.Remove(found));
}
}
/// <summary>
/// End the measurement for a specific puzzle and store it in the database. Also stores the results of the current puzzle plan.
/// </summary>
public void EndMeasurement(Session session, PuzzleModuleDescription puzzle, PuzzleMeasurement measurement)
{
var found = LoadOrNew(puzzle);
_realm.Write(() =>
{
measurement.TimeSolved = GameControl.Instance.TimeElapsed;
found.Measurements.Add(measurement);
// add solved puzzle to session
session.PuzzlesSolved.Add(found);
// add plan result to session
var percentile = found.Distribution.Cumulative(measurement.Time);
session.PlanResults.Add(new PlanResult(
GameControl.Instance.TargetTime,
percentile,
GameControl.Instance.EstimatedTime));
});
}
#endregion
}
}