refactor modules

This commit is contained in:
2023-03-22 17:03:55 +01:00
parent 52cf3a7fbd
commit 128ab216d2
503 changed files with 1835 additions and 379 deletions

View File

@@ -0,0 +1,124 @@
using System;
using JetBrains.Annotations;
using NaughtyAttributes;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
namespace Station46.Runtime
{
public enum ButtonEventType
{
Pressed, Released, Activated, Deactivated
}
public static class ButtonEventExtensions
{
public static string Description(this ButtonEventType type, Button button)
{
var action = type switch
{
ButtonEventType.Pressed => "pressed",
ButtonEventType.Released => "released",
ButtonEventType.Activated => "activated",
ButtonEventType.Deactivated => "deactivated",
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
return $"{button} was {action}";
}
}
public delegate void ButtonEventHandler(Button source, ButtonEventType e);
/// <summary>
/// A general component for buttons that handles button events.
/// </summary>
public class Button : MonoBehaviour
{
public event ButtonEventHandler ButtonEvent;
/// <summary>
/// Whether this button accepts input.
/// </summary>
[ShowNativeProperty]
protected bool Active
{
get => _active;
set
{
var previous = _active;
_active = value;
if (previous != _active)
{
OnButtonEvent(_active ? ButtonEventType.Activated : ButtonEventType.Deactivated);
}
}
}
/// <summary>
/// Whether this button is currently pressed.
/// </summary>
[ShowNativeProperty]
protected bool Pressed
{
get => _pressed;
set
{
var previous = _pressed;
_pressed = Active && value;
if (previous != _pressed)
{
OnButtonEvent(_pressed ? ButtonEventType.Pressed : ButtonEventType.Released);
}
}
}
private bool _active = true, _pressed;
protected virtual void Start()
{
ButtonEvent += (_, type) =>
{
if (type == ButtonEventType.Deactivated)
{
Pressed = false; // release button if it is deactivated
}
};
}
private void OnButtonEvent(ButtonEventType type)
{
Logger.Log(type.Description(this), LogType.PuzzleDetail);
ButtonEvent?.Invoke(this, type);
}
#region Debug Buttons
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void Enable() => Active = true;
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void Disable() => Active = false;
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void Press() => Pressed = true;
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void Release() => Pressed = false;
[UsedImplicitly]
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void PressAndRelease()
{
Press();
Release();
}
#endregion
public override string ToString()
{
return name;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0388274fd30c44089477f6bed40e1e23
timeCreated: 1668813709

View File

@@ -0,0 +1,40 @@
using NaughtyAttributes;
using UnityEngine;
namespace Station46.Runtime
{
/// <summary>
/// A <see cref="StepPuzzle"/> whose steps are considered a cycle that can be started anywhere and must be stepped through once.
/// </summary>
public class CyclicStepPuzzle : StepPuzzle
{
[Tooltip("The current step in the cycle.")]
[BoxGroup("Step Puzzle")] [Min(0)]
public int cycleStep;
protected override void CheckStep(int step)
{
if (!Solved)
{
if (currentStep == 0)
{
// begin at any step
cycleStep = NextInCycle(step);
Step();
}
else if (step == cycleStep)
{
// next step in cycle
cycleStep = NextInCycle(cycleStep);
Step();
}
else
{
WrongInput();
}
}
}
private int NextInCycle(int step) => (step + 1) % totalSteps;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4551ae21288a497dac75931c56f86409
timeCreated: 1669057382

View File

@@ -0,0 +1,71 @@
using NaughtyAttributes;
using UnityEngine;
namespace Station46.Runtime
{
/// <summary>
/// A general component for controlling the emission of an object.
/// </summary>
public class Emission : MonoBehaviour
{
private static readonly int EmissionColorNameID = Shader.PropertyToID("_EmissionColor");
[Tooltip("The colour of the emission.")]
[ColorUsage(false, true)]
public Color color;
[BoxGroup("Internal")] [Required]
public MeshRenderer emissionRenderer;
/// <summary>
/// Whether the emission is on.
/// </summary>
internal bool active;
private bool _previousActive;
private Color _previousColor;
private Material _material;
private void Awake()
{
_material = emissionRenderer.material;
}
private void Start()
{
ChangedToggle();
ChangedColor();
}
private void Update()
{
if (_previousActive != active)
{
ChangedToggle();
_previousActive = active;
}
if (!_previousColor.Equals(color))
{
ChangedColor();
_previousColor = color;
}
}
private void ChangedToggle()
{
if (active)
{
_material.EnableKeyword("_EMISSION");
}
else
{
_material.DisableKeyword("_EMISSION");
}
}
private void ChangedColor()
{
_material.SetColor(EmissionColorNameID, color);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 17de1e2991b64847bceea06f966f0560
timeCreated: 1668704065

View File

@@ -0,0 +1,43 @@
using NaughtyAttributes;
using UnityEngine;
namespace Station46.Runtime
{
/// <summary>
/// A holographic <see cref="Button"/> that changes its colour when it is pressed.
/// </summary>
public class HoloButton : Button
{
private static readonly int FresnelColor = Shader.PropertyToID("_FresnelColor");
private static readonly int Color = Shader.PropertyToID("_Color");
[BoxGroup("Internal")] [Required] public MeshRenderer holoRenderer;
private Material _material;
private void Awake()
{
_material = holoRenderer.material;
}
protected override void Start()
{
base.Start();
ButtonEvent += (_, _) =>
{
var color = EscapeRoomEngine.Engine.Runtime.Engine.Theme.puzzleColor;
if (!Active)
{
color = EscapeRoomEngine.Engine.Runtime.Engine.Theme.solvedColor;
} else if (Pressed)
{
color = EscapeRoomEngine.Engine.Runtime.Engine.Theme.activeColor;
}
_material.SetColor(FresnelColor, color.hdr);
_material.SetColor(Color, color.hdr);
};
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 352860bb2c6549d0b3e84104afef3f54
timeCreated: 1670019940

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using EscapeRoomEngine.Engine.Runtime.Modules.State;
using JetBrains.Annotations;
using NaughtyAttributes;
using UnityEngine;
namespace Station46.Runtime
{
/// <summary>
/// The <see cref="PuzzleState"/> of a puzzle that requires a specific state to be solved.
/// </summary>
public class StatePuzzle : PuzzleState
{
[Tooltip("The state this puzzle starts at.")]
[BoxGroup("State Puzzle")]
[SerializeField]
protected List<int> states;
[Tooltip("The state that needs to be reached for this puzzle to be solved.")]
[BoxGroup("State Puzzle")]
[SerializeField]
protected List<int> solution;
[Tooltip("Set this to the total number of states this puzzle has.")]
[BoxGroup("State Puzzle")]
[SerializeField]
[ValidateInput("CorrectStateCount", "States count must be equal to the number of states and the length of the solution.")]
[Min(0)]
protected int stateCount;
[BoxGroup("State Puzzle")]
[ProgressBar("Correct States", "stateCount", EColor.Orange)]
public int correctStates;
private List<int> _initialStates;
protected virtual void Awake()
{
_initialStates = new List<int>(states);
}
protected override void Start()
{
PuzzleEvent += (_, type) =>
{
switch (type)
{
case PuzzleEventType.Restarted:
for (var i = 0; i < stateCount; i++)
{
SetState(i, _initialStates[i], false);
}
break;
case PuzzleEventType.Solved:
for (var i = 0; i < stateCount; i++)
{
SetState(i, solution[i], false);
}
break;
case PuzzleEventType.WrongInput:
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
};
base.Start();
}
protected virtual void SetState(int index, int value, bool checkSolution)
{
if (index >= 0 && index < stateCount)
{
states[index] = value;
correctStates = 0;
for (var i = 0; i < stateCount; i++)
{
if (states[i] == solution[i])
{
correctStates++;
}
}
if (checkSolution && correctStates == stateCount && correctStates > 0)
{
Solve();
}
}
}
[UsedImplicitly] // used for field validation
private bool CorrectStateCount(int count) =>
states != null && count == states.Count &&
solution != null && count == solution.Count;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 713782041b1d40a28cfe199081a4a009
timeCreated: 1669687388

View File

@@ -0,0 +1,85 @@
using System;
using EscapeRoomEngine.Engine.Runtime.Modules.State;
using NaughtyAttributes;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
namespace Station46.Runtime
{
/// <summary>
/// The <see cref="PuzzleState"/> of a puzzle that includes a number of steps that need to be completed to solve it.
/// </summary>
public abstract class StepPuzzle : PuzzleState
{
[BoxGroup("Step Puzzle")]
[InfoBox("In easy mode, the step puzzle will not reset if a wrong input is made.")]
public bool easyMode;
[BoxGroup("Step Puzzle")] [Min(0)]
public int totalSteps;
[BoxGroup("Step Puzzle")] [ProgressBar("Step", "totalSteps", EColor.Orange)]
public int currentStep;
protected override void Start()
{
PuzzleEvent += (_, type) =>
{
switch (type)
{
case PuzzleEventType.Restarted:
currentStep = 0;
break;
case PuzzleEventType.Solved:
currentStep = totalSteps;
break;
case PuzzleEventType.WrongInput:
if (!easyMode)
{
currentStep = 0;
}
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
};
base.Start();
}
protected virtual void CheckStep(int step)
{
if (!Solved)
{
if (step == currentStep)
{
Step();
}
else
{
WrongInput();
}
}
}
#region Debug Buttons
[Button(enabledMode: EButtonEnableMode.Playmode)]
protected void Step()
{
if (!Solved)
{
currentStep++;
if (currentStep >= totalSteps)
{
Solve();
}
else
{
Logger.Log($"{this} step {currentStep}/{totalSteps}", LogType.PuzzleDetail);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5095ea3f77724269857f7275fbf7159b
timeCreated: 1669052447