PuzzleMeasurement, add Realm, door ExitedFrom event

This commit is contained in:
2022-12-05 18:11:00 +01:00
parent 5449283e5d
commit b776e6744e
34 changed files with 344 additions and 63 deletions

View File

@@ -9,7 +9,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 5782403741593619305}
- component: {fileID: 2398776566740968028}
- component: {fileID: 1834615596445353898}
m_Layer: 0
m_Name: Desert Spawn
m_TagString: Untagged
@@ -30,9 +30,9 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 7
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2398776566740968028
--- !u!114 &1834615596445353898
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -41,7 +41,7 @@ MonoBehaviour:
m_GameObject: {fileID: 615130069026427904}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 696181e3eda449d49d4c1c88b07d7b05, type: 3}
m_Script: {fileID: 11500000, guid: 404f750726904ea98f8a85feaca0df66, type: 3}
m_Name:
m_EditorClassIdentifier:
size: {x: 1, y: 1}

View File

@@ -5,6 +5,7 @@ PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 2
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1322900129209232937, guid: da9b7a57e7c37d149827fe17188bdeea,
@@ -72,5 +73,26 @@ PrefabInstance:
propertyPath: m_Name
value: Spawn
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedComponents:
- {fileID: 7146915386488129308, guid: da9b7a57e7c37d149827fe17188bdeea, type: 3}
m_AddedGameObjects: []
m_SourcePrefab: {fileID: 100100000, guid: da9b7a57e7c37d149827fe17188bdeea, type: 3}
--- !u!1 &641449049689494886 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 5399176795272327488, guid: da9b7a57e7c37d149827fe17188bdeea,
type: 3}
m_PrefabInstance: {fileID: 4758994409158878246}
m_PrefabAsset: {fileID: 0}
--- !u!114 &5940521204297009715
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 641449049689494886}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 404f750726904ea98f8a85feaca0df66, type: 3}
m_Name:
m_EditorClassIdentifier:
size: {x: 2, y: 1}

View File

@@ -43,7 +43,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Editor
{
if (EditorApplication.isPlaying)
{
Engine.DefaultEngine.HidePreviousRoom();
Engine.DefaultEngine.CurrentRoom.Match(some: room => room.EnterRoom());
UpdateUI();
}
}
@@ -62,7 +62,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Editor
if (EditorApplication.isPlaying)
{
Engine.DefaultEngine.CurrentRoom.Match(some: room => room.SkipRoom());
Engine.DefaultEngine.HidePreviousRoom();
Engine.DefaultEngine.CurrentRoom.Match(some: room => room.EnterRoom());
UpdateUI();
}
}

View File

@@ -7,8 +7,10 @@
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"overrideReferences": true,
"precompiledReferences": [
"Realm.dll"
],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],

View File

@@ -1,3 +1,7 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 2d68e204354e44f2a2ecf3cfa9213c5f
timeCreated: 1668940905
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using EscapeRoomEngine.Engine.Runtime.Measurements;
using EscapeRoomEngine.Engine.Runtime.Modules;
using EscapeRoomEngine.Engine.Runtime.Utilities;
using NaughtyAttributes;
@@ -38,6 +39,11 @@ namespace EscapeRoomEngine.Engine.Runtime
private readonly List<Room> _rooms = new();
private GameObject _playSpaceOrigin;
private void Awake()
{
Measure.Clear();
}
private void Start()
{
_playSpaceOrigin = new GameObject("Play Space Origin");

View File

@@ -51,6 +51,8 @@ namespace EscapeRoomEngine.Engine.Runtime
[BoxGroup("Puzzles")]
public List<PuzzleModuleDescription> puzzleTypes;
public PuzzleModuleDescription GetPuzzle(int id) => puzzleTypes.Find(puzzle => puzzle.Id == id);
#endregion
[UsedImplicitly]

View File

@@ -1,8 +0,0 @@
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
public interface IMeasurementStorage
{
public void Save(MeasurementCollection measurements);
public MeasurementCollection Load(int key);
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 6c93e87219e64bc3ad8263da8109e51c
timeCreated: 1670750698

View File

@@ -1,7 +1,44 @@
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
public class Measure
{
using System.Collections.Generic;
using EscapeRoomEngine.Engine.Runtime.Modules;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
public static class Measure
{
private static Dictionary<int, PuzzleMeasurement> _runningMeasurements;
public static void StartMeasuring(PuzzleModuleDescription puzzle)
{
_runningMeasurements[puzzle.Id] = new PuzzleMeasurement
{
TimeStarted = Time.time,
TimeSolved = Time.time
};
Logger.Log($"Started measuring {puzzle}", LogType.Measuring);
LogAllMeasurements();
}
public static void Solve(PuzzleModuleDescription puzzle)
{
var measurement = _runningMeasurements[puzzle.Id];
PuzzleStorage.Instance.EndMeasurement(puzzle, measurement);
Logger.Log($"Solved {puzzle} with measurement {measurement}", LogType.Measuring);
}
public static void LogAllMeasurements()
{
Engine.DefaultEngine.theme.puzzleTypes.ForEach(puzzle =>
{
Logger.Log(PuzzleStorage.Instance.LoadOrNew(puzzle).ToString(), LogType.Measuring);
});
}
public static void Clear() => _runningMeasurements = new Dictionary<int, PuzzleMeasurement>();
}
}

View File

@@ -1,13 +0,0 @@
using System;
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
[Serializable]
public struct MeasurementCollection
{
/// <summary>
/// The module id is a
/// </summary>
public int moduleId;
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: e6d831555dc34776b8212a9d9de33414
timeCreated: 1670695633

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using EscapeRoomEngine.Engine.Runtime.Modules;
using EscapeRoomEngine.Engine.Runtime.Utilities;
using JetBrains.Annotations;
using Realms;
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
public class Puzzle : RealmObject
{
[PrimaryKey]
public int ID { get; set; }
public IList<PuzzleMeasurement> Measurements { get; }
public float TotalTimeSpentOnPuzzle => Measurements.Sum(measurement => measurement.Time);
public float AverageTimeToSolve => Measurements.Count > 0 ? TotalTimeSpentOnPuzzle / Measurements.Count : 0f;
[UsedImplicitly]
public Puzzle() {}
public Puzzle(PuzzleModuleDescription puzzle)
{
ID = puzzle.Id;
}
public override string ToString()
{
return $"{Engine.DefaultEngine.theme.GetPuzzle(ID)}: avg. {AverageTimeToSolve.ToTimeSpan():m':'ss} ({string.Join(", ", Measurements)})";
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0fb9915d920c4298a8ceeba7df5112b5
timeCreated: 1670773536

View File

@@ -1,15 +1,18 @@
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using EscapeRoomEngine.Engine.Runtime.Utilities;
using Realms;
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
[Serializable]
public struct PuzzleMeasurement
public class PuzzleMeasurement : EmbeddedObject
{
public void a()
public float TimeStarted { get; set; }
public float TimeSolved { get; set; }
public float Time => TimeSolved - TimeStarted;
public override string ToString()
{
new BinaryFormatter().Serialize(new MemoryStream(), this);
return $"{Time.ToTimeSpan():m':'ss}";
}
}
}

View File

@@ -0,0 +1,82 @@
using EscapeRoomEngine.Engine.Runtime.Modules;
using Realms;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
namespace EscapeRoomEngine.Engine.Runtime.Measurements
{
public class PuzzleStorage : MonoBehaviour
{
public static PuzzleStorage Instance
{
get
{
if (_foundStorage == null)
{
_foundStorage = FindObjectOfType<PuzzleStorage>();
}
return _foundStorage;
}
}
private static PuzzleStorage _foundStorage;
[SerializeField]
private string databasePath = "measurements.realm";
private Realm _realm;
private void OnEnable()
{
_realm = Realm.GetInstance(databasePath);
}
private void Start()
{
Logger.Log($"Using realm database at {_realm.Config.DatabasePath}", LogType.Measuring);
}
private void OnDisable()
{
_realm?.Dispose();
}
public Puzzle New(PuzzleModuleDescription puzzle)
{
Puzzle created = null;
_realm.Write(() =>
{
created = _realm.Add(new Puzzle(puzzle));
});
return created;
}
public Puzzle LoadOrNew(PuzzleModuleDescription puzzle) =>
_realm.Find<Puzzle>(puzzle.Id) ?? New(puzzle);
public Puzzle Load(PuzzleModuleDescription puzzle) =>
_realm.Find<Puzzle>(puzzle.Id);
public void Delete(PuzzleModuleDescription puzzle)
{
var found = Load(puzzle);
if (found != null)
{
_realm.Write(() => _realm.Remove(found));
}
}
public void EndMeasurement(PuzzleModuleDescription puzzle, PuzzleMeasurement measurement)
{
var found = LoadOrNew(puzzle);
_realm.Write(() =>
{
measurement.TimeSolved = Time.time;
found.Measurements.Add(measurement);
});
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: adcd0bf392c89ae4da3c50e3f06735a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -5,7 +5,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
{
public enum DoorEventType
{
Locked, Unlocked, Connected
Locked, Unlocked, Connected, ExitedFrom
}
public delegate void DoorEventHandler(DoorModule source, DoorEventType e);
@@ -31,7 +31,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
private bool _unlocked;
private void OnDoorEvent(DoorEventType type)
protected void OnDoorEvent(DoorEventType type)
{
Logger.Log($"{Module} has been {type}", LogType.PuzzleFlow);
@@ -53,6 +53,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
[Button(enabledMode: EButtonEnableMode.Playmode)]
internal void Lock() => Unlocked = false;
[Button(enabledMode: EButtonEnableMode.Playmode)]
internal void ExitFrom() => OnDoorEvent(DoorEventType.ExitedFrom);
#endregion
public static DoorState FromState(ModuleState state)

View File

@@ -9,5 +9,12 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
public string puzzleName;
[InfoBox("Puzzle measurements will only be combined for the same puzzle with the same version. If large changes are made to the puzzle that might influence its measurements, the version should be incremented.")]
public int puzzleVersion = 1;
public int Id => puzzleName.GetHashCode() + puzzleVersion;
public override string ToString()
{
return $"{puzzleName} v{puzzleVersion} ({Id})";
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using EscapeRoomEngine.Engine.Runtime.Measurements;
using EscapeRoomEngine.Engine.Runtime.Utilities;
using NaughtyAttributes;
using UnityEngine;
@@ -53,6 +54,14 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
protected virtual void Start()
{
OnPuzzleEvent(PuzzleEventType.Restarted);
PuzzleEvent += (_, type) =>
{
if (type == PuzzleEventType.Solved)
{
Measure.Solve((PuzzleModuleDescription)Module.description);
}
};
}
private void OnPuzzleEvent(PuzzleEventType type)

View File

@@ -0,0 +1,10 @@
namespace EscapeRoomEngine.Engine.Runtime.Modules
{
internal class Spawn : DoorState
{
private void Start()
{
ExitFrom();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 404f750726904ea98f8a85feaca0df66
timeCreated: 1670779750

View File

@@ -1,7 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using EscapeRoomEngine.Engine.Runtime.Modules;
using NaughtyAttributes;
using UnityEngine;
namespace EscapeRoomEngine.Engine.Runtime.Requirements

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using EscapeRoomEngine.Engine.Runtime.Measurements;
using EscapeRoomEngine.Engine.Runtime.Modules;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
@@ -35,13 +36,17 @@ namespace EscapeRoomEngine.Engine.Runtime
Logger.Log($"Skipping {this}...", LogType.PuzzleFlow);
_puzzles.ForEach(puzzle => puzzle.PuzzleState.Solve());
if (_puzzles.Count == 0)
{
exit.fromOut.DoorState.Unlock();
}
}
public void EnterRoom()
{
entrance.toIn.DoorState.ExitFrom();
}
internal void AddPuzzle(PuzzleModule puzzle)
{
_puzzles.Add(puzzle);
@@ -67,9 +72,18 @@ namespace EscapeRoomEngine.Engine.Runtime
private void OnDoorEvent(DoorModule door, DoorEventType type)
{
if (type == DoorEventType.Unlocked && door.Equals(exit.fromOut))
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (type)
{
// generate a new room as soon as the player completes all puzzles in this one
case DoorEventType.Unlocked when door.Equals(exit.fromOut):
Engine.DefaultEngine.GenerateRoom();
break;
// start measurements on every puzzle as soon as the player enters this room
case DoorEventType.ExitedFrom when door.Equals(entrance.toIn):
_puzzles.ForEach(puzzle => Measure.StartMeasuring((PuzzleModuleDescription)puzzle.description));
Engine.DefaultEngine.HidePreviousRoom();
break;
}
}

View File

@@ -13,7 +13,8 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
RequirementResolution,
PuzzleFlow,
PuzzleDetail,
Portals
Portals,
Measuring
}
public class Logger : MonoBehaviour

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
namespace EscapeRoomEngine.Engine.Runtime.Utilities
{
@@ -37,4 +39,10 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
public static Vector3Int ProjectAtHeight(this Vector2Int vector, int height) =>
new Vector3Int(vector.x, height, vector.y);
}
public static class FloatExtensions
{
public static TimeSpan ToTimeSpan(this float seconds) =>
new(0, 0, 0, Mathf.RoundToInt(seconds), 0);
}
}

View File

@@ -52,6 +52,10 @@ namespace EscapeRoomEngine.Portal.Runtime
StopTrackingDriver(portalDriver);
linkedPortal.StartTrackingDriver(portalDriver, -1);
portalDriver.Teleport(this, linkedPortal);
if (portalDriver.player)
{
linkedPortal.OnDoorEvent(DoorEventType.ExitedFrom);
}
i--; // decrease the loop counter because the list is one element smaller now
}
}

View File

@@ -16,6 +16,10 @@ namespace EscapeRoomEngine.Portal.Runtime
/// Whether this portal driver has a clone mirroring it at other portals. Disable this for the player.
/// </summary>
public bool hasClone = true;
/// <summary>
/// Whether this portal driver is the player. Used by portals to tell when the player has passed to another space.
/// </summary>
public bool player;
/// <summary>
/// The side of the portal this became tracked on.

View File

@@ -628,6 +628,7 @@ GameObject:
m_Component:
- component: {fileID: 1568048335}
- component: {fileID: 1568048334}
- component: {fileID: 1568048339}
- component: {fileID: 1568048336}
m_Layer: 0
m_Name: Engine
@@ -679,4 +680,17 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
loggingEnabled: 1
typeFilter: 00000000
typeFilter: 0000000009000000
--- !u!114 &1568048339
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1568048333}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: adcd0bf392c89ae4da3c50e3f06735a1, type: 3}
m_Name:
m_EditorClassIdentifier:
databasePath: measurements.realm

View File

@@ -458,6 +458,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
traveller: {fileID: 419816429471595185}
hasClone: 0
player: 1
entrySide: 0
clone: {fileID: 0}
--- !u!135 &419816428804372195
@@ -964,6 +965,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
traveller: {fileID: 419816429504646916}
hasClone: 1
player: 0
entrySide: 0
clone: {fileID: 0}
--- !u!1 &419816429471595190
@@ -1369,6 +1371,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
traveller: {fileID: 419816428170395206}
hasClone: 1
player: 0
entrySide: 0
clone: {fileID: 0}
--- !u!1 &2085627837412252196

View File

@@ -1,5 +1,6 @@
{
"dependencies": {
"io.realm.unity": "10.18.0",
"com.dbrizov.naughtyattributes": "https://github.com/dbrizov/NaughtyAttributes.git#upm",
"com.unity.ide.rider": "3.0.17",
"com.unity.ide.visualstudio": "2.0.17",
@@ -43,5 +44,14 @@
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
},
"scopedRegistries": [
{
"name": "NPM",
"url": "https://registry.npmjs.org",
"scopes": [
"io.realm.unity"
]
}
]
}

View File

@@ -219,6 +219,13 @@
},
"url": "https://packages.unity.com"
},
"io.realm.unity": {
"version": "10.18.0",
"depth": 0,
"source": "registry",
"dependencies": {},
"url": "https://registry.npmjs.org"
},
"com.unity.modules.ai": {
"version": "1.0.0",
"depth": 0,

View File

@@ -17,6 +17,7 @@ MonoBehaviour:
m_AdvancedSettingsExpanded: 1
m_ScopedRegistriesSettingsExpanded: 1
m_SeeAllPackageVersions: 0
m_DismissPreviewPackagesInUse: 0
oneTimeWarningShown: 1
m_Registries:
- m_Id: main
@@ -25,11 +26,20 @@ MonoBehaviour:
m_Scopes: []
m_IsDefault: 1
m_Capabilities: 7
m_UserSelectedRegistryName:
m_ConfigSource: 0
- m_Id: scoped:project:NPM
m_Name: NPM
m_Url: https://registry.npmjs.org
m_Scopes:
- io.realm.unity
m_IsDefault: 0
m_Capabilities: 0
m_ConfigSource: 4
m_UserSelectedRegistryName: NPM
m_UserAddingNewScopedRegistry: 0
m_RegistryInfoDraft:
m_Modified: 0
m_ErrorMessage:
m_UserModificationsInstanceId: -846
m_OriginalInstanceId: -848
m_UserModificationsInstanceId: -828
m_OriginalInstanceId: -830
m_LoadAssets: 0

View File

@@ -12,7 +12,7 @@ PlayerSettings:
targetDevice: 2
useOnDemandResources: 0
accelerometerFrequency: 60
companyName: DefaultCompany
companyName: University of Basel
productName: Escape Room Engine
defaultCursor: {fileID: 0}
cursorHotspot: {x: 0, y: 0}