A lot of changes

This commit is contained in:
Rabidus 2023-08-22 15:41:12 +03:00
parent 66c6898e17
commit 6771ed8340
538 changed files with 53627 additions and 5548 deletions

View File

@ -33,8 +33,6 @@ namespace BNG {
lookAt = Camera.main.transform; lookAt = Camera.main.transform;
lineTo = GetComponentInChildren<LineToTransform>(); lineTo = GetComponentInChildren<LineToTransform>();
childTransform = transform.GetChild(0);
if (DrawLineTo && lineTo) { if (DrawLineTo && lineTo) {
lineTo.ConnectTo = DrawLineTo; lineTo.ConnectTo = DrawLineTo;
} }

View File

@ -1,4 +1,5 @@
using System.Collections; using QFSW.QC;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;

View File

@ -81,7 +81,6 @@ namespace BNG {
public void Update() { public void Update() {
data = uiSystem.EventData; data = uiSystem.EventData;
// Can bail early if not looking at anything // Can bail early if not looking at anything
if (data == null || data.pointerCurrentRaycast.gameObject == null) { if (data == null || data.pointerCurrentRaycast.gameObject == null) {

71
Assets/BonusController.cs Normal file
View File

@ -0,0 +1,71 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class BonusController : MonoBehaviour, ITextChangable
{
public UnityEvent<object> OnTextChange => _OnTextChange;
private UnityEvent<object> _OnTextChange = new UnityEvent<object>();
private float _bonusValue = 1f;
public float BonusValue
{
get => _bonusValue;
set
{
_bonusValue = value;
_OnTextChange?.Invoke(_bonusValue);
}
}
[SerializeField]
private float _bonusOffset = 0.1f;
[SerializeField]
private float _decreaseReloadTime = 5f;
[SerializeField]
private float _decreaseSpeed = 0.6f;
private bool _decreaseBonus = false;
private Coroutine _decreaseReloadCoroutine;
private void Start()
{
BonusValue = 1;
}
private IEnumerator DecreaseReload_Coroutine()
{
_decreaseBonus = false;
yield return new WaitForSeconds(_decreaseReloadTime);
_decreaseBonus = true;
}
public void DecreaseReload()
{
if (_decreaseReloadCoroutine != null)
{
StopCoroutine(_decreaseReloadCoroutine);
}
_decreaseReloadCoroutine = StartCoroutine(DecreaseReload_Coroutine());
}
public void UseBonus()
{
BonusValue += _bonusOffset;
}
private void FixedUpdate()
{
if (_decreaseBonus)
{
BonusValue -= Time.deltaTime * _decreaseSpeed;
BonusValue = Mathf.Clamp(BonusValue, 1, float.MaxValue);
_OnTextChange?.Invoke(BonusValue);
if (BonusValue == 1)
_decreaseBonus = false;
}
}
}

View File

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

View File

@ -21,7 +21,7 @@ public class CockpitUIModule : MonoBehaviour
_UITextShow.ShowSubtitle _UITextShow.ShowSubtitle
( (
description, description,
0.01f, 0.1f,
5, 5,
null, null,
() => { _previewPanel.HidePanel(); } () => { _previewPanel.HidePanel(); }

View File

@ -0,0 +1,75 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
public class DynamicLeaderboard : MonoBehaviour, ITextChangable
{
private ScoreController _scoreController;
public UnityEvent<object> OnTextChange => _OnTextChange;
private UnityEvent<object> _OnTextChange = new UnityEvent<object>();
[SerializeField]
private RectTransform _content;
[SerializeField]
private LeaderboardEntry _leaderboardEntryPrefab;
private List<LeaderboardEntry> _entries = new List<LeaderboardEntry>();
[SerializeField]
private int _abovePlayersCount = 6;
[SerializeField]
private int _totalPlayersCount = 10;
private void Awake()
{
_scoreController = FindObjectOfType<ScoreController>();
}
private void OnEnable()
{
_scoreController.OnScoreChange += OnScoreChange;
}
private void OnDisable()
{
_scoreController.OnScoreChange -= OnScoreChange;
}
private void OnScoreChange(float value)
{
Debug.Log("Refactor leaderboard");
Debug.Log($"New player {value}");
UpdateLeaderboard();
}
[ContextMenu("Debug Update LB")]
private void UpdateLeaderboard()
{
_entries.ForEach(x => Destroy(x.gameObject));
_entries.Clear();
_entries = new List<LeaderboardEntry>();
Debug.Log("Tst");
var sortedList = PlayerSetup.Instance.PlayerInfo.Players.OrderByDescending(x => x.Score).ToList();
int indexOfOutPlayer = sortedList.IndexOf(PlayerSetup.Instance.CurrentPlayer);
int startIndex = Mathf.Clamp(indexOfOutPlayer - _abovePlayersCount, 0, sortedList.Count);
int lastIndex = Mathf.Clamp(startIndex + _totalPlayersCount, 0, sortedList.Count);
for (int i = startIndex; i < lastIndex; i++)
{
var newEntry = Instantiate(_leaderboardEntryPrefab, _content);
_entries.Add(newEntry);
newEntry.Init(sortedList[i], i, i == indexOfOutPlayer);
}
_OnTextChange?.Invoke(indexOfOutPlayer + 1);
}
}

View File

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

View File

@ -1,3 +1,4 @@
using BNG;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@ -12,9 +13,19 @@ public class EndGameModule : MonoBehaviour
[SerializeField] [SerializeField]
private UITextShow _textShow; private UITextShow _textShow;
[SerializeField]
private UITextShow _textTimer;
[SerializeField] [SerializeField]
private UIPanel _uiPanel; private UIPanel _uiPanel;
private SceneLoader _sceneLoader;
private void Awake()
{
_sceneLoader = FindObjectOfType<SceneLoader>();
}
public void ShowEndMenu(bool success) public void ShowEndMenu(bool success)
{ {
_uiPanel.ShowPanel(); _uiPanel.ShowPanel();
@ -27,5 +38,7 @@ public class EndGameModule : MonoBehaviour
{ {
_textShow.SetText(LoseText); _textShow.SetText(LoseText);
} }
_textTimer.ShowTimer(3, string.Empty, 0, null, () => { _sceneLoader.LoadScene("ResultScene"); });
} }
} }

View File

@ -8,13 +8,15 @@ public class MonumentController : MonoBehaviour
private float _energyToUnlock; private float _energyToUnlock;
[SerializeField] [SerializeField]
private MonumentInfo _info; private MonumentInfo _info;
private EnergyController _energyController; private EnergyController _energyController;
private float _currentEnergy; private float _currentEnergy;
private ScoreController _scoreController;
private CockpitUIModule _cockpitUI; private CockpitUIModule _cockpitUI;
private void Awake() private void Awake()
{ {
_scoreController = FindObjectOfType<ScoreController>();
_cockpitUI = FindObjectOfType<CockpitUIModule>(); _cockpitUI = FindObjectOfType<CockpitUIModule>();
_energyController = FindObjectOfType<EnergyController>(); _energyController = FindObjectOfType<EnergyController>();
_currentEnergy = _energyToUnlock; _currentEnergy = _energyToUnlock;
@ -31,10 +33,12 @@ public class MonumentController : MonoBehaviour
Debug.Log($"Clamped energy value: {_currentEnergy / _energyToUnlock}"); Debug.Log($"Clamped energy value: {_currentEnergy / _energyToUnlock}");
}); });
_scoreController.AddScoreInTime(_info.Score, 1, false);
//TODO: ÐÀÇÁËÎÊÈÐÎÂÀÒÜ ÌÎÍÓÌÅÍÒ ÒÎËÜÊÎ ÅÑËÈ ÕÂÀÒÈËÎ ÝÍÅÐÃÈÈ //TODO: ÐÀÇÁËÎÊÈÐÎÂÀÒÜ ÌÎÍÓÌÅÍÒ ÒÎËÜÊÎ ÅÑËÈ ÕÂÀÒÈËÎ ÝÍÅÐÃÈÈ
PlayerSetup.Instance.UnlockMonument(_info); PlayerSetup.Instance.UnlockMonument(_info);
} }
[ContextMenu("Debug Preview")]
public void ShowPreview() public void ShowPreview()
{ {
_cockpitUI.ShowInfo(_info.Image, _info.Description); _cockpitUI.ShowInfo(_info.Image, _info.Description);

8
Assets/Plugins/QFSW.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 82d1493c4b76fa64485519afe8919eae
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b8ce61d0462147c4789d22c6bdacd045
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7288d5d133aff2a4ea46b88ef2d9a151
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0b8922a5489a74b5ebfd54fa257dbfc6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b6dcd5bbe38024ae6b2389ff04c696a0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,167 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Gate
serializedVersion: 5
m_AnimatorParameters:
- m_Name: opened
m_Type: 4
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 0}
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: 1107068299116960040}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1101 &1101412341846453426
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: opened
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 1102542311080980048}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0
m_TransitionOffset: 0
m_ExitTime: 1
m_HasExitTime: 0
m_HasFixedDuration: 0
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1101 &1101867287240705608
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 2
m_ConditionEvent: opened
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 1102970369894184824}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0
m_TransitionOffset: 0
m_ExitTime: 1
m_HasExitTime: 0
m_HasFixedDuration: 0
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1102 &1102542311080980048
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: GateOpen
m_Speed: 1
m_CycleOffset: 0
m_Transitions:
- {fileID: 1101867287240705608}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 509dd06e376974a80be87395ca1da5b8, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &1102970369894184824
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 3
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: GateClose
m_Speed: -1
m_CycleOffset: 0
m_Transitions:
- {fileID: 1101412341846453426}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 509dd06e376974a80be87395ca1da5b8, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &1107068299116960040
AnimatorStateMachine:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 1102542311080980048}
m_Position: {x: 276, y: 60, z: 0}
- serializedVersion: 1
m_State: {fileID: 1102970369894184824}
m_Position: {x: 276, y: 120, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions:
- {fileID: 1109804302365171388}
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 1102970369894184824}
--- !u!1109 &1109804302365171388
AnimatorTransition:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name:
m_Conditions: []
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 1102970369894184824}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4116117e33ea046eab1abc1d101b4086
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,169 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: GateOpen
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: {x: 0, y: 0, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
weightedMode: 0
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 1
value: {x: 0, y: 8, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
weightedMode: 0
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
path:
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings:
- serializedVersion: 2
path: 0
attribute: 1
script: {fileID: 0}
typeID: 4
customType: 0
isPPtrCurve: 0
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalPosition.x
path:
classID: 4
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 8
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalPosition.y
path:
classID: 4
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalPosition.z
path:
classID: 4
script: {fileID: 0}
m_EulerEditorCurves: []
m_HasGenericRootTransform: 1
m_HasMotionFloatCurves: 0
m_GenerateMotionCurves: 0
m_Events: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 509dd06e376974a80be87395ca1da5b8
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,199 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: PortalSpin
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: {x: 0, y: 0, z: 0}
inSlope: {x: 0, y: 0, z: 0}
outSlope: {x: 0, y: 0, z: 360}
tangentMode: 0
weightedMode: 0
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
- serializedVersion: 3
time: 1
value: {x: 0, y: 0, z: 360}
inSlope: {x: 0, y: 0, z: 360}
outSlope: {x: 0, y: 0, z: 0}
tangentMode: 0
weightedMode: 0
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
path:
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings:
- serializedVersion: 2
path: 0
attribute: 4
script: {fileID: 0}
typeID: 4
customType: 4
isPPtrCurve: 0
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 1
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: localEulerAnglesRaw.x
path:
classID: 4
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: localEulerAnglesRaw.y
path:
classID: 4
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 360
tangentMode: 69
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 360
inSlope: 360
outSlope: 0
tangentMode: 69
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: localEulerAnglesRaw.z
path:
classID: 4
script: {fileID: 0}
m_EulerEditorCurves:
- curve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.x
path:
classID: 4
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.y
path:
classID: 4
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_LocalEulerAngles.z
path:
classID: 4
script: {fileID: 0}
m_HasGenericRootTransform: 1
m_HasMotionFloatCurves: 0
m_GenerateMotionCurves: 0
m_Events: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 369af09a6286845af89edd5fb87ea4ab
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,69 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Robot
serializedVersion: 5
m_AnimatorParameters: []
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: 1107790489636618392}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1102 &1102928324420026016
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: RobotSpawn
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: e0cdbf2bd85184df4876857725a99162, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &1107790489636618392
AnimatorStateMachine:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 1102928324420026016}
m_Position: {x: 200, y: 0, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 1102928324420026016}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fcb592e7f51614bc6be3d2034b632324
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,116 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: RobotSpawn
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.a
path:
classID: 212
script: {fileID: 0}
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings:
- serializedVersion: 2
path: 0
attribute: 304273561
script: {fileID: 0}
typeID: 212
customType: 0
isPPtrCurve: 0
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.a
path:
classID: 212
script: {fileID: 0}
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_GenerateMotionCurves: 0
m_Events: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e0cdbf2bd85184df4876857725a99162
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,69 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Spawner
serializedVersion: 5
m_AnimatorParameters: []
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: 1107650806890895214}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1102 &1102004645330244398
AnimatorState:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: PortalSpin
m_Speed: 0.1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 369af09a6286845af89edd5fb87ea4ab, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &1107650806890895214
AnimatorStateMachine:
serializedVersion: 5
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 1102004645330244398}
m_Position: {x: 288, y: 12, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 1102004645330244398}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 218385955853b4c2aa8e61d73c9ccf9a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cbc636f930f78c841a91c76a805bdfec
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bc50aa7d3c68e401fb3939c922f370de
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Wall
m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 0, g: 0, b: 0, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 74fff7569131340688b27f2f282eee79
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 58f99f13eb6344631a9c68dc36ae0da2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 936e24cdf062b45d7a0d2fecc1c4645f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 100100000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6aaea0b280ad247e6b395b06007de823
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 100100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,10 @@
{
"name": "QFSW.QC.Demo",
"references": [
"QFSW.QC"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 81dcdc43a74004ddaa6ad1d5df1941d9
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c52af6b1dac954e92b05a602b0bd809e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using UnityEngine;
namespace QFSW.QC.Demo
{
[CommandPrefix("demo.gate.")]
public class Gate : MonoBehaviour
{
[Command("opened")]
private bool IsOpened
{
get { return GetComponent<Animator>().GetBool("opened"); }
set { GetComponent<Animator>().SetBool("opened", value); }
}
}
}

View File

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

View File

@ -0,0 +1,63 @@
using QFSW.QC.Actions;
using System.Collections.Generic;
using UnityEngine;
namespace QFSW.QC.Demo
{
[CommandPrefix("demo.robot.")]
public class Robot : MonoBehaviour
{
[SerializeField] private GameObject deathFX = null;
[Command("speed")]
private static float robotSpeed = 25f;
[Command("rotation-speed")]
private static float robotRotationSpeed = 40f;
private Vector2 direction;
private void Start()
{
SpriteRenderer rend = GetComponent<SpriteRenderer>();
rend.color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1);
float size = Random.Range(0.8f, 1.2f);
transform.localScale = new Vector3(size, size, size);
direction = Quaternion.Euler(0, 0, Random.Range(0, 306f)) * Vector3.up;
}
private void FixedUpdate()
{
GetComponent<Rigidbody2D>().AddForce(direction * robotSpeed * Time.fixedDeltaTime, ForceMode2D.Force);
direction = Quaternion.Euler(0, 0, robotRotationSpeed * Time.fixedDeltaTime) * direction;
}
[Command("kill")]
private static IEnumerator<ICommandAction> KillAction()
{
Robot robot = default;
IEnumerable<Robot> robots = InvocationTargetFactory.FindTargets<Robot>(MonoTargetType.All);
yield return new Value("Please select a robot");
yield return new Choice<Robot>(robots, r => robot = r);
robot.Die();
yield return new Typewriter($"{robot.name} has been killed");
}
[Command("kill-all", MonoTargetType.All)]
public void Die()
{
Destroy(gameObject);
Destroy(Instantiate(deathFX, transform.position, Quaternion.identity), 3);
}
[Command("position", MonoTargetType.All)]
private Vector3 GetPosition()
{
return transform.position;
}
}
}

View File

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

View File

@ -0,0 +1,32 @@
using QFSW.QC.Utilities;
using UnityEngine;
using UnityEngine.UI;
namespace QFSW.QC.Demo
{
public class RobotCollector : MonoBehaviour
{
[SerializeField] private Text text = null;
[SerializeField] private QuantumTheme theme = null;
public int RescueCount { [Command("demo.rescue-count")] get; set; }
private void Start() { UpdateText(); }
private void UpdateText()
{
if (!theme) { text.text = $"{RescueCount} robots saved"; }
else { text.text = $"{RescueCount.ToString().ColorText(theme.DefaultReturnValueColor)} robots saved"; }
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
Robot robot = collision.gameObject.GetComponent<Robot>();
robot.Die();
RescueCount++;
UpdateText();
}
}
}
}

View File

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

View File

@ -0,0 +1,41 @@
using QFSW.QC.Utilities;
using UnityEngine;
using UnityEngine.UI;
namespace QFSW.QC.Demo
{
public class RobotSpawner : MonoBehaviour
{
[SerializeField] private Robot robotPrefab = null;
[SerializeField] private Text text = null;
[SerializeField] private QuantumTheme theme = null;
public int SpawnCount { [Command("demo.spawn-count")] get; private set; }
private void Start()
{
UpdateText();
SpawnRobot(3);
}
private void UpdateText()
{
if (!theme) { text.text = $"{SpawnCount} robots spawned"; }
else { text.text = $"{SpawnCount.ToString().ColorText(theme.DefaultReturnValueColor)} robots spawned"; }
}
[Command("demo.spawn-robot", MonoTargetType.Single)]
private void SpawnRobot(int count = 1)
{
for (int i = 0; i < count; i++)
{
SpawnCount++;
Vector3 position = transform.position;
position += new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f));
Instantiate(robotPrefab, position, Quaternion.identity).name = $"Robot {SpawnCount}";
}
UpdateText();
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b260e8963b08448ca8ae2d294cd86a9d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 21fb6714fde0b41b9ba9639d03f5a2a6
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 5
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 250
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 74ba36e6ac0d745c797b45b2c532ddd4
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: c1df40d40cc814a5695dee0e707cc03a
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 5
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 2
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 2
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 2
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 2
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 23ecb33d1ab634744b034264cd11fdc3
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 8cc6f758dd676460aac0a91f8280a09d
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 5
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 3
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 3feb5bdcb77204fdd9c897cd167575ea
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 19ace80b238594f46b6f69852fb1f584
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 5
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 3
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 200
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e7a1b038cc18484292116f59906d7b7
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 952ba3bc3099845f7b7ba6943e79ce9f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class ApplicationCommands
{
[Command("quit", "Quits the player application")]
[CommandPlatform(Platform.AllPlatforms ^ (Platform.EditorPlatforms | Platform.WebGLPlayer))]
private static void Quit()
{
Application.Quit();
}
}
}

View File

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

View File

@ -0,0 +1,24 @@
using System;
using System.Collections;
using UnityEngine;
namespace QFSW.QC.Extras
{
[AddComponentMenu("")]
public class CoroutineCommands : MonoBehaviour
{
[Command("start-coroutine", "starts the supplied command as a coroutine", MonoTargetType.Singleton)]
private void StartCoroutineCommand(string coroutineCommand)
{
object coroutineReturn = QuantumConsoleProcessor.InvokeCommand(coroutineCommand);
if (coroutineReturn is IEnumerator)
{
StartCoroutine(coroutineReturn as IEnumerator);
}
else
{
throw new ArgumentException($"{coroutineCommand} is not a coroutine");
}
}
}
}

View File

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

View File

@ -0,0 +1,115 @@
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Extras
{
internal static class EditorCommands
{
private static IEnumerable<GameObject> LoadPrefabs(string prefabName, params PrefabAssetType[] prefabTypes)
{
string filter = $"{prefabName} t:GameObject";
string[] guids = AssetDatabase.FindAssets(filter);
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (obj.name == prefabName)
{
if (prefabTypes.Contains(PrefabUtility.GetPrefabAssetType(obj)))
{
yield return obj;
}
}
}
}
private static T ForceSingle<T>(IEnumerable<T> stream, string errorMessage, string warningMessage)
{
bool singleFound = false;
T single = default;
foreach (T item in stream)
{
if (singleFound)
{
Debug.LogWarning(warningMessage);
break;
}
single = item;
singleFound = true;
}
if (singleFound)
{
return single;
}
else
{
throw new ArgumentException(errorMessage);
}
}
private static GameObject LoadPrefab(string prefabName)
{
IEnumerable<GameObject> prefabs = LoadPrefabs(prefabName, PrefabAssetType.Regular, PrefabAssetType.Variant);
return ForceSingle(prefabs, $"No prefab with the name {prefabName} could be found.", $"Multiple prefabs with the name {prefabName} were found");
}
private static GameObject LoadModel(string modelName)
{
IEnumerable<GameObject> models = LoadPrefabs(modelName, PrefabAssetType.Model);
return ForceSingle(models, $"No model with the name {modelName} could be found.", $"Multiple models with the name {modelName} were found");
}
[Command("instantiate-prefab", "Instantiates a GameObject from the specified prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromPrefab(
[CommandParameterDescription("The name of the prefab to instantiate a copy of.")]string prefabName,
[CommandParameterDescription("The position of the instantiated GameObject.")]Vector3 position,
[CommandParameterDescription("The rotation of the instantiated GameObject.")]Quaternion rotation)
{
GameObject.Instantiate(LoadPrefab(prefabName), position, rotation);
}
[Command("instantiate-prefab", "Instantiates a GameObject from the specified prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromPrefab(string prefabName, Vector3 position)
{
GameObject prefab = LoadPrefab(prefabName);
GameObject.Instantiate(prefab, position, prefab.transform.rotation);
}
[Command("instantiate-prefab", "Instantiates a GameObject from the specified prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromPrefab(string prefabName)
{
GameObject.Instantiate(LoadPrefab(prefabName));
}
[Command("instantiate-model", "Instantiates a GameObject from the specified model prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromModelPrefab(
[CommandParameterDescription("The name of the model to instantiate a copy of.")]string modelName,
[CommandParameterDescription("The position of the instantiated GameObject.")]Vector3 position,
[CommandParameterDescription("The rotation of the instantiated GameObject.")]Quaternion rotation)
{
GameObject.Instantiate(LoadModel(modelName), position, rotation);
}
[Command("instantiate-model", "Instantiates a GameObject from the specified model prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromModelPrefab(string modelName, Vector3 position)
{
GameObject prefab = LoadModel(modelName);
GameObject.Instantiate(prefab, position, prefab.transform.rotation);
}
[Command("instantiate-model", "Instantiates a GameObject from the specified model prefab", Platform.EditorPlatforms)]
private static void InstantiateGOFromModelPrefab(string modelName)
{
GameObject.Instantiate(LoadModel(modelName));
}
}
}
#endif

View File

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

View File

@ -0,0 +1,31 @@
using System.IO;
using System.Threading.Tasks;
namespace QFSW.QC.Extras
{
public static class FileCommands
{
[Command("write-file", Platform.AllPlatforms ^ Platform.WebGLPlayer)]
[CommandDescription("Writes the provided data to a file at the provided path")]
private static async Task WriteFile(string path, string data)
{
FileInfo file = new FileInfo(path);
file.Directory?.Create();
using (StreamWriter writer = new StreamWriter(path))
{
await writer.WriteAsync(data);
}
}
[Command("read-file", Platform.AllPlatforms ^ Platform.WebGLPlayer)]
[CommandDescription("Reads the contents of the file at the provided path")]
private static string ReadFile(string path)
{
using (StreamReader reader = new StreamReader(path))
{
return reader.ReadToEnd();
}
}
}
}

View File

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

View File

@ -0,0 +1,28 @@
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class GraphicsCommands
{
[Command("max-fps", "the maximum FPS imposed on the application. Set to -1 for unlimited.")]
private static int MaxFPS
{
get => Application.targetFrameRate;
set => Application.targetFrameRate = value;
}
[Command("vsync", "enables or disables vsync for the application.")]
private static bool VSync
{
get => QualitySettings.vSyncCount > 0;
set => QualitySettings.vSyncCount = value ? 1 : 0;
}
[Command("msaa", "Gets or sets the number of msaa samples in use. Valid values are 0, 2, 4 and 8.")]
private static int MSAA
{
get => QualitySettings.antiAliasing;
set => QualitySettings.antiAliasing = value;
}
}
}

View File

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

View File

@ -0,0 +1,48 @@
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace QFSW.QC.Extras
{
[CommandPrefix("http.")]
public static class HttpCommands
{
private static readonly HttpClient _client = new HttpClient();
[Command("get", "Sends a GET request to the specified URL.")]
private static async Task<string> Get(string url)
{
HttpResponseMessage response = await _client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
[Command("delete", "Sends a DELETE request to the specified URL.")]
private static async Task<string> Delete(string url)
{
HttpResponseMessage response = await _client.DeleteAsync(url);
return await response.Content.ReadAsStringAsync();
}
[Command("post", "Sends a POST request to the specified URL. " +
"A body may be sent with the request, with a default mediaType of text/plain.")]
private static async Task<string> Post(string url, string content = "", string mediaType = "text/plain")
{
HttpContent body = new StringContent(content, Encoding.Default, mediaType);
HttpResponseMessage response = await _client.PostAsync(url, body);
return await response.Content.ReadAsStringAsync();
}
[Command("put", "Sends a PUT request to the specified URL. " +
"A body may be sent with the request, with a default mediaType of text/plain.")]
private static async Task<string> Put(string url, string content = "", string mediaType = "text/plain")
{
HttpContent body = new StringContent(content, Encoding.Default, mediaType);
HttpResponseMessage response = await _client.PutAsync(url, body);
return await response.Content.ReadAsStringAsync();
}
}
}

View File

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

View File

@ -0,0 +1,98 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QFSW.QC.Extras
{
public class KeyBinderModule : MonoBehaviour
{
private readonly struct Binding
{
public readonly KeyCode Key;
public readonly string Command;
public Binding(KeyCode key, string command)
{
Key = key;
Command = command;
}
}
private readonly List<Binding> _bindings = new List<Binding>();
private QuantumConsole _consoleInstance;
private bool _blocked = false;
private void BlockInput() { _blocked = true; }
private void UnblockInput() { _blocked = false; }
private void BindToConsoleInstance()
{
if (!_consoleInstance) { _consoleInstance = FindObjectOfType<QuantumConsole>(); }
if (_consoleInstance)
{
_consoleInstance.OnActivate += BlockInput;
_consoleInstance.OnDeactivate += UnblockInput;
_blocked = _consoleInstance.IsActive;
}
else
{
UnblockInput();
}
}
private void Awake()
{
BindToConsoleInstance();
}
private void Update()
{
if (!_blocked)
{
foreach (Binding binding in _bindings)
{
if (InputHelper.GetKeyDown(binding.Key))
{
try
{
QuantumConsoleProcessor.InvokeCommand(binding.Command);
}
catch (System.Exception e) { Debug.LogException(e); }
}
}
}
}
[Command("bind", MonoTargetType.Singleton)]
[CommandDescription("Binds a given command to a given key, so that every time the key is pressed, the command is invoked.")]
private void AddBinding(KeyCode key, string command)
{
_bindings.Add(new Binding(key, command));
}
[Command("unbind", MonoTargetType.Singleton)]
[CommandDescription("Removes every binding for the given key")]
private void RemoveBindings(KeyCode key)
{
_bindings.RemoveAll(x => x.Key == key);
}
[Command("unbind-all", MonoTargetType.Singleton)]
[CommandDescription("Unbinds every existing key binding")]
private void RemoveAllBindings()
{
_bindings.Clear();
}
[Command("display-bindings", MonoTargetType.Singleton)]
[CommandDescription("Displays all existing bindings on the key binder")]
private IEnumerable<object> DisplayAllBindings()
{
foreach (Binding binding in _bindings.OrderBy(x => x.Key))
{
yield return new KeyValuePair<KeyCode, string>(binding.Key, binding.Command);
}
}
}
}

View File

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

View File

@ -0,0 +1,249 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace QFSW.QC.Extras
{
public static class MegaCommands
{
private static readonly QuantumSerializer Serializer = new QuantumSerializer();
private static readonly QuantumParser Parser = new QuantumParser();
private static MethodInfo[] ExtractMethods(Type type, string name)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod |
BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
MethodInfo[] methods = type.GetMethods(flags).Where(x => x.Name == name).ToArray();
if (!methods.Any())
{
PropertyInfo property = type.GetProperty(name, flags);
if (property != null)
{
methods = new[] {property.GetMethod, property.SetMethod}.Where(x => x != null).ToArray();
if (methods.Length > 0)
{
return methods;
}
}
throw new ArgumentException($"No method or property named {name} could be found in class {Serializer.SerializeFormatted(type)}");
}
return methods;
}
private static string GenerateSignature(MethodInfo method)
{
IEnumerable<string> paramParts = method.GetParameters()
.Select(x => (x.Name, x.ParameterType))
.Select(x => $"{x.ParameterType.GetDisplayName()} {x.Name}");
string paramSignature = string.Join(", ", paramParts);
return $"{method.Name}({paramSignature})";
}
private static MethodInfo GetIdealOverload(MethodInfo[] methods, bool isStatic, int argc)
{
methods = methods.Where(x => x.IsStatic == isStatic).ToArray();
if (methods.Length == 0)
{
throw new ArgumentException($"No {(isStatic ? "static" : "non-static")} overloads could be found.");
}
if (methods.Length == 1)
{
return methods[0];
}
methods = methods.Where(x => !x.IsGenericMethod).ToArray();
if (methods.Length == 0)
{
throw new ArgumentException("Generic methods are not supported.");
}
MethodInfo[] argcMatches = methods.Where(x => x.GetParameters().Length == argc).ToArray();
if (argcMatches.Length == 1)
{
return argcMatches[0];
}
else if (argcMatches.Length == 0)
{
IEnumerable<string> signatures = methods.Select(GenerateSignature);
string combinedSignatures = string.Join("\n", signatures);
throw new ArgumentException($"No overloads with {argc} arguments were found. the following overloads are available:\n{combinedSignatures}");
}
else
{
IEnumerable<string> signatures = argcMatches.Select(GenerateSignature);
string combinedSignatures = string.Join("\n", signatures);
throw new ArgumentException($"Multiple overloads with the same argument count were found: please specify the types explicitly.\n{combinedSignatures}");
}
}
private static MethodInfo GetIdealOverload(MethodInfo[] methods, bool isStatic, Type[] argTypes)
{
// Exact matching
foreach (MethodInfo method in methods)
{
if (method.IsStatic == isStatic)
{
IEnumerable<Type> methodParamTypes = method.GetParameters().Select(x => x.ParameterType);
if (methodParamTypes.SequenceEqual(argTypes))
{
return method;
}
}
}
// Polymorphic matching
foreach (MethodInfo method in methods)
{
if (method.IsStatic == isStatic)
{
ParameterInfo[] methodParams = method.GetParameters();
if (methodParams.Length == argTypes.Length)
{
bool isMatch = methodParams
.Select(x => x.ParameterType)
.Zip(argTypes, (x, y) => (x, y))
.All(pair => pair.x.IsAssignableFrom(pair.y));
if (isMatch)
{
return method;
}
}
}
}
throw new ArgumentException("No overload with the supplied argument types could be found.");
}
private static object[] CreateArgs(MethodInfo method, string[] rawArgs)
{
ParameterInfo[] methodParams = method.GetParameters();
Type[] argTypes = methodParams.Select(x => x.ParameterType).ToArray();
return CreateArgs(method, argTypes, rawArgs);
}
private static object[] CreateArgs(MethodInfo method, Type[] argTypes, string[] rawArgs)
{
ParameterInfo[] methodParams = method.GetParameters();
int defaultArgs = methodParams.Count(x => x.HasDefaultValue);
if (rawArgs.Length < argTypes.Length - defaultArgs || rawArgs.Length > argTypes.Length)
{
throw new ArgumentException($"Incorrect number ({rawArgs.Length}) of arguments supplied for {Serializer.SerializeFormatted(method.DeclaringType)}.{method.Name}" +
$", expected {argTypes.Length}");
}
object[] parsedArgs = new object[argTypes.Length];
for (int i = 0; i < parsedArgs.Length; i++)
{
if (i < rawArgs.Length)
{
parsedArgs[i] = Parser.Parse(rawArgs[i], argTypes[i]);
}
else
{
parsedArgs[i] = methodParams[i].DefaultValue;
}
}
return parsedArgs;
}
private static object InvokeAndUnwrapException(this MethodInfo method, object[] args)
{
try
{
return method.Invoke(null, args);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
private static object InvokeAndUnwrapException(this MethodInfo method, IEnumerable<object> targets, object[] args)
{
try
{
return InvocationTargetFactory.InvokeOnTargets(method, targets, args);
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
[Command("call-static")]
private static object CallStatic(Type classType, string funcName)
{
return CallStatic(classType, funcName, Array.Empty<string>());
}
[Command("call-static")]
private static object CallStatic(Type classType, string funcName, string[] args)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, true, args.Length);
object[] parsedArgs = CreateArgs(method, args);
return method.InvokeAndUnwrapException(parsedArgs);
}
[Command("call-static")]
[CommandDescription("Invokes the specified static method or property with the provided arguments. Provide [argTypes] if there are ambiguous overloads")]
private static object CallStatic(
[CommandParameterDescription("Namespace qualified typename of the class.")] Type classType,
[CommandParameterDescription("Name of the method or property.")] string funcName,
[CommandParameterDescription("The arguments for the function call.")] string[] args,
[CommandParameterDescription("The types of the arguments to resolve ambiguous overloads.")] Type[] argTypes)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, true, argTypes);
object[] parsedArgs = CreateArgs(method, argTypes, args);
return method.InvokeAndUnwrapException(parsedArgs);
}
[Command("call-instance")]
private static object CallInstance(Type classType, string funcName, MonoTargetType targetType)
{
return CallInstance(classType, funcName, targetType, Array.Empty<string>());
}
[Command("call-instance")]
private static object CallInstance(Type classType, string funcName, MonoTargetType targetType, string[] args)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, false, args.Length);
object[] parsedArgs = CreateArgs(method, args);
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(classType, targetType);
return method.InvokeAndUnwrapException(targets, parsedArgs);
}
[Command("call-instance")]
[CommandDescription("Invokes the specified non-static method or property with the provided arguments. Provide [argTypes] if there are ambiguous overloads")]
private static object CallInstance(
[CommandParameterDescription("Namespace qualified typename of the class.")] Type classType,
[CommandParameterDescription("Name of the method or property.")] string funcName,
[CommandParameterDescription("The MonoTargetType used to find the target instances.")] MonoTargetType targetType,
[CommandParameterDescription("The arguments for the function call.")] string[] args,
[CommandParameterDescription("The types of the arguments to resolve ambiguous overloads.")] Type[] argTypes)
{
MethodInfo[] methods = ExtractMethods(classType, funcName);
MethodInfo method = GetIdealOverload(methods, false, argTypes);
object[] parsedArgs = CreateArgs(method, argTypes, args);
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(classType, targetType);
return method.InvokeAndUnwrapException(targets, parsedArgs);
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
{
"name": "QFSW.QC.Extras",
"references": [
"QFSW.QC"
],
"includePlatforms": [],
"excludePlatforms": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dbe7cf6698bd54a63bc00412d71f8b48
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace QFSW.QC.Extras
{
public static class SceneCommands
{
private static async Task PollUntilAsync(int pollInterval, Func<bool> predicate)
{
while (!predicate())
{
await Task.Delay(pollInterval);
}
}
[Command("load-scene", "loads a scene by name into the game")]
private static async Task LoadScene(string sceneName,
[CommandParameterDescription("'Single' mode replaces the current scene with the new scene, whereas 'Additive' merges them")]LoadSceneMode loadMode = LoadSceneMode.Single)
{
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName, loadMode);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("load-scene-index", "loads a scene by index into the game")]
private static async Task LoadScene(int sceneIndex,
[CommandParameterDescription("'Single' mode replaces the current scene with the new scene, whereas 'Additive' merges them")]LoadSceneMode loadMode = LoadSceneMode.Single)
{
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneIndex, loadMode);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("unload-scene", "unloads a scene by name")]
private static async Task UnloadScene(string sceneName)
{
AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneName);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
[Command("unload-scene-index", "unloads a scene by index")]
private static async Task UnloadScene(int sceneIndex)
{
AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneIndex);
await PollUntilAsync(16, () => asyncOperation.isDone);
}
private static IEnumerable<Scene> GetScenesInBuild()
{
int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++)
{
Scene scene = SceneManager.GetSceneByBuildIndex(i);
yield return scene;
}
}
[Command("all-scenes", "gets the name and index of every scene included in the build")]
private static Dictionary<int, string> GetAllScenes()
{
Dictionary<int, string> sceneData = new Dictionary<int, string>();
int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++)
{
int sceneIndex = i;
string scenePath = SceneUtility.GetScenePathByBuildIndex(sceneIndex);
string sceneName = System.IO.Path.GetFileNameWithoutExtension(scenePath);
sceneData.Add(sceneIndex, sceneName);
}
return sceneData;
}
[Command("loaded-scenes", "gets the name and index of every scene currently loaded")]
private static Dictionary<int, string> GetLoadedScenes()
{
IEnumerable<Scene> loadedScenes = GetScenesInBuild().Where(x => x.isLoaded);
Dictionary<int, string> sceneData = loadedScenes.ToDictionary(x => x.buildIndex, x => x.name);
return sceneData;
}
[Command("active-scene", "gets the name of the active primary scene")]
private static string GetCurrentScene()
{
Scene scene = SceneManager.GetActiveScene();
return scene.name;
}
[Command("set-active-scene", "sets the active scene to the scene with name 'sceneName'")]
private static void SetActiveScene(string sceneName)
{
Scene scene = SceneManager.GetSceneByName(sceneName);
if (!scene.isLoaded) { throw new ArgumentException($"Scene {sceneName} must be loaded before it can be set active"); }
SceneManager.SetActiveScene(scene);
}
}
}

View File

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

View File

@ -0,0 +1,72 @@
using System.Collections.Generic;
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class ScreenCommands
{
[Command("fullscreen", "fullscreen state of the application.")]
private static bool Fullscreen
{
get => Screen.fullScreen;
set => Screen.fullScreen = value;
}
[Command("screen-dpi", "dpi of the current device's screen.")]
private static float DPI => Screen.dpi;
[Command("screen-orientation", "the orientation of the screen.")]
[CommandPlatform(Platform.MobilePlatforms)]
private static ScreenOrientation Orientation
{
get => Screen.orientation;
set => Screen.orientation = value;
}
[Command("current-resolution", "current resolution of the application or window.")]
private static Resolution GetCurrentResolution()
{
Resolution resolution = new Resolution
{
width = Screen.width,
height = Screen.height,
refreshRate = Screen.currentResolution.refreshRate
};
return resolution;
}
[Command("supported-resolutions", "all resolutions supported by this device in fullscreen mode.")]
[CommandPlatform(Platform.AllPlatforms ^ Platform.WebGLPlayer)]
private static IEnumerable<Resolution> GetSupportedResolutions()
{
foreach (Resolution resolution in Screen.resolutions)
{
yield return resolution;
}
}
[Command("set-resolution")]
private static void SetResolution(int x, int y)
{
SetResolution(x, y, Screen.fullScreen);
}
[Command("set-resolution", "sets the resolution of the current application, optionally setting the fullscreen state too.")]
private static void SetResolution(int x, int y, bool fullscreen)
{
Screen.SetResolution(x, y, fullscreen);
}
[Command("capture-screenshot")]
[CommandDescription("Captures a screenshot and saves it to the supplied file path as a PNG.\n" +
"If superSize is supplied the screenshot will be captured at a higher than native resolution.")]
private static void CaptureScreenshot(
[CommandParameterDescription("The name of the file to save the screenshot in")] string filename,
[CommandParameterDescription("Factor by which to increase resolution")] int superSize = 1
)
{
ScreenCapture.CaptureScreenshot(filename, superSize);
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
using UnityEngine;
namespace QFSW.QC.Extras
{
public static class TimeCommands
{
[Command("time-scale", "the scale at which time is passing by.")]
private static float TimeScale
{
get => Time.timeScale;
set => Time.timeScale = value;
}
}
}

View File

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

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC.Extras
{
public static class TypeCommands
{
[Command("enum-info", "gets all of the numeric values and value names for the specified enum type.")]
private static IEnumerable<object> GetEnumInfo(Type enumType)
{
if (!enumType.IsEnum) { throw new ArgumentException($"Supplied type '{enumType}' must be an enum type"); }
Type enumInnerType = enumType.GetEnumUnderlyingType();
Array vals = enumType.GetEnumValues();
for (int i = 0; i < vals.Length; i++)
{
object name = vals.GetValue(i);
object val = Convert.ChangeType(name, enumInnerType);
KeyValuePair<object, object> pair = new KeyValuePair<object, object>(val, name);
yield return pair;
}
}
}
}

View File

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

View File

@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace QFSW.QC.Extras
{
public static class UtilCommands
{
private static readonly Pool<StringBuilder> _builderPool = new Pool<StringBuilder>();
[Command("get-object-info", "Finds the specified GameObject and displays its transform and component data")]
private static string ExtractObjectInfo(GameObject target)
{
StringBuilder builder = _builderPool.GetObject();
builder.Clear();
builder.AppendLine($"Extracted info for object '{target.name}'");
builder.AppendLine("Transform data:");
builder.AppendLine($" - position: {target.transform.position}");
builder.AppendLine($" - rotation: {target.transform.localRotation}");
builder.AppendLine($" - scale: {target.transform.localScale}");
if (target.transform.childCount > 0) { builder.AppendLine($" - child count: {target.transform.childCount}"); }
if (target.transform.parent) { builder.AppendLine($" - parent: {target.transform.parent.name}"); }
Component[] components = target.GetComponents<Component>().OrderBy(x => x.GetType().Name).ToArray();
if (components.Length > 0)
{
builder.AppendLine("Component data:");
for (int i = 0; i < components.Length; i++)
{
int componentCount = 1;
Type componentType = components[i].GetType();
builder.AppendLine($" - {componentType.Name}");
while (i + 1 < components.Length && components[i + 1].GetType() == componentType)
{
componentCount++;
i++;
}
if (componentCount > 1) { builder.Append($" ({componentCount})"); }
}
}
if (target.transform.childCount > 0)
{
builder.AppendLine("Children:");
int childCount = target.transform.childCount;
for (int i = 0; i < childCount; i++)
{
builder.AppendLine($" - {target.transform.GetChild(i).name}");
}
}
string info = builder.ToString();
_builderPool.Release(builder);
return info;
}
[Command("get-scene-hierarchy", "Renders the GameObject hierarchy of the currently open scenes")]
private static string GetSceneHierarchy()
{
List<GameObject> objects = new List<GameObject>();
StringBuilder buffer = _builderPool.GetObject();
buffer.Clear();
int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++)
{
Scene scene = SceneManager.GetSceneByBuildIndex(i);
if (scene.isLoaded)
{
objects.Clear();
scene.GetRootGameObjects(objects);
buffer.AppendLine(scene.name);
GetSceneHierarchy(objects.Select(x => x.transform).ToArray(), 0, buffer, new List<bool>());
}
}
string result = buffer.ToString();
_builderPool.Release(buffer);
return result;
}
private static IEnumerable<Transform> GetChildren(this Transform transform)
{
for (int i = 0; i < transform.childCount; i++)
{
yield return transform.GetChild(i);
}
}
private static void GetSceneHierarchy(IList<Transform> roots, int depth, StringBuilder buffer, IList<bool> drawVertical)
{
const char terminalSymbol = '|';
const char verticalSplitSymbol = '|';
const char verticalSymbol = '|';
const char horizontalSymbol = '-';
const int indentation = 3;
for (int i = 0; i < roots.Count; i++)
{
Transform root = roots[i];
for (int j = 0; j < depth; j++)
{
buffer.Append(drawVertical[j] ? verticalSymbol : ' ');
buffer.Append(' ', indentation - 1);
}
bool terminal = i == roots.Count - 1;
drawVertical.Add(!terminal);
buffer.Append(terminal ? terminalSymbol : verticalSplitSymbol);
buffer.Append(horizontalSymbol, indentation - 1);
buffer.AppendLine(root.name);
GetSceneHierarchy(root.GetChildren().ToList(), depth + 1, buffer, drawVertical);
drawVertical.RemoveAt(drawVertical.Count - 1);
}
}
[Command("add-component", "Adds a component of type T to the specified GameObject")]
private static void AddComponent<T>(GameObject target) where T : Component { target.AddComponent<T>(); }
[Command("destroy-component", "Destroys the component of type T on the specified GameObject")]
private static void DestroyComponent<T>(T target) where T : Component { GameObject.Destroy(target); }
[Command("destroy", "Destroys a GameObject")]
private static void DestroyGO(GameObject target) { GameObject.Destroy(target); }
[Command("instantiate", "Instantiates a GameObject")]
private static void InstantiateGO(
[CommandParameterDescription("The original GameObject to instantiate a copy of.")] GameObject original,
[CommandParameterDescription("The position of the instantiated GameObject.")] Vector3 position,
[CommandParameterDescription("The rotation of the instantiated GameObject.")] Quaternion rotation)
{
GameObject.Instantiate(original, position, rotation);
}
[Command("instantiate", "Instantiates a GameObject")]
private static void InstantiateGO(GameObject original, Vector3 position) { GameObject.Instantiate(original).transform.position = position; }
[Command("instantiate", "Instantiates a GameObject")]
private static void InstantiateGO(GameObject original) { GameObject.Instantiate(original); }
[Command("teleport", "Teleports a GameObject")]
private static void TeleportGO(GameObject target, Vector3 position) { target.transform.position = position; }
[Command("teleport-relative", "Teleports a GameObject by a relative offset to its current position")]
private static void TeleportRelativeGO(GameObject target, Vector3 offset) { target.transform.Translate(offset); }
[Command("rotate", "Rotates a GameObject")]
private static void RotateGO(GameObject target, Quaternion rotation) { target.transform.Rotate(rotation.eulerAngles); }
[Command("set-active", "Activates/deactivates a GameObject")]
private static void SetGOActive(GameObject target, bool active) { target.SetActive(active); }
[Command("set-parent", "Sets the parent of the targert transform.")]
private static void SetGOParent(Transform target, Transform parentTarget) { target.SetParent(parentTarget); }
[Command("send-message", "Calls the method named 'methodName' on every MonoBehaviour in the target GameObject")]
private static void SendGOMessage(GameObject target, string methodName) { target.SendMessage(methodName); }
}
}

View File

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

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 496cffde696095c439db4ee329062978
folderAsset: yes
timeCreated: 1553955817
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 015e5afa17239334c8f085479673d346
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,153 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
using Mono.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection.Emit;
using System.Text;
#if QC_SUPPORTED
namespace CSharpCompiler
{
public class CodeCompiler : ICodeCompiler
{
static long assemblyCounter = 0;
public CompilerResults CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit compilationUnit)
{
return CompileAssemblyFromDomBatch(options, new[] { compilationUnit });
}
public CompilerResults CompileAssemblyFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
try
{
return CompileFromDomBatch(options, ea);
}
finally
{
options.TempFiles.Delete();
}
}
private CompilerResults CompileFromDomBatch(CompilerParameters options, CodeCompileUnit[] ea)
{
throw new NotImplementedException("sorry ICodeGenerator is not implemented, feel free to fix it and request merge");
}
public CompilerResults CompileAssemblyFromFile(CompilerParameters options, string fileName)
{
return CompileAssemblyFromFileBatch(options, new[] { fileName });
}
public CompilerResults CompileAssemblyFromFileBatch(CompilerParameters options, string[] fileNames)
{
var settings = ParamsToSettings(options);
foreach (var fileName in fileNames)
{
string path = Path.GetFullPath(fileName);
var unit = new SourceFile(fileName, path, settings.SourceFiles.Count + 1);
settings.SourceFiles.Add(unit);
}
return CompileFromCompilerSettings(settings, options.GenerateInMemory);
}
public CompilerResults CompileAssemblyFromSource(CompilerParameters options, string source)
{
return CompileAssemblyFromSourceBatch(options, new[] { source });
}
public CompilerResults CompileAssemblyFromSourceBatch(CompilerParameters options, string[] sources)
{
var settings = ParamsToSettings(options);
int i = 0;
foreach (var _source in sources)
{
var source = _source;
Func<Stream> getStream = () => { return new MemoryStream(Encoding.UTF8.GetBytes(source ?? "")); };
var fileName = i.ToString();
var unit = new SourceFile(fileName, fileName, settings.SourceFiles.Count + 1, getStream);
settings.SourceFiles.Add(unit);
i++;
}
return CompileFromCompilerSettings(settings, options.GenerateInMemory);
}
CompilerResults CompileFromCompilerSettings(CompilerSettings settings, bool generateInMemory)
{
var compilerResults = new CompilerResults(new TempFileCollection(Path.GetTempPath()));
var driver = new CustomDynamicDriver(new CompilerContext(settings, new CustomReportPrinter(compilerResults)));
AssemblyBuilder outAssembly = null;
try
{
driver.Compile(out outAssembly, AppDomain.CurrentDomain, generateInMemory);
}
catch (Exception e)
{
compilerResults.Errors.Add(new CompilerError()
{
IsWarning = false,
ErrorText = e.Message,
});
}
compilerResults.CompiledAssembly = outAssembly;
return compilerResults;
}
CompilerSettings ParamsToSettings(CompilerParameters parameters)
{
var settings = new CompilerSettings();
foreach (var assembly in parameters.ReferencedAssemblies) settings.AssemblyReferences.Add(assembly);
settings.Encoding = System.Text.Encoding.UTF8;
settings.GenerateDebugInfo = parameters.IncludeDebugInformation;
settings.MainClass = parameters.MainClass;
settings.Platform = Platform.AnyCPU;
settings.StdLibRuntimeVersion = RuntimeVersion.v4;
if (parameters.GenerateExecutable)
{
settings.Target = Target.Exe;
settings.TargetExt = ".exe";
}
else
{
settings.Target = Target.Library;
settings.TargetExt = ".dll";
}
if (parameters.GenerateInMemory) settings.Target = Target.Library;
if (string.IsNullOrEmpty(parameters.OutputAssembly))
{
parameters.OutputAssembly = settings.OutputFile = "DynamicAssembly_" + assemblyCounter + settings.TargetExt;
assemblyCounter++;
}
settings.OutputFile = parameters.OutputAssembly; // if it is not being outputted, we use this to set name of the dynamic assembly
settings.Version = LanguageVersion.Default;
settings.WarningLevel = parameters.WarningLevel;
settings.WarningsAreErrors = parameters.TreatWarningsAsErrors;
return settings;
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f3f2a9227250eeb43a8e3c138ce1a6a1
timeCreated: 1438909233
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,317 @@
// modified version of Mono.CSharp.Driver
// driver.cs: The compiler command line driver.
//
// Authors:
// Miguel de Icaza (miguel@gnu.org)
// Marek Safar (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
// Copyright 2011 Xamarin Inc
//
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
#if QC_SUPPORTED
using Mono.CSharp;
using System;
using System.IO;
using System.Reflection.Emit;
namespace CSharpCompiler
{
/// <summary>
/// The compiler driver.
/// </summary>
public class CustomDynamicDriver
{
readonly CompilerContext ctx;
public CustomDynamicDriver(CompilerContext ctx)
{
this.ctx = ctx;
}
public Report Report
{
get
{
return ctx.Report;
}
}
void tokenize_file(SourceFile sourceFile, ModuleContainer module, ParserSession session)
{
Stream input;
try
{
input = sourceFile.GetDataStream();
}
catch
{
Report.Error(2001, "Source file `" + sourceFile.Name + "' could not be found");
return;
}
using (input)
{
SeekableStreamReader reader = new SeekableStreamReader(input, ctx.Settings.Encoding);
var file = new CompilationSourceFile(module, sourceFile);
Tokenizer lexer = new Tokenizer(reader, file, session, ctx.Report);
int token, tokens = 0, errors = 0;
while ((token = lexer.token()) != Token.EOF)
{
tokens++;
if (token == Token.ERROR)
errors++;
}
Console.WriteLine("Tokenized: " + tokens + " found " + errors + " errors");
}
return;
}
public void Parse(ModuleContainer module)
{
bool tokenize_only = module.Compiler.Settings.TokenizeOnly;
var sources = module.Compiler.SourceFiles;
Location.Initialize(sources);
var session = new ParserSession
{
UseJayGlobalArrays = true,
LocatedTokens = new LocatedToken[15000]
};
for (int i = 0; i < sources.Count; ++i)
{
if (tokenize_only)
{
tokenize_file(sources[i], module, session);
}
else
{
Parse(sources[i], module, session, Report);
}
}
}
public void Parse(SourceFile file, ModuleContainer module, ParserSession session, Report report)
{
Stream input;
try
{
input = file.GetDataStream();
}
catch
{
report.Error(2001, "Source file `{0}' could not be found", file.Name);
return;
}
// Check 'MZ' header
if (input.ReadByte() == 77 && input.ReadByte() == 90)
{
report.Error(2015, "Source file `{0}' is a binary file and not a text file", file.Name);
input.Close();
return;
}
input.Position = 0;
SeekableStreamReader reader = new SeekableStreamReader(input, ctx.Settings.Encoding, session.StreamReaderBuffer);
Parse(reader, file, module, session, report);
if (ctx.Settings.GenerateDebugInfo && report.Errors == 0 && !file.HasChecksum)
{
input.Position = 0;
var checksum = session.GetChecksumAlgorithm();
file.SetChecksum(checksum.ComputeHash(input));
}
reader.Dispose();
input.Close();
}
public static void Parse(SeekableStreamReader reader, SourceFile sourceFile, ModuleContainer module, ParserSession session, Report report)
{
var file = new CompilationSourceFile(module, sourceFile);
module.AddTypeContainer(file);
CSharpParser parser = new CSharpParser(reader, file, report, session);
parser.parse();
}
//
// Main compilation method
//
public bool Compile(out AssemblyBuilder outAssembly, AppDomain domain, bool generateInMemory)
{
var settings = ctx.Settings;
outAssembly = null;
//
// If we are an exe, require a source file for the entry point or
// if there is nothing to put in the assembly, and we are not a library
//
if (settings.FirstSourceFile == null &&
((settings.Target == Target.Exe || settings.Target == Target.WinExe || settings.Target == Target.Module) ||
settings.Resources == null))
{
Report.Error(2008, "No files to compile were specified");
return false;
}
if (settings.Platform == Platform.AnyCPU32Preferred && (settings.Target == Target.Library || settings.Target == Target.Module))
{
Report.Error(4023, "Platform option `anycpu32bitpreferred' is valid only for executables");
return false;
}
TimeReporter tr = new TimeReporter(settings.Timestamps);
ctx.TimeReporter = tr;
tr.StartTotal();
var module = new ModuleContainer(ctx);
RootContext.ToplevelTypes = module;
tr.Start(TimeReporter.TimerType.ParseTotal);
Parse(module);
tr.Stop(TimeReporter.TimerType.ParseTotal);
if (Report.Errors > 0)
return false;
if (settings.TokenizeOnly || settings.ParseOnly)
{
tr.StopTotal();
tr.ShowStats();
return true;
}
var output_file = settings.OutputFile;
string output_file_name;
/* if (output_file == null)
{
var source_file = settings.FirstSourceFile;
if (source_file == null)
{
Report.Error(1562, "If no source files are specified you must specify the output file with -out:");
return false;
}
output_file_name = source_file.Name;
int pos = output_file_name.LastIndexOf('.');
if (pos > 0)
output_file_name = output_file_name.Substring(0, pos);
output_file_name += settings.TargetExt;
output_file = output_file_name;
}
else
{*/
output_file_name = Path.GetFileName(output_file);
/* if (string.IsNullOrEmpty(Path.GetFileNameWithoutExtension(output_file_name)) ||
output_file_name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
{
Report.Error(2021, "Output file name is not valid");
return false;
}
}*/
var assembly = new AssemblyDefinitionDynamic(module, output_file_name, output_file);
module.SetDeclaringAssembly(assembly);
var importer = new ReflectionImporter(module, ctx.BuiltinTypes);
assembly.Importer = importer;
var loader = new DynamicLoader(importer, ctx);
loader.LoadReferences(module);
if (!ctx.BuiltinTypes.CheckDefinitions(module))
return false;
if (!assembly.Create(domain, AssemblyBuilderAccess.RunAndSave))
return false;
module.CreateContainer();
loader.LoadModules(assembly, module.GlobalRootNamespace);
module.InitializePredefinedTypes();
if (settings.GetResourceStrings != null)
module.LoadGetResourceStrings(settings.GetResourceStrings);
tr.Start(TimeReporter.TimerType.ModuleDefinitionTotal);
module.Define();
tr.Stop(TimeReporter.TimerType.ModuleDefinitionTotal);
if (Report.Errors > 0)
return false;
if (settings.DocumentationFile != null)
{
var doc = new DocumentationBuilder(module);
doc.OutputDocComment(output_file, settings.DocumentationFile);
}
assembly.Resolve();
if (Report.Errors > 0)
return false;
tr.Start(TimeReporter.TimerType.EmitTotal);
assembly.Emit();
tr.Stop(TimeReporter.TimerType.EmitTotal);
if (Report.Errors > 0)
{
return false;
}
tr.Start(TimeReporter.TimerType.CloseTypes);
module.CloseContainer();
tr.Stop(TimeReporter.TimerType.CloseTypes);
tr.Start(TimeReporter.TimerType.Resouces);
if (!settings.WriteMetadataOnly)
assembly.EmbedResources();
tr.Stop(TimeReporter.TimerType.Resouces);
if (Report.Errors > 0)
return false;
if (!generateInMemory) assembly.Save();
outAssembly = assembly.Builder;
tr.StopTotal();
tr.ShowStats();
return Report.Errors == 0;
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e389d8a5b0e25ae44a841060cecca276
timeCreated: 1435446720
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,53 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
using Mono.CSharp;
using System.CodeDom.Compiler;
#if QC_SUPPORTED
namespace CSharpCompiler
{
public class CustomReportPrinter : ReportPrinter
{
readonly CompilerResults compilerResults;
#region Properties
public new int ErrorsCount { get; protected set; }
public new int WarningsCount { get; private set; }
#endregion
public CustomReportPrinter(CompilerResults compilerResults)
{
this.compilerResults = compilerResults;
}
public override void Print(AbstractMessage msg, bool showFullPath)
{
if (msg.IsWarning)
{
++WarningsCount;
}
else
{
++ErrorsCount;
}
compilerResults.Errors.Add(new CompilerError()
{
IsWarning = msg.IsWarning,
Column = msg.Location.Column,
Line = msg.Location.Row,
ErrorNumber = msg.Code.ToString(),
ErrorText = msg.Text,
FileName = showFullPath ? msg.Location.SourceFile.FullPathName : msg.Location.SourceFile.Name,
// msg.RelatedSymbols // extra info
});
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 39ec208e78505e342a2829289445b934
timeCreated: 1438909233
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,99 @@
/*
Implementation of ISynchronizeInvoke for Unity3D game engine.
Can be used to invoke anything on main Unity thread.
ISynchronizeInvoke is used extensively in .NET forms it's is elegant and quite useful in Unity as well.
I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject.
help from: http://www.codeproject.com/Articles/12082/A-DelegateQueue-Class
example usage: https://gist.github.com/aeroson/90bf21be3fdc4829e631
license: WTFPL (http://www.wtfpl.net/)
contact: aeroson (theaeroson @gmail.com)
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading;
public class DeferredSynchronizeInvoke : ISynchronizeInvoke
{
Queue<UnityAsyncResult> fifoToExecute = new Queue<UnityAsyncResult>();
Thread mainThread;
public bool InvokeRequired { get { return mainThread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId; } }
public DeferredSynchronizeInvoke()
{
mainThread = Thread.CurrentThread;
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
var asyncResult = new UnityAsyncResult()
{
method = method,
args = args,
IsCompleted = false,
AsyncWaitHandle = new ManualResetEvent(false),
};
lock (fifoToExecute)
{
fifoToExecute.Enqueue(asyncResult);
}
return asyncResult;
}
public object EndInvoke(IAsyncResult result)
{
if (!result.IsCompleted)
{
result.AsyncWaitHandle.WaitOne();
}
return result.AsyncState;
}
public object Invoke(Delegate method, object[] args)
{
if (InvokeRequired)
{
var asyncResult = BeginInvoke(method, args);
return EndInvoke(asyncResult);
}
else
{
return method.DynamicInvoke(args);
}
}
public void ProcessQueue()
{
if (Thread.CurrentThread != mainThread)
{
throw new TargetException(
this.GetType() + "." + MethodBase.GetCurrentMethod().Name + "() " +
"must be called from the same thread it was created on " +
"(created on thread id: " + mainThread.ManagedThreadId + ", called from thread id: " + Thread.CurrentThread.ManagedThreadId
);
}
bool loop = true;
UnityAsyncResult data = null;
while (loop)
{
lock (fifoToExecute)
{
loop = fifoToExecute.Count > 0;
if (!loop) break;
data = fifoToExecute.Dequeue();
}
data.AsyncState = Invoke(data.method, data.args);
data.IsCompleted = true;
}
}
class UnityAsyncResult : IAsyncResult
{
public Delegate method;
public object[] args;
public bool IsCompleted { get; set; }
public WaitHandle AsyncWaitHandle { get; internal set; }
public object AsyncState { get; set; }
public bool CompletedSynchronously { get { return IsCompleted; } }
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f6228134abfaad746965d9639b73908a
timeCreated: 1435576341
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
Copyright (c) 2001, 2002, 2003 Ximian, Inc and the individuals listed
on the ChangeLog entries.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 09298e73731a3b64fbedf483cf7d4e42
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2ce9bfedd125d1c49adb5c65c9e8ce53
folderAsset: yes
timeCreated: 1435432572
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
fileFormatVersion: 2
guid: 0447405aaa6f3bd4c96d4c64631542fd
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,172 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
#if QC_SUPPORTED
namespace CSharpCompiler
{
public class ScriptBundleLoader
{
public Func<Type, object> createInstance = (Type type) => { return Activator.CreateInstance(type); };
public Action<object> destroyInstance = delegate { };
public TextWriter logWriter = Console.Out;
ISynchronizeInvoke synchronizedInvoke;
List<ScriptBundle> allFilesBundle = new List<ScriptBundle>();
public ScriptBundleLoader(ISynchronizeInvoke synchronizedInvoke)
{
this.synchronizedInvoke = synchronizedInvoke;
}
/// <summary>
///
/// </summary>
/// <param name="fileSources"></param>
/// <returns>true on success, false on failure</returns>
public ScriptBundle LoadAndWatchScriptsBundle(IEnumerable<string> fileSources)
{
var bundle = new ScriptBundle(this, fileSources);
allFilesBundle.Add(bundle);
return bundle;
}
/// <summary>
/// Manages a bundle of files which form one assembly, if one file changes entire assembly is recompiled.
/// </summary>
public class ScriptBundle
{
Assembly assembly;
IEnumerable<string> filePaths;
List<FileSystemWatcher> fileSystemWatchers = new List<FileSystemWatcher>();
List<object> instances = new List<object>();
ScriptBundleLoader manager;
string[] assemblyReferences;
public ScriptBundle(ScriptBundleLoader manager, IEnumerable<string> filePaths)
{
this.filePaths = filePaths.Select(x => Path.GetFullPath(x));
this.manager = manager;
var domain = System.AppDomain.CurrentDomain;
this.assemblyReferences = domain
.GetAssemblies()
.Where(a => !(a is System.Reflection.Emit.AssemblyBuilder) && !string.IsNullOrEmpty(a.Location))
.Select(a => a.Location)
.ToArray();
manager.logWriter.WriteLine("loading " + string.Join(", ", filePaths.ToArray()));
CompileFiles();
CreateFileWatchers();
CreateNewInstances();
}
void CompileFiles()
{
filePaths = filePaths.Where(x => File.Exists(x)).ToArray();
var options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.AddRange(assemblyReferences);
var compiler = new CodeCompiler();
var result = compiler.CompileAssemblyFromFileBatch(options, filePaths.ToArray());
foreach (var err in result.Errors)
{
manager.logWriter.WriteLine(err);
}
this.assembly = result.CompiledAssembly;
}
void CreateFileWatchers()
{
foreach (var filePath in filePaths)
{
FileSystemWatcher watcher = new FileSystemWatcher();
fileSystemWatchers.Add(watcher);
watcher.Path = Path.GetDirectoryName(filePath);
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = Path.GetFileName(filePath);
// Add event handlers.
watcher.Changed += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { Reload(recreateWatchers: false); });
//watcher.Created += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { });
watcher.Deleted += new FileSystemEventHandler((object o, FileSystemEventArgs a) => { Reload(recreateWatchers: false); });
watcher.Renamed += new RenamedEventHandler((object o, RenamedEventArgs a) =>
{
filePaths = filePaths.Select(x =>
{
if (x == a.OldFullPath) return a.FullPath;
else return x;
});
Reload(recreateWatchers: true);
});
watcher.SynchronizingObject = manager.synchronizedInvoke;
// Begin watching.
watcher.EnableRaisingEvents = true;
}
}
void StopFileWatchers()
{
foreach (var w in fileSystemWatchers)
{
w.EnableRaisingEvents = false;
w.Dispose();
}
fileSystemWatchers.Clear();
}
void Reload(bool recreateWatchers = false)
{
manager.logWriter.WriteLine("reloading " + string.Join(", ", filePaths.ToArray()));
StopInstances();
CompileFiles();
CreateNewInstances();
if (recreateWatchers)
{
StopFileWatchers();
CreateFileWatchers();
}
}
void CreateNewInstances()
{
if (assembly == null) return;
foreach (var type in assembly.GetTypes())
{
manager.synchronizedInvoke.Invoke((System.Action)(() =>
{
instances.Add(manager.createInstance(type));
}), null);
}
}
void StopInstances()
{
foreach (var instance in instances)
{
manager.synchronizedInvoke.Invoke((System.Action)(() =>
{
manager.destroyInstance(instance);
}), null);
}
instances.Clear();
}
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3dfc88ca39a87dc46bc7fd337be863bb
timeCreated: 1440503653
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,110 @@
#if NET_4_6 && !NET_STANDARD_2_0
#define QC_SUPPORTED
#endif
#if QC_SUPPORTED
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
namespace QFSW.QC
{
public static class DynamicCodeCommands
{
private const Platform execAvailability = Platform.AllPlatforms ^ (Platform.WebGLPlayer | Platform.IPhonePlayer | Platform.XboxOne | Platform.PS4 | Platform.Switch);
[CommandDescription("Loads the code at the specified file and compiles it to C# which will then be executed. Use with caution as no safety checks will be performed. Not supported in AOT (IL2CPP) builds." +
"\n\nBy default, boiler plate code will NOT be inserted around the code you provide. Please see 'exec' for more information about boilerplate insertion")]
[Command("exec-extern", execAvailability)]
private static async Task ExecuteExternalArbitaryCodeAsync(string filePath, bool insertBoilerplate = false)
{
if (!File.Exists(filePath)) { throw new ArgumentException($"file at the specified path '{filePath}' did not exist."); }
string code = File.ReadAllText(filePath);
await ExecuteArbitaryCodeAsync(code.Replace("”", "\"").Replace("“", "\""), insertBoilerplate);
}
[CommandDescription("Compiles the given code to C# which will then be executed. Use with caution as no safety checks will be performed. Not supported in AOT (IL2CPP) builds." +
"\n\nBy default, boiler plate code will be inserted around the code you provide. This means various namespaces will be included, and the main class and main function entry point will " +
"provided. In this case, the code you provide should be code that would exist within the body of the main function, and thus cannot contain things such as class definition. If you " +
"disable boiler plate insertion, you can write whatever code you want, however you must provide a static entry point called Main in a static class called Program")]
[Command("exec", execAvailability)]
private static async Task ExecuteArbitaryCodeAsync(string code, bool insertBoilerplate = true)
{
#if !UNITY_EDITOR && ENABLE_IL2CPP
await Task.FromException(new Exception("exec is not supported on AOT platforms such as IL2CPP and requires JIT (Mono)."));
#else
MethodInfo entryPoint = await Task.Run(() =>
{
string fullCode = string.Empty;
if (insertBoilerplate)
{
string[] includedNamespaces = new string[] { "System", "System.Collections", "System.Collections.Generic",
"System.Reflection", "System.Linq", "System.Text", "System.Globalization",
"UnityEngine", "UnityEngine.Events", "UnityEngine.EventSystems", "UnityEngine.UI" };
for (int i = 0; i < includedNamespaces.Length; i++) { fullCode += $"using {includedNamespaces[i]};\n"; }
fullCode += @"
public class Program
{
public static void Main()
{"
+ code +
@"}
}";
}
else { fullCode = code; }
Assembly assembly = CompileCode(fullCode);
BindingFlags searchFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
Type program = assembly.GetType("Program");
if (program == null) { throw new ArgumentException("Code Execution Failure - required static class Program could not be found"); }
entryPoint = program.GetMethod("Main", searchFlags);
if (entryPoint == null) { throw new ArgumentException("Code Execution Failure - required static entry point Main could not be found"); }
return entryPoint;
});
entryPoint.Invoke(null, null);
#endif
}
private static Assembly CompileCode(string code)
{
#if !UNITY_EDITOR && ENABLE_IL2CPP
throw new Exception("Code compilation is not supported on AOT platforms such as IL2CPP and requires JIT (Mono).");
#else
CSharpCompiler.CodeCompiler compiler = new CSharpCompiler.CodeCompiler();
CompilerParameters compilerParams = new CompilerParameters();
Assembly[] allLoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
for (int i = 0; i < allLoadedAssemblies.Length; i++)
{
if (!allLoadedAssemblies[i].IsDynamic)
{
string dllName = allLoadedAssemblies[i].Location;
compilerParams.ReferencedAssemblies.Add(dllName);
}
}
CompilerResults compiledCode = compiler.CompileAssemblyFromSource(compilerParams, code);
if (compiledCode.Errors.HasErrors)
{
string errorMessage = "Code Compilation Failure";
for (int i = 0; i < compiledCode.Errors.Count; i++)
{
errorMessage += $"\n{compiledCode.Errors[i].ErrorNumber} - {compiledCode.Errors[i].ErrorText}";
}
throw new ArgumentException(errorMessage);
}
return compiledCode.CompiledAssembly;
#endif
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e32a67fb03a2f6548b653203ff9fedf3
timeCreated: 1553955853
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 62f36e9490c247741aa6c9b5e545f9be
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,111 @@
SIL Open Font License v1.1
---------------------------------------
This Font Software is licensed under the SIL Open Font License, Version 1.1
This license is also available with a FAQ at: http://scripts.sil.org/OFL
Reserved font name: "Office Code Pro"
Copyright © 2015 Nathan Rutzky ( www.nath.co )
Copyright © 2015 Adobe Systems ( www.adobe.com )
All Rights Reserved.
PREAMBLE
---------------------------------------
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
---------------------------------------
`"Font Software"` refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
`"Reserved Font Name"` refers to any names specified as such after the
copyright statement(s).
`"Original Version"` refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
`"Modified Version"` refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
`"Author"` refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
---------------------------------------
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1. Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2. Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3. No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4. The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5. The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
---------------------------------------
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
---------------------------------------
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5cfab2462b62dee47ba1dc3ebb9eb955
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
fileFormatVersion: 2
guid: d0fb8e3996ea8e7419e719f298606d45
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 4b7d48f1a9584dc4a978e5413f2f0cdc, type: 3}
- {fileID: 12800000, guid: 999b9956011029e489cf8670db0e3da1, type: 3}
- {fileID: 12800000, guid: 5e9f3008ed4fcd44abfab02627813be7, type: 3}
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
- {fileID: 12800000, guid: 7b29088eb3cae8e4dac72276f32da198, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
fileFormatVersion: 2
guid: 32c1196d211019546904eb4ea3890aec
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 4b7d48f1a9584dc4a978e5413f2f0cdc
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
fileFormatVersion: 2
guid: 7b29088eb3cae8e4dac72276f32da198
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 4b7d48f1a9584dc4a978e5413f2f0cdc, type: 3}
- {fileID: 12800000, guid: 5e9f3008ed4fcd44abfab02627813be7, type: 3}
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: e7f9c7e4780a90b45b581308e8a2f94a
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 4b7d48f1a9584dc4a978e5413f2f0cdc, type: 3}
- {fileID: 12800000, guid: 999b9956011029e489cf8670db0e3da1, type: 3}
- {fileID: 12800000, guid: 5e9f3008ed4fcd44abfab02627813be7, type: 3}
- {fileID: 12800000, guid: d0fb8e3996ea8e7419e719f298606d45, type: 3}
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
- {fileID: 12800000, guid: 7b29088eb3cae8e4dac72276f32da198, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
fileFormatVersion: 2
guid: 999b9956011029e489cf8670db0e3da1
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 4b7d48f1a9584dc4a978e5413f2f0cdc, type: 3}
- {fileID: 12800000, guid: 5e9f3008ed4fcd44abfab02627813be7, type: 3}
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
- {fileID: 12800000, guid: 7b29088eb3cae8e4dac72276f32da198, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
fileFormatVersion: 2
guid: eb42c3b8bd49c574bb98289bb3ea122c
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 4b7d48f1a9584dc4a978e5413f2f0cdc, type: 3}
- {fileID: 12800000, guid: e7f9c7e4780a90b45b581308e8a2f94a, type: 3}
- {fileID: 12800000, guid: 999b9956011029e489cf8670db0e3da1, type: 3}
- {fileID: 12800000, guid: 5e9f3008ed4fcd44abfab02627813be7, type: 3}
- {fileID: 12800000, guid: d0fb8e3996ea8e7419e719f298606d45, type: 3}
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
- {fileID: 12800000, guid: 7b29088eb3cae8e4dac72276f32da198, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
fileFormatVersion: 2
guid: 5e9f3008ed4fcd44abfab02627813be7
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontName: Office Code Pro
fontNames:
- Office Code Pro
fallbackFontReferences:
- {fileID: 12800000, guid: 4b7d48f1a9584dc4a978e5413f2f0cdc, type: 3}
- {fileID: 12800000, guid: 32c1196d211019546904eb4ea3890aec, type: 3}
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 683b46b9fd7bc7f4f8bda19cacf1c25d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 03667487b095d134cb5d244fc285c9d1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 82a04213dfb8df0418ea8f3f47099dc5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,131 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Blur Panel
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _Blend: 0
- _BumpAmt: 10
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _QueueOffset: 0
- _Radius: 3
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Surface: 0
- _UVSec: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0.11320752, g: 0.11320752, b: 0.11320752, a: 1}
- _Color: {r: 0.1132075, g: 0.1132075, b: 0.1132075, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _OverlayColor: {r: 0.0754902, g: 0.1237255, b: 0.19607843, a: 0.16862746}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
--- !u!114 &2339474354693369228
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 5

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3f5fb7a53313bca46bc093dae10de6e4
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6040c682eb70bbf418ab42e0fe8f1fb9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,62 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a59acf1affd56c94fa937563dd75c947, type: 3}
m_Name: Default Key Config
m_EditorClassIdentifier:
SubmitCommandKey: 13
ShowConsoleKey:
Key: 0
Ctrl: 0
Alt: 0
Shift: 0
HideConsoleKey:
Key: 0
Ctrl: 0
Alt: 0
Shift: 0
ToggleConsoleVisibilityKey:
Key: 113
Ctrl: 0
Alt: 0
Shift: 0
ZoomInKey:
Key: 61
Ctrl: 1
Alt: 0
Shift: 0
ZoomOutKey:
Key: 45
Ctrl: 1
Alt: 0
Shift: 0
DragConsoleKey:
Key: 323
Ctrl: 0
Alt: 0
Shift: 1
SuggestNextCommandKey:
Key: 9
Ctrl: 0
Alt: 0
Shift: 0
SuggestPreviousCommandKey:
Key: 9
Ctrl: 0
Alt: 0
Shift: 1
NextCommandKey: 273
PreviousCommandKey: 274
CancelActionsKey:
Key: 99
Ctrl: 1
Alt: 0
Shift: 0

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 090da11157287de47ae5c615b8ed3cf9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 49e15215dd5c7444aa955d9a8a83fea0, type: 3}
m_Name: Default Theme (SRP)
m_EditorClassIdentifier:
Font: {fileID: 11400000, guid: 03667487b095d134cb5d244fc285c9d1, type: 2}
PanelMaterial: {fileID: 0}
PanelColor: {r: 0.105882354, g: 0.1254902, b: 0.14901961, a: 0.9411765}
CommandLogColor: {r: 0, g: 1, b: 1, a: 1}
SelectedSuggestionColor: {r: 1, g: 1, b: 0.427, a: 1}
SuggestionColor: {r: 0.601, g: 0.601, b: 0.601, a: 1}
ErrorColor: {r: 1, g: 0, b: 0, a: 1}
WarningColor: {r: 1, g: 0.5, b: 0, a: 1}
SuccessColor: {r: 0, g: 1, b: 0, a: 1}
TimestampFormat: '[{0:00}:{1:00}:{2:00}]'
DefaultReturnValueColor: {r: 1, g: 0.7372549, b: 0.54901963, a: 1}
TypeFormatters:
- _type: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Color: {r: 1, g: 1, b: 1, a: 1}
- _type: System.Collections.IEnumerable, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Color: {r: 0.99215686, g: 0.9490196, b: 0.4117647, a: 1}
- _type: System.Collections.Generic.KeyValuePair`2, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Color: {r: 0.7311321, g: 1, b: 0.9315609, a: 1}
- _type: System.Collections.DictionaryEntry, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Color: {r: 0.7294118, g: 1, b: 0.93333334, a: 1}
- _type: System.Enum, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Color: {r: 0.7698444, g: 1, b: 0.54901963, a: 1}
- _type: UnityEngine.Object, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null
Color: {r: 0.96862745, g: 0.6, b: 1, a: 1}
CollectionFormatters:
- _type: System.Collections.Generic.Dictionary`2, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
SeperatorString: \n
LeftScoper:
RightScoper:
- _type: System.Collections.ICollection, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
SeperatorString: ', '
LeftScoper: '['
RightScoper: ']'
- _type: System.Collections.IEnumerable, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
SeperatorString: \n
LeftScoper:
RightScoper:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 769f3deee63c82a4c9896ac917227625
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 49e15215dd5c7444aa955d9a8a83fea0, type: 3}
m_Name: Default Theme
m_EditorClassIdentifier:
Font: {fileID: 11400000, guid: 03667487b095d134cb5d244fc285c9d1, type: 2}
PanelMaterial: {fileID: 2100000, guid: 3f5fb7a53313bca46bc093dae10de6e4, type: 2}
PanelColor: {r: 1, g: 1, b: 1, a: 1}
CommandLogColor: {r: 0, g: 1, b: 1, a: 1}
SelectedSuggestionColor: {r: 1, g: 1, b: 0.427, a: 1}
SuggestionColor: {r: 0.601, g: 0.601, b: 0.601, a: 1}
ErrorColor: {r: 1, g: 0, b: 0, a: 1}
WarningColor: {r: 1, g: 0.5, b: 0, a: 1}
SuccessColor: {r: 0, g: 1, b: 0, a: 1}
TimestampFormat: '[{0:00}:{1:00}:{2:00}]'
DefaultReturnValueColor: {r: 1, g: 0.7372549, b: 0.54901963, a: 1}
TypeFormatters:
- _type: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Color: {r: 1, g: 1, b: 1, a: 1}
- _type: System.Collections.IEnumerable, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Color: {r: 0.99215686, g: 0.9490196, b: 0.4117647, a: 1}
- _type: System.Collections.Generic.KeyValuePair`2, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Color: {r: 0.7311321, g: 1, b: 0.9315609, a: 1}
- _type: System.Collections.DictionaryEntry, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Color: {r: 0.7294118, g: 1, b: 0.93333334, a: 1}
- _type: System.Enum, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Color: {r: 0.7698444, g: 1, b: 0.54901963, a: 1}
- _type: UnityEngine.Object, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null
Color: {r: 0.96862745, g: 0.6, b: 1, a: 1}
CollectionFormatters:
- _type: System.Collections.Generic.Dictionary`2, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
SeperatorString: \n
LeftScoper:
RightScoper:
- _type: System.Collections.ICollection, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
SeperatorString: ', '
LeftScoper: '['
RightScoper: ']'
- _type: System.Collections.IEnumerable, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
SeperatorString: \n
LeftScoper:
RightScoper:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5a19be32700ef4a13bfa337a662ef25b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,481 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &4621155404233898149
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1263217620473054, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f, type: 3}
propertyPath: m_Name
value: Quantum Console (SRP)
objectReference: {fileID: 0}
- target: {fileID: 224130951485110974, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224130951485110974, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -517
objectReference: {fileID: 0}
- target: {fileID: 224296548220470038, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224296548220470038, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224296548220470038, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224296548220470038, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224296548220470038, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224296548220470038, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224005418473288314, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224005418473288314, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 114689057623555238, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Size
value: 1
objectReference: {fileID: 0}
- target: {fileID: 224711696876568682, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224711696876568682, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224711696876568682, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224711696876568682, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224711696876568682, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224166536479716514, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224166536479716514, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224166536479716514, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224166536479716514, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224166536479716514, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224166536479716514, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224773539050736570, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224773539050736570, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224773539050736570, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224773539050736570, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224773539050736570, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224091110387865490, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224091110387865490, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224091110387865490, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224091110387865490, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224091110387865490, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224484317424158076, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224484317424158076, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224484317424158076, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224484317424158076, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224484317424158076, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224642173552212536, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224642173552212536, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224642173552212536, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224642173552212536, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 224642173552212536, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 114372194528546136, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Material
value:
objectReference: {fileID: 0}
- target: {fileID: 114372194528546136, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.r
value: 0.105882354
objectReference: {fileID: 0}
- target: {fileID: 114372194528546136, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.g
value: 0.1254902
objectReference: {fileID: 0}
- target: {fileID: 114372194528546136, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.b
value: 0.14901961
objectReference: {fileID: 0}
- target: {fileID: 114372194528546136, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.a
value: 0.9411765
objectReference: {fileID: 0}
- target: {fileID: 114934208999440956, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Material
value:
objectReference: {fileID: 0}
- target: {fileID: 114934208999440956, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.r
value: 0.105882354
objectReference: {fileID: 0}
- target: {fileID: 114934208999440956, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.g
value: 0.1254902
objectReference: {fileID: 0}
- target: {fileID: 114934208999440956, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.b
value: 0.14901961
objectReference: {fileID: 0}
- target: {fileID: 114934208999440956, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.a
value: 0.9411765
objectReference: {fileID: 0}
- target: {fileID: 114478704479367178, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Material
value:
objectReference: {fileID: 0}
- target: {fileID: 114478704479367178, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.r
value: 0.105882354
objectReference: {fileID: 0}
- target: {fileID: 114478704479367178, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.g
value: 0.1254902
objectReference: {fileID: 0}
- target: {fileID: 114478704479367178, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.b
value: 0.14901961
objectReference: {fileID: 0}
- target: {fileID: 114478704479367178, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.a
value: 0.9411765
objectReference: {fileID: 0}
- target: {fileID: 114174508808301238, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Material
value:
objectReference: {fileID: 0}
- target: {fileID: 114174508808301238, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.r
value: 0.105882354
objectReference: {fileID: 0}
- target: {fileID: 114174508808301238, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.g
value: 0.1254902
objectReference: {fileID: 0}
- target: {fileID: 114174508808301238, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.b
value: 0.14901961
objectReference: {fileID: 0}
- target: {fileID: 114174508808301238, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.a
value: 0.9411765
objectReference: {fileID: 0}
- target: {fileID: 3005720477010286325, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2353330868778903658, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Material
value:
objectReference: {fileID: 0}
- target: {fileID: 2353330868778903658, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.r
value: 0.105882354
objectReference: {fileID: 0}
- target: {fileID: 2353330868778903658, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.g
value: 0.1254902
objectReference: {fileID: 0}
- target: {fileID: 2353330868778903658, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.b
value: 0.14901961
objectReference: {fileID: 0}
- target: {fileID: 2353330868778903658, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_Color.a
value: 0.9411765
objectReference: {fileID: 0}
- target: {fileID: 363657505470348732, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 363657505470348732, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 363657505470348732, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 363657505470348732, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 363657505470348732, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 363657505470348732, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4011473737907365368, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4011473737907365368, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4011473737907365368, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4011473737907365368, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4011473737907365368, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4011473737907365368, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3143326541157679684, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3143326541157679684, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3143326541157679684, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3143326541157679684, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3143326541157679684, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3143326541157679684, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 143246068027918357, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 143246068027918357, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 143246068027918357, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 143246068027918357, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 143246068027918357, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 143246068027918357, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 114600693638766706, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f,
type: 3}
propertyPath: _theme
value:
objectReference: {fileID: 11400000, guid: 769f3deee63c82a4c9896ac917227625,
type: 2}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 9ed2a051c32b4fe47a5e4fb95c20b03f, type: 3}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2da3dcc22749e7f4280737786d898334
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 9ed2a051c32b4fe47a5e4fb95c20b03f
timeCreated: 1541120106
licenseType: Store
NativeFormatImporter:
mainObjectFileID: 100100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7cd0938e3c7f0d94f978be0829c6cb85
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a3eaecc6a5f4f974092a4aae01bb5b48
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,78 @@
using System;
using System.Threading.Tasks;
namespace QFSW.QC.Actions
{
/// <summary>
/// Converts an async Task into an action.
/// </summary>
public class Async : ICommandAction
{
private readonly Task _task;
public bool IsFinished => _task.IsCompleted ||
_task.IsCanceled ||
_task.IsFaulted;
public bool StartsIdle => false;
/// <param name="task">The async Task to convert.</param>
public Async(Task task)
{
_task = task;
}
public void Start(ActionContext context) { }
public void Finalize(ActionContext context)
{
if (_task.IsFaulted)
{
throw _task.Exception.InnerException;
}
if (_task.IsCanceled)
{
throw new TaskCanceledException();
}
}
}
/// <summary>
/// Converts an async Task into an action.
/// </summary>
/// <typeparam name="T">The return type of the Task to convert.</typeparam>
public class Async<T> : ICommandAction
{
private readonly Task<T> _task;
private readonly Action<T> _onResult;
public bool IsFinished => _task.IsCompleted ||
_task.IsCanceled ||
_task.IsFaulted;
public bool StartsIdle => false;
/// <param name="task">The async Task to convert.</param>
/// <param name="onResult">The action to invoke when the Task completes.</param>
public Async(Task<T> task, Action<T> onResult)
{
_task = task;
_onResult = onResult;
}
public void Start(ActionContext context) { }
public void Finalize(ActionContext context)
{
if (_task.IsFaulted)
{
throw _task.Exception.InnerException;
}
if (_task.IsCanceled)
{
throw new TaskCanceledException();
}
_onResult(_task.Result);
}
}
}

View File

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

View File

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QFSW.QC.Utilities;
using UnityEngine;
namespace QFSW.QC.Actions
{
/// <summary>
/// Give the user a selection of choices which can be made by using the arrow keys and enter key.
/// </summary>
/// <typeparam name="T">The type of the choices.</typeparam>
public class Choice<T> : Composite
{
/// <summary>
/// Configuration for the Choice action.
/// </summary>
public struct Config
{
public string ItemFormat;
public string Delimiter;
public Color SelectedColor;
public static readonly Config Default = new Config
{
ItemFormat = "{0} [{1}]",
Delimiter = " ",
SelectedColor = Color.green
};
}
/// <param name="choices">The choices to select between.</param>
/// <param name="onSelect">Action to invoke when a selection is made.</param>
public Choice(IEnumerable<T> choices, Action<T> onSelect)
: this(choices, onSelect, Config.Default)
{ }
/// <param name="choices">The choices to select between.</param>
/// <param name="onSelect">Action to invoke when a selection is made.</param>
/// <param name="config">The configuration to be used.</param>
public Choice(IEnumerable<T> choices, Action<T> onSelect, Config config)
: base(Generate(choices, onSelect, config))
{ }
private static IEnumerator<ICommandAction> Generate(IEnumerable<T> choices, Action<T> onSelect, Config config)
{
QuantumConsole console = null;
StringBuilder builder = new StringBuilder();
IReadOnlyList<T> choiceList = choices as IReadOnlyList<T> ?? choices.ToList();
KeyCode key = KeyCode.None;
int choice = 0;
yield return new GetContext(ctx => console = ctx.Console);
ICommandAction DrawRow()
{
builder.Clear();
for (int i = 0; i < choiceList.Count; i++)
{
string item = console.Serialize(choiceList[i]);
builder.Append(i == choice
? string.Format(config.ItemFormat, item, 'x').ColorText(config.SelectedColor)
: string.Format(config.ItemFormat, item, ' '));
if (i != choiceList.Count - 1)
{
builder.Append(config.Delimiter);
}
}
return new Value(builder.ToString());
}
yield return DrawRow();
while (key != KeyCode.Return)
{
yield return new GetKey(k => key = k);
switch (key)
{
case KeyCode.LeftArrow: choice--; break;
case KeyCode.RightArrow: choice++; break;
case KeyCode.DownArrow: choice++; break;
case KeyCode.UpArrow: choice--; break;
}
choice = (choice + choiceList.Count) % choiceList.Count;
yield return new RemoveLog();
yield return DrawRow();
}
onSelect(choiceList[choice]);
}
}
}

View File

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

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace QFSW.QC.Actions
{
/// <summary>
/// Combines a sequence of actions into a single action.
/// </summary>
public class Composite : ICommandAction
{
private ActionContext _context;
private readonly IEnumerator<ICommandAction> _actions;
public bool IsFinished => _actions.Execute(_context) == ActionState.Complete;
public bool StartsIdle => false;
/// <param name="actions">The sequence of actions to create the composite from.</param>
public Composite(IEnumerator<ICommandAction> actions)
{
_actions = actions;
}
/// <param name="actions">The sequence of actions to create the composite from.</param>
public Composite(IEnumerable<ICommandAction> actions) : this(actions.GetEnumerator())
{
}
public void Start(ActionContext context)
{
_context = context;
}
public void Finalize(ActionContext context) { }
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3dba2d4b65cfdad428d18b1bd91c54e7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,10 @@
namespace QFSW.QC
{
/// <summary>
/// The context that an action is being invoked on.
/// </summary>
public struct ActionContext
{
public QuantumConsole Console;
}
}

View File

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

View File

@ -0,0 +1,53 @@
using System.Collections.Generic;
namespace QFSW.QC
{
public static class ActionExecuter
{
/// <summary>
/// Executes an action command until it becomes idle.
/// </summary>
/// <param name="action">The action command to execute.</param>
/// <param name="context">The context that the command is being executed on.</param>
/// <returns>The current state of the action command.</returns>
public static ActionState Execute(this IEnumerator<ICommandAction> action, ActionContext context)
{
ActionState state = ActionState.Running;
bool idle = false;
void MoveNext()
{
if (action.MoveNext())
{
action.Current?.Start(context);
idle = action.Current?.StartsIdle ?? false;
}
else
{
idle = true;
state = ActionState.Complete;
action.Dispose();
}
}
while (!idle)
{
if (action.Current == null)
{
MoveNext();
}
else if (action.Current.IsFinished)
{
action.Current.Finalize(context);
MoveNext();
}
else
{
idle = true;
}
}
return state;
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
namespace QFSW.QC
{
/// <summary>
/// The execution state of an action.
/// </summary>
public enum ActionState
{
Unknown = 0,
Running = 1,
Complete = 2
}
}

View File

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

View File

@ -0,0 +1,31 @@
namespace QFSW.QC
{
/// <summary>
/// Creates an action that can be yielded in commands.
/// </summary>
public interface ICommandAction
{
/// <summary>
/// Starts the action.
/// </summary>
/// <param name="context">The context that the action is being executed on.</param>
void Start(ActionContext context);
/// <summary>
/// Finalizes the action. Should not be called unless <c>IsFinished</c> is true.
/// </summary>
/// <param name="context">The context that the action is being executed on.</param>
void Finalize(ActionContext context);
/// <summary>
/// If the action has finished. Should not be called before <c>Start</c>.
/// </summary>
bool IsFinished { get; }
/// <summary>
/// If the action should start off idle, causing the execution to suspend until executed again.
/// It is recommended to make this <c>false</c> if the action should be instant.
/// </summary>
bool StartsIdle { get; }
}
}

View File

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

View File

@ -0,0 +1,36 @@
using System;
namespace QFSW.QC.Actions
{
/// <summary>
/// Custom action implemented via delegates.
/// For more complex actions it is usually recommended to create a new action implementing <c>ICommandAction</c>.
/// </summary>
public class Custom : ICommandAction
{
private readonly Func<bool> _isFinished;
private readonly Func<bool> _startsIdle;
private readonly Action<ActionContext> _start;
private readonly Action<ActionContext> _finalize;
public Custom(
Func<bool> isFinished,
Func<bool> startsIdle,
Action<ActionContext> start,
Action<ActionContext> finalize
)
{
_isFinished = isFinished;
_startsIdle = startsIdle;
_start = start;
_finalize = finalize;
}
public bool IsFinished => _isFinished();
public bool StartsIdle => _startsIdle();
public void Start(ActionContext context) { _start(context); }
public void Finalize(ActionContext context) { _finalize(context); }
}
}

View File

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

View File

@ -0,0 +1,28 @@
using System;
namespace QFSW.QC.Actions
{
/// <summary>
/// Gets the <c>ActionContext</c> that the command is currently being invoked on.
/// </summary>
public class GetContext : ICommandAction
{
private readonly Action<ActionContext> _onContext;
public bool IsFinished => true;
public bool StartsIdle => false;
/// <param name="onContext">Action to invoke when the context is retrieved.</param>
public GetContext(Action<ActionContext> onContext)
{
_onContext = onContext;
}
public void Start(ActionContext context) { }
public void Finalize(ActionContext context)
{
_onContext(context);
}
}
}

View File

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

View File

@ -0,0 +1,48 @@
using System;
using System.Linq;
using UnityEngine;
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits for any key to be pressed and returns the key via the given delegate.
/// </summary>
public class GetKey : ICommandAction
{
private KeyCode _key;
private readonly Action<KeyCode> _onKey;
private static readonly KeyCode[] KeyCodes = Enum.GetValues(typeof(KeyCode))
.Cast<KeyCode>()
.Where(k => (int)k < (int)KeyCode.Mouse0)
.ToArray();
public bool IsFinished
{
get
{
_key = GetCurrentKeyDown();
return _key != KeyCode.None;
}
}
public bool StartsIdle => true;
/// <param name="onKey">The action to perform when a key is pressed.</param>
public GetKey(Action<KeyCode> onKey)
{
_onKey = onKey;
}
private KeyCode GetCurrentKeyDown()
{
return KeyCodes.FirstOrDefault(InputHelper.GetKeyDown);
}
public void Start(ActionContext context) { }
public void Finalize(ActionContext context)
{
_onKey(_key);
}
}
}

View File

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

View File

@ -0,0 +1,18 @@
namespace QFSW.QC.Actions
{
/// <summary>
/// Removes the most recent log from the console.
/// </summary>
public class RemoveLog : ICommandAction
{
public bool IsFinished => true;
public bool StartsIdle => false;
public void Start(ActionContext context) { }
public void Finalize(ActionContext context)
{
context.Console.RemoveLogTrace();
}
}
}

View File

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

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace QFSW.QC.Actions
{
/// <summary>
/// Gradually types a message to the console.
/// </summary>
public class Typewriter : Composite
{
/// <summary>
/// Configuration for the Typewriter action.
/// </summary>
public struct Config
{
public enum ChunkType
{
Character,
Word,
Line
}
public float PrintInterval;
public ChunkType Chunks;
public static readonly Config Default = new Config
{
PrintInterval = 0f,
Chunks = ChunkType.Character
};
}
private static readonly Regex WhiteRegex = new Regex(@"(?<=[\s+])", RegexOptions.Compiled);
private static readonly Regex LineRegex = new Regex(@"(?<=[\n+])", RegexOptions.Compiled);
/// <param name="message">The message to display to the console.</param>
public Typewriter(string message)
: this(message, Config.Default)
{ }
/// <param name="message">The message to display to the console.</param>
/// <param name="config">The configuration to be used.</param>
public Typewriter(string message, Config config)
: base(Generate(message, config))
{ }
private static IEnumerator<ICommandAction> Generate(string message, Config config)
{
string[] chunks;
switch (config.Chunks)
{
case Config.ChunkType.Character: chunks = message.Select(c => c.ToString()).ToArray(); break;
case Config.ChunkType.Word: chunks = WhiteRegex.Split(message); break;
case Config.ChunkType.Line: chunks = LineRegex.Split(message); break;
default: throw new ArgumentException($"Chunk type {config.Chunks} is not supported.");
}
for (int i = 0; i < chunks.Length; i++)
{
yield return new WaitRealtime(config.PrintInterval);
yield return new Value(chunks[i], i == 0);
}
}
}
}

View File

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

View File

@ -0,0 +1,31 @@
namespace QFSW.QC.Actions
{
/// <summary>
/// Serializes and logs a value to the console.
/// </summary>
public class Value : ICommandAction
{
private readonly object _value;
private readonly bool _newline;
public bool IsFinished => true;
public bool StartsIdle => false;
/// <param name="value">The value to log to the console.</param>
/// <param name="newline">If the value should be logged on a new line.</param>
public Value(object value, bool newline = true)
{
_value = value;
_newline = newline;
}
public void Start(ActionContext context) { }
public void Finalize(ActionContext context)
{
QuantumConsole console = context.Console;
string serialized = _value as string ?? console.Serialize(_value);
console.LogToConsole(serialized, _newline);
}
}
}

View File

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

View File

@ -0,0 +1,30 @@
using UnityEngine;
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits for the given amount of seconds using scaled time.
/// </summary>
public class Wait : ICommandAction
{
private float _startTime;
private readonly float _duration;
public bool IsFinished => Time.time >= _startTime + _duration;
public bool StartsIdle => true;
/// <param name="seconds">The duration to wait in seconds.</param>
public Wait(float seconds)
{
_duration = seconds;
}
public void Start(ActionContext ctx)
{
_startTime = Time.time;
}
public void Finalize(ActionContext ctx) { }
}
}

View File

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

View File

@ -0,0 +1,13 @@
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits until the next frame.
/// </summary>
public class WaitFrame : WaitRealtime
{
public WaitFrame() : base(0)
{
}
}
}

View File

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

View File

@ -0,0 +1,16 @@
using UnityEngine;
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits until the given key is pressed.
/// </summary>
public class WaitKey : WaitUntil
{
/// <param name="key">The key to wait for.</param>
public WaitKey(KeyCode key) : base(() => InputHelper.GetKeyDown(key))
{
}
}
}

View File

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

View File

@ -0,0 +1,30 @@
using UnityEngine;
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits for the given amount of seconds using real time.
/// </summary>
public class WaitRealtime : ICommandAction
{
private float _startTime;
private readonly float _duration;
public bool IsFinished => Time.realtimeSinceStartup >= _startTime + _duration;
public bool StartsIdle => true;
/// <param name="seconds">The duration to wait for in seconds.</param>
public WaitRealtime(float seconds)
{
_duration = seconds;
}
public void Start(ActionContext ctx)
{
_startTime = Time.realtimeSinceStartup;
}
public void Finalize(ActionContext ctx) { }
}
}

View File

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

View File

@ -0,0 +1,16 @@
using System;
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits until the given condition is met.
/// </summary>
public class WaitUntil : WaitWhile
{
/// <param name="condition">The condition to wait on.</param>
public WaitUntil(Func<bool> condition) : base(() => !condition())
{
}
}
}

View File

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

View File

@ -0,0 +1,25 @@
using System;
namespace QFSW.QC.Actions
{
/// <summary>
/// Waits while the given condition is met.
/// </summary>
public class WaitWhile : ICommandAction
{
private readonly Func<bool> _condition;
public bool IsFinished => _condition();
public bool StartsIdle => true;
/// <param name="condition">The condition to wait on.</param>
public WaitWhile(Func<bool> condition)
{
_condition = condition;
}
public void Start(ActionContext context) { }
public void Finalize(ActionContext context) { }
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f98c28cf2a7c934db3f256bd3921741
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,49 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace QFSW.QC
{
/// <summary>
/// Marks the associated method as a command, allowing it to be loaded by the QuantumConsoleProcessor. This means it will be usable as a command from a Quantum Console.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]
public sealed class CommandAttribute : Attribute
{
public readonly string Alias;
public readonly string Description;
public readonly Platform SupportedPlatforms;
public readonly MonoTargetType MonoTarget;
public readonly bool Valid = true;
private static readonly char[] _bannedAliasChars = new char[] { ' ', '(', ')', '{', '}', '[', ']', '<', '>' };
public CommandAttribute([CallerMemberName] string aliasOverride = "", Platform supportedPlatforms = Platform.AllPlatforms, MonoTargetType targetType = MonoTargetType.Single)
{
Alias = aliasOverride;
MonoTarget = targetType;
SupportedPlatforms = supportedPlatforms;
for (int i = 0; i < _bannedAliasChars.Length; i++)
{
if (Alias.Contains(_bannedAliasChars[i]))
{
string errorMessage = $"Development Processor Error: Command with alias '{Alias}' contains the char '{_bannedAliasChars[i]}' which is banned. Unexpected behaviour may occur.";
Debug.LogError(errorMessage);
Valid = false;
throw new ArgumentException(errorMessage, nameof(aliasOverride));
}
}
}
public CommandAttribute(string aliasOverride, MonoTargetType targetType, Platform supportedPlatforms = Platform.AllPlatforms) : this(aliasOverride, supportedPlatforms, targetType) { }
public CommandAttribute(string aliasOverride, string description, Platform supportedPlatforms = Platform.AllPlatforms, MonoTargetType targetType = MonoTargetType.Single) : this(aliasOverride, supportedPlatforms, targetType)
{
Description = description;
}
public CommandAttribute(string aliasOverride, string description, MonoTargetType targetType, Platform supportedPlatforms = Platform.AllPlatforms) : this(aliasOverride, description, supportedPlatforms, targetType) { }
}
}

View File

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

View File

@ -0,0 +1,18 @@
using System;
namespace QFSW.QC
{
/// <summary>Provides a command with a description. If the [Command] attribute already provides a description, that will supersede this one. Useful for when you have several [Command]s on a single method.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public sealed class CommandDescriptionAttribute : Attribute
{
public readonly string Description;
public readonly bool Valid;
public CommandDescriptionAttribute(string description)
{
Description = description;
Valid = !string.IsNullOrWhiteSpace(description);
}
}
}

View File

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

View File

@ -0,0 +1,18 @@
using System;
namespace QFSW.QC
{
/// <summary>Provides a command paremeter with a description.</summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class CommandParameterDescriptionAttribute : Attribute
{
public readonly string Description;
public readonly bool Valid;
public CommandParameterDescriptionAttribute(string description)
{
Description = description;
Valid = !string.IsNullOrWhiteSpace(description);
}
}
}

View File

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

View File

@ -0,0 +1,16 @@
using System;
namespace QFSW.QC
{
/// <summary>Determines which platforms the command is available on. Supersedes platform availability determined in the [Command].</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public sealed class CommandPlatformAttribute : Attribute
{
public readonly Platform SupportedPlatforms;
public CommandPlatformAttribute(Platform supportedPlatforms)
{
SupportedPlatforms = supportedPlatforms;
}
}
}

View File

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

View File

@ -0,0 +1,35 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace QFSW.QC
{
/// <summary>
/// Creates a prefix that will be prepended to all commands made within this class. Works recursively with sub-classes.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
public sealed class CommandPrefixAttribute : Attribute
{
public readonly string Prefix;
public readonly bool Valid = true;
private static readonly char[] _bannedAliasChars = { ' ', '(', ')', '{', '}', '[', ']', '<', '>' };
public CommandPrefixAttribute([CallerMemberName] string prefixName = "")
{
Prefix = prefixName;
foreach (var c in _bannedAliasChars)
{
if (Prefix.Contains(c))
{
string errorMessage = $"Development Processor Error: Command prefix '{Prefix}' contains the char '{c}' which is banned. Unexpected behaviour may occurr.";
Debug.LogError(errorMessage);
Valid = false;
throw new ArgumentException(errorMessage, nameof(prefixName));
}
}
}
}
}

View File

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

View File

@ -0,0 +1,11 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Instructs QC to ignore this entity when scanning the code base for commands.
/// This can be used to optimise QCs loading times in large codebases when there are large entities that do not have any commands present.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class QcIgnoreAttribute : Attribute { }
}

View File

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

View File

@ -0,0 +1,9 @@
namespace QFSW.QC
{
public enum AutoScrollOptions
{
Never = 0,
OnInvoke = 1,
Always = 2
}
}

View File

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

View File

@ -0,0 +1,267 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace QFSW.QC
{
/// <summary>
/// Contains the full data about a command and provides an execution point for invoking the command.
/// </summary>
public class CommandData
{
public readonly string CommandName;
public readonly string CommandDescription;
public readonly string CommandSignature;
public readonly string ParameterSignature;
public readonly string GenericSignature;
public readonly ParameterInfo[] MethodParamData;
public readonly Type[] ParamTypes;
public readonly Type[] GenericParamTypes;
public readonly MethodInfo MethodData;
public readonly MonoTargetType MonoTarget;
private readonly object[] _defaultParameters;
public bool IsGeneric => GenericParamTypes.Length > 0;
public bool IsStatic => MethodData.IsStatic;
public bool HasDescription => !string.IsNullOrWhiteSpace(CommandDescription);
public int ParamCount => ParamTypes.Length - _defaultParameters.Length;
public Type[] MakeGenericArguments(params Type[] genericTypeArguments)
{
if (genericTypeArguments.Length != GenericParamTypes.Length)
{
throw new ArgumentException("Incorrect number of generic substitution types were supplied.");
}
Dictionary<string, Type> substitutionTable = new Dictionary<string, Type>();
for (int i = 0; i < genericTypeArguments.Length; i++)
{
substitutionTable.Add(GenericParamTypes[i].Name, genericTypeArguments[i]);
}
Type[] types = new Type[ParamTypes.Length];
for (int i = 0; i < types.Length; i++)
{
if (ParamTypes[i].ContainsGenericParameters)
{
Type substitution = ConstructGenericType(ParamTypes[i], substitutionTable);
types[i] = substitution;
}
else
{
types[i] = ParamTypes[i];
}
}
return types;
}
private Type ConstructGenericType(Type genericType, Dictionary<string, Type> substitutionTable)
{
if (!genericType.ContainsGenericParameters) { return genericType; }
if (substitutionTable.ContainsKey(genericType.Name)) { return substitutionTable[genericType.Name]; }
if (genericType.IsArray) { return ConstructGenericType(genericType.GetElementType(), substitutionTable).MakeArrayType(); }
if (genericType.IsGenericType)
{
Type baseType = genericType.GetGenericTypeDefinition();
Type[] typeArguments = genericType.GetGenericArguments();
for (int i = 0; i < typeArguments.Length; i++)
{
typeArguments[i] = ConstructGenericType(typeArguments[i], substitutionTable);
}
return baseType.MakeGenericType(typeArguments);
}
throw new ArgumentException($"Could not construct the generic type {genericType}");
}
public object Invoke(object[] paramData, Type[] genericTypeArguments)
{
object[] data = new object[paramData.Length + _defaultParameters.Length];
Array.Copy(paramData, 0, data, 0, paramData.Length);
Array.Copy(_defaultParameters, 0, data, paramData.Length, _defaultParameters.Length);
MethodInfo invokingMethod = GetInvokingMethod(genericTypeArguments);
if (IsStatic)
{
return invokingMethod.Invoke(null, data);
}
IEnumerable<object> targets = InvocationTargetFactory.FindTargets(invokingMethod.DeclaringType, MonoTarget);
return InvocationTargetFactory.InvokeOnTargets(invokingMethod, targets, data);
}
private MethodInfo GetInvokingMethod(Type[] genericTypeArguments)
{
if (!IsGeneric)
{
return MethodData;
}
T WrapConstruction<T>(Func<T> f)
{
try
{
return f();
}
catch (ArgumentException)
{
throw new ArgumentException($"Supplied generic parameters did not satisfy the generic constraints imposed by '{CommandName}'");
}
}
Type declaringType = MethodData.DeclaringType;
MethodInfo method = MethodData;
if (declaringType.IsGenericTypeDefinition)
{
int typeCount = declaringType.GetGenericArguments().Length;
Type[] genericTypes = genericTypeArguments
.Take(typeCount)
.ToArray();
genericTypeArguments = genericTypeArguments
.Skip(typeCount)
.ToArray();
declaringType = WrapConstruction(() => declaringType.MakeGenericType(genericTypes));
method = method.RebaseMethod(declaringType);
}
return genericTypeArguments.Length == 0
? method
: WrapConstruction(() => method.MakeGenericMethod(genericTypeArguments));
}
private string BuildPrefix(Type declaringType)
{
List<string> prefixes = new List<string>();
Assembly assembly = declaringType.Assembly;
void AddPrefixes(IEnumerable<CommandPrefixAttribute> prefixAttributes, string defaultName)
{
foreach (CommandPrefixAttribute prefixAttribute in prefixAttributes.Reverse())
{
if (prefixAttribute.Valid)
{
string prefix = prefixAttribute.Prefix;
if (string.IsNullOrWhiteSpace(prefix)) { prefix = defaultName; }
prefixes.Add(prefix);
}
}
}
while (declaringType != null)
{
IEnumerable<CommandPrefixAttribute> typePrefixes = declaringType.GetCustomAttributes<CommandPrefixAttribute>();
AddPrefixes(typePrefixes, declaringType.Name);
declaringType = declaringType.DeclaringType;
}
IEnumerable<CommandPrefixAttribute> assemblyPrefixes = assembly.GetCustomAttributes<CommandPrefixAttribute>();
AddPrefixes(assemblyPrefixes, assembly.GetName().Name);
return string.Join("", prefixes.Reversed());
}
private string BuildGenericSignature(Type[] genericParamTypes)
{
if (genericParamTypes.Length == 0)
{
return string.Empty;
}
IEnumerable<string> names = genericParamTypes.Select(x => x.Name);
return $"<{string.Join(", ", names)}>";
}
private string BuildParameterSignature(ParameterInfo[] methodParams, int defaultParameterCount)
{
string signature = string.Empty;
for (int i = 0; i < methodParams.Length - defaultParameterCount; i++)
{
signature += $"{(i == 0 ? string.Empty : " ")}{methodParams[i].Name}";
}
return signature;
}
private Type[] BuildGenericParamTypes(MethodInfo method, Type declaringType)
{
List<Type> types = new List<Type>();
if (declaringType.IsGenericTypeDefinition)
{
types.AddRange(declaringType.GetGenericArguments());
}
if (method.IsGenericMethodDefinition)
{
types.AddRange(method.GetGenericArguments());
}
return types.ToArray();
}
public CommandData(MethodInfo methodData, int defaultParameterCount = 0) : this(methodData, methodData.Name, defaultParameterCount) { }
public CommandData(MethodInfo methodData, string commandName, int defaultParameterCount = 0)
{
CommandName = commandName;
MethodData = methodData;
if (string.IsNullOrWhiteSpace(commandName))
{
CommandName = methodData.Name;
}
Type declaringType = methodData.DeclaringType;
string prefix = BuildPrefix(declaringType);
CommandName = $"{prefix}{CommandName}";
MethodParamData = methodData.GetParameters();
ParamTypes = MethodParamData
.Select(x => x.ParameterType)
.ToArray();
_defaultParameters = new object[defaultParameterCount];
for (int i = 0; i < defaultParameterCount; i++)
{
int j = MethodParamData.Length - defaultParameterCount + i;
_defaultParameters[i] = MethodParamData[j].DefaultValue;
}
GenericParamTypes = BuildGenericParamTypes(methodData, declaringType);
ParameterSignature = BuildParameterSignature(MethodParamData, defaultParameterCount);
GenericSignature = BuildGenericSignature(GenericParamTypes);
CommandSignature = ParamCount > 0
? $"{CommandName}{GenericSignature} {ParameterSignature}"
: $"{CommandName}{GenericSignature}";
}
public CommandData(MethodInfo methodData, CommandAttribute commandAttribute, int defaultParameterCount = 0) : this(methodData, commandAttribute.Alias, defaultParameterCount)
{
CommandDescription = commandAttribute.Description;
MonoTarget = commandAttribute.MonoTarget;
}
public CommandData(MethodInfo methodData, CommandAttribute commandAttribute, CommandDescriptionAttribute descriptionAttribute, int defaultParameterCount = 0)
: this(methodData, commandAttribute, defaultParameterCount)
{
if ((descriptionAttribute?.Valid ?? false) && string.IsNullOrWhiteSpace(commandAttribute.Description))
{
CommandDescription = descriptionAttribute.Description;
}
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 48497173fbbd4884682d42192fdb2df6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,149 @@
using System.Collections.Generic;
namespace QFSW.QC.Comparators
{
public class AlphanumComparator : IComparer<string>
{
private const int MaxStackSize = 512;
public unsafe int Compare(string x, string y)
{
if (x == null) { return 0; }
if (y == null) { return 0; }
int len1 = x.Length;
int len2 = y.Length;
if (len1 + len2 + 2 <= MaxStackSize)
{
char* buffer1 = stackalloc char[len1 + 1];
char* buffer2 = stackalloc char[len2 + 1];
return Compare(x, buffer1, len1, y, buffer2, len2);
}
else
{
char[] buffer1 = new char[len1 + 1];
char[] buffer2 = new char[len2 + 1];
fixed (char* ptr1 = buffer1)
fixed (char* ptr2 = buffer2)
{
return Compare(x, ptr1, len1, y, ptr2, len2);
}
}
}
public unsafe int Compare(string x, char* buffer1, int len1, string y, char* buffer2, int len2)
{
int marker1 = 0;
int marker2 = 0;
while (marker1 < len1 && marker2 < len2)
{
char ch1 = x[marker1];
char ch2 = y[marker2];
int loc1 = 0;
int loc2 = 0;
do
{
buffer1[loc1++] = ch1;
marker1++;
if (marker1 < len1)
{
ch1 = x[marker1];
}
else
{
break;
}
} while (char.IsDigit(ch1) == char.IsDigit(buffer1[0]));
do
{
buffer2[loc2++] = ch2;
marker2++;
if (marker2 < len2)
{
ch2 = y[marker2];
}
else
{
break;
}
} while (char.IsDigit(ch2) == char.IsDigit(buffer2[0]));
//null terminate buffers
buffer1[loc1] = buffer2[loc2] = (char)0;
int result;
if (char.IsDigit(buffer1[0]) && char.IsDigit(buffer2[0]))
{
int chunk1 = ParseInt(buffer1);
int chunk2 = ParseInt(buffer2);
result = chunk1 - chunk2;
}
else
{
result = CompareStrings(buffer1, buffer2);
}
if (result != 0)
{
return result;
}
}
return len1 - len2;
}
private unsafe int ParseInt(char* buffer)
{
int acc = 0;
while (*buffer != 0)
{
acc *= 10;
acc += *buffer++ - '0';
}
return acc;
}
private unsafe int CompareStrings(char* buffer1, char* buffer2)
{
int index = 0;
while (buffer1[index] != 0 && buffer2[index] != 0)
{
char c1 = buffer1[index];
char c2 = buffer2[index++];
if (c1 > c2)
{
return 1;
}
else if (c1 < c2)
{
return -1;
}
}
if (buffer1[index] != 0)
{
return 1;
}
else if (buffer2[index] != 0)
{
return -1;
}
else
{
return 0;
}
}
}
}

View File

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

View File

@ -0,0 +1,40 @@
using System.Collections.Concurrent;
namespace QFSW.QC
{
public class ConcurrentPool<T> where T : class, new()
{
private readonly ConcurrentStack<T> _objs;
public ConcurrentPool()
{
_objs = new ConcurrentStack<T>();
}
public ConcurrentPool(int objCount)
{
_objs = new ConcurrentStack<T>();
for (int i = 0; i < objCount; i++)
{
_objs.Push(new T());
}
}
public T GetObject()
{
if (_objs.TryPop(out T obj))
{
return obj;
}
else
{
return new T();
}
}
public void Release(T obj)
{
_objs.Push(obj);
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d2efd1c3b1ea14940bbea68283e5ae22
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
using System.Collections;
using System.Collections.Generic;
namespace QFSW.QC.Containers
{
public struct ArraySingle<T> : IReadOnlyList<T>
{
private readonly T _data;
public ArraySingle(T data)
{
_data = data;
}
public T this[int index] => _data;
public int Count => 1;
public IEnumerator<T> GetEnumerator()
{
yield return _data;
}
IEnumerator IEnumerable.GetEnumerator()
{
yield return _data;
}
}
public static class ArraySingleExtensions
{
public static ArraySingle<T> AsArraySingle<T>(this T data)
{
return new ArraySingle<T>(data);
}
}
}

View File

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

View File

@ -0,0 +1,53 @@
using System.Collections;
using System.Collections.Generic;
namespace QFSW.QC.Containers
{
public struct StringContainer : IReadOnlyList<char>
{
private readonly string _str;
public StringContainer(string str)
{
_str = str;
}
public char this[int index] => _str[index];
public int Count => _str.Length;
public IEnumerator<char> GetEnumerator()
{
for (int i = 0; i < _str.Length; i++)
{
yield return _str[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
for (int i = 0; i < _str.Length; i++)
{
yield return _str[i];
}
}
public static implicit operator StringContainer(string str)
{
return new StringContainer(str);
}
public static implicit operator string(StringContainer str)
{
return str._str;
}
}
public static class StringContainerExtensions
{
public static StringContainer AsIReadOnlyList(this string str)
{
return str;
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6189a8da57915c848abf41c6ae6fc7f4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,63 @@
using System;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor
{
public class DataEntryPopup : PopupWindowContent
{
private readonly string _title;
private readonly string _btnName;
private string _data;
private string _errors;
private bool _success;
private GUIStyle _errorStyle;
private GUIStyle _successStyle;
private readonly Action<string> _submitCallback;
public DataEntryPopup(string title, string btnName, Action<string> SubmitCallback)
{
CreateStyles();
_title = title;
_btnName = btnName;
_submitCallback = SubmitCallback;
}
public override Vector2 GetWindowSize() { return new Vector2(500, 100); }
private void CreateStyles()
{
_errorStyle = new GUIStyle(EditorStyles.wordWrappedLabel);
_errorStyle.normal.textColor = new Color(1, 0, 0);
_successStyle = new GUIStyle(EditorStyles.wordWrappedLabel);
_successStyle.normal.textColor = new Color(0, 0.5f, 0);
}
public override void OnGUI(Rect rect)
{
_data = EditorGUILayout.TextField(_title, _data);
GUI.enabled = !string.IsNullOrWhiteSpace(_data);
if (GUILayout.Button(_btnName))
{
try
{
_submitCallback(_data);
_success = true;
_errors = "";
}
catch (Exception e)
{
_errors = e.Message;
_success = false;
}
}
if (!string.IsNullOrWhiteSpace(_errors)) { EditorGUILayout.LabelField(_errors, _errorStyle); }
else if (_success) { EditorGUILayout.LabelField("Success!", _successStyle); }
}
}
}

View File

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

View File

@ -0,0 +1,95 @@
using QFSW.QC.QGUI;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor
{
public static class EditorHelpers
{
private struct SupportItem
{
public string Name;
public string Tooltip;
public string Url;
}
private static readonly SupportItem[] _supportItems =
{
new SupportItem
{
Name = "Docs",
Tooltip = "Official and up to date documentation for Quantum Console.",
Url = "https://qfsw.co.uk/docs/QC/"
},
new SupportItem
{
Name = "Email",
Tooltip = "Email address for support and other inquiries.",
Url = "mailto:support@qfsw.co.uk"
},
new SupportItem
{
Name = "Discord",
Tooltip = "Discord server for customer support, WIPs and more.",
Url = "https://discord.gg/g8SJ7X6"
},
new SupportItem
{
Name = "Twitter",
Tooltip = "Get in touch or show off what you've made with QC.",
Url = "https://twitter.com/QFSW1024"
},
new SupportItem
{
Name = "Review",
Tooltip = "Leave a review to share your opinion and support Quantum Console!",
Url = "https://assetstore.unity.com/packages/tools/utilities/quantum-console-128881#reviews"
},
new SupportItem
{
Name = "Survey",
Tooltip = "A short survey to help me get feedback on Quantum Console and prioritize what needs the most focus.",
Url = "https://forms.gle/TZbpg1t6hc6sypZA9"
}
};
private static Rect[] _supportItemRects = new Rect[_supportItems.Length];
public static void DrawBanner(Texture2D banner, float sizeMultiplier = 1f)
{
if (banner)
{
sizeMultiplier = Mathf.Clamp01(sizeMultiplier);
Rect bannerRect = GUILayoutUtility.GetRect(0.0f, 0.0f);
bannerRect.height = Screen.width / EditorGUIUtility.pixelsPerPoint * banner.height / banner.width;
bannerRect.x += bannerRect.width * (1 - sizeMultiplier) / 2;
bannerRect.width *= sizeMultiplier;
bannerRect.height *= sizeMultiplier;
GUILayout.Space(bannerRect.height);
GUI.Label(bannerRect, banner);
}
}
public static void DrawSupportRow()
{
LayoutController layout = new LayoutController(EditorGUILayout.GetControlRect());
layout.SpliceRow(_supportItemRects.Length, ref _supportItemRects);
for (int i = 0; i < _supportItems.Length; i++)
{
SupportItem item = _supportItems[i];
if (GUI.Button(_supportItemRects[i], new GUIContent(item.Name, item.Tooltip)))
{
Application.OpenURL(item.Url);
}
}
}
public static void DrawHeader(Texture2D banner)
{
DrawBanner(banner);
DrawSupportRow();
}
}
}

View File

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

View File

@ -0,0 +1,42 @@
using QFSW.QC.QGUI;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor
{
[CustomPropertyDrawer(typeof(ModifierKeyCombo), true)]
public class ModifierKeyComboEditor : PropertyDrawer
{
private readonly GUIContent _shiftLabel = new GUIContent("shift");
private readonly GUIContent _altLabel = new GUIContent("alt");
private readonly GUIContent _ctrlLabel = new GUIContent("ctrl");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
LayoutController layout = new LayoutController(position);
EditorGUI.BeginProperty(layout.CurrentRect, label, property);
const float boolWidth = 10;
bool enableState = GUI.enabled;
float boolLabelWidth = QGUILayout.GetMaxContentSize(EditorStyles.label, _shiftLabel, _altLabel, _ctrlLabel).x;
SerializedProperty key = property.FindPropertyRelative("Key");
SerializedProperty ctrl = property.FindPropertyRelative("Ctrl");
SerializedProperty alt = property.FindPropertyRelative("Alt");
SerializedProperty shift = property.FindPropertyRelative("Shift");
GUI.enabled &= ((KeyCode)key.enumValueIndex) != KeyCode.None;
EditorGUI.LabelField(layout.ReserveHorizontalReversed(boolLabelWidth), _shiftLabel);
EditorGUI.PropertyField(layout.ReserveHorizontalReversed(boolWidth), shift, GUIContent.none);
EditorGUI.LabelField(layout.ReserveHorizontalReversed(boolLabelWidth), _altLabel);
EditorGUI.PropertyField(layout.ReserveHorizontalReversed(boolWidth), alt, GUIContent.none);
EditorGUI.LabelField(layout.ReserveHorizontalReversed(boolLabelWidth), _ctrlLabel);
EditorGUI.PropertyField(layout.ReserveHorizontalReversed(boolWidth), ctrl, GUIContent.none);
GUI.enabled = enableState;
EditorGUI.PropertyField(layout.CurrentRect, key, label);
EditorGUI.EndProperty();
}
}
}

View File

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

View File

@ -0,0 +1,47 @@
using QFSW.QC.Utilities;
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor
{
public class QCInspectorBase : UnityEditor.Editor
{
const string ROOT_PATH = "Source";
protected string BannerName => "Banner.png";
protected Texture2D Banner { get; private set; }
protected T LoadAssetInSource<T>(string assetName, string root) where T : UnityEngine.Object
{
MonoScript src = MonoScript.FromScriptableObject(this);
string srcPath = AssetDatabase.GetAssetPath(src);
string dirPath = Path.GetDirectoryName(srcPath);
string[] pathParts = dirPath.Split(new string[] { root }, StringSplitOptions.None);
string rootPath = string.Join(root, pathParts.SkipLast()) + root;
string[] files = Directory.GetFiles(rootPath, assetName, SearchOption.AllDirectories);
if (files.Length > 0)
{
string bannerPath = files[0];
return AssetDatabase.LoadAssetAtPath<T>(bannerPath);
}
return null;
}
protected virtual void OnEnable()
{
if (!Banner)
{
Banner = LoadAssetInSource<Texture2D>(BannerName, ROOT_PATH);
}
}
public override void OnInspectorGUI()
{
EditorHelpers.DrawHeader(Banner);
base.OnInspectorGUI();
}
}
}

View File

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

View File

@ -0,0 +1,19 @@
{
"name": "QFSW.QC.Editor",
"references": [
"QFSW.QC",
"QFSW.QC.Editor.Tools",
"QFSW.QC.QGUI",
"Unity.TextMeshPro"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 50b2bdd4833ec8043a7227258a04ccb7
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 979ba78ee0b3f154ab44f1295d48ce61
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
namespace QFSW.QC.QGUI
{
public interface IGUIItem
{
void DrawGUI(LayoutController layout);
}
}

View File

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

View File

@ -0,0 +1,140 @@
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.QGUI
{
public class LayoutController
{
public static float HorizontalPadding => 4;
public static float RowPadding => EditorGUIUtility.standardVerticalSpacing;
public static float RowHeight => EditorGUIUtility.singleLineHeight;
public bool IsValid
{
get
{
if (_currentRect.width < 0) { return false; }
if (_currentRect.height < 0) { return false; }
if (_currentRect.x < TotalDrawRect.x) { return false; }
if (_currentRect.y < TotalDrawRect.y) { return false; }
if (_currentRect.x + _currentRect.width > TotalDrawRect.x + TotalDrawRect.width) { return false; }
if (_currentRect.y + _currentRect.height > TotalDrawRect.y + TotalDrawRect.height) { return false; }
return true;
}
}
public Rect TotalDrawRect { get; }
public Rect CurrentRect => _currentRect;
private Rect _currentRect;
public LayoutController(Rect drawRect)
{
TotalDrawRect = drawRect;
_currentRect = drawRect;
_currentRect.height = RowHeight;
}
public Rect BeginNewLine()
{
_currentRect.y += RowPadding + RowHeight;
_currentRect.x = TotalDrawRect.x;
_currentRect.width = TotalDrawRect.width;
return _currentRect;
}
public Rect ReserveHorizontal(float width)
{
Rect drawRect = _currentRect;
drawRect.width = width;
drawRect.width -= HorizontalPadding;
_currentRect.x += width;
_currentRect.width -= width;
return drawRect;
}
public Rect ReserveHorizontalPercentage(float widthPercentage)
{
float width = _currentRect.width * widthPercentage;
return ReserveHorizontal(width);
}
public Rect ReserveHorizontalReversed(float width)
{
Rect drawRect = _currentRect;
drawRect.x += drawRect.width;
drawRect.x -= width;
drawRect.width = width;
_currentRect.width -= HorizontalPadding;
_currentRect.width -= width;
return drawRect;
}
public Rect ReserveHorizontalReversedPercentage(float widthPercentage)
{
float width = _currentRect.width * widthPercentage;
return ReserveHorizontalReversed(width);
}
public Rect ResizeRectHeight(Rect rect, float height)
{
rect.y += (rect.height - height) / 2;
rect.height = height;
return rect;
}
public Rect ReserveHorizontal(float width, float height)
{
return ResizeRectHeight(ReserveHorizontal(width), height);
}
public Rect ReserveHorizontalReversed(float width, float height)
{
return ResizeRectHeight(ReserveHorizontalReversed(width), height);
}
public Rect ReserveSquare()
{
return ReserveHorizontal(RowHeight);
}
public Rect ReserveSquareReversed()
{
return ReserveHorizontalReversed(RowHeight);
}
public Rect ReserveAuto(GUIContent content, GUIStyle style)
{
Vector2 size = style.CalcSize(content);
return ReserveHorizontal(size.x, size.y);
}
public Rect ReserveAutoReversed(GUIContent content, GUIStyle style)
{
Vector2 size = style.CalcSize(content);
return ReserveHorizontalReversed(size.x, size.y);
}
public void SpliceRow(int colCount, ref Rect[] rects)
{
float width = _currentRect.width / colCount;
for (int i = 0; i < rects.Length; i++)
{
rects[i] = ReserveHorizontal(width);
}
}
public Rect[] SpliceRow(int colCount)
{
Rect[] rects = new Rect[colCount];
SpliceRow(colCount, ref rects);
return rects;
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
{
"name": "QFSW.QC.QGUI",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2c8115fef53c440a1873e4077e45b326
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,49 @@
using System;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.QGUI
{
public static class QGUILayout
{
public static T EnumPopup<T>(T selected, params GUILayoutOption[] options) where T : Enum
{
return (T)EditorGUILayout.EnumPopup(selected, options);
}
public static T EnumPopup<T>(GUIContent content, T selected, params GUILayoutOption[] options) where T : Enum
{
return (T)EditorGUILayout.EnumPopup(content, selected, options);
}
public static T EnumFlagsField<T>(GUIContent content, T enumValue, params GUILayoutOption[] options) where T : Enum
{
return (T)EditorGUILayout.EnumFlagsField(content, enumValue, options);
}
public static bool ButtonAuto(GUIContent content, GUIStyle style)
{
Vector2 size = style.CalcSize(content);
return GUILayout.Button(content, style, GUILayout.Width(size.x));
}
public static bool ButtonAuto(LayoutController layout, GUIContent content, GUIStyle style)
{
Rect rect = layout.ReserveAuto(content, style);
return GUI.Button(rect, content, style);
}
public static Vector2 GetMaxContentSize(GUIStyle style, params GUIContent[] contents)
{
Vector2 maxSize = new Vector2();
foreach (GUIContent content in contents)
{
Vector2 size = style.CalcSize(content);
maxSize.x = Mathf.Max(maxSize.x, size.x);
maxSize.y = Mathf.Max(maxSize.y, size.y);
}
return maxSize;
}
}
}

View File

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

View File

@ -0,0 +1,242 @@
using QFSW.QC.Editor.Tools;
using QFSW.QC.QGUI;
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor
{
[CustomEditor(typeof(QuantumConsole), true)]
public class QuantumConsoleInspector : QCInspectorBase
{
private QuantumConsole QCInstance;
private SerializedProperty _themeProperty;
private SerializedProperty _keyConfigProperty;
private SerializedProperty _verboseLoggingProperty;
private SerializedProperty _verboseErrorsProperty;
private SerializedProperty _loggingLevelProperty;
private SerializedProperty _openOnLogLevelProperty;
private SerializedProperty _supportedStateProperty;
private SerializedProperty _autoScrollProperty;
private SerializedProperty _interceptDebugProperty;
private SerializedProperty _interceptInactiveProperty;
private SerializedProperty _prependTimestampsProperty;
private SerializedProperty _activateOnStartupProperty;
private SerializedProperty _initialiseOnStartupProperty;
private SerializedProperty _closeOnSubmitProperty;
private SerializedProperty _singletonModeProperty;
private SerializedProperty _inputProperty;
private SerializedProperty _inputPlaceholderProperty;
private SerializedProperty _logProperty;
private SerializedProperty _containerProperty;
private SerializedProperty _scrollRectProperty;
private SerializedProperty _suggestionProperty;
private SerializedProperty _popupProperty;
private SerializedProperty _popupTextProperty;
private SerializedProperty _jobCounterTextProperty;
private SerializedProperty _jobCounterRectProperty;
private SerializedProperty _panelsProperty;
private SerializedProperty _commandHistoryProperty;
private SerializedProperty _commandHistorySizeProperty;
private SerializedProperty _commandHistoryDuplicatesProperty;
private SerializedProperty _commandHistoryAdjacentDuplicatesProperty;
private SerializedProperty _usePopupProperty;
private SerializedProperty _maxSuggestionProperty;
private SerializedProperty _popupOrderProperty;
private SerializedProperty _fuzzyProperty;
private SerializedProperty _caseSensitiveProperty;
private SerializedProperty _showCurrentJobsProperty;
private SerializedProperty _blockOnAsyncProperty;
private SerializedProperty _maxStoredLogsProperty;
private SerializedProperty _maxLogSizeProperty;
private SerializedProperty _showInitLogsProperty;
protected override void OnEnable()
{
base.OnEnable();
QCInstance = (QuantumConsole)target;
QCInstance.OnStateChange += Repaint;
FetchSerializedProperties();
}
private void FetchSerializedProperties()
{
_themeProperty = serializedObject.FindProperty("_theme");
_keyConfigProperty = serializedObject.FindProperty("_keyConfig");
_verboseLoggingProperty = serializedObject.FindProperty("_verboseLogging");
_verboseErrorsProperty = serializedObject.FindProperty("_verboseErrors");
_loggingLevelProperty = serializedObject.FindProperty("_loggingLevel");
_openOnLogLevelProperty = serializedObject.FindProperty("_openOnLogLevel");
_supportedStateProperty = serializedObject.FindProperty("_supportedState");
_autoScrollProperty = serializedObject.FindProperty("_autoScroll");
_interceptDebugProperty = serializedObject.FindProperty("_interceptDebugLogger");
_interceptInactiveProperty = serializedObject.FindProperty("_interceptWhilstInactive");
_prependTimestampsProperty = serializedObject.FindProperty("_prependTimestamps");
_activateOnStartupProperty = serializedObject.FindProperty("_activateOnStartup");
_initialiseOnStartupProperty = serializedObject.FindProperty("_initialiseOnStartup");
_closeOnSubmitProperty = serializedObject.FindProperty("_closeOnSubmit");
_singletonModeProperty = serializedObject.FindProperty("_singletonMode");
_containerProperty = serializedObject.FindProperty("_containerRect");
_scrollRectProperty = serializedObject.FindProperty("_scrollRect");
_popupProperty = serializedObject.FindProperty("_suggestionPopupRect");
_jobCounterRectProperty = serializedObject.FindProperty("_jobCounterRect");
_panelsProperty = serializedObject.FindProperty("_panels");
_commandHistoryProperty = serializedObject.FindProperty("_storeCommandHistory");
_commandHistoryDuplicatesProperty = serializedObject.FindProperty("_storeDuplicateCommands");
_commandHistoryAdjacentDuplicatesProperty = serializedObject.FindProperty("_storeAdjacentDuplicateCommands");
_commandHistorySizeProperty = serializedObject.FindProperty("_commandHistorySize");
_showCurrentJobsProperty = serializedObject.FindProperty("_showCurrentJobs");
_blockOnAsyncProperty = serializedObject.FindProperty("_blockOnAsync");
_usePopupProperty = serializedObject.FindProperty("_showPopupDisplay");
_maxSuggestionProperty = serializedObject.FindProperty("_maxSuggestionDisplaySize");
_popupOrderProperty = serializedObject.FindProperty("_suggestionDisplayOrder");
_fuzzyProperty = serializedObject.FindProperty("_useFuzzySearch");
_caseSensitiveProperty = serializedObject.FindProperty("_caseSensitiveSearch");
_maxStoredLogsProperty = serializedObject.FindProperty("_maxStoredLogs");
_maxLogSizeProperty = serializedObject.FindProperty("_maxLogSize");
_showInitLogsProperty = serializedObject.FindProperty("_showInitLogs");
_inputProperty = serializedObject.FindProperty("_consoleInput");
_inputPlaceholderProperty = serializedObject.FindProperty("_inputPlaceholderText");
_logProperty = serializedObject.FindProperty("_consoleLogText");
_suggestionProperty = serializedObject.FindProperty("_consoleSuggestionText");
_popupTextProperty = serializedObject.FindProperty("_suggestionPopupText");
_jobCounterTextProperty = serializedObject.FindProperty("_jobCounterText");
}
private void OnDisable()
{
QCInstance.OnStateChange -= Repaint;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorHelpers.DrawHeader(Banner);
if (QuantumConsoleProcessor.TableGenerated || QuantumConsoleProcessor.TableIsGenerating)
{
EditorGUILayout.LabelField("Quantum Console Processor Information", EditorStyles.miniBoldLabel);
if (QuantumConsoleProcessor.TableIsGenerating) { EditorGUILayout.LabelField("Command Table Generating...", EditorStyles.miniLabel); }
EditorGUILayout.LabelField($"Commands Loaded: {QuantumConsoleProcessor.LoadedCommandCount}", EditorStyles.miniLabel);
EditorGUILayout.Space();
}
EditorGUILayout.LabelField(new GUIContent("General Settings", "All general and basic settings for the Quantum Console."), EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(_themeProperty, new GUIContent("Theme", "QuantumTheme to use for this Quantum Console."));
if (_themeProperty.objectReferenceValue)
{
GUIContent applyBtnContent = new GUIContent("Apply", "Forces an application of the theme now allowing you to see any GUI changes it would make");
if (QGUILayout.ButtonAuto(applyBtnContent, EditorStyles.miniButton))
{
Undo.RecordObject(QCInstance, "Applied a theme to the Quantum Console");
QCInstance.ApplyTheme((QuantumTheme)_themeProperty.objectReferenceValue, true);
PrefabUtil.RecordPrefabInstancePropertyModificationsFullyRecursive(QCInstance.gameObject);
EditorUtility.SetDirty(QCInstance);
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(_keyConfigProperty, new GUIContent("Key Configuration", "Key configuration for the various keyboard shortcuts used by Quantum Console."));
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(_supportedStateProperty, new GUIContent("Enabled", "On which build/editor states should the console be enabled on"));
ShowSceneViewToggle();
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(_activateOnStartupProperty, new GUIContent("Activate on Startup", "If the Quantum Console should be shown and activated on startup."));
if (!_activateOnStartupProperty.boolValue)
{
EditorGUILayout.PropertyField(_initialiseOnStartupProperty, new GUIContent("Initialise on Startup", "If the Quantum Console should be initialised on startup in the background."));
}
EditorGUILayout.PropertyField(_closeOnSubmitProperty, new GUIContent("Close on Submit", "If the Quantum Console should be hidden and closed when a command is submitted and invoked."));
EditorGUILayout.PropertyField(_singletonModeProperty, new GUIContent("Singleton", "Forces the console into singleton mode. " +
"This means the console will be made scene persistent and will not be destroyed when new scenes are loaded. " +
"Additionally, only one instance of the console will be allowed to exist, and it will be accessible via QuantumConsole.Instance"));
EditorGUILayout.PropertyField(_verboseErrorsProperty, new GUIContent("Verbose Errors", "If errors caused by the Quantum Console Processor or commands should be logged in verbose mode."));
EditorGUILayout.PropertyField(_autoScrollProperty, new GUIContent("Autoscroll", "Determine if and when the console should autoscroll."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Debug Interception", "All settings relating to the interception of Unity's Debug class."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_interceptDebugProperty, new GUIContent("Intercept Debug Messages", "If the Quantum Console should intercept and display messages from the Unity Debug logging."));
if (_interceptDebugProperty.boolValue)
{
EditorGUILayout.PropertyField(_interceptInactiveProperty, new GUIContent("Intercept Whilst Inactive", "If the Quantum Console should continue to intercept messages whilst inactive."));
EditorGUILayout.PropertyField(_prependTimestampsProperty, new GUIContent("Enable Timestamps", "If the timestamp of the log message should be prepended."));
EditorGUILayout.PropertyField(_loggingLevelProperty, new GUIContent("Logging Level", "The minimum log severity required to intercept and display the log."));
EditorGUILayout.PropertyField(_verboseLoggingProperty, new GUIContent("Verbose Logging", "The minimum log severity required to use verbose logging."));
EditorGUILayout.PropertyField(_openOnLogLevelProperty, new GUIContent("Open Console", "The minimum log severity required to open the console."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Async Settings", "All settings related to async commands."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_showCurrentJobsProperty, new GUIContent("Show Current Jobs", "Shows a popup counter with the currently executing async commands."));
EditorGUILayout.PropertyField(_blockOnAsyncProperty, new GUIContent("Block on Execute", "Blocks the Quantum Console from being used until the current async command has finished."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Command Search", "Settings relating to searching for commands in the console using tab."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_fuzzyProperty, new GUIContent("Use Fuzzy Search", "If fuzzy search is disabled, then your current search must match the beginning of the command to be suggested (foo*). If fuzzy search is enabled, it can be anywhere within the command name to be suggested (*foo*)."));
EditorGUILayout.PropertyField(_caseSensitiveProperty, new GUIContent("Case Sensitive", "If the search should be case sensitive or not."));
EditorGUILayout.PropertyField(_usePopupProperty, new GUIContent("Show Popup Display", "If enabled, a popup display will be shown containing potential command autocompletions as you type."));
if (_usePopupProperty.boolValue)
{
EditorGUILayout.PropertyField(_maxSuggestionProperty, new GUIContent("Max Suggestion Count", "The maximum number of suggestions to display in the popup. Set to -1 for unlimited."));
EditorGUILayout.PropertyField(_popupOrderProperty, new GUIContent("Suggestion Popup Order", "The sort direction used when displaying suggestions to the popup display."));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Command History", "Settings relating to storing previous commands so that they can be easily accessed with the arrow keys."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_commandHistoryProperty, new GUIContent("Store Previous Commands", "If previous commands should be stored, allowing them to be accessed with the arrow keys."));
if (_commandHistoryProperty.boolValue)
{
EditorGUILayout.PropertyField(_commandHistoryDuplicatesProperty, new GUIContent("Allow Duplicates", "Store commands into the history even if they have already appeared."));
if (_commandHistoryDuplicatesProperty.boolValue) { EditorGUILayout.PropertyField(_commandHistoryAdjacentDuplicatesProperty, new GUIContent("Allow Adjacent Duplicates", "Store commands in the history even if they are adjacent duplicates (i.e same command multiple times in a row).")); }
_commandHistorySizeProperty.intValue = Mathf.Max(-1, EditorGUILayout.IntField(new GUIContent("Max Size", "The maximum size of the command history buffer; exceeding this size will cause the oldest commands to be removed to make space. Set to -1 for unlimited."), _commandHistorySizeProperty.intValue));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Advanced Settings", "Advanced settings such as buffer sizes."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_maxStoredLogsProperty, new GUIContent("Maximum Stored Logs", "Maximum number of logtraces to store before discarding old logs. Set to -1 for unlimited."));
EditorGUILayout.PropertyField(_maxLogSizeProperty, new GUIContent("Maximum Log Size", "Logs exceeding this size will be discarded and an error will be shown. Set to -1 for no maximum size on a single log."));
EditorGUILayout.PropertyField(_showInitLogsProperty, new GUIContent("Show Initialization Logs", "Whether the initialization logs should be shown or not."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("References", "All the references needed by the Quantum Console"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_containerProperty, new GUIContent("Container Rect", "The top level container rect-transform containing all of the Quantum Console UI elements."));
EditorGUILayout.PropertyField(_scrollRectProperty, new GUIContent("Scroll Rect", "(Optional) The scroll rect of the console text, required for auto scrolling."));
EditorGUILayout.PropertyField(_popupProperty, new GUIContent("Suggestion Popup Display", "Top level transform for the suggestion popup display."));
EditorGUILayout.PropertyField(_jobCounterRectProperty, new GUIContent("Job Counter Display", "Top level transform for the job counter display."));
EditorGUILayout.PropertyField(_inputProperty, new GUIContent("Console Input Field", "The input field used for interfacing with the Quantum Console."));
EditorGUILayout.PropertyField(_inputPlaceholderProperty, new GUIContent("Console Input Placeholder", "The placeholder text component for when the input field is not in use."));
EditorGUILayout.PropertyField(_popupTextProperty, new GUIContent("Suggestion Popup Text", "Text display for the suggestion popup display."));
EditorGUILayout.PropertyField(_logProperty, new GUIContent("Console Log Display", "The text display used as the log output by the Quantum Console."));
EditorGUILayout.PropertyField(_suggestionProperty, new GUIContent("Command Suggestion Display", "(optional) If assigned, the Quantum Console will show the paramater signature for suggested commands here."));
EditorGUILayout.PropertyField(_jobCounterTextProperty, new GUIContent("Job Counter Text", "Text display for the job counter display."));
EditorGUILayout.PropertyField(_panelsProperty, new GUIContent("UI Panels", "All panels in the UI to control with the Quantum Theme."), true);
serializedObject.ApplyModifiedProperties();
}
private void ShowSceneViewToggle()
{
RectTransform consoleContainer = (RectTransform)_containerProperty.objectReferenceValue;
bool containerFound = consoleContainer;
bool containerHidden = containerFound ? consoleContainer.gameObject.activeSelf : false;
GUI.enabled = containerFound;
GUIContent message = new GUIContent(containerFound ? containerHidden ? "Hide Console" : "Show Console" : "Console Missing");
if (QGUILayout.ButtonAuto(message, EditorStyles.miniButton)) { consoleContainer.gameObject.SetActive(!consoleContainer.gameObject.activeSelf); }
GUI.enabled = true;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 183567afdaef7164f803d9188375d34b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- banner: {fileID: 2800000, guid: 0a00d33b88ebe3f4eb5dfb0d2a1c0726, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,86 @@
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor
{
[CustomEditor(typeof(QuantumKeyConfig))]
public class QuantumKeyConfigInspector : QCInspectorBase
{
private QuantumKeyConfig _keyConfigInstance;
private SerializedProperty _submitCommandKeyProperty;
private SerializedProperty _hideConsoleKeyProperty;
private SerializedProperty _showConsoleKeyProperty;
private SerializedProperty _toggleConsoleVisibilityKeyProperty;
private SerializedProperty _zoomInKeyProperty;
private SerializedProperty _zoomOutKeyProperty;
private SerializedProperty _dragConsoleKeyProperty;
private SerializedProperty _suggestNextCommandKeyProperty;
private SerializedProperty _suggestPreviousCommandKeyProperty;
private SerializedProperty _nextCommandKeyProperty;
private SerializedProperty _previousCommandKeyProperty;
private SerializedProperty _cancelActionsKeyProperty;
protected override void OnEnable()
{
base.OnEnable();
_keyConfigInstance = (QuantumKeyConfig)target;
_submitCommandKeyProperty = serializedObject.FindProperty("SubmitCommandKey");
_hideConsoleKeyProperty = serializedObject.FindProperty("HideConsoleKey");
_showConsoleKeyProperty = serializedObject.FindProperty("ShowConsoleKey");
_toggleConsoleVisibilityKeyProperty = serializedObject.FindProperty("ToggleConsoleVisibilityKey");
_zoomInKeyProperty = serializedObject.FindProperty("ZoomInKey");
_zoomOutKeyProperty = serializedObject.FindProperty("ZoomOutKey");
_dragConsoleKeyProperty = serializedObject.FindProperty("DragConsoleKey");
_suggestNextCommandKeyProperty = serializedObject.FindProperty("SuggestNextCommandKey");
_suggestPreviousCommandKeyProperty = serializedObject.FindProperty("SuggestPreviousCommandKey");
_nextCommandKeyProperty = serializedObject.FindProperty("NextCommandKey");
_previousCommandKeyProperty = serializedObject.FindProperty("PreviousCommandKey");
_cancelActionsKeyProperty = serializedObject.FindProperty("CancelActionsKey");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorHelpers.DrawHeader(Banner);
EditorGUILayout.LabelField(new GUIContent("General"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_submitCommandKeyProperty, new GUIContent("Submit Command", "The key to submit and invoke the current console input."));
EditorGUILayout.PropertyField(_showConsoleKeyProperty, new GUIContent("Show Console", "The key used to show and activate the console."));
EditorGUILayout.PropertyField(_hideConsoleKeyProperty, new GUIContent("Hide Console", "The key used to hide and deactivate the console."));
EditorGUILayout.PropertyField(_toggleConsoleVisibilityKeyProperty, new GUIContent("Toggle Console", "The key used to toggle the active and visibility state of the console."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("UI"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_zoomInKeyProperty, new GUIContent("Zoom In", "Zooms in the console scaling."));
EditorGUILayout.PropertyField(_zoomOutKeyProperty, new GUIContent("Zoom Out", "Zooms out the console scaling."));
EditorGUILayout.PropertyField(_dragConsoleKeyProperty, new GUIContent("Drag Console", "Drags the console window with the cursor."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Command Suggestions"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_suggestNextCommandKeyProperty, new GUIContent("Show Suggested Commands", "The key to show and suggest commands based on the current console input."));
EditorGUILayout.PropertyField(_suggestPreviousCommandKeyProperty, new GUIContent("Show Previous Suggestion", "The key to show the previous suggestion."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Command History"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_nextCommandKeyProperty, new GUIContent("Select Next Command", "The key to be used to select the next command from the console history."));
EditorGUILayout.PropertyField(_previousCommandKeyProperty, new GUIContent("Select Previous Command", "The key to be used to select the previous command from the console history."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Actions"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_cancelActionsKeyProperty, new GUIContent("Cancel Actions", "Cancels any actions currently executing."));
serializedObject.ApplyModifiedProperties();
}
}
}

View File

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

View File

@ -0,0 +1,237 @@
using QFSW.QC.Utilities;
using System;
using System.Collections;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace QFSW.QC.Editor
{
[CustomEditor(typeof(QuantumTheme), true)]
public class QuantumThemeInspector : QCInspectorBase
{
private QuantumTheme _themeInstance;
private SerializedProperty _fontProperty;
private SerializedProperty _panelMaterialProperty;
private SerializedProperty _panelColorProperty;
private SerializedProperty _errorColorProperty;
private SerializedProperty _warningColorProperty;
private SerializedProperty _successColorProperty;
private SerializedProperty _selectedSuggestionColorProperty;
private SerializedProperty _suggestionColorProperty;
private SerializedProperty _commandLogColorProperty;
private SerializedProperty _defaultValueColorProperty;
private SerializedProperty _timestampFormatProperty;
private ReorderableList _typeFormattersListDisplay;
private SerializedProperty _typeFormattersProperty;
private ReorderableList _collectionFormattersListDisplay;
private SerializedProperty _collectionFormattersProperty;
private GUIStyle _centeredMiniLabel;
private GUIStyle _centeredLabel;
private GUIStyle _centeredTextField;
private bool _initialisedStyles;
protected override void OnEnable()
{
base.OnEnable();
_themeInstance = (QuantumTheme)target;
_fontProperty = serializedObject.FindProperty("Font");
_panelMaterialProperty = serializedObject.FindProperty("PanelMaterial");
_panelColorProperty = serializedObject.FindProperty("PanelColor");
_defaultValueColorProperty = serializedObject.FindProperty("DefaultReturnValueColor");
_errorColorProperty = serializedObject.FindProperty("ErrorColor");
_warningColorProperty = serializedObject.FindProperty("WarningColor");
_successColorProperty = serializedObject.FindProperty("SuccessColor");
_selectedSuggestionColorProperty = serializedObject.FindProperty("SelectedSuggestionColor");
_suggestionColorProperty = serializedObject.FindProperty("SuggestionColor");
_commandLogColorProperty = serializedObject.FindProperty("CommandLogColor");
_timestampFormatProperty = serializedObject.FindProperty("TimestampFormat");
_typeFormattersProperty = serializedObject.FindProperty("TypeFormatters");
_typeFormattersListDisplay = new ReorderableList(serializedObject, _typeFormattersProperty, true, true, true, true);
_typeFormattersListDisplay.onAddCallback = AppendNewTypeFormatter;
_typeFormattersListDisplay.drawElementCallback = DrawTypeFormatterInspector;
_typeFormattersListDisplay.drawHeaderCallback = DrawTypeFormatterListHeader;
_collectionFormattersProperty = serializedObject.FindProperty("CollectionFormatters");
_collectionFormattersListDisplay = new ReorderableList(serializedObject, _collectionFormattersProperty, true, true, true, true);
_collectionFormattersListDisplay.onAddCallback = AppendNewCollectionFormatter;
_collectionFormattersListDisplay.drawElementCallback = DrawCollectionFormatterInspector;
_collectionFormattersListDisplay.drawHeaderCallback = DrawCollectionFormatterListHeader;
}
private void CreateStyles()
{
if (!_initialisedStyles)
{
_initialisedStyles = true;
_centeredMiniLabel = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
_centeredMiniLabel.normal.textColor = EditorGUIUtility.isProSkin ? new Color(0.7f, 0.7f, 0.7f, 1) : new Color(0.3f, 0.3f, 0.3f, 1);
_centeredLabel = new GUIStyle(EditorStyles.label);
_centeredLabel.alignment = TextAnchor.MiddleCenter;
_centeredLabel.richText = true;
_centeredTextField = new GUIStyle(EditorStyles.textField);
_centeredTextField.alignment = TextAnchor.MiddleCenter;
}
}
public override void OnInspectorGUI()
{
CreateStyles();
serializedObject.Update();
EditorHelpers.DrawHeader(Banner);
EditorGUILayout.LabelField(new GUIContent("UI", "Theme customisations for the Quantum Console UI."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_fontProperty, new GUIContent("Font", "The font to be used throughout the Quantum Console."));
EditorGUILayout.PropertyField(_panelMaterialProperty, new GUIContent("Panel Material", "The material to use in the UI panels. Leave null for default."));
EditorGUILayout.PropertyField(_panelColorProperty, new GUIContent("Panel Color", "The color to use in the UI panels."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Colors", "Color customisation for various aspects of the Quantum Console."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_errorColorProperty, new GUIContent("Error Color", "The color to use when formatting errors in the console log."));
EditorGUILayout.PropertyField(_warningColorProperty, new GUIContent("Warning Color", "The color to use when formatting warnings in the console log."));
EditorGUILayout.PropertyField(_successColorProperty, new GUIContent("Success Color", "The color to use when formatting successful void commands."));
EditorGUILayout.PropertyField(_selectedSuggestionColorProperty, new GUIContent("Selected Suggestion Color", "The color to use for the selected suggestion from the suggestion popup display."));
EditorGUILayout.PropertyField(_suggestionColorProperty, new GUIContent("Suggestion Signature Color", "The color to use when displaying the paramater signature for suggested commands."));
EditorGUILayout.PropertyField(_commandLogColorProperty, new GUIContent("Command Log Color", "The color to use when displaying logged commands in the console log."));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Formatting", "Control various formatting within Quantum Console."), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_timestampFormatProperty, new GUIContent("Timestamp Format", "The format to use when generating timestamps." +
"\n{0} = Hour" +
"\n{1} = Minute" +
"\n{2} = Second"));
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Return Value Formatting", "Formatting options for the return serialization"), EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_defaultValueColorProperty, new GUIContent("Default Color", "The default color for return values"));
_typeFormattersListDisplay.DoLayoutList();
_collectionFormattersListDisplay.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
private void DrawTypeFormatterInspector(Rect drawRect, int index, bool isActive, bool isFocused)
{
float nameWidth = 150f;
drawRect.y += 2;
SerializedProperty currentTypeFormatter = _typeFormattersListDisplay.serializedProperty.GetArrayElementAtIndex(index);
SerializedProperty colorProperty = currentTypeFormatter.FindPropertyRelative("Color");
string typeName = _themeInstance.TypeFormatters[index].Type.GetDisplayName();
Rect labelRect = new Rect(drawRect.x, drawRect.y, nameWidth, EditorGUIUtility.singleLineHeight);
Rect colorRect = new Rect(drawRect.x + nameWidth, drawRect.y, drawRect.width - nameWidth, EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(labelRect, typeName);
EditorGUI.PropertyField(colorRect, colorProperty, new GUIContent());
}
private void DrawTypeFormatterListHeader(Rect drawRect)
{
EditorGUI.LabelField(new Rect(drawRect.x, drawRect.y, 150, drawRect.height), new GUIContent("Type Formatters", "The different colors that should be used for formatting different type returns."));
EditorGUI.LabelField(new Rect((drawRect.x + drawRect.width) / 2 - 40, drawRect.y, 80, drawRect.height), _typeFormattersProperty.arraySize.ToString() + (_typeFormattersProperty.arraySize == 1 ? " Formatter" : " Formatters"), _centeredMiniLabel);
}
private void AppendNewTypeFormatter(ReorderableList listTarget)
{
Action<string> SubmitCallback = (string data) =>
{
Type type = QuantumParser.ParseType(data);
if (type == null) { throw new ArgumentException($"No type of name '{data}' could be found. Are you missing a namespace?"); }
Undo.RecordObject(_themeInstance, "Added a new Type Formatter");
_themeInstance.TypeFormatters.Add(new TypeColorFormatter(type));
EditorUtility.SetDirty(_themeInstance);
};
PopupWindow.Show(new Rect(5, 5, 0, 0), new DataEntryPopup("Type Name", "Create Type Formatter", SubmitCallback));
}
private void DrawCollectionFormatterInspector(Rect drawRect, int index, bool isActive, bool isFocused)
{
float itemWidth = 40f;
float dataWidth = 35f;
float padding = 5f;
float endPadding = 10f;
float nameWidth = drawRect.width - (6 * itemWidth + 3 * dataWidth + 5 * padding + endPadding);
drawRect.y += 2;
SerializedProperty currentCollectionFormatter = _collectionFormattersListDisplay.serializedProperty.GetArrayElementAtIndex(index);
SerializedProperty seperatorProperty = currentCollectionFormatter.FindPropertyRelative("SeperatorString");
SerializedProperty leftScoperProperty = currentCollectionFormatter.FindPropertyRelative("LeftScoper");
SerializedProperty rightScoperProperty = currentCollectionFormatter.FindPropertyRelative("RightScoper");
string typeName = _themeInstance.CollectionFormatters[index].Type.GetDisplayName();
Rect rect = new Rect(drawRect.x, drawRect.y, nameWidth, EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(rect, typeName);
rect.x += nameWidth + padding;
Action<SerializedProperty, float> DrawTextField = (SerializedProperty prop, float width) =>
{
rect.width = width;
prop.stringValue = EditorGUI.TextField(rect, new GUIContent(), prop.stringValue, _centeredTextField);
rect.x += width + padding;
};
Action<string, float> DrawLabelField = (string text, float width) =>
{
rect.width = width;
EditorGUI.LabelField(rect, text, _centeredLabel);
rect.x += width + padding;
};
string highlightCol = EditorGUIUtility.isProSkin ? "#1fe035" : "#005209";
string itemCol = EditorGUIUtility.isProSkin ? "#ff8280" : "#6A0301";
string example = $"<b><color={highlightCol}>{leftScoperProperty.stringValue}</color></b>" +
$"<color={itemCol}>item1</color><b><color={highlightCol}>{seperatorProperty.stringValue}</color></b>" +
$"<color={itemCol}>item2</color><b><color={highlightCol}>{rightScoperProperty.stringValue}</color></b>";
DrawTextField(leftScoperProperty, dataWidth);
DrawLabelField("item1", itemWidth);
DrawTextField(seperatorProperty, dataWidth);
DrawLabelField("item2", itemWidth);
DrawTextField(rightScoperProperty, dataWidth);
DrawLabelField("<b>=></b>", itemWidth * 1.5f);
DrawLabelField(example, itemWidth * 2.5f);
}
private void DrawCollectionFormatterListHeader(Rect drawRect)
{
EditorGUI.LabelField(new Rect(drawRect.x, drawRect.y, 150, drawRect.height), new GUIContent("Collection Formatters", "The different strings that should be used for seperating and enclosing collections when serialized."));
EditorGUI.LabelField(new Rect((drawRect.x + drawRect.width) / 2 - 40, drawRect.y, 80, drawRect.height), _collectionFormattersProperty.arraySize.ToString() + (_collectionFormattersProperty.arraySize == 1 ? " Formatter" : " Formatters"), _centeredMiniLabel);
}
private void AppendNewCollectionFormatter(ReorderableList listTarget)
{
Action<string> SubmitCallback = (string data) =>
{
Type type = QuantumParser.ParseType(data);
if (type == null) { throw new ArgumentException($"No type of name '{data}' could be found. Are you missing a namespace?"); }
if (!typeof(IEnumerable).IsAssignableFrom(type))
{
throw new ArgumentException("Collection type must implement IEnumerator");
}
Undo.RecordObject(_themeInstance, "Added a new Collection Formatter");
_themeInstance.CollectionFormatters.Add(new CollectionFormatter(type));
EditorUtility.SetDirty(_themeInstance);
};
PopupWindow.Show(new Rect(5, 5, 0, 0), new DataEntryPopup("Collection Type Name", "Create Collection Formatter", SubmitCallback));
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3c958f403b85740698edbcc10c951bce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- banner: {fileID: 2800000, guid: 0a00d33b88ebe3f4eb5dfb0d2a1c0726, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 248ef14759720fa4a800416d09dc3b23
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
using UnityEditor;
using UnityEngine;
namespace QFSW.QC.Editor.Tools
{
public static class PrefabUtil
{
public static void RecordPrefabInstancePropertyModificationsFullyRecursive(GameObject objRoot)
{
PrefabUtility.RecordPrefabInstancePropertyModifications(objRoot);
foreach (Component comp in objRoot.GetComponents<Component>())
{
PrefabUtility.RecordPrefabInstancePropertyModifications(comp);
}
for (int i = 0; i < objRoot.transform.childCount; i++)
{
Transform child = objRoot.transform.GetChild(i);
RecordPrefabInstancePropertyModificationsFullyRecursive(child.gameObject);
}
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
{
"name": "QFSW.QC.Editor.Tools",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a02547252a8685b458cb58325927f320
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
namespace QFSW.QC.Editor.Tools
{
public static class SymbolEditor
{
public static IEnumerable<T> AsEnumerable<T>(this T val)
{
yield return val;
}
private static IEnumerable<BuildTargetGroup> GetPresentBuildTargetGroups()
{
foreach (BuildTarget target in (BuildTarget[])Enum.GetValues(typeof(BuildTarget)))
{
BuildTargetGroup group = BuildPipeline.GetBuildTargetGroup(target);
if (BuildPipeline.IsBuildTargetSupported(group, target))
{
yield return group;
}
}
}
public static void AddSymbol(string symbol)
{
AddSymbols(symbol.AsEnumerable());
}
public static void AddSymbols(IEnumerable<string> symbols)
{
AddSymbols(GetPresentBuildTargetGroups(), symbols);
}
public static void AddSymbols(IEnumerable<BuildTargetGroup> groups, IEnumerable<string> symbols)
{
foreach (BuildTargetGroup group in groups)
{
string currentSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
foreach (string symbol in symbols)
{
if (!currentSymbols.Contains(symbol))
{
currentSymbols = $"{currentSymbols};{symbol}";
}
}
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, currentSymbols);
}
}
public static void RemoveSymbol(string symbol)
{
RemoveSymbols(symbol.AsEnumerable());
}
public static void RemoveSymbols(IEnumerable<string> symbols)
{
RemoveSymbols(GetPresentBuildTargetGroups(), symbols);
}
public static void RemoveSymbols(IEnumerable<BuildTargetGroup> groups, IEnumerable<string> symbols)
{
foreach (BuildTargetGroup group in groups)
{
string currentSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
foreach (string symbol in symbols)
{
currentSymbols = Regex.Replace(currentSymbols, symbol, string.Empty);
}
currentSymbols = string.Join(";", currentSymbols.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, currentSymbols);
}
}
}
}

View File

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

View File

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QFSW.QC
{
/// <summary>
/// Prevents the type from being loaded by an InjectionLoader
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class NoInjectAttribute : Attribute { }
/// <summary>
/// Loads and instantiates instances of the injectable types.
/// </summary>
/// <typeparam name="T">The base type for the instances that will be injected.</typeparam>
public class InjectionLoader<T>
{
private Type[] _injectableTypes;
/// <summary>
/// Retrieves all of the injectable types.
/// </summary>
/// <param name="forceReload">Forces a reload of the types instead of using the cache.</param>
/// <returns>The injectable types.</returns>
public Type[] GetInjectableTypes(bool forceReload = false)
{
if (_injectableTypes == null || forceReload)
{
#if UNITY_2019_2_OR_NEWER && UNITY_EDITOR
_injectableTypes = UnityEditor.TypeCache.GetTypesDerivedFrom<T>()
.Where(type => !type.IsAbstract)
.Where(type => !type.IsDefined(typeof(NoInjectAttribute), false))
.ToArray();
#else
_injectableTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => typeof(T).IsAssignableFrom(type))
.Where(type => !type.IsAbstract)
.Where(type => !type.IsDefined(typeof(NoInjectAttribute), false))
.ToArray();
#endif
}
return _injectableTypes;
}
/// <summary>
/// Creates instances for all of the injectable types available.
/// </summary>
/// <param name="forceReload">Forces a reload of the types instead of using the cache.</param>
/// <returns>The injectable instances.</returns>
public IEnumerable<T> GetInjectedInstances(bool forceReload = false)
{
IEnumerable<Type> injectableTypes = GetInjectableTypes(forceReload);
return GetInjectedInstances(injectableTypes);
}
/// <summary>
/// Creates instances from a custom sequence of injectable types.
/// </summary>
/// <param name="injectableTypes">The types to create instances for.</param>
/// <returns>The injectable instances.</returns>
public IEnumerable<T> GetInjectedInstances(IEnumerable<Type> injectableTypes)
{
foreach (Type type in injectableTypes)
{
T instance = default;
bool success = false;
try
{
instance = (T)Activator.CreateInstance(type);
success = true;
}
catch (MissingMethodException)
{
Debug.LogError($"Could not load {typeof(T)} {type} as it is missing a public parameterless constructor.");
}
catch (Exception e)
{
Debug.LogException(e);
}
if (success)
{
yield return instance;
}
}
}
}
}

View File

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

View File

@ -0,0 +1,187 @@
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
#define NEW_INPUT
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
#endif
using UnityEngine;
namespace QFSW.QC
{
public static class InputHelper
{
private static bool IsKeySupported(KeyCode key)
{
#if NEW_INPUT
bool KeyExists()
{
Key keyConverted = key.ToKey();
foreach (KeyControl k in Keyboard.current.allKeys)
{
if (k.keyCode == keyConverted)
{
return true;
}
}
return false;
}
return key != KeyCode.None
&& Keyboard.current != null
&& KeyExists();
#else
return true;
#endif
}
public static bool GetKey(KeyCode key)
{
#if NEW_INPUT
return IsKeySupported(key)
&& Keyboard.current[key.ToKey()].isPressed;
#else
return Input.GetKey(key);
#endif
}
public static bool GetKeyDown(KeyCode key)
{
#if NEW_INPUT
return IsKeySupported(key)
&& Keyboard.current[key.ToKey()].wasPressedThisFrame;
#else
return Input.GetKeyDown(key);
#endif
}
public static bool GetKeyUp(KeyCode key)
{
#if NEW_INPUT
return IsKeySupported(key)
&& Keyboard.current[key.ToKey()].wasReleasedThisFrame;
#else
return Input.GetKeyDown(key);
#endif
}
#if NEW_INPUT
private static Key ToKey(this KeyCode key)
{
switch (key)
{
case KeyCode.None: return Key.None;
case KeyCode.Space: return Key.Space;
case KeyCode.Return: return Key.Enter;
case KeyCode.Tab: return Key.Tab;
case KeyCode.BackQuote: return Key.Backquote;
case KeyCode.Quote: return Key.Quote;
case KeyCode.Semicolon: return Key.Semicolon;
case KeyCode.Comma: return Key.Comma;
case KeyCode.Period: return Key.Period;
case KeyCode.Slash: return Key.Slash;
case KeyCode.Backslash: return Key.Backslash;
case KeyCode.LeftBracket: return Key.LeftBracket;
case KeyCode.RightBracket: return Key.RightBracket;
case KeyCode.Minus: return Key.Minus;
case KeyCode.Equals: return Key.Equals;
case KeyCode.A: return Key.A;
case KeyCode.B: return Key.B;
case KeyCode.C: return Key.C;
case KeyCode.D: return Key.D;
case KeyCode.E: return Key.E;
case KeyCode.F: return Key.F;
case KeyCode.G: return Key.G;
case KeyCode.H: return Key.H;
case KeyCode.I: return Key.I;
case KeyCode.J: return Key.J;
case KeyCode.K: return Key.K;
case KeyCode.L: return Key.L;
case KeyCode.M: return Key.M;
case KeyCode.N: return Key.N;
case KeyCode.O: return Key.O;
case KeyCode.P: return Key.P;
case KeyCode.Q: return Key.Q;
case KeyCode.R: return Key.R;
case KeyCode.S: return Key.S;
case KeyCode.T: return Key.T;
case KeyCode.U: return Key.U;
case KeyCode.V: return Key.V;
case KeyCode.W: return Key.W;
case KeyCode.X: return Key.X;
case KeyCode.Y: return Key.Y;
case KeyCode.Z: return Key.Z;
case KeyCode.Alpha1: return Key.Digit1;
case KeyCode.Alpha2: return Key.Digit2;
case KeyCode.Alpha3: return Key.Digit3;
case KeyCode.Alpha4: return Key.Digit4;
case KeyCode.Alpha5: return Key.Digit5;
case KeyCode.Alpha6: return Key.Digit6;
case KeyCode.Alpha7: return Key.Digit7;
case KeyCode.Alpha8: return Key.Digit8;
case KeyCode.Alpha9: return Key.Digit9;
case KeyCode.Alpha0: return Key.Digit0;
case KeyCode.LeftShift: return Key.LeftShift;
case KeyCode.RightShift: return Key.RightShift;
case KeyCode.LeftAlt: return Key.LeftAlt;
case KeyCode.RightAlt: return Key.RightAlt;
case KeyCode.AltGr: return Key.AltGr;
case KeyCode.LeftControl: return Key.LeftCtrl;
case KeyCode.RightControl: return Key.RightCtrl;
case KeyCode.LeftWindows: return Key.LeftWindows;
case KeyCode.RightWindows: return Key.RightWindows;
case KeyCode.LeftCommand: return Key.LeftCommand;
case KeyCode.RightCommand: return Key.RightCommand;
case KeyCode.Escape: return Key.Escape;
case KeyCode.LeftArrow: return Key.LeftArrow;
case KeyCode.RightArrow: return Key.RightArrow;
case KeyCode.UpArrow: return Key.UpArrow;
case KeyCode.DownArrow: return Key.DownArrow;
case KeyCode.Backspace: return Key.Backspace;
case KeyCode.PageDown: return Key.PageDown;
case KeyCode.PageUp: return Key.PageUp;
case KeyCode.Home: return Key.Home;
case KeyCode.End: return Key.End;
case KeyCode.Insert: return Key.Insert;
case KeyCode.Delete: return Key.Delete;
case KeyCode.CapsLock: return Key.CapsLock;
case KeyCode.Numlock: return Key.NumLock;
case KeyCode.Print: return Key.PrintScreen;
case KeyCode.ScrollLock: return Key.ScrollLock;
case KeyCode.Pause: return Key.Pause;
case KeyCode.KeypadEnter: return Key.NumpadEnter;
case KeyCode.KeypadDivide: return Key.NumpadDivide;
case KeyCode.KeypadMultiply: return Key.NumpadMultiply;
case KeyCode.KeypadPlus: return Key.NumpadPlus;
case KeyCode.KeypadMinus: return Key.NumpadMinus;
case KeyCode.KeypadPeriod: return Key.NumpadPeriod;
case KeyCode.KeypadEquals: return Key.NumpadEquals;
case KeyCode.Keypad0: return Key.Numpad0;
case KeyCode.Keypad1: return Key.Numpad1;
case KeyCode.Keypad2: return Key.Numpad2;
case KeyCode.Keypad3: return Key.Numpad3;
case KeyCode.Keypad4: return Key.Numpad4;
case KeyCode.Keypad5: return Key.Numpad5;
case KeyCode.Keypad6: return Key.Numpad6;
case KeyCode.Keypad7: return Key.Numpad7;
case KeyCode.Keypad8: return Key.Numpad8;
case KeyCode.Keypad9: return Key.Numpad9;
case KeyCode.F1: return Key.F1;
case KeyCode.F2: return Key.F2;
case KeyCode.F3: return Key.F3;
case KeyCode.F4: return Key.F4;
case KeyCode.F5: return Key.F5;
case KeyCode.F6: return Key.F6;
case KeyCode.F7: return Key.F7;
case KeyCode.F8: return Key.F8;
case KeyCode.F9: return Key.F9;
case KeyCode.F10: return Key.F10;
case KeyCode.F11: return Key.F11;
case KeyCode.F12: return Key.F12;
default: return Key.None;
}
}
#endif
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 47e7833318a87461886e1eb355a9c7bb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace QFSW.QC.Internal
{
internal class CustomParameter : ParameterInfo
{
private readonly ParameterInfo _internalParameter;
private readonly Type _typeOverride;
private readonly string _nameOverride;
public CustomParameter(ParameterInfo internalParameter, Type typeOverride, string nameOverride)
{
_typeOverride = typeOverride;
_nameOverride = nameOverride;
_internalParameter = internalParameter;
}
public CustomParameter(ParameterInfo internalParameter, string nameOverride) : this(internalParameter, internalParameter.ParameterType, nameOverride) { }
public override Type ParameterType { get { return _typeOverride; } }
public override string Name { get { return _nameOverride; } }
public override ParameterAttributes Attributes { get { return _internalParameter.Attributes; } }
public override object DefaultValue { get { return _internalParameter.DefaultValue; } }
public override bool Equals(object obj) { return _internalParameter.Equals(obj); }
public override IEnumerable<CustomAttributeData> CustomAttributes { get { return _internalParameter.CustomAttributes; } }
public override object[] GetCustomAttributes(bool inherit) { return _internalParameter.GetCustomAttributes(inherit); }
public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _internalParameter.GetCustomAttributes(attributeType, inherit); }
public override IList<CustomAttributeData> GetCustomAttributesData() { return _internalParameter.GetCustomAttributesData(); }
public override int GetHashCode() { return _internalParameter.GetHashCode(); }
public override Type[] GetOptionalCustomModifiers() { return _internalParameter.GetOptionalCustomModifiers(); }
public override Type[] GetRequiredCustomModifiers() { return _internalParameter.GetRequiredCustomModifiers(); }
public override bool HasDefaultValue => _internalParameter.HasDefaultValue;
public override bool IsDefined(Type attributeType, bool inherit) { return _internalParameter.IsDefined(attributeType, inherit); }
public override MemberInfo Member { get { return _internalParameter.Member; } }
public override int MetadataToken { get { return _internalParameter.MetadataToken; } }
public override int Position { get { return _internalParameter.Position; } }
public override object RawDefaultValue { get { return _internalParameter.RawDefaultValue; } }
public override string ToString() { return _internalParameter.ToString(); }
}
}

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9e07451b78498b4408061ec6a2cc95dd
timeCreated: 1543091613
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,36 @@
using System;
using System.Reflection;
namespace QFSW.QC.Internal
{
internal class FieldAutoMethod : FieldMethod
{
public enum AccessType
{
Read = 0,
Write = 1
}
private readonly AccessType _accessType;
public FieldAutoMethod(FieldInfo fieldInfo, AccessType accessType) : base(fieldInfo)
{
_accessType = accessType;
if (_accessType == AccessType.Read)
{
if (_fieldInfo.IsStatic) { _internalDelegate = (Func<FieldInfo, object>)_StaticReader; }
else { _internalDelegate = (Func<object, object>)_fieldInfo.GetValue; }
_parameters = Array.Empty<ParameterInfo>();
}
else
{
if (_fieldInfo.IsStatic) { _internalDelegate = (Action<FieldInfo, object>)_StaticWriter; }
else { _internalDelegate = (Action<object, object>)_fieldInfo.SetValue; }
_parameters = new ParameterInfo[] { new CustomParameter(_internalDelegate.Method.GetParameters()[1], _fieldInfo.FieldType, "value") };
}
}
private static object _StaticReader(FieldInfo field) { return field.GetValue(null); }
private static void _StaticWriter(FieldInfo field, object value) { field.SetValue(null, value); }
}
}

View File

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

View File

@ -0,0 +1,57 @@
using QFSW.QC.Utilities;
using System;
using System.Globalization;
using System.Reflection;
namespace QFSW.QC.Internal
{
internal class FieldDelegateMethod : FieldMethod
{
public FieldDelegateMethod(FieldInfo fieldInfo) : base(fieldInfo)
{
if (!_fieldInfo.IsStrongDelegate())
{
throw new ArgumentException("Invalid delegate type.", nameof(fieldInfo));
}
if (_fieldInfo.IsStatic)
{
_internalDelegate = (Func<FieldInfo, object[], object>)StaticInvoker;
}
else
{
_internalDelegate = (Func<object, FieldInfo, object[], object>)NonStaticInvoker;
}
_parameters = _fieldInfo.FieldType.GetMethod("Invoke").GetParameters();
for (int i = 0; i < _parameters.Length; i++)
{
_parameters[i] = new CustomParameter(_parameters[i], $"arg{i}");
}
}
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
{
object[] realParameters = new object[_internalDelegate.Method.GetParameters().Length];
if (realParameters.Length < 2) { throw new Exception("FieldDelegateMethod's internal delegate must contain at least two paramaters."); }
if (!IsStatic) { realParameters[0] = obj; }
realParameters[realParameters.Length - 2] = _fieldInfo;
realParameters[realParameters.Length - 1] = parameters;
return _internalDelegate.DynamicInvoke(realParameters);
}
private static object StaticInvoker(FieldInfo field, params object[] args)
{
Delegate del = (Delegate)field.GetValue(null);
if (del != null) { return del.DynamicInvoke(args); }
else { throw new Exception("Delegate was invalid and could not be invoked."); }
}
private object NonStaticInvoker(object obj, FieldInfo field, params object[] args)
{
Delegate del = (Delegate)field.GetValue(obj);
if (del != null) { return del.DynamicInvoke(args); }
else { throw new Exception("Delegate was invalid and could not be invoked."); }
}
}
}

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b9425c6d4746d884f9a82b6a9ba522f7
timeCreated: 1543091933
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,42 @@
using System;
using System.Globalization;
using System.Reflection;
namespace QFSW.QC.Internal
{
internal abstract class FieldMethod : MethodInfo
{
protected readonly FieldInfo _fieldInfo;
protected Delegate _internalDelegate;
protected ParameterInfo[] _parameters;
public FieldMethod(FieldInfo fieldInfo) { _fieldInfo = fieldInfo; }
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
{
object[] realParameters = new object[parameters.Length + 1];
if (IsStatic) { realParameters[0] = _fieldInfo; }
else { realParameters[0] = obj; }
Array.Copy(parameters, 0, realParameters, 1, parameters.Length);
return _internalDelegate.DynamicInvoke(realParameters);
}
public override ParameterInfo[] GetParameters()
{
return _parameters;
}
public override string Name { get { return _fieldInfo.Name; } }
public override Type DeclaringType { get { return _fieldInfo.DeclaringType; } }
public override Type ReflectedType { get { { return _fieldInfo.ReflectedType; } } }
public override object[] GetCustomAttributes(bool inherit) { return _fieldInfo.GetCustomAttributes(inherit); }
public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _fieldInfo.GetCustomAttributes(attributeType, inherit); }
public override MethodAttributes Attributes { get { return _internalDelegate.Method.Attributes; } }
public override RuntimeMethodHandle MethodHandle { get { return _internalDelegate.Method.MethodHandle; } }
public override ICustomAttributeProvider ReturnTypeCustomAttributes { get { return _internalDelegate.Method.ReturnTypeCustomAttributes; } }
public override MethodInfo GetBaseDefinition() { return _internalDelegate.Method.GetBaseDefinition(); }
public override MethodImplAttributes GetMethodImplementationFlags() { return _internalDelegate.Method.GetMethodImplementationFlags(); }
public override bool IsDefined(Type attributeType, bool inherit) { return _internalDelegate.Method.IsDefined(attributeType, inherit); }
}
}

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: bc3a8d5d7bf0b284fb3e38019fb1c469
timeCreated: 1543091424
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,160 @@
using QFSW.QC.Comparators;
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;
namespace QFSW.QC
{
public static class InvocationTargetFactory
{
private static readonly Dictionary<(MonoTargetType, Type), object> TargetCache = new Dictionary<(MonoTargetType, Type), object>();
public static IEnumerable<T> FindTargets<T>(MonoTargetType method) where T : MonoBehaviour
{
foreach (object target in FindTargets(typeof(T), method))
{
yield return target as T;
}
}
public static IEnumerable<object> FindTargets(Type classType, MonoTargetType method)
{
switch (method)
{
case MonoTargetType.Single:
{
Object target = Object.FindObjectOfType(classType);
return target == null ? Enumerable.Empty<object>() : target.Yield();
}
case MonoTargetType.SingleInactive:
{
return WrapSingleCached(classType, method, type =>
{
return Resources.FindObjectsOfTypeAll(type)
.FirstOrDefault(x => !x.hideFlags.HasFlag(HideFlags.HideInHierarchy));
});
}
case MonoTargetType.All:
{
return Object.FindObjectsOfType(classType)
.OrderBy(x => x.name, new AlphanumComparator());
}
case MonoTargetType.AllInactive:
{
return Resources.FindObjectsOfTypeAll(classType)
.Where(x => !x.hideFlags.HasFlag(HideFlags.HideInHierarchy))
.OrderBy(x => x.name, new AlphanumComparator());
}
case MonoTargetType.Registry:
{
return QuantumRegistry.GetRegistryContents(classType);
}
case MonoTargetType.Singleton:
{
return GetSingletonInstance(classType).Yield();
}
default:
{
throw new ArgumentException($"Unsupported MonoTargetType {method}");
}
}
}
private static IEnumerable<object> WrapSingleCached(Type classType, MonoTargetType method, Func<Type, object> targetFinder)
{
if (!TargetCache.TryGetValue((method, classType), out object target) || target as Object == null)
{
target = targetFinder(classType);
TargetCache[(method, classType)] = target;
}
return target == null ? Enumerable.Empty<object>() : target.Yield();
}
public static object InvokeOnTargets(MethodInfo invokingMethod, IEnumerable<object> targets, object[] data)
{
int returnCount = 0;
int invokeCount = 0;
Dictionary<object, object> resultsParts = new Dictionary<object, object>();
foreach (object target in targets)
{
invokeCount++;
object result = invokingMethod.Invoke(target, data);
if (result != null)
{
resultsParts.Add(target, result);
returnCount++;
}
}
if (returnCount > 1)
{
return resultsParts;
}
if (returnCount == 1)
{
return resultsParts.Values.First();
}
if (invokeCount == 0)
{
string typeName = invokingMethod.DeclaringType.GetDisplayName();
throw new Exception($"Could not invoke the command because no objects of type {typeName} could be found.");
}
return null;
}
private static string FormatInvocationMessage(int invocationCount, object lastTarget = null)
{
switch (invocationCount)
{
case 0:
throw new Exception("No targets could be found");
case 1:
{
string name;
if (lastTarget is Object obj)
{
name = obj.name;
}
else
{
name = lastTarget?.ToString();
}
return $"> Invoked on {name}";
}
default:
return $"> Invoked on {invocationCount} targets";
}
}
private static object GetSingletonInstance(Type classType)
{
if (QuantumRegistry.GetRegistrySize(classType) > 0)
{
return QuantumRegistry.GetRegistryContents(classType).First();
}
object target = CreateCommandSingletonInstance(classType);
QuantumRegistry.RegisterObject(classType, target);
return target;
}
private static Component CreateCommandSingletonInstance(Type classType)
{
GameObject obj = new GameObject($"{classType}Singleton");
Object.DontDestroyOnLoad(obj);
return obj.AddComponent(classType);
}
}
}

View File

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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 048bc3796092478d8319d7d1054a547d
timeCreated: 1615081377

View File

@ -0,0 +1,11 @@
using UnityEngine;
namespace QFSW.QC
{
public interface ILog
{
string Text { get; }
LogType Type { get; }
bool NewLine { get; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e5def4ecf09b4133b054e98f9afcc5c8
timeCreated: 1615116599

View File

@ -0,0 +1,12 @@
namespace QFSW.QC
{
public interface ILogQueue
{
int MaxStoredLogs { get; set; }
bool IsEmpty { get; }
void QueueLog(ILog log);
bool TryDequeue(out ILog log);
void Clear();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b76bcf3d7eaa412cb2428e464882ed89
timeCreated: 1615123713

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace QFSW.QC
{
public interface ILogStorage
{
int MaxStoredLogs { get; set; }
IReadOnlyList<ILog> Logs { get; }
void AddLog(ILog log);
void RemoveLog();
void Clear();
string GetLogString();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 859434497f964d328b18530b1230d97f
timeCreated: 1615116625

View File

@ -0,0 +1,18 @@
using UnityEngine;
namespace QFSW.QC
{
public readonly struct Log : ILog
{
public string Text { get; }
public LogType Type { get; }
public bool NewLine { get; }
public Log(string text, LogType type = LogType.Log, bool newLine = true)
{
Text = text;
Type = type;
NewLine = newLine;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f183a6a7c8672b9448d3c1023b68df30
timeCreated: 1554340584
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,36 @@
using System.Collections.Concurrent;
namespace QFSW.QC
{
public class LogQueue : ILogQueue
{
private readonly ConcurrentQueue<ILog> _queuedLogs = new ConcurrentQueue<ILog>();
public int MaxStoredLogs { get; set; }
public bool IsEmpty => _queuedLogs.IsEmpty;
public LogQueue(int maxStoredLogs = -1)
{
MaxStoredLogs = maxStoredLogs;
}
public void QueueLog(ILog log)
{
_queuedLogs.Enqueue(log);
if (MaxStoredLogs > 0 && _queuedLogs.Count > MaxStoredLogs)
{
_queuedLogs.TryDequeue(out _);
}
}
public bool TryDequeue(out ILog log)
{
return _queuedLogs.TryDequeue(out log);
}
public void Clear()
{
while (TryDequeue(out ILog _)) { }
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 20c64958e7fb4ef6a8089b2cdb9e651a
timeCreated: 1615123680

View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace QFSW.QC
{
public class LogStorage : ILogStorage
{
private readonly List<ILog> _consoleLogs = new List<ILog>(10);
private readonly StringBuilder _logTraceBuilder = new StringBuilder(2048);
public int MaxStoredLogs { get; set; }
public IReadOnlyList<ILog> Logs => _consoleLogs;
public LogStorage(int maxStoredLogs = -1)
{
MaxStoredLogs = maxStoredLogs;
}
public void AddLog(ILog log)
{
_consoleLogs.Add(log);
int logLength = _logTraceBuilder.Length + log.Text.Length;
if (log.NewLine && _logTraceBuilder.Length > 0)
{
logLength += Environment.NewLine.Length;
}
if (MaxStoredLogs > 0)
{
while (_consoleLogs.Count > MaxStoredLogs)
{
int junkLength = _consoleLogs[0].Text.Length;
if (_consoleLogs.Count > 1 &&_consoleLogs[1].NewLine)
{
junkLength += Environment.NewLine.Length;
}
junkLength = Mathf.Min(junkLength, _logTraceBuilder.Length);
logLength -= junkLength;
_logTraceBuilder.Remove(0, junkLength);
_consoleLogs.RemoveAt(0);
}
}
int capacity = _logTraceBuilder.Capacity;
while (capacity < logLength)
{
capacity *= 2;
}
_logTraceBuilder.EnsureCapacity(capacity);
if (log.NewLine && _logTraceBuilder.Length > 0)
{
_logTraceBuilder.Append(Environment.NewLine);
}
_logTraceBuilder.Append(log.Text);
}
public void RemoveLog()
{
if (_consoleLogs.Count > 0)
{
ILog log = _consoleLogs[_consoleLogs.Count - 1];
_consoleLogs.RemoveAt(_consoleLogs.Count - 1);
int removeLength = log.Text.Length;
if (log.NewLine && _consoleLogs.Count > 0)
{
removeLength += Environment.NewLine.Length;
}
_logTraceBuilder.Remove(_logTraceBuilder.Length - removeLength, removeLength);
}
}
public void Clear()
{
_consoleLogs.Clear();
_logTraceBuilder.Length = 0;
}
public string GetLogString()
{
return _logTraceBuilder.ToString();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d0b5e8fa829c491eb694d1dfc7a1842a
timeCreated: 1615081378

View File

@ -0,0 +1,14 @@
namespace QFSW.QC
{
/// <summary>
/// Thresholds for log severities.
/// </summary>
public enum LoggingThreshold
{
Never = 0,
Exception = 1,
Error = 2,
Warning = 3,
Always = 4
}
}

View File

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

View File

@ -0,0 +1,51 @@
using UnityEngine;
using UnityEngine.Serialization;
namespace QFSW.QC
{
[System.Serializable]
public struct ModifierKeyCombo
{
[FormerlySerializedAs("key")]
public KeyCode Key;
[FormerlySerializedAs("ctrl")]
public bool Ctrl;
[FormerlySerializedAs("alt")]
public bool Alt;
[FormerlySerializedAs("shift")]
public bool Shift;
public bool ModifiersActive
{
get
{
bool ctrlDown = !Ctrl ^
(InputHelper.GetKey(KeyCode.LeftControl) ||
InputHelper.GetKey(KeyCode.RightControl) ||
InputHelper.GetKey(KeyCode.LeftCommand) ||
InputHelper.GetKey(KeyCode.RightCommand));
bool altDown = !Alt ^ (InputHelper.GetKey(KeyCode.LeftAlt) || InputHelper.GetKey(KeyCode.RightAlt));
bool shiftDown =
!Shift ^ (InputHelper.GetKey(KeyCode.LeftShift) || InputHelper.GetKey(KeyCode.RightShift));
return ctrlDown && altDown && shiftDown;
}
}
public bool IsHeld()
{
return ModifiersActive && InputHelper.GetKey(Key);
}
public bool IsPressed()
{
return ModifiersActive && InputHelper.GetKeyDown(Key);
}
public static implicit operator ModifierKeyCombo(KeyCode key)
{
return new ModifierKeyCombo { Key = key };
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 60f8d052d71b77a47b602bb7b96e02d5
timeCreated: 1541125662
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,39 @@
namespace QFSW.QC
{
/// <summary>
/// Determines the target type for non static MonoBehaviour commands.
/// </summary>
public enum MonoTargetType
{
/// <summary>
/// Targets the first instance found of the MonoBehaviour.
/// </summary>
Single = 0,
/// <summary>
/// Targets all instances found of the MonoBehaviour.
/// </summary>
All = 1,
/// <summary>
/// Targets all instances registered in the QuantumConsoleProcessor registry. Instances can be added using <c>QFSW.QC.QuantumConsoleProcessor.Register</c>.
/// The only supported target type for non MonoBehaviour commands
/// </summary>
Registry = 2,
/// <summary>
/// Automatically creates an instance if it does not yet exist and adds it to the registry, where it will be used for all future function calls.
/// </summary>
Singleton = 3,
/// <summary>
/// Targets the first instance found of the MonoBehaviour. Includes inactive objects in its search
/// </summary>
SingleInactive = 4,
/// <summary>
/// Targets all instances found of the MonoBehaviour. Includes inactive objects in its search
/// </summary>
AllInactive = 5
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 39128e97dd5df334f930d2ffa6544602
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC
{
/// <summary>
/// Parser for a single type.
/// Caches results and reuses them if the incoming string has already been parsed.
/// </summary>
/// <typeparam name="T">The type to parse.</typeparam>
public abstract class BasicCachedQcParser<T> : BasicQcParser<T>
{
private readonly Dictionary<string, T> _cacheLookup = new Dictionary<string, T>();
public override object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
if (_cacheLookup.ContainsKey(value))
{
return _cacheLookup[value];
}
T result = (T)base.Parse(value, type, recursiveParser);
_cacheLookup[value] = result;
return result;
}
}
}

View File

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

View File

@ -0,0 +1,38 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Parser for a single type.
/// </summary>
/// <typeparam name="T">The type to parse.</typeparam>
public abstract class BasicQcParser<T> : IQcParser
{
private Func<string, Type, object> _recursiveParser;
public virtual int Priority => 0;
public bool CanParse(Type type)
{
return type == typeof(T);
}
public virtual object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
_recursiveParser = recursiveParser;
return Parse(value);
}
protected object ParseRecursive(string value, Type type)
{
return _recursiveParser(value, type);
}
protected TElement ParseRecursive<TElement>(string value)
{
return (TElement)_recursiveParser(value, typeof(TElement));
}
public abstract T Parse(string value);
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 223d79a496072b94bb244a4a1f7fc489
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Exception to be thrown by an IQcParser.
/// </summary>
public class ParserException : Exception
{
public ParserException(string message) : base(message) { }
public ParserException(string message, Exception innerException) : base(message, innerException) { }
}
}

View File

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

View File

@ -0,0 +1,13 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Exception to be thrown by an IQcParser to indicate the input was invalid.
/// </summary>
public class ParserInputException : ParserException
{
public ParserInputException(string message) : base(message) { }
public ParserInputException(string message, Exception innerException) : base(message, innerException) { }
}
}

View File

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

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC
{
/// <summary>
/// Parser for all types that are generic constructions of a single type.
/// Caches results and reuses them if the incoming string has already been parsed.
/// </summary>
public abstract class GenericCachedQcParser : GenericQcParser
{
private readonly Dictionary<(string, Type), object> _cacheLookup = new Dictionary<(string, Type), object>();
public override object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
(string value, Type type) key = (value, type);
if (_cacheLookup.ContainsKey(key))
{
return _cacheLookup[key];
}
object result = base.Parse(value, type, recursiveParser);
_cacheLookup[key] = result;
return result;
}
}
}

View File

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

View File

@ -0,0 +1,56 @@
using QFSW.QC.Utilities;
using System;
namespace QFSW.QC
{
/// <summary>
/// Parser for all types that are generic constructions of a single type.
/// </summary>
public abstract class GenericQcParser : IQcParser
{
/// <summary>
/// The incomplete generic type of this parser.
/// </summary>
protected abstract Type GenericType { get; }
private Func<string, Type, object> _recursiveParser;
protected GenericQcParser()
{
if (!GenericType.IsGenericType)
{
throw new ArgumentException($"Generic Parsers must use a generic type as their base");
}
if (GenericType.IsConstructedGenericType)
{
throw new ArgumentException($"Generic Parsers must use an incomplete generic type as their base");
}
}
public virtual int Priority => -500;
public bool CanParse(Type type)
{
return type.IsGenericTypeOf(GenericType);
}
public virtual object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
_recursiveParser = recursiveParser;
return Parse(value, type);
}
protected object ParseRecursive(string value, Type type)
{
return _recursiveParser(value, type);
}
protected TElement ParseRecursive<TElement>(string value)
{
return (TElement)_recursiveParser(value, typeof(TElement));
}
public abstract object Parse(string value, Type type);
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 14f1f27cf493be645ba8db007b704475
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f7627ba6a0fc6d34182bb1aa178b4be5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class AdditionOperatorGrammar : BinaryAndUnaryOperatorGrammar
{
public override int Precedence => 0;
protected override char OperatorToken => '+';
protected override string OperatorMethodName => "op_Addition";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Add;
}
}

View File

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

View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC.Grammar
{
public abstract class BinaryAndUnaryOperatorGrammar : BinaryOperatorGrammar
{
private readonly HashSet<char> _operatorChars = new HashSet<char>()
{
'+',
'-',
'*',
'/',
'&',
'|',
'^',
'=',
'!',
','
};
private readonly HashSet<char> _ignoreChars = new HashSet<char>()
{
' ',
'\0'
};
protected override int GetOperatorPosition(string value)
{
IEnumerable<int> splitPoints = TextProcessing.GetScopedSplitPoints(value, OperatorToken, TextProcessing.DefaultLeftScopers, TextProcessing.DefaultRightScopers);
foreach (int index in splitPoints.Reverse())
{
if (IsValidBinaryOperator(value, index))
{
return index;
}
}
return -1;
}
private bool IsValidBinaryOperator(string value, int position)
{
while (position > 0)
{
char ch = value[--position];
if (_operatorChars.Contains(ch)) { return false; }
if (!_ignoreChars.Contains(ch)) { return true; }
}
return false;
}
}
}

View File

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

View File

@ -0,0 +1,34 @@
using System;
using System.Reflection;
namespace QFSW.QC.Grammar
{
internal class BinaryOperatorData : IBinaryOperator
{
public Type LArg { get; }
public Type RArg { get; }
public Type Ret { get; }
private readonly MethodInfo _method;
public BinaryOperatorData(MethodInfo OperatorMethod)
{
_method = OperatorMethod;
Ret = OperatorMethod.ReturnType;
ParameterInfo[] paramData = _method.GetParameters();
if (paramData.Length != 2)
{
throw new ArgumentException($"Cannot create a binary operator from a method with {paramData.Length} parameters");
}
LArg = paramData[0].ParameterType;
RArg = paramData[1].ParameterType;
}
public object Invoke(object left, object right)
{
return _method.Invoke(null, new[] { left, right });
}
}
}

View File

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

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using QFSW.QC.Utilities;
namespace QFSW.QC.Grammar
{
public abstract class BinaryOperatorGrammar : IQcGrammarConstruct
{
public abstract int Precedence { get; }
protected abstract char OperatorToken { get; }
protected abstract string OperatorMethodName { get; }
protected abstract Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator { get; }
private Regex _operatorRegex;
private readonly HashSet<Type> _missingOperatorTable = new HashSet<Type>();
private readonly Dictionary<Type, IBinaryOperator> _foundOperatorTable = new Dictionary<Type, IBinaryOperator>();
public bool Match(string value, Type type)
{
if (_missingOperatorTable.Contains(type))
{
return false;
}
if (!IsSyntaxMatch(value))
{
return false;
}
if (_foundOperatorTable.ContainsKey(type))
{
return true;
}
IBinaryOperator operatorData = GetOperatorData(type);
if (operatorData != null)
{
_foundOperatorTable.Add(type, operatorData);
return true;
}
_missingOperatorTable.Add(type);
return false;
}
private bool IsSyntaxMatch(string value)
{
if (_operatorRegex == null)
{
_operatorRegex = new Regex($@"^.+\{OperatorToken}.+$");
}
if (!_operatorRegex.IsMatch(value))
{
return false;
}
int operatorPos = GetOperatorPosition(value);
return operatorPos > 0 && operatorPos < value.Length;
}
private IBinaryOperator GetOperatorData(Type type)
{
if (type.IsPrimitive)
{
#if !ENABLE_IL2CPP
return GeneratePrimitiveOperator(type);
#else
string typeName = QFSW.QC.Utilities.ReflectionExtensions.GetDisplayName(type);
UnityEngine.Debug.LogWarning($"{typeName} {OperatorToken} {typeName} is not supported as IL2CPP does not support dynamic value typed generics.");
#endif
}
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
BinaryOperatorData[] candidates = methods.Where(x => x.Name == OperatorMethodName)
.Where(x => x.ReturnType == type)
.Where(x => x.GetParameters().Length == 2)
.Select(x => new BinaryOperatorData(x))
.ToArray();
BinaryOperatorData idealCandidate = candidates.FirstOrDefault(x => x.LArg == type && x.RArg == type)
?? candidates.FirstOrDefault(x => x.LArg == type)
?? candidates.FirstOrDefault(x => x.RArg == type)
?? candidates.FirstOrDefault();
return idealCandidate;
}
private IBinaryOperator GeneratePrimitiveOperator(Type type)
{
ParameterExpression leftParam = Expression.Parameter(type, "left");
ParameterExpression rightParam = Expression.Parameter(type, "right");
BinaryExpression body;
try
{
body = PrimitiveExpressionGenerator(leftParam, rightParam);
}
catch (InvalidOperationException)
{
return null;
}
Delegate expr = Expression.Lambda(body, true, leftParam, rightParam).Compile();
return new DynamicBinaryOperator(expr, type, type, type);
}
/// <summary>
/// Get the position of the right-most valid operator token.
/// </summary>
/// <param name="value">The string to find the operator in.</param>
/// <returns>The position of the operator. -1 if none can be found</returns>
protected virtual int GetOperatorPosition(string value)
{
return TextProcessing.GetScopedSplitPoints(value, OperatorToken, TextProcessing.DefaultLeftScopers, TextProcessing.DefaultRightScopers).LastOr(-1);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
IBinaryOperator operatorData = _foundOperatorTable[type];
int splitIndex = GetOperatorPosition(value);
string left = value.Substring(0, splitIndex);
string right = value.Substring(splitIndex + 1);
object leftVal = recursiveParser(left, operatorData.LArg);
object rightVal = recursiveParser(right, operatorData.RArg);
try
{
return operatorData.Invoke(leftVal, rightVal);
}
catch (TargetInvocationException e)
{
throw e.InnerException ?? e;
}
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class BitwiseAndOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 6;
protected override char OperatorToken => '&';
protected override string OperatorMethodName => "op_bitwiseAnd";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.And;
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class BitwiseOrOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 5;
protected override char OperatorToken => '|';
protected override string OperatorMethodName => "op_bitwiseOr";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Or;
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class DivisionOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 3;
protected override char OperatorToken => '/';
protected override string OperatorMethodName => "op_Division";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Divide;
}
}

View File

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

View File

@ -0,0 +1,26 @@
using System;
namespace QFSW.QC.Grammar
{
internal class DynamicBinaryOperator : IBinaryOperator
{
public Type LArg { get; }
public Type RArg { get; }
public Type Ret { get; }
private readonly Delegate _del;
public DynamicBinaryOperator(Delegate del, Type lArg, Type rArg, Type ret)
{
_del = del;
LArg = lArg;
RArg = rArg;
Ret = ret;
}
public object Invoke(object left, object right)
{
return _del.DynamicInvoke(left, right);
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class ExclusiveOrOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 7;
protected override char OperatorToken => '^';
protected override string OperatorMethodName => "op_ExclusiveOr";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.ExclusiveOr;
}
}

View File

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

View File

@ -0,0 +1,13 @@
using System;
namespace QFSW.QC.Grammar
{
public interface IBinaryOperator
{
Type LArg { get; }
Type RArg { get; }
Type Ret { get; }
object Invoke(object left, object right);
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class ModulusOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 4;
protected override char OperatorToken => '%';
protected override string OperatorMethodName => "op_Modulus";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Modulo;
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class MultiplyOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 2;
protected override char OperatorToken => '*';
protected override string OperatorMethodName => "op_Multiply";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Multiply;
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class SubtractionOperatorGrammar : BinaryAndUnaryOperatorGrammar
{
public override int Precedence => 1;
protected override char OperatorToken => '-';
protected override string OperatorMethodName => "op_Subtraction";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Subtract;
}
}

View File

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

View File

@ -0,0 +1,23 @@
using System;
using System.Text.RegularExpressions;
namespace QFSW.QC.Grammar
{
public class BooleanNegationGrammar : IQcGrammarConstruct
{
private readonly Regex _negationRegex = new Regex(@"^!\S+$");
public int Precedence => 0;
public bool Match(string value, Type type)
{
return type == typeof(bool) && _negationRegex.IsMatch(value);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
value = value.Substring(1);
return !(bool)recursiveParser(value, type);
}
}
}

View File

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

View File

@ -0,0 +1,59 @@
using QFSW.QC.Utilities;
using System;
using System.Text.RegularExpressions;
namespace QFSW.QC.Grammar
{
public class ExpressionBodyGrammar : IQcGrammarConstruct
{
private readonly Regex _expressionBodyRegex = new Regex(@"^{.+}\??$");
public int Precedence => 0;
public bool Match(string value, Type type)
{
return _expressionBodyRegex.IsMatch(value);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
bool nullable = false;
if (value.EndsWith("?"))
{
nullable = true;
value = value.Substring(0, value.Length - 1);
}
value = value.ReduceScope('{', '}');
object result = QuantumConsoleProcessor.InvokeCommand(value);
if (result is null)
{
if (nullable)
{
if (type.IsClass)
{
return result;
}
else
{
throw new ParserInputException($"Expression body {{{value}}} evaluated to null which is incompatible with the expected type '{type.GetDisplayName()}'.");
}
}
else
{
throw new ParserInputException($"Expression body {{{value}}} evaluated to null. If this is intended, please use nullable expression bodies, {{expr}}?");
}
}
else if (result.GetType().IsCastableTo(type, true))
{
return type.Cast(result);
}
else
{
throw new ParserInputException($"Expression body {{{value}}} evaluated to an object of type '{result.GetType().GetDisplayName()}', " +
$"which is incompatible with the expected type '{type.GetDisplayName()}'.");
}
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
{
"name": "QFSW.QC.Grammar",
"references": [
"QFSW.QC"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ad10a660d2aec9d449de236f5524cb5c
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Creates a Parser for a custom grammar construct that is loaded and used by the QuantumParser.
/// Grammar constructs are tested and used before resorting to IQcParsers for object value parsing.
/// </summary>
public interface IQcGrammarConstruct
{
/// <summary>
/// The precedence of this grammar construct.
/// </summary>
int Precedence { get; }
/// <summary>
/// If the incoming data matches this grammar construct.
/// </summary>
/// <param name="value">The incoming string data.</param>
/// <param name="type">The type to test.</param>
/// <returns>If it matches the grammar defined by this construct.</returns>
bool Match(string value, Type type);
/// <summary>
/// Parses the incoming string to the specified type.
/// </summary>
/// <param name="value">The incoming string data.</param>
/// <param name="type">The type to parse the incoming string to.</param>
/// <param name="recursiveParser">Delegate back to the main parser to allow for recursive parsing of sub elements.</param>
/// <returns>The parsed object.</returns>
object Parse(string value, Type type, Func<string, Type, object> recursiveParser);
}
}

View File

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

View File

@ -0,0 +1,31 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Creates a Parser that is loaded and used by the QuantumParser.
/// </summary>
public interface IQcParser
{
/// <summary>
/// The priority of this parser to resolve multiple parsers covering the same type.
/// </summary>
int Priority { get; }
/// <summary>
/// If this parser can parse to the incoming type.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>If it can be parsed.</returns>
bool CanParse(Type type);
/// <summary>
/// Parses the incoming string to the specified type.
/// </summary>
/// <param name="value">The incoming string data.</param>
/// <param name="type">The type to parse the incoming string to.</param>
/// <param name="recursiveParser">Delegate back to the main parser to allow for recursive parsing of sub elements.</param>
/// <returns>The parsed object.</returns>
object Parse(string value, Type type, Func<string, Type, object> recursiveParser);
}
}

View File

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

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC
{
/// <summary>
/// Parser for all types that are generic constructions of a several types.
/// </summary>
public abstract class MassGenericQcParser : IQcParser
{
/// <summary>
/// The incomplete generic types of this parser.
/// </summary>
protected abstract HashSet<Type> GenericTypes { get; }
private Func<string, Type, object> _recursiveParser;
protected MassGenericQcParser()
{
foreach (Type type in GenericTypes)
{
if (!type.IsGenericType)
{
throw new ArgumentException($"Generic Parsers must use a generic type as their base");
}
if (type.IsConstructedGenericType)
{
throw new ArgumentException($"Generic Parsers must use an incomplete generic type as their base");
}
}
}
public virtual int Priority => -2000;
public bool CanParse(Type type)
{
if (type.IsGenericType)
{
return GenericTypes.Contains(type.GetGenericTypeDefinition());
}
return false;
}
public virtual object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
_recursiveParser = recursiveParser;
return Parse(value, type);
}
protected object ParseRecursive(string value, Type type)
{
return _recursiveParser(value, type);
}
protected TElement ParseRecursive<TElement>(string value)
{
return (TElement)_recursiveParser(value, typeof(TElement));
}
public abstract object Parse(string value, Type type);
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 819146b9096942b48914d95b8268664a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
using System;
using System.Collections;
namespace QFSW.QC.Parsers
{
public class ArrayParser : IQcParser
{
public int Priority => -100;
public bool CanParse(Type type)
{
return type.IsArray;
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
Type elementType = type.GetElementType();
string[] valueParts = value.ReduceScope('[', ']').SplitScoped(',');
IList dataArray = Array.CreateInstance(elementType, valueParts.Length);
for (int i = 0; i < valueParts.Length; i++)
{
dataArray[i] = recursiveParser(valueParts[i], elementType);
}
return dataArray;
}
}
}

View File

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

View File

@ -0,0 +1,22 @@
namespace QFSW.QC.Parsers
{
public class BoolParser : BasicCachedQcParser<bool>
{
public override bool Parse(string value)
{
value = value.ToLower().Trim();
switch (value)
{
case "true": return true;
case "on": return true;
case "1": return true;
case "yes": return true;
case "false": return false;
case "off": return false;
case "0": return false;
case "no": return false;
default: throw new ParserInputException($"Cannot parse '{value}' to a bool.");
}
}
}
}

View File

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

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace QFSW.QC.Parsers
{
public class CollectionParser : MassGenericQcParser
{
protected override HashSet<Type> GenericTypes { get; } = new HashSet<Type>
{
typeof(List<>),
typeof(Stack<>),
typeof(Queue<>),
typeof(HashSet<>),
typeof(LinkedList<>),
typeof(ConcurrentStack<>),
typeof(ConcurrentQueue<>),
typeof(ConcurrentBag<>)
};
public override object Parse(string value, Type type)
{
Type arrayType = type.GetGenericArguments()[0].MakeArrayType();
object array = ParseRecursive(value, arrayType);
return Activator.CreateInstance(type, array);
}
}
}

View File

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

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class ColorParser : BasicCachedQcParser<Color>
{
private readonly Dictionary<string, Color> _colorLookup;
public ColorParser()
{
_colorLookup = new Dictionary<string, Color>();
PropertyInfo[] colorProperties = typeof(Color).GetProperties(BindingFlags.Static | BindingFlags.Public);
foreach (PropertyInfo prop in colorProperties)
{
if (prop.CanRead && !prop.CanWrite)
{
MethodInfo propReader = prop.GetMethod;
if (propReader.ReturnType == typeof(Color))
{
_colorLookup.Add(prop.Name, (Color)propReader.Invoke(null, Array.Empty<object>()));
}
}
}
}
public override Color Parse(string value)
{
if (_colorLookup.ContainsKey(value.ToLower()))
{
return _colorLookup[value.ToLower()];
}
try
{
if (value.StartsWith("0x"))
{
return ParseHexColor(value);
}
else
{
return ParseRGBAColor(value);
}
}
catch (FormatException e)
{
throw new ParserInputException($"{e.Message}\nThe format must be either of:" +
$"\n - R,G,B" +
$"\n - R,G,B,A" +
$"\n - 0xRRGGBB" +
$"\n - 0xRRGGBBAA" +
$"\n - A preset color such as 'red'", e);
}
}
private Color ParseRGBAColor(string value)
{
string[] colorParts = value.Split(',');
Color parsedColor = Color.white;
int i = 0;
if (colorParts.Length < 3 || colorParts.Length > 4) { throw new FormatException($"Cannot parse '{value}' as a Color."); }
float ParsePart(string part)
{
float val = float.Parse(part);
if (val < 0 || val > 1) { throw new FormatException($"{val} falls outside of the valid [0,1] range for a component of a Color."); }
return val;
}
try
{
for (; i < colorParts.Length; i++)
{
parsedColor[i] = ParsePart(colorParts[i]);
}
return parsedColor;
}
catch (FormatException)
{
throw new FormatException($"Cannot parse '{colorParts[i]}' as part of a Color, it must be numerical and in the valid range [0,1].");
}
}
private Color ParseHexColor(string value)
{
int digitCount = value.Length - 2;
if (digitCount != 6 && digitCount != 8)
{
throw new FormatException("Hex colors must contain either 6 or 8 hex digits.");
}
Color parsedColor = Color.white;
int byteCount = digitCount / 2;
int i = 0;
try
{
for (; i < byteCount; i++)
{
parsedColor[i] = int.Parse(value.Substring(2 * (1 + i), 2), System.Globalization.NumberStyles.HexNumber) / 255f;
}
return parsedColor;
}
catch (FormatException)
{
throw new FormatException($"Cannot parse '{value.Substring(2 * (1 + i), 2)}' as part of a Color as it was invalid hex.");
}
}
}
}

View File

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

View File

@ -0,0 +1,22 @@
using QFSW.QC.Utilities;
using System;
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class ComponentParser : PolymorphicQcParser<Component>
{
public override Component Parse(string value, Type type)
{
GameObject obj = ParseRecursive<GameObject>(value);
Component objComponent = obj.GetComponent(type);
if (!objComponent)
{
throw new ParserInputException($"No component on the object '{value}' of type {type.GetDisplayName()} existed.");
}
return objComponent;
}
}
}

View File

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

View File

@ -0,0 +1,20 @@
using QFSW.QC.Utilities;
using System;
namespace QFSW.QC.Parsers
{
public class EnumParser : PolymorphicCachedQcParser<Enum>
{
public override Enum Parse(string value, Type type)
{
try
{
return (Enum)Enum.Parse(type, value);
}
catch (Exception e)
{
throw new ParserInputException($"Cannot parse '{value}' to the type '{type.GetDisplayName()}'. To see the supported values, use the command `enum-info {type}`", e);
}
}
}
}

View File

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

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC.Parsers
{
public class EnumerableParser : MassGenericQcParser
{
protected override HashSet<Type> GenericTypes { get; } = new HashSet<Type>()
{
typeof(IEnumerable<>),
typeof(ICollection<>),
typeof(IReadOnlyCollection<>),
typeof(IList<>),
typeof(IReadOnlyList<>)
};
public override object Parse(string value, Type type)
{
Type arrayType = type.GetGenericArguments()[0].MakeArrayType();
return ParseRecursive(value, arrayType);
}
}
}

View File

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

View File

@ -0,0 +1,21 @@
using QFSW.QC.Utilities;
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class GameObjectParser : BasicQcParser<GameObject>
{
public override GameObject Parse(string value)
{
string name = ParseRecursive<string>(value);
GameObject obj = GameObjectExtensions.Find(name, true);
if (!obj)
{
throw new ParserInputException($"Could not find GameObject of name {value}.");
}
return obj;
}
}
}

View File

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

View File

@ -0,0 +1,46 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace QFSW.QC.Parsers
{
public class PrimitiveParser : IQcParser
{
private readonly HashSet<Type> _primitiveTypes = new HashSet<Type>
{
typeof(int),
typeof(float),
typeof(decimal),
typeof(double),
typeof(bool),
typeof(byte),
typeof(sbyte),
typeof(uint),
typeof(short),
typeof(ushort),
typeof(long),
typeof(ulong),
typeof(char)
};
public int Priority => -1000;
public bool CanParse(Type type)
{
return _primitiveTypes.Contains(type);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
try
{
return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
}
catch (FormatException e)
{
throw new ParserInputException($"Cannot parse '{value}' to the type '{type.GetDisplayName()}'.", e);
}
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
{
"name": "QFSW.QC.Parsers",
"references": [
"QFSW.QC"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a5d04fa5e431fa844be99e9199658b16
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class QuaternionParser : BasicCachedQcParser<Quaternion>
{
public override Quaternion Parse(string value)
{
Vector4 vector = ParseRecursive<Vector4>(value);
return new Quaternion(vector.x, vector.y, vector.z, vector.w);
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
namespace QFSW.QC.Parsers
{
public class StringParser : BasicCachedQcParser<string>
{
public override int Priority => int.MaxValue;
public override string Parse(string value)
{
return value
.ReduceScope('"', '"')
.UnescapeText('"');
}
}
}

View File

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

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC.Parsers
{
public class TupleParser : MassGenericQcParser
{
private const int MaxFlatTupleSize = 8;
protected override HashSet<Type> GenericTypes { get; } = new HashSet<Type>
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>),
typeof(Tuple<>),
typeof(Tuple<,>),
typeof(Tuple<,,>),
typeof(Tuple<,,,>),
typeof(Tuple<,,,,>),
typeof(Tuple<,,,,,>),
typeof(Tuple<,,,,,,>),
typeof(Tuple<,,,,,,,>)
};
public override object Parse(string value, Type type)
{
string[] inputParts = value.ReduceScope('(', ')').SplitScoped(',', MaxFlatTupleSize);
Type[] elementTypes = type.GetGenericArguments();
if (elementTypes.Length != inputParts.Length)
{
throw new ParserInputException($"Desired tuple type {type} has {elementTypes.Length} elements but input contained {inputParts.Length}.");
}
object[] tupleParts = new object[inputParts.Length];
for (int i = 0; i < tupleParts.Length; i++)
{
tupleParts[i] = ParseRecursive(inputParts[i], elementTypes[i]);
}
return Activator.CreateInstance(type, tupleParts);
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using System;
namespace QFSW.QC.Parsers
{
public class TypeParser : BasicCachedQcParser<Type>
{
public override Type Parse(string value)
{
return QuantumParser.ParseType(value);
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class Vector2IntParser : BasicCachedQcParser<Vector2Int>
{
public override Vector2Int Parse(string value)
{
return (Vector2Int)ParseRecursive<Vector3Int>(value);
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class Vector2Parser : BasicCachedQcParser<Vector2>
{
public override Vector2 Parse(string value)
{
return ParseRecursive<Vector4>(value);
}
}
}

View File

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

View File

@ -0,0 +1,33 @@
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class Vector3IntParser : BasicCachedQcParser<Vector3Int>
{
public override Vector3Int Parse(string value)
{
string[] vectorParts = value.Split(',');
Vector3Int parsedVector = new Vector3Int();
if (vectorParts.Length < 2 || vectorParts.Length > 3)
{
throw new ParserInputException($"Cannot parse '{value}' as an int vector, the format must be either x,y or x,y,z");
}
int i = 0;
try
{
for (; i < vectorParts.Length; i++)
{
parsedVector[i] = int.Parse(vectorParts[i]);
}
return parsedVector;
}
catch
{
throw new ParserInputException($"Cannot parse '{vectorParts[i]}' as it must be integral.");
}
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class Vector3Parser : BasicCachedQcParser<Vector3>
{
public override Vector3 Parse(string value)
{
return ParseRecursive<Vector4>(value);
}
}
}

View File

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

View File

@ -0,0 +1,25 @@
using UnityEngine;
namespace QFSW.QC.Parsers
{
public class Vector4Parser : BasicCachedQcParser<Vector4>
{
public override Vector4 Parse(string value)
{
string[] vectorParts = value.SplitScoped(',');
Vector4 parsedVector = new Vector4();
if (vectorParts.Length < 2 || vectorParts.Length > 4)
{
throw new ParserInputException($"Cannot parse '{value}' as a vector, the format must be either x,y x,y,z or x,y,z,w.");
}
for (int i = 0; i < vectorParts.Length; i++)
{
parsedVector[i] = ParseRecursive<float>(vectorParts[i]);
}
return parsedVector;
}
}
}

View File

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

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
namespace QFSW.QC
{
/// <summary>
/// Parser for all types inheriting from a single type.
/// Caches results and reuses them if the incoming string has already been parsed.
/// </summary>
/// <typeparam name="T">Base type of the types to parse.</typeparam>
public abstract class PolymorphicCachedQcParser<T> : PolymorphicQcParser<T> where T : class
{
private readonly Dictionary<(string, Type), T> _cacheLookup = new Dictionary<(string, Type), T>();
public override object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
(string value, Type type) key = (value, type);
if (_cacheLookup.ContainsKey(key))
{
return _cacheLookup[key];
}
T result = (T)base.Parse(value, type, recursiveParser);
_cacheLookup[key] = result;
return result;
}
}
}

View File

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

View File

@ -0,0 +1,38 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Parser for all types inheriting from a single type.
/// </summary>
/// <typeparam name="T">Base type of the types to parse.</typeparam>
public abstract class PolymorphicQcParser<T> : IQcParser where T : class
{
private Func<string, Type, object> _recursiveParser;
public virtual int Priority => -1000;
public bool CanParse(Type type)
{
return typeof(T).IsAssignableFrom(type);
}
public virtual object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
_recursiveParser = recursiveParser;
return Parse(value, type);
}
protected object ParseRecursive(string value, Type type)
{
return _recursiveParser(value, type);
}
protected TElement ParseRecursive<TElement>(string value)
{
return (TElement)_recursiveParser(value, typeof(TElement));
}
public abstract T Parse(string value, Type type);
}
}

View File

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

View File

@ -0,0 +1,383 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEngine;
namespace QFSW.QC
{
/// <summary>
/// Handles parsing values to use as console inputs.
/// </summary>
public class QuantumParser
{
private readonly IQcParser[] _parsers;
private readonly IQcGrammarConstruct[] _grammarConstructs;
private readonly ConcurrentDictionary<Type, IQcParser> _parserLookup = new ConcurrentDictionary<Type, IQcParser>();
private readonly HashSet<Type> _unparseableLookup = new HashSet<Type>();
private readonly Func<string, Type, object> _recursiveParser;
/// <summary>
/// Creates a Parser Serializer with a custom set of parsers.
/// </summary>
/// <param name="parsers">The IQcParsers to use in this Quantum Parser.</param>
/// <param name="grammarConstructs">The IQcGrammarConstructs to use in this Quantum Parser</param>
public QuantumParser(IEnumerable<IQcParser> parsers, IEnumerable<IQcGrammarConstruct> grammarConstructs)
{
_recursiveParser = Parse;
_parsers = parsers.OrderByDescending(x => x.Priority)
.ToArray();
_grammarConstructs = grammarConstructs.OrderBy(x => x.Precedence)
.ToArray();
}
/// <summary>
/// Creates a Quantum Parser with the default injected parsers.
/// </summary>
public QuantumParser() : this(new InjectionLoader<IQcParser>().GetInjectedInstances(), new InjectionLoader<IQcGrammarConstruct>().GetInjectedInstances())
{
}
public IQcParser GetParser(Type type)
{
if (_parserLookup.ContainsKey(type))
{
return _parserLookup[type];
}
else if (!_unparseableLookup.Contains(type))
{
foreach (IQcParser parser in _parsers)
{
try
{
if (parser.CanParse(type))
{
return _parserLookup[type] = parser;
}
}
catch (Exception e)
{
Debug.LogError($"{parser.GetType().GetDisplayName()}.CanParse is malformed and throws");
Debug.LogException(e);
}
}
_unparseableLookup.Add(type);
}
return null;
}
public bool CanParse(Type type)
{
return GetParser(type) != null;
}
private IQcGrammarConstruct GetMatchingGrammar(string value, Type type)
{
foreach (IQcGrammarConstruct grammar in _grammarConstructs)
{
try
{
if (grammar.Match(value, type))
{
return grammar;
}
}
catch (Exception e)
{
Debug.LogError($"{grammar.GetType().GetDisplayName()}.Match is malformed and throws");
Debug.LogException(e);
}
}
return null;
}
/// <summary>
/// Parses a serialized string of data.
/// </summary>
/// <typeparam name="T">The type of the value to parse.</typeparam>
/// <param name="value">The string to parse.</param>
/// <returns>The parsed value.</returns>
public T Parse<T>(string value)
{
return (T)Parse(value, typeof(T));
}
/// <summary>
/// Parses a serialized string of data.
/// </summary>
/// <param name="value">The string to parse.</param>
/// <param name="type">The type of the value to parse.</param>
/// <returns>The parsed value.</returns>
public object Parse(string value, Type type)
{
value = value.ReduceScope('(', ')');
if (type.IsClass && value == "null")
{
return null;
}
IQcGrammarConstruct grammar = GetMatchingGrammar(value, type);
if (grammar != null)
{
try
{
return grammar.Parse(value, type, _recursiveParser);
}
catch (ParserException) { throw; }
catch (Exception e)
{
throw new Exception($"Parsing of {type.GetDisplayName()} via {grammar} failed:\n{e.Message}", e);
}
}
IQcParser parser = GetParser(type);
if (parser == null)
{
throw new ArgumentException($"Cannot parse object of type '{type.GetDisplayName()}'");
}
try
{
return parser.Parse(value, type, _recursiveParser);
}
catch (ParserException) { throw; }
catch (Exception e)
{
throw new Exception($"Parsing of {type.GetDisplayName()} via {parser} failed:\n{e.Message}", e);
}
}
#region Type Parser
private static readonly Dictionary<Type, string> _typeDisplayNames = new Dictionary<Type, string>
{
{ typeof(int), "int" }, { typeof(float), "float" }, { typeof(decimal), "decimal" },
{ typeof(double), "double" }, { typeof(string), "string" }, { typeof(bool), "bool" },
{ typeof(byte), "byte" }, { typeof(sbyte), "sbyte" }, { typeof(uint), "uint" },
{ typeof(short), "short" }, { typeof(ushort), "ushort" }, { typeof(long), "long" },
{ typeof(ulong), "ulong" }, { typeof(char), "char" }, { typeof(object), "object" }
};
private static readonly Dictionary<string, Type> _reverseTypeDisplayNames = _typeDisplayNames.Invert();
private static readonly Assembly[] _loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
private static readonly string[] _defaultNamespaces = new string[] { "System", "System.Collections", "System.Collections.Generic", "UnityEngine", "UnityEngine.UI", "QFSW.QC" };
private static readonly List<string> _namespaceTable = new List<string>(_defaultNamespaces);
private static readonly Regex _arrayTypeRegex = new Regex(@"^.*\[,*\]$");
private static readonly Regex _genericTypeRegex = new Regex(@"^.+<.*>$");
private static readonly Regex _tupleTypeRegex = new Regex(@"^\(.*\)$");
/// <summary>
/// Resets the namespace table to its initial state.
/// </summary>
[Command("reset-namespaces", "Resets the namespace table to its initial state")]
public static void ResetNamespaceTable()
{
_namespaceTable.Clear();
_namespaceTable.AddRange(_defaultNamespaces);
}
/// <summary>
/// Adds a namespace to the table so that it can be used to type resolution.
/// </summary>
[Command("use-namespace", "Adds a namespace to the table so that it can be used to type resolution")]
public static void AddNamespace(string namespaceName)
{
if (!_namespaceTable.Contains(namespaceName))
{
_namespaceTable.Add(namespaceName);
}
}
/// <summary>
/// Removes a namespace to the table so that it is no longer used to type resolution.
/// </summary>
[Command("remove-namespace", "Removes a namespace from the table")]
public static void RemoveNamespace(string namespaceName)
{
if (_namespaceTable.Contains(namespaceName))
{
_namespaceTable.Remove(namespaceName);
}
else
{
throw new ArgumentException($"No namespace named {namespaceName} was present in the table");
}
}
[Command("all-namespaces", "Displays all of the namespaces currently in use by the namespace table")]
private static string ShowNamespaces()
{
_namespaceTable.Sort();
if (_namespaceTable.Count == 0) { return "Namespace table is empty"; }
else { return string.Join("\n", _namespaceTable); }
}
/// <summary>
/// Returns a copy of the namespace table.
/// </summary>
public static IEnumerable<string> GetAllNamespaces() { return _namespaceTable; }
/// <summary>
/// Parses and infers the type specified by the string.
/// </summary>
/// <returns>The parsed type.</returns>
/// <param name="typeName">The type to parse.</param>
public static Type ParseType(string typeName)
{
typeName = typeName.Trim();
if (_reverseTypeDisplayNames.ContainsKey(typeName))
{
return _reverseTypeDisplayNames[typeName];
}
if (_tupleTypeRegex.IsMatch(typeName))
{
return ParseTupleType(typeName);
}
if (_arrayTypeRegex.IsMatch(typeName))
{
return ParseArrayType(typeName);
}
if (_genericTypeRegex.IsMatch(typeName))
{
return ParseGenericType(typeName);
}
if (typeName.Contains('`'))
{
string genericName = typeName.Split('`')[0];
if (_reverseTypeDisplayNames.ContainsKey(genericName))
{
return _reverseTypeDisplayNames[genericName];
}
}
return ParseTypeBaseCase(typeName);
}
private static Type ParseArrayType(string typeName)
{
int arrayPos = typeName.LastIndexOf('[');
int arrayRank = typeName.CountFromIndex(',', arrayPos) + 1;
Type elementType = ParseType(typeName.Substring(0, arrayPos));
return arrayRank > 1
? elementType.MakeArrayType(arrayRank)
: elementType.MakeArrayType();
}
private static Type ParseGenericType(string typeName)
{
string[] parts = typeName.Split(new[] { '<' }, 2);
string[] genericArgNames = $"<{parts[1]}".ReduceScope('<', '>').SplitScoped(',');
string incompleteGenericName = $"{parts[0]}`{Math.Max(1, genericArgNames.Length)}";
Type incompleteGenericType = ParseType(incompleteGenericName);
if (genericArgNames.All(string.IsNullOrWhiteSpace))
{
return incompleteGenericType;
}
Type[] genericArgs = genericArgNames.Select(ParseType).ToArray();
return incompleteGenericType.MakeGenericType(genericArgs);
}
private static Type ParseTupleType(string typeName)
{
string inner = typeName.Substring(1, typeName.Length - 2);
Type[] parts = inner
.SplitScoped(',')
.Select(ParseType)
.ToArray();
return CreateTupleType(parts);
}
private static readonly Type[] _valueTupleTypes =
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>)
};
private static Type CreateTupleType(Type[] types)
{
const int maxFlatTupleSize = 8;
if (types.Length > maxFlatTupleSize - 1)
{
Type[] innerTypes = types.Skip(maxFlatTupleSize - 1).ToArray();
types = types
.Take(maxFlatTupleSize - 1)
.Concat(CreateTupleType(innerTypes).Yield())
.ToArray();
}
return _valueTupleTypes[types.Length - 1].MakeGenericType(types);
}
private static Type ParseTypeBaseCase(string typeName)
{
return GetTypeFromAssemblies(typeName, _loadedAssemblies, false, false)
?? GetTypeFromAssemblies(typeName, _namespaceTable, _loadedAssemblies, false, false)
?? GetTypeFromAssemblies(typeName, _loadedAssemblies, false, true)
?? GetTypeFromAssemblies(typeName, _namespaceTable, _loadedAssemblies, true, true);
}
private static Type GetTypeFromAssemblies(string typeName, IEnumerable<string> namespaces, IEnumerable<Assembly> assemblies, bool throwOnError, bool ignoreCase)
{
foreach (string namespaceName in namespaces)
{
Type type = GetTypeFromAssemblies($"{namespaceName}.{typeName}", assemblies, false, ignoreCase);
if (type != null) { return type; }
}
if (throwOnError)
{
throw new TypeLoadException($"No type of name '{typeName}' could be found in the specified assemblies and namespaces.");
}
return null;
}
private static Type GetTypeFromAssemblies(string typeName, IEnumerable<Assembly> assemblies, bool throwOnError, bool ignoreCase)
{
foreach (Assembly assembly in assemblies)
{
Type type = Type.GetType($"{typeName}, {assembly.FullName}", false, ignoreCase);
if (type != null) { return type; }
}
if (throwOnError)
{
throw new TypeLoadException($"No type of name '{typeName}' could be found in the specified assemblies.");
}
return null;
}
#endregion
}
}

View File

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

View File

@ -0,0 +1,69 @@
using System;
using UnityEngine;
namespace QFSW.QC
{
/// <summary>
/// Bitwise flag enum for the runtime platform. Setting a platform bit to 0 includes it as a supported platform.
/// </summary>
[Flags]
public enum Platform : long
{
#pragma warning disable 612,618
OSXEditor = 1L << RuntimePlatform.OSXEditor,
OSXPlayer = 1L << RuntimePlatform.OSXPlayer,
WindowsPlayer = 1L << RuntimePlatform.WindowsPlayer,
OSXWebPlayer = 1L << 3,
OSXDashboardPlayer = 1L << 4,
WindowsWebPlayer = 1L << 5,
WindowsEditor = 1L << RuntimePlatform.WindowsEditor,
IPhonePlayer = 1L << RuntimePlatform.IPhonePlayer,
PS3 = 1L << RuntimePlatform.PS3,
XBOX360 = 1L << RuntimePlatform.XBOX360,
Android = 1L << RuntimePlatform.Android,
NaCl = 1L << RuntimePlatform.NaCl,
LinuxPlayer = 1L << RuntimePlatform.LinuxPlayer,
FlashPlayer = 1L << RuntimePlatform.FlashPlayer,
LinuxEditor = 1L << RuntimePlatform.LinuxEditor,
WebGLPlayer = 1L << RuntimePlatform.WebGLPlayer,
MetroPlayerX86 = 1L << RuntimePlatform.MetroPlayerX86,
WSAPlayerX86 = 1L << RuntimePlatform.WSAPlayerX86,
MetroPlayerX64 = 1L << RuntimePlatform.MetroPlayerX64,
WSAPlayerX64 = 1L << RuntimePlatform.WSAPlayerX64,
MetroPlayerARM = 1L << RuntimePlatform.MetroPlayerARM,
WSAPlayerARM = 1L << RuntimePlatform.WSAPlayerARM,
WP8Player = 1L << RuntimePlatform.WP8Player,
BlackBerryPlayer = 1L << RuntimePlatform.BlackBerryPlayer,
TizenPlayer = 1L << RuntimePlatform.TizenPlayer,
PSP2 = 1L << RuntimePlatform.PSP2,
PS4 = 1L << RuntimePlatform.PS4,
PSM = 1L << RuntimePlatform.PSM,
XboxOne = 1L << RuntimePlatform.XboxOne,
SamsungTVPlayer = 1L << RuntimePlatform.SamsungTVPlayer,
WiiU = 1L << RuntimePlatform.WiiU,
tvOS = 1L << RuntimePlatform.tvOS,
Switch = 1L << RuntimePlatform.Switch,
Lumin = 1L << RuntimePlatform.Lumin,
#if UNITY_2019_3_OR_NEWER
Stadia = 1L << RuntimePlatform.Stadia,
#endif
#pragma warning restore 612, 618
None = 0,
AllPlatforms = ~0,
EditorPlatforms = LinuxEditor | OSXEditor | WindowsEditor,
BuildPlatforms = AllPlatforms ^ EditorPlatforms,
MobilePlatforms = IPhonePlayer | Android | WP8Player
}
public static class PlatformExtensions
{
/// <summary>Converts Unity's RuntimePlatform to QC's bitwise Platform.</summary>
public static Platform ToPlatform(this RuntimePlatform pl)
{
int val = (int)pl;
long bitwise = 1L << val;
return (Platform)bitwise;
}
}
}

View File

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

View File

@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace QFSW.QC
{
public class Pool<T> where T : class, new()
{
private readonly Stack<T> _objs;
public Pool()
{
_objs = new Stack<T>();
}
public Pool(int objCount)
{
_objs = new Stack<T>(objCount);
for (int i = 0; i < objCount; i++)
{
_objs.Push(new T());
}
}
public T GetObject()
{
if (_objs.Count > 0)
{
return _objs.Pop();
}
else
{
return new T();
}
}
public void Release(T obj)
{
_objs.Push(obj);
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f6f8de740c67e8448ac5b693bf65900
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
namespace QFSW.QC
{
/// <summary>
/// Creates a Preprocessor that is loaded and used by the QuantumConsoleProcessor.
/// </summary>
public interface IQcPreprocessor
{
/// <summary>
/// The priority of this preprocessor to resolve processing order.
/// </summary>
int Priority { get; }
/// <summary>
/// Processes the provided text.
/// </summary>
/// <param name="text">The text to process.</param>
/// <returns>The processed text.</returns>
string Process(string text);
}
}

View File

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

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC
{
/// <summary>
/// Handles preprocessing of console input.
/// </summary>
public class QuantumPreprocessor
{
private readonly IQcPreprocessor[] _preprocessors;
/// <summary>
/// Creates a Quantum Preprocessor with a custom set of preprocessors.
/// </summary>
/// <param name="preprocessors">The IQcPreprocessors to use in this Quantum Preprocessor.</param>
public QuantumPreprocessor(IEnumerable<IQcPreprocessor> preprocessors)
{
_preprocessors = preprocessors.OrderByDescending(x => x.Priority)
.ToArray();
}
/// <summary>
/// Creates a Quantum Preprocessor with the default injected preprocessors
/// </summary>
public QuantumPreprocessor() : this(new InjectionLoader<IQcPreprocessor>().GetInjectedInstances())
{
}
/// <summary>
/// Processes the provided text.
/// </summary>
/// <param name="text">The text to process.</param>
/// <returns>The processed text.</returns>
public string Process(string text)
{
foreach (IQcPreprocessor preprocessor in _preprocessors)
{
try
{
text = preprocessor.Process(text);
}
catch (Exception e)
{
throw new Exception($"Preprocessor {preprocessor} failed:\n{e.Message}", e);
}
}
return text;
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
{
"name": "QFSW.QC",
"references": [
"Unity.TextMeshPro",
"Unity.InputSystem"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fb24642277b1db2449da7ac148ce939d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,193 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace QFSW.QC
{
public static partial class QuantumConsoleProcessor
{
private const string helpStr = "Welcome to Quantum Console! In order to see specific help about any specific command, " +
"please use the 'man' command. Use 'man man' to see more about the man command. To see a full list of all " +
"commands, use 'all-commands'.\n\n" +
"mono-targets\nVarious commands may show a mono-target in their command signature.\n" +
"This means they are not static commands, and instead requires instance(s) of the class in order to invoke the command." +
"\nEach mono-target works differently as follows:" +
"\n - single: uses the first instance of the type found in the scene" +
"\n - all: uses all instances of the type found in the scene" +
"\n - registry: uses all instances of the type found in the registry" +
"\n - singleton: creates and manages a single instance automatically" +
"\n\nThe registry is a part of the Quantum Registry that allows you to decide which specific instances of the class " +
"should be used when invoking the command. In order to add an object to the registry, either use " +
"QFSW.QC.QuantumRegistry.RegisterObject<T> or the runtime command 'register-object<T>'.";
[Command("help", "Shows a basic help guide for Quantum Console")]
private static string GetHelp()
{
return helpStr;
}
[Command("manual")]
[Command("man")]
private static string ManualHelp()
{
return "To use the man command, simply put the desired command name in front of it. For example, 'man my-command' will generate the manual for 'my-command'";
}
[CommandDescription("Generates a user manual for any given command, including built in ones. To use the man command, simply put the desired command name infront of it. For example, 'man my-command' will generate the manual for 'my-command'")]
[Command("help")]
[Command("manual")]
[Command("man")]
private static string GenerateCommandManual(string commandName)
{
string[] matchingCommands = _commandTable.Keys.Where((string key) => key.Split('(')[0] == commandName).OrderBy((string key) => key).ToArray();
if (matchingCommands.Length == 0) { throw new ArgumentException($"No command with the name {commandName} was found."); }
else
{
Dictionary<string, ParameterInfo> foundParams = new Dictionary<string, ParameterInfo>();
Dictionary<string, Type> foundGenericArguments = new Dictionary<string, Type>();
Dictionary<string, CommandParameterDescriptionAttribute> foundParamDescriptions = new Dictionary<string, CommandParameterDescriptionAttribute>();
List<Type> declaringTypes = new List<Type>(1);
string manual = $"Generated user manual for {commandName}\nAvailable command signatures:";
for (int i = 0; i < matchingCommands.Length; i++)
{
CommandData currentCommand = _commandTable[matchingCommands[i]];
declaringTypes.Add(currentCommand.MethodData.DeclaringType);
manual += $"\n - {currentCommand.CommandSignature}";
if (!currentCommand.IsStatic) { manual += $" (mono-target = {currentCommand.MonoTarget.ToString().ToLower()})"; }
for (int j = 0; j < currentCommand.ParamCount; j++)
{
ParameterInfo param = currentCommand.MethodParamData[j];
if (!foundParams.ContainsKey(param.Name)) { foundParams.Add(param.Name, param); }
if (!foundParamDescriptions.ContainsKey(param.Name))
{
CommandParameterDescriptionAttribute descriptionAttribute = param.GetCustomAttribute<CommandParameterDescriptionAttribute>();
if (descriptionAttribute != null && descriptionAttribute.Valid) { foundParamDescriptions.Add(param.Name, descriptionAttribute); }
}
}
if (currentCommand.IsGeneric)
{
Type[] genericArgs = currentCommand.GenericParamTypes;
for (int j = 0; j < genericArgs.Length; j++)
{
Type arg = genericArgs[j];
if (!foundGenericArguments.ContainsKey(arg.Name)) { foundGenericArguments.Add(arg.Name, arg); }
}
}
}
if (foundParams.Count > 0)
{
manual += "\nParameter info:";
ParameterInfo[] commandParams = foundParams.Values.ToArray();
for (int i = 0; i < commandParams.Length; i++)
{
ParameterInfo currentParam = commandParams[i];
manual += $"\n - {currentParam.Name}: {currentParam.ParameterType.GetDisplayName()}";
}
}
string genericConstraintInformation = "";
if (foundGenericArguments.Count > 0)
{
Type[] genericArgs = foundGenericArguments.Values.ToArray();
for (int i = 0; i < genericArgs.Length; i++)
{
Type arg = genericArgs[i];
Type[] typeConstraints = arg.GetGenericParameterConstraints();
GenericParameterAttributes attributes = arg.GenericParameterAttributes;
List<string> formattedConstraints = new List<string>();
if (attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint)) { formattedConstraints.Add("struct"); }
if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint)) { formattedConstraints.Add("class"); }
for (int j = 0; j < typeConstraints.Length; j++) { formattedConstraints.Add(typeConstraints[i].GetDisplayName()); }
if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint)) { formattedConstraints.Add("new()"); }
if (formattedConstraints.Count > 0)
{
genericConstraintInformation += $"\n - {arg.Name}: {string.Join(", ", formattedConstraints)}";
}
}
}
if (!string.IsNullOrWhiteSpace(genericConstraintInformation)) { manual += $"\nGeneric constraints:{genericConstraintInformation}"; }
for (int i = 0; i < matchingCommands.Length; i++)
{
CommandData currentCommand = _commandTable[matchingCommands[i]];
if (currentCommand.HasDescription)
{
manual += $"\n\nCommand description:\n{currentCommand.CommandDescription}";
i = matchingCommands.Length;
}
}
if (foundParamDescriptions.Count > 0)
{
manual += "\n\nParameter descriptions:";
ParameterInfo[] commandParams = foundParams.Values.ToArray();
for (int i = 0; i < commandParams.Length; i++)
{
ParameterInfo currentParam = commandParams[i];
if (foundParamDescriptions.ContainsKey(currentParam.Name))
{
manual += $"\n - {currentParam.Name}: {foundParamDescriptions[currentParam.Name].Description}";
}
}
}
declaringTypes = declaringTypes.Distinct().ToList();
manual += "\n\nDeclared in";
if (declaringTypes.Count == 1) { manual += $" {declaringTypes[0].GetDisplayName(true)}"; }
else
{
manual += ":";
foreach (Type type in declaringTypes)
{
manual += $"\n - {type.GetDisplayName(true)}";
}
}
return manual;
}
}
/// <summary>
/// Gets all loaded unique commands. Unique excludes multiple overloads of the same command from appearing.
/// </summary>
/// <returns>All loaded unique commands.</returns>
public static IEnumerable<CommandData> GetUniqueCommands()
{
return GetAllCommands()
.DistinctBy(x => x.CommandName)
.OrderBy(x => x.CommandName);
}
[CommandDescription("Generates a list of all commands currently loaded by the Quantum Console Processor")]
[Command("commands")]
[Command("all-commands")]
private static string GenerateCommandList()
{
string output = "List of all commands loaded by the Quantum Processor. Use 'man' on any command to see more:";
foreach (CommandData command in GetUniqueCommands())
{
output += $"\n - {command.CommandName}";
}
return output;
}
[Command("user-commands", "Generates a list of all commands added by the user")]
private static IEnumerable<string> GenerateUserCommandList()
{
return GetUniqueCommands()
.Where(x => !x.MethodData.DeclaringType.Assembly.FullName.StartsWith("QFSW.QC"))
.Select(x => $" - {x.CommandName}");
}
}
}

View File

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

View File

@ -0,0 +1,552 @@
#if UNITY_EDITOR || !UNITY_WEBGL
#define THREADS_SUPPORTED
#endif
using QFSW.QC.Internal;
using QFSW.QC.Utilities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace QFSW.QC
{
public enum LoggingLevel
{
None = 0,
Errors = 1,
Warnings = 2,
Full = 3
}
/// <summary>The core processor of Quantum Console handling command table generation and invocation.</summary>
public static partial class QuantumConsoleProcessor
{
/// <summary>The logging level to use during operation of the Quantum Console Processor.</summary>
public static LoggingLevel loggingLevel = LoggingLevel.Full;
private static readonly QuantumParser _parser = new QuantumParser();
private static readonly QuantumPreprocessor _preprocessor = new QuantumPreprocessor();
private static readonly ConcurrentDictionary<string, CommandData> _commandTable = new ConcurrentDictionary<string, CommandData>();
public static bool TableGenerated { get; private set; }
public static bool TableIsGenerating { get; private set; }
[Command("command-count", "Gets the number of loaded commands")]
public static int LoadedCommandCount => _loadedCommandCount;
private static int _loadedCommandCount = 0;
private static readonly Assembly[] _loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
/// <summary>
/// Gets all loaded commands.
/// </summary>
/// <returns>All loaded commands.</returns>
public static IEnumerable<CommandData> GetAllCommands()
{
return _commandTable.Values;
}
#region Table Generation
/// <summary>
/// Generates the command table so that commands can be invoked.
/// </summary>
/// <param name="deployThread">If set to <c>true</c> a second thread will be deployed for the table generation.</param>
/// <param name="forceReload">If set to <c>true</c> then the table will be cleared and generated again.</param>
public static void GenerateCommandTable(bool deployThread = false, bool forceReload = false)
{
#if THREADS_SUPPORTED
if (deployThread)
{
ThreadPool.QueueUserWorkItem(state =>
{
try
{
GenerateCommandTable(false, forceReload);
}
catch (Exception e)
{
Debug.LogException(e);
}
});
return;
}
#endif
lock (_commandTable)
{
if (!TableGenerated || forceReload)
{
TableIsGenerating = true;
{
if (forceReload && TableGenerated)
{
_commandTable.Clear();
_loadedCommandCount = 0;
}
#if THREADS_SUPPORTED
Parallel.ForEach(_loadedAssemblies, assembly =>
{
if (AssemblyRequiresScan(assembly))
{
LoadCommandsFromAssembly(assembly);
}
});
#else
foreach (Assembly assembly in _loadedAssemblies)
{
if (AssemblyRequiresScan(assembly))
{
LoadCommandsFromAssembly(assembly);
}
}
#endif
}
TableIsGenerating = false;
TableGenerated = true;
GC.Collect(3, GCCollectionMode.Forced, false, true);
}
}
}
private static IEnumerable<(MethodInfo method, MemberInfo member)> ExtractCommandMethods(Type type)
{
const BindingFlags flags =
BindingFlags.Static
| BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.DeclaredOnly;
MethodInfo[] methods = type.GetMethods(flags);
PropertyInfo[] properties = type.GetProperties(flags);
FieldInfo[] fields = type.GetFields(flags);
foreach (MethodInfo method in methods)
{
yield return (method, method);
}
foreach (PropertyInfo property in properties)
{
if (property.CanWrite)
{
yield return (property.SetMethod, property);
}
if (property.CanRead)
{
yield return (property.GetMethod, property);
}
}
foreach (FieldInfo field in fields)
{
if (field.HasAttribute<CommandAttribute>())
{
if (field.IsDelegate())
{
if (field.IsStrongDelegate())
{
FieldDelegateMethod executer = new FieldDelegateMethod(field);
yield return (executer, field);
}
else if (loggingLevel >= LoggingLevel.Warnings)
{
Debug.LogWarning($"Quantum Processor Warning: Could not add '{field.Name}' from {field.DeclaringType} to the table as it is an invalid delegate type.");
}
}
else
{
FieldAutoMethod reader = new FieldAutoMethod(field, FieldAutoMethod.AccessType.Read);
yield return (reader, field);
if (!(field.IsLiteral || field.IsInitOnly))
{
FieldAutoMethod writer = new FieldAutoMethod(field, FieldAutoMethod.AccessType.Write);
yield return (writer, field);
}
}
}
}
}
private static bool GetCommandSupported(CommandData command, out string unsupportedReason)
{
for (int i = 0; i < command.ParamCount; i++)
{
ParameterInfo param = command.MethodParamData[i];
Type paramType = param.ParameterType;
if (!_parser.CanParse(paramType) && !paramType.IsGenericParameter)
{
unsupportedReason = $"Parameter type {paramType} is not supported by the Quantum Parser.";
return false;
}
}
if (command.MonoTarget != MonoTargetType.Registry
&& !command.MethodData.IsStatic
&& !command.MethodData.DeclaringType.IsDerivedTypeOf(typeof(MonoBehaviour)))
{
unsupportedReason = $"Non static non MonoBehaviour commands are incompatible with MonoTargetType.{command.MonoTarget}.";
return false;
}
unsupportedReason = string.Empty;
return true;
}
private static bool AssemblyRequiresScan(Assembly assembly)
{
if (assembly.HasAttribute<QcIgnoreAttribute>(false))
{
return false;
}
string[] bannedPrefixes = new string[]
{
"System", "Unity", "Microsoft", "Mono.", "mscorlib", "NSubstitute", "JetBrains", "nunit.",
"GeNa."
#if QC_DISABLE_BUILTIN_ALL
, "QFSW.QC"
#elif QC_DISABLE_BUILTIN_EXTRA
, "QFSW.QC.Extra"
#endif
};
string[] bannedAssemblies = new string[]
{
"mcs", "AssetStoreTools"
};
string assemblyFullName = assembly.FullName;
foreach (string prefix in bannedPrefixes)
{
if (assemblyFullName.StartsWith(prefix))
{
return false;
}
}
string assemblyShortName = assembly.GetName().Name;
foreach (string name in bannedAssemblies)
{
if (assemblyShortName == name)
{
return false;
}
}
return true;
}
private static void LoadCommandsFromAssembly(Assembly assembly)
{
Type[] loadedTypes = assembly.GetTypes();
foreach (Type type in loadedTypes)
{
try
{
LoadCommandsFromType(type);
}
catch (TypeLoadException)
{
// Issue under investigation
/*
if (loggingLevel >= LoggingLevel.Warnings)
{
Debug.LogWarning($"Unable to extract command data from type {type} in assembly {assembly.GetName().Name} as it may be corrupted. The following exception was thrown: {e.Message}");
}
*/
}
catch (BadImageFormatException)
{
// Confirmed to be an issue on Unity/Mono's side
// Extremely unlikely that it will ever occur in user code, so for this reason it is ignored silently
// QC Issue: https://bitbucket.org/QFSW/quantum-console/issues/67/add-protection-against-corrupt-dlls
// Unity Issue: https://issuetracker.unity3d.com/issues/badimageformatexception-is-thrown-when-calling-getcustomattributes-on-certain-memberinfo-instances
// Mono Issue: https://github.com/mono/mono/issues/17278
/*
if (loggingLevel >= LoggingLevel.Warnings)
{
Debug.LogWarning($"Unable to extract command data from type {type} in assembly {assembly.GetName().Name} as it may be corrupted. The following exception was thrown: {e.Message}");
}
*/
}
}
}
private static void LoadCommandsFromType(Type type)
{
if (type.HasAttribute<QcIgnoreAttribute>(false)) return;
if (type.HasAttribute<CompilerGeneratedAttribute>(true)) { return; }
foreach ((MethodInfo method, MemberInfo member) in ExtractCommandMethods(type))
{
if (member.DeclaringType == type)
{
LoadCommandsFromMember(member, method);
}
}
}
private static void LoadCommandsFromMember(MemberInfo member, MethodInfo method)
{
IEnumerable<CommandAttribute> commandAttributes = member.GetCustomAttributes<CommandAttribute>();
CommandDescriptionAttribute descriptionAttribute = member.GetCustomAttribute<CommandDescriptionAttribute>();
foreach (CommandAttribute commandAttribute in commandAttributes)
{
if (!commandAttribute.Valid)
{
if (loggingLevel >= LoggingLevel.Warnings)
{
Debug.LogWarning($"Quantum Processor Warning: Could not add '{commandAttribute.Alias}' to the table as it is invalid.");
}
}
else
{
CommandPlatformAttribute platformAttribute = member.GetCustomAttribute<CommandPlatformAttribute>();
Platform commandPlatforms = platformAttribute?.SupportedPlatforms ?? commandAttribute.SupportedPlatforms;
if (commandPlatforms.HasFlag(Application.platform.ToPlatform()))
{
IEnumerable<CommandData> newCommands = CreateCommandOverloads(method, commandAttribute, descriptionAttribute);
foreach (CommandData command in newCommands)
{
TryAddCommand(command);
}
}
}
}
}
private static IEnumerable<CommandData> CreateCommandOverloads(MethodInfo method, CommandAttribute commandAttribute, CommandDescriptionAttribute descriptionAttribute)
{
int defaultParameters = method.GetParameters().Count(x => x.HasDefaultValue);
for (int i = 0; i < defaultParameters + 1; i++)
{
CommandData command = new CommandData(method, commandAttribute, descriptionAttribute, i);
yield return command;
}
}
private static string GenerateCommandKey(CommandData command)
{
return $"{command.CommandName}({command.ParamCount})";
}
/// <summary>
/// Registers a new command.
/// </summary>
/// <param name="command">The command to register.</param>
/// <returns>If the addition was successful.</returns>
public static bool TryAddCommand(CommandData command)
{
if (!GetCommandSupported(command, out string reason))
{
if (loggingLevel >= LoggingLevel.Warnings)
{
Debug.LogWarning($"Quantum Processor Warning: Could not add '{command.CommandSignature}' from {command.MethodData.DeclaringType.GetDisplayName()} " +
$"to the table as it is not supported. {reason}");
}
return false;
}
string key = GenerateCommandKey(command);
bool alreadyExists = !_commandTable.TryAdd(key, command);
if (alreadyExists)
{
if (loggingLevel >= LoggingLevel.Warnings)
{
string fullMethodName = $"{command.MethodData.DeclaringType.FullName}.{command.MethodData.Name}";
Debug.LogWarning($"Quantum Processor Warning: Could not add {fullMethodName} to the table as another method with the same alias and parameter count, {key}, already exists.");
}
return false;
}
Interlocked.Increment(ref _loadedCommandCount);
return true;
}
/// <summary>
/// Removes an existing command.
/// </summary>
/// <param name="command">The command to remove.</param>
/// <returns>If the removal was successful.</returns>
public static bool TryRemoveCommand(CommandData command)
{
string key = GenerateCommandKey(command);
if (_commandTable.TryRemove(key, out _))
{
Interlocked.Decrement(ref _loadedCommandCount);
return true;
}
return false;
}
#endregion
#region Command Invocation
/// <summary>Invokes a command on the QuantumConsoleProcessor.</summary>
/// <returns>Return value of the invocation.</returns>
/// <param name="commandString">The command to invoke.</param>
public static object InvokeCommand(string commandString)
{
GenerateCommandTable();
commandString = commandString.Trim();
commandString = _preprocessor.Process(commandString);
if (string.IsNullOrWhiteSpace(commandString)) { throw new ArgumentException("Cannot parse an empty string."); }
string[] commandParts = commandString.SplitScoped(' ');
commandParts = commandParts.Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
string commandName = commandParts[0];
string[] commandParams = commandParts.SubArray(1, commandParts.Length - 1);
int paramCount = commandParams.Length;
string[] commandNameParts = commandName.Split(new[] { '<' }, 2);
string genericSignature = commandNameParts.Length > 1 ? $"<{commandNameParts[1]}" : "";
commandName = commandNameParts[0];
string keyName = $"{commandName}({paramCount})";
if (!_commandTable.ContainsKey(keyName))
{
bool overloadExists = _commandTable.Keys.Any(key => key.Contains($"{commandName}(") && _commandTable[key].CommandName == commandName);
if (overloadExists) { throw new ArgumentException($"No overload of '{commandName}' with {paramCount} parameters could be found."); }
else { throw new ArgumentException($"Command '{commandName}' could not be found."); }
}
CommandData command = _commandTable[keyName];
Type[] genericTypes = Array.Empty<Type>();
if (command.IsGeneric)
{
int expectedArgCount = command.GenericParamTypes.Length;
string[] genericArgNames = genericSignature.ReduceScope('<', '>').SplitScoped(',');
if (genericArgNames.Length == expectedArgCount)
{
genericTypes = new Type[genericArgNames.Length];
for (int i = 0; i < genericTypes.Length; i++)
{
genericTypes[i] = QuantumParser.ParseType(genericArgNames[i]);
}
}
else
{
throw new ArgumentException($"Generic command '{commandName}' requires {expectedArgCount} generic parameter{(expectedArgCount == 1 ? "" : "s")} but was supplied with {genericArgNames.Length}.");
}
}
else if (genericSignature != string.Empty)
{
throw new ArgumentException($"Command '{commandName}' is not a generic command and cannot be invoked as such.");
}
#if !UNITY_EDITOR && ENABLE_IL2CPP
if (genericTypes.Any((Type x) => x.IsValueType))
{
throw new NotSupportedException("Value types in generic commands are not currently supported by Unity in IL2CPP");
}
#endif
object[] parsedCommandParams = ParseParamData(command.MakeGenericArguments(genericTypes), commandParams);
return command.Invoke(parsedCommandParams, genericTypes);
}
private static object[] ParseParamData(Type[] paramTypes, string[] paramData)
{
object[] parsedData = new object[paramData.Length];
for (int i = 0; i < parsedData.Length; i++)
{
parsedData[i] = _parser.Parse(paramData[i], paramTypes[i]);
}
return parsedData;
}
#endregion
/// <summary>Gets suggestions for possible commands given the currently entered command fragment.</summary>
/// <returns>All commands suggested for the provided fragment.</returns>
/// <param name="incompleteCommandName">Incomplete command name to base the search off of.</param>
/// <param name="fuzzy">If fuzzy search is disabled, then your current search must match the beginning of the command to be suggested (foo*). If fuzzy search is enabled, it can be anywhere within the command name to be suggested (*foo*).</param>
/// <param name="caseSensitive">If the search should be case sensitive or not.</param>
/// <param name="includeOverloads">If multiple overloads of the same command should be included.</param>
public static IEnumerable<CommandData> GetCommandSuggestions(string incompleteCommandName, bool fuzzy = false, bool caseSensitive = true, bool includeOverloads = true)
{
if (string.IsNullOrWhiteSpace(incompleteCommandName))
{
return Enumerable.Empty<CommandData>();
}
HashSet<string> foundNames = includeOverloads ? null : new HashSet<string>();
List<CommandData> foundCommands = new List<CommandData>();
bool MatchFound(string incompleteCommand, string commandSuggestion)
{
if (commandSuggestion.Length < incompleteCommand.Length) { return false; }
if (fuzzy)
{
if (caseSensitive) { return commandSuggestion.Contains(incompleteCommand); }
else { return commandSuggestion.ContainsCaseInsensitive(incompleteCommand); }
}
else
{
return commandSuggestion.StartsWith(incompleteCommand, !caseSensitive, null);
}
}
foreach (CommandData command in _commandTable.Values)
{
if (includeOverloads || !foundNames.Contains(command.CommandName))
{
if (MatchFound(incompleteCommandName, command.CommandName))
{
if (!includeOverloads) { foundNames.Add(command.CommandName); }
foundCommands.Add(command);
}
}
}
IOrderedEnumerable<CommandData> sortedSuggestions;
if (includeOverloads)
{
sortedSuggestions = foundCommands.OrderBy(x => x.ParamCount)
.OrderBy(x => x.CommandName)
.OrderBy(x => x.CommandName.Length);
}
else
{
sortedSuggestions = foundCommands.OrderBy(x => x.CommandName)
.OrderBy(x => x.CommandName.Length);
}
if (fuzzy)
{
if (caseSensitive)
{
sortedSuggestions = sortedSuggestions.OrderBy(x => x.CommandName.IndexOf(incompleteCommandName, StringComparison.CurrentCulture));
}
else
{
sortedSuggestions = sortedSuggestions.OrderBy(x => x.CommandName.IndexOf(incompleteCommandName, StringComparison.CurrentCultureIgnoreCase));
}
}
return sortedSuggestions;
}
}
}

View File

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

View File

@ -0,0 +1,25 @@
using UnityEngine;
namespace QFSW.QC
{
[CreateAssetMenu(fileName = "Untitled Key Config", menuName = "Quantum Console/Key Config")]
public class QuantumKeyConfig : ScriptableObject
{
public KeyCode SubmitCommandKey = KeyCode.Return;
public ModifierKeyCombo ShowConsoleKey = KeyCode.None;
public ModifierKeyCombo HideConsoleKey = KeyCode.None;
public ModifierKeyCombo ToggleConsoleVisibilityKey = KeyCode.Escape;
public ModifierKeyCombo ZoomInKey = new ModifierKeyCombo { Key = KeyCode.Equals, Ctrl = true };
public ModifierKeyCombo ZoomOutKey = new ModifierKeyCombo { Key = KeyCode.Minus, Ctrl = true };
public ModifierKeyCombo DragConsoleKey = new ModifierKeyCombo { Key = KeyCode.Mouse0, Shift = true };
public ModifierKeyCombo SuggestNextCommandKey = KeyCode.Tab;
public ModifierKeyCombo SuggestPreviousCommandKey = new ModifierKeyCombo { Key = KeyCode.Tab, Shift = true };
public KeyCode NextCommandKey = KeyCode.UpArrow;
public KeyCode PreviousCommandKey = KeyCode.DownArrow;
public ModifierKeyCombo CancelActionsKey = new ModifierKeyCombo { Key = KeyCode.C, Ctrl = true };
}
}

View File

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

View File

@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace QFSW.QC
{
public static class QuantumMacros
{
private class MacroPreprocessor : IQcPreprocessor
{
public int Priority => 1000;
public string Process(string text)
{
if (!text.StartsWith("#define", StringComparison.CurrentCulture))
{
text = ExpandMacros(text);
}
return text;
}
}
private static readonly Dictionary<string, string> _macroTable = new Dictionary<string, string>();
/// <summary>
/// Expands all the macros in the given text.
/// </summary>
/// <returns>The macro expanded text.</returns>
/// <param name="text">The text to expand the macros in.</param>
/// <param name="maximumExpansions">The maximum number of macro expansions that can be performed before an exception is thrown.</param>
public static string ExpandMacros(string text, int maximumExpansions = 1000)
{
if (_macroTable.Count == 0) { return text; }
int expansionCount = 0;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '#')
{
foreach (KeyValuePair<string, string> macro in _macroTable)
{
int keyLength = macro.Key.Length;
if (i + keyLength < text.Length)
{
if (text.Substring(i + 1, keyLength) == macro.Key)
{
if (expansionCount >= maximumExpansions)
{
throw new ArgumentException($"Maximum macro expansions of {maximumExpansions} was exhausted: infinitely recursive macro is likely.");
}
else
{
string start = text.Substring(0, i);
string end = text.Substring(i + 1 + keyLength);
text = $"{start}{macro.Value}{end}";
expansionCount++;
i--;
}
}
}
}
}
}
return text;
}
[Command("#define")]
[CommandDescription("Adds a macro to the macro table which can then be used in the Quantum Console. If the macro 'name' is added, " +
"then all instances of '#name' will be expanded into the full macro expansion. This allows you to define " +
"shortcuts for various things such as long type names or commonly used command strings.\n\n" +
"Macros may not contain hashtags or whitespace in their name.\n\n" +
"Note: macros will not be expanded when using #define, this is so that defining nested macros is possible.")]
public static void DefineMacro(string macroName, string macroExpansion)
{
macroName = macroName.Trim();
if (macroName.Contains(' ')) { throw new ArgumentException("Macro names cannot contain whitespace."); }
if (macroName.Contains('\n')) { throw new ArgumentException("Macro names cannot contain newlines."); }
if (macroName.Contains('#')) { throw new ArgumentException("Macro names cannot contain hashtags."); }
if (macroName == "define") { throw new ArgumentException("Macros cannot be named define."); }
if (macroExpansion.Contains('\n')) { throw new ArgumentException("Macro names cannot contain newlines."); }
if (macroExpansion.Contains($"#{macroName}")) { throw new ArgumentException("Macros cannot contain themselves within the expansion."); }
if (_macroTable.ContainsKey(macroName)) { _macroTable[macroName] = macroExpansion; }
else { _macroTable.Add(macroName, macroExpansion); }
}
[Command("remove-macro")]
[CommandDescription("Removes the specified macro from the macro table")]
public static void RemoveMacro(string macroName)
{
if (_macroTable.ContainsKey(macroName)) { _macroTable.Remove(macroName); }
else { throw new Exception($"Specified macro #{macroName} as it was not defined."); }
}
[Command("clear-macros")]
[CommandDescription("Clears the macro table")]
public static void ClearMacros() { _macroTable.Clear(); }
[Command("all-macros", "Displays all of the macros currently stored in the macro table")]
private static string GetAllMacros()
{
if (_macroTable.Count == 0) { return "Macro table is empty"; }
else { return $"Macro table:\n{string.Join("\n", _macroTable.Select((x) => $"#{x.Key} = {x.Value}"))}"; }
}
[Command("dump-macros", "Creates a file dump of macro table which can the be loaded to repopulate the table using load-macros")]
[CommandPlatform(Platform.AllPlatforms ^ (Platform.WebGLPlayer))]
public static void DumpMacrosToFile(string filePath)
{
using (StreamWriter dumpFile = new StreamWriter(filePath))
{
foreach (KeyValuePair<string, string> macro in _macroTable)
{
dumpFile.WriteLine($"{macro.Key} {macro.Value}");
}
dumpFile.Flush();
dumpFile.Close();
}
}
[Command("load-macros", "Loads macros from an external file into the macro table")]
[CommandPlatform(Platform.AllPlatforms ^ (Platform.WebGLPlayer))]
public static string LoadMacrosFromFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new ArgumentException($"file at the specified path '{filePath}' did not exist.");
}
using (StreamReader macroFile = new StreamReader(filePath))
{
List<string> messages = new List<string>();
while (!macroFile.EndOfStream)
{
string line = macroFile.ReadLine();
string[] parts = line.Split(" ".ToCharArray(), 2);
if (parts.Length != 2)
{
messages.Add($"'{line}' is not a valid macro definition");
}
try
{
DefineMacro(parts[0], parts[1]);
messages.Add($"#{parts[0]} was successfully defined");
}
catch (Exception e)
{
messages.Add($"#{parts[0]} could not be defined: {e.Message}");
}
}
macroFile.Close();
return string.Join("\n", messages);
}
}
}
}

View File

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

View File

@ -0,0 +1,149 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC
{
public static class QuantumRegistry
{
private static readonly Dictionary<Type, List<object>> _objectRegistry = new Dictionary<Type, List<object>>();
private static bool IsNull(object x)
{
if (x is UnityEngine.Object u)
{
return !u;
}
return x is null;
}
/// <summary>Adds the object to the registry.</summary>
/// <param name="obj">The object to add to the registry.</param>
/// <typeparam name="T">The type of the object to add to the registry.</typeparam>
[Command("register-object", "Adds the object to the registry to be used by commands with MonoTargetType = Registry")]
public static void RegisterObject<T>(T obj) where T : class { RegisterObject(typeof(T), obj); }
/// <summary>Adds the object to the registry.</summary>
/// <param name="type">The type of the object to add to the registry.</param>
/// <param name="obj">The object to add to the registry.</param>
public static void RegisterObject(Type type, object obj)
{
if (!type.IsClass) { throw new Exception("Registry may only contain class types"); }
lock (_objectRegistry)
{
if (_objectRegistry.ContainsKey(type))
{
if (_objectRegistry[type].Contains(obj))
{
throw new ArgumentException($"Could not register object '{obj}' of type {type.GetDisplayName()} as it was already registered.");
}
_objectRegistry[type].Add(obj);
}
else
{
_objectRegistry.Add(type, new List<object>() { obj });
}
}
}
/// <summary>Removes the object from the registry.</summary>
/// <param name="obj">The object to remove from the registry.</param>
/// <typeparam name="T">The type of the object to remove from the registry.</typeparam>
[Command("deregister-object", "Removes the object to the registry to be used by commands with MonoTargetType = Registry")]
public static void DeregisterObject<T>(T obj) where T : class { DeregisterObject(typeof(T), obj); }
/// <summary>Removes the object to the registry.</summary>
/// <param name="type">The type of the object to remove from the registry.</param>
/// <param name="obj">The object to remove from the registry.</param>
public static void DeregisterObject(Type type, object obj)
{
if (!type.IsClass) { throw new Exception("Registry may only contain class types"); }
lock (_objectRegistry)
{
if (_objectRegistry.ContainsKey(type) && _objectRegistry[type].Contains(obj))
{
_objectRegistry[type].Remove(obj);
}
else
{
throw new ArgumentException($"Could not deregister object '{obj}' of type {type.GetDisplayName()} as it was not found in the registry.");
}
}
}
/// <summary>Gets the size of the specified registry.</summary>
/// <returns>The registry size.</returns>
/// <typeparam name="T">The registry to query.</typeparam>
public static int GetRegistrySize<T>() where T : class { return GetRegistrySize(typeof(T)); }
/// <summary>Gets the size of the specified registry.</summary>
/// <returns>The registry size.</returns>
/// <param name="type">The registry to query.</param>
public static int GetRegistrySize(Type type)
{
return GetRegistryContents(type).Count();
}
/// <summary>Gets the contents of the specified registry.</summary>
/// <returns>The registry contents.</returns>
/// <typeparam name="T">The registry to query.</typeparam>
public static IEnumerable<T> GetRegistryContents<T>() where T : class
{
foreach (object obj in GetRegistryContents(typeof(T)))
{
yield return (T)obj;
}
}
/// <summary>Gets the contents of the specified registry.</summary>
/// <returns>The registry contents.</returns>
/// <param name="type">The registry to query.</param>
public static IEnumerable<object> GetRegistryContents(Type type)
{
if (!type.IsClass) { throw new Exception("Registry may only contain class types"); }
lock (_objectRegistry)
{
if (_objectRegistry.ContainsKey(type))
{
List<object> registry = _objectRegistry[type];
registry.RemoveAll(IsNull);
return registry;
}
return Enumerable.Empty<object>();
}
}
/// <summary>clears the contents of the specified registry.</summary>
/// <typeparam name="T">The registry to clear.</typeparam>
public static void ClearRegistryContents<T>() where T : class
{
ClearRegistryContents(typeof(T));
}
/// <summary>clears the contents of the specified registry.</summary>
/// <param name="type">The registry to clear.</param>
public static void ClearRegistryContents(Type type)
{
if (!type.IsClass) { throw new Exception("Registry may only contain class types"); }
lock (_objectRegistry)
{
if (_objectRegistry.ContainsKey(type))
{
_objectRegistry.Clear();
}
}
}
[Command("display-registry", "Displays the contents of the specified registry")]
private static string DisplayRegistry([CommandParameterDescription("Full namespace qualified name of the type of the registry.")]Type type)
{
int registrySize = GetRegistrySize(type);
if (registrySize < 1) { return $"registry '{type.GetDisplayName()}' was empty"; }
else { return string.Join("\n", GetRegistryContents(type).Select(x => x.ToString())); }
}
}
}

View File

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

View File

@ -0,0 +1,74 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
namespace QFSW.QC
{
[CreateAssetMenu(fileName = "Untitled Theme", menuName = "Quantum Console/Theme")]
public class QuantumTheme : ScriptableObject
{
[SerializeField] public TMP_FontAsset Font = null;
[SerializeField] public Material PanelMaterial = null;
[SerializeField] public Color PanelColor = Color.white;
[SerializeField] public Color CommandLogColor = new Color(0, 1, 1);
[SerializeField] public Color SelectedSuggestionColor = new Color(1, 1, 0.55f);
[SerializeField] public Color SuggestionColor = Color.gray;
[SerializeField] public Color ErrorColor = Color.red;
[SerializeField] public Color WarningColor = new Color(1, 0.5f, 0);
[SerializeField] public Color SuccessColor = Color.green;
[SerializeField] public string TimestampFormat = "[{0}:{1}:{2}]";
[SerializeField] public Color DefaultReturnValueColor = Color.white;
[SerializeField] public List<TypeColorFormatter> TypeFormatters = new List<TypeColorFormatter>(0);
[SerializeField] public List<CollectionFormatter> CollectionFormatters = new List<CollectionFormatter>(0);
private T FindTypeFormatter<T>(List<T> formatters, Type type) where T : TypeFormatter
{
foreach (T formatter in formatters)
{
if (type == formatter.Type || type.IsGenericTypeOf(formatter.Type))
{
return formatter;
}
}
foreach (T formatter in formatters)
{
if (formatter.Type.IsAssignableFrom(type))
{
return formatter;
}
}
return null;
}
public string ColorizeReturn(string data, Type type)
{
TypeColorFormatter formatter = FindTypeFormatter(TypeFormatters, type);
if (formatter == null) { return data.ColorText(DefaultReturnValueColor); }
else { return data.ColorText(formatter.Color); }
}
public void GetCollectionFormatting(Type type, out string leftScoper, out string seperator, out string rightScoper)
{
CollectionFormatter formatter = FindTypeFormatter(CollectionFormatters, type);
if (formatter == null)
{
leftScoper = "[";
seperator = ",";
rightScoper = "]";
}
else
{
leftScoper = formatter.LeftScoper.Replace("\\n", "\n");
seperator = formatter.SeperatorString.Replace("\\n", "\n");
rightScoper = formatter.RightScoper.Replace("\\n", "\n");
}
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cab58cf9e8aea91499df0cc05f876361
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Serializer for a single type.
/// </summary>
/// <typeparam name="T">The type to serialize.</typeparam>
public abstract class BasicQcSerializer<T> : IQcSerializer
{
private Func<object, QuantumTheme, string> _recursiveSerializer;
public virtual int Priority => 0;
public bool CanSerialize(Type type)
{
return type == typeof(T);
}
string IQcSerializer.SerializeFormatted(object value, QuantumTheme theme, Func<object, QuantumTheme, string> recursiveSerializer)
{
_recursiveSerializer = recursiveSerializer;
return SerializeFormatted((T)value, theme);
}
protected string SerializeRecursive(object value, QuantumTheme theme)
{
return _recursiveSerializer(value, theme);
}
public abstract string SerializeFormatted(T value, QuantumTheme theme);
}
}

View File

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

View File

@ -0,0 +1,51 @@
using QFSW.QC.Utilities;
using System;
namespace QFSW.QC
{
/// <summary>
/// Serializer for all types that are generic constructions of a single type.
/// </summary>
public abstract class GenericQcSerializer : IQcSerializer
{
/// <summary>
/// The incomplete generic type of this serializer.
/// </summary>
protected abstract Type GenericType { get; }
private Func<object, QuantumTheme, string> _recursiveSerializer;
protected GenericQcSerializer()
{
if (!GenericType.IsGenericType)
{
throw new ArgumentException($"Generic Serializers must use a generic type as their base");
}
if (GenericType.IsConstructedGenericType)
{
throw new ArgumentException($"Generic Serializers must use an incomplete generic type as their base");
}
}
public virtual int Priority => -500;
public bool CanSerialize(Type type)
{
return type.IsGenericTypeOf(GenericType);
}
string IQcSerializer.SerializeFormatted(object value, QuantumTheme theme, Func<object, QuantumTheme, string> recursiveSerializer)
{
_recursiveSerializer = recursiveSerializer;
return SerializeFormatted(value, theme);
}
protected string SerializeRecursive(object value, QuantumTheme theme)
{
return _recursiveSerializer(value, theme);
}
public abstract string SerializeFormatted(object value, QuantumTheme theme);
}
}

View File

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

View File

@ -0,0 +1,31 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Creates a Serializer that is loaded and used by the QuantumSerializer.
/// </summary>
public interface IQcSerializer
{
/// <summary>
/// The priority of this serializer to resolve multiple serializers covering the same type.
/// </summary>
int Priority { get; }
/// <summary>
/// If this serializer can serialize the incoming type.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>If it can serialize.</returns>
bool CanSerialize(Type type);
/// <summary>
/// Serializes the incoming data.
/// </summary>
/// <param name="value">The value to serialize.</param>
/// <param name="theme">The (optional) theme to use for formatted serialization.</param>
/// <param name="recursiveSerializer">Delegate back to the main serializer to allow for recursive serialization of sub elements.</param>
/// <returns>The serialized result.</returns>
string SerializeFormatted(object value, QuantumTheme theme, Func<object, QuantumTheme, string> recursiveSerializer);
}
}

View File

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

View File

@ -0,0 +1,33 @@
using System;
namespace QFSW.QC
{
/// <summary>
/// Serializer for all types inheriting from a single type.
/// </summary>
/// <typeparam name="T">Base type of the types to serialize.</typeparam>
public abstract class PolymorphicQcSerializer<T> : IQcSerializer where T : class
{
private Func<object, QuantumTheme, string> _recursiveSerializer;
public virtual int Priority => -1000;
public bool CanSerialize(Type type)
{
return typeof(T).IsAssignableFrom(type);
}
string IQcSerializer.SerializeFormatted(object value, QuantumTheme theme, Func<object, QuantumTheme, string> recursiveSerializer)
{
_recursiveSerializer = recursiveSerializer;
return SerializeFormatted((T)value, theme);
}
protected string SerializeRecursive(object value, QuantumTheme theme)
{
return _recursiveSerializer(value, theme);
}
public abstract string SerializeFormatted(T value, QuantumTheme theme);
}
}

View File

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

View File

@ -0,0 +1,105 @@
using QFSW.QC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC
{
/// <summary>
/// Handles formatted serialization for console returns.
/// </summary>
public class QuantumSerializer
{
private readonly IQcSerializer[] _serializers;
private readonly Dictionary<Type, IQcSerializer> _serializerLookup = new Dictionary<Type, IQcSerializer>();
private readonly HashSet<Type> _unserializableLookup = new HashSet<Type>();
private readonly Func<object, QuantumTheme, string> _recursiveSerializer;
/// <summary>
/// Creates a Quantum Serializer with a custom set of serializers.
/// </summary>
/// <param name="serializers">The IQcSerializers to use in this Quantum Serializer.</param>
public QuantumSerializer(IEnumerable<IQcSerializer> serializers)
{
_recursiveSerializer = SerializeFormatted;
_serializers = serializers.OrderByDescending(x => x.Priority)
.ToArray();
}
/// <summary>
/// Creates a Quantum Serializer with the default injected serializers
/// </summary>
public QuantumSerializer() : this(new InjectionLoader<IQcSerializer>().GetInjectedInstances())
{
}
/// <summary>
/// Serializes the object with formatting for displaying in the console.
/// </summary>
/// <param name="value">The value to format and serialize.</param>
/// <param name="theme">(Optional) QuantumTheme to use for formatting the results.</param>
/// <returns>The formatted serialization.</returns>
public string SerializeFormatted(object value, QuantumTheme theme = null)
{
if (value is null)
{
return string.Empty;
}
Type type = value.GetType();
string result = string.Empty;
string SerializeInternal(IQcSerializer serializer)
{
try
{
return serializer.SerializeFormatted(value, theme, _recursiveSerializer);
}
catch (Exception e)
{
throw new Exception($"Serialization of {type.GetDisplayName()} via {serializer} failed:\n{e.Message}", e);
}
}
if (_serializerLookup.ContainsKey(type))
{
result = SerializeInternal(_serializerLookup[type]);
}
else if (_unserializableLookup.Contains(type))
{
result = value.ToString();
}
else
{
bool converted = false;
foreach (IQcSerializer serializer in _serializers)
{
if (serializer.CanSerialize(type))
{
result = SerializeInternal(serializer);
_serializerLookup[type] = serializer;
converted = true;
break;
}
}
if (!converted)
{
result = value.ToString();
_unserializableLookup.Add(type);
}
}
if (theme && !string.IsNullOrWhiteSpace(result))
{
result = theme.ColorizeReturn(result, type);
}
return result;
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3ea795e317dd5b64f8b699ef7a640f92
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using System.Collections;
namespace QFSW.QC.Serializers
{
public class DictionaryEntrySerializer : BasicQcSerializer<DictionaryEntry>
{
public override string SerializeFormatted(DictionaryEntry value, QuantumTheme theme)
{
string innerKey = SerializeRecursive(value.Key, theme);
string innerValue = SerializeRecursive(value.Value, theme);
return $"{innerKey}: {innerValue}";
}
}
}

View File

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

View File

@ -0,0 +1,15 @@
using System.Collections;
namespace QFSW.QC.Serializers
{
public class IDictionarySerializer : IEnumerableSerializer<IDictionary>
{
protected override IEnumerable GetObjectStream(IDictionary value)
{
foreach (DictionaryEntry item in value)
{
yield return item;
}
}
}
}

View File

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

View File

@ -0,0 +1,61 @@
using System;
using System.Collections;
using System.Text;
namespace QFSW.QC.Serializers
{
public class IEnumerableSerializer : IEnumerableSerializer<IEnumerable>
{
public override int Priority => base.Priority - 1000;
protected override IEnumerable GetObjectStream(IEnumerable value)
{
return value;
}
}
public abstract class IEnumerableSerializer<T> : PolymorphicQcSerializer<T> where T : class, IEnumerable
{
private readonly Pool<StringBuilder> _builderPool = new Pool<StringBuilder>();
public override string SerializeFormatted(T value, QuantumTheme theme)
{
Type type = value.GetType();
StringBuilder builder = _builderPool.GetObject();
string left = "[";
string seperator = ",";
string right = "]";
if (theme)
{
theme.GetCollectionFormatting(type, out left, out seperator, out right);
}
builder.Clear();
builder.Append(left);
bool firstIteration = true;
foreach (object item in GetObjectStream(value))
{
if (firstIteration)
{
firstIteration = false;
}
else
{
builder.Append(seperator);
}
builder.Append(SerializeRecursive(item, theme));
}
builder.Append(right);
string result = builder.ToString();
_builderPool.Release(builder);
return result;
}
protected abstract IEnumerable GetObjectStream(T value);
}
}

View File

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

View File

@ -0,0 +1,21 @@
#if !NET_STANDARD_2_0
using System.Runtime.CompilerServices;
namespace QFSW.QC.Serializers
{
public class ITupleSerializer : PolymorphicQcSerializer<ITuple>
{
public override string SerializeFormatted(ITuple value, QuantumTheme theme)
{
string[] serializedItems = new string[value.Length];
for (int i = 0; i < value.Length; i++)
{
serializedItems[i] = SerializeRecursive(value[i], theme);
}
return $"({string.Join(", ", serializedItems)})";
}
}
}
#endif

View File

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

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace QFSW.QC.Serializers
{
public class KeyValuePairSerializer : GenericQcSerializer
{
protected override Type GenericType { get; } = typeof(KeyValuePair<,>);
private readonly Dictionary<Type, PropertyInfo> _keyPropertyLookup = new Dictionary<Type, PropertyInfo>();
private readonly Dictionary<Type, PropertyInfo> _valuePropertyLookup = new Dictionary<Type, PropertyInfo>();
public override string SerializeFormatted(object value, QuantumTheme theme)
{
Type type = value.GetType();
PropertyInfo keyProperty;
PropertyInfo valueProperty;
if (_keyPropertyLookup.ContainsKey(type))
{
keyProperty = _keyPropertyLookup[type];
}
else
{
keyProperty = type.GetProperty("Key");
_keyPropertyLookup[type] = keyProperty;
}
if (_valuePropertyLookup.ContainsKey(type))
{
valueProperty = _valuePropertyLookup[type];
}
else
{
valueProperty = type.GetProperty("Value");
_valuePropertyLookup[type] = valueProperty;
}
string innerKey = SerializeRecursive(keyProperty.GetValue(value, null), theme);
string innerValue = SerializeRecursive(valueProperty.GetValue(value, null), theme);
return $"{innerKey}: {innerValue}";
}
}
}

View File

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

View File

@ -0,0 +1,14 @@
{
"name": "QFSW.QC.Serializers",
"references": [
"QFSW.QC"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b2b4ba6eb36b7bb49beadaf8e4db329a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,12 @@
namespace QFSW.QC.Serializers
{
public class StringSerializer : BasicQcSerializer<string>
{
public override int Priority => int.MaxValue;
public override string SerializeFormatted(string value, QuantumTheme theme)
{
return value;
}
}
}

View File

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

View File

@ -0,0 +1,13 @@
using QFSW.QC.Utilities;
using System;
namespace QFSW.QC.Serializers
{
public class TypeSerialiazer : PolymorphicQcSerializer<Type>
{
public override string SerializeFormatted(Type value, QuantumTheme theme)
{
return value.GetDisplayName();
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Serializers
{
public class UnityObjectSerializer : PolymorphicQcSerializer<Object>
{
public override string SerializeFormatted(Object value, QuantumTheme theme)
{
return value.name;
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Serializers
{
public class Vector2IntSerializer : BasicQcSerializer<Vector2Int>
{
public override string SerializeFormatted(Vector2Int value, QuantumTheme theme)
{
return $"({value.x}, {value.y})";
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Serializers
{
public class Vector2Serializer : BasicQcSerializer<Vector2>
{
public override string SerializeFormatted(Vector2 value, QuantumTheme theme)
{
return $"({value.x}, {value.y})";
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Serializers
{
public class Vector3IntSerializer : BasicQcSerializer<Vector3Int>
{
public override string SerializeFormatted(Vector3Int value, QuantumTheme theme)
{
return $"({value.x}, {value.y}, {value.z})";
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Serializers
{
public class Vector3Serializer : BasicQcSerializer<Vector3>
{
public override string SerializeFormatted(Vector3 value, QuantumTheme theme)
{
return $"({value.x}, {value.y}, {value.z})";
}
}
}

View File

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

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace QFSW.QC.Serializers
{
public class Vector4Serializer : BasicQcSerializer<Vector4>
{
public override string SerializeFormatted(Vector4 value, QuantumTheme theme)
{
return $"({value.x}, {value.y}, {value.z}, {value.w})";
}
}
}

View File

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

View File

@ -0,0 +1,11 @@
namespace QFSW.QC
{
/// <summary>
/// Sort order options.
/// </summary>
public enum SortOrder
{
Ascending = 0,
Descending = 1
}
}

View File

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

View File

@ -0,0 +1,25 @@
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
namespace QFSW.QC
{
public class SuggestionDisplay : MonoBehaviour, IPointerClickHandler
{
[SerializeField] private QuantumConsole _quantumConsole = null;
[SerializeField] private TextMeshProUGUI _textArea = null;
public void OnPointerClick(PointerEventData eventData)
{
int linkIndex = TMP_TextUtilities.FindIntersectingLink(_textArea, eventData.position, null);
if (linkIndex >= 0)
{
TMP_LinkInfo link = _textArea.textInfo.linkInfo[linkIndex];
if (int.TryParse(link.GetLinkID(), out int suggestionIndex))
{
_quantumConsole.SetCommandSuggestion(suggestionIndex);
}
}
}
}
}

View File

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

View File

@ -0,0 +1,13 @@
namespace QFSW.QC
{
/// <summary>
/// Which states of the build will be supported.
/// </summary>
public enum SupportedState
{
Always = 0,
Development = 1,
Editor = 2,
Never = 3
}
}

View File

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

View File

@ -0,0 +1,65 @@
using System;
using UnityEngine;
using UnityEngine.Serialization;
#region Preserve Fix
#if UNITY_2018_4_OR_NEWER
using UnityEngine.Scripting;
#else
/// <summary>
/// <para>PreserveAttribute prevents byte code stripping from removing a class, method, field, or property.</para>
/// </summary>
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
public sealed class PreserveAttribute : Attribute
{
}
#endif
#endregion
namespace QFSW.QC
{
[Serializable]
public abstract class TypeFormatter : ISerializationCallbackReceiver
{
public Type Type { get; private set; }
[SerializeField, HideInInspector] private string _type;
[Preserve]
protected TypeFormatter(Type type) { Type = type; }
public void OnAfterDeserialize()
{
Type = Type.GetType(_type, false);
if (Type == null) { Type = QuantumParser.ParseType(_type.Split(',')[0]); }
}
public void OnBeforeSerialize()
{
if (Type != null) { _type = Type.AssemblyQualifiedName; }
}
}
[Serializable]
public class TypeColorFormatter : TypeFormatter
{
[FormerlySerializedAs("color")]
public Color Color = Color.white;
[Preserve]
public TypeColorFormatter(Type type) : base(type) { }
}
[Serializable]
public class CollectionFormatter : TypeFormatter
{
[FormerlySerializedAs("seperatorString")]
public string SeperatorString = ",";
[FormerlySerializedAs("leftScoper")]
public string LeftScoper = "[";
[FormerlySerializedAs("rightScoper")]
public string RightScoper = "]";
[Preserve]
public CollectionFormatter(Type type) : base(type) { }
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4463cd27ce1497447be2ab49507ed2d3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
using UnityEngine;
namespace QFSW.QC.UI
{
[ExecuteInEditMode]
public class BlurShaderController : MonoBehaviour
{
[SerializeField] private Material _blurMaterial = null;
[SerializeField] private float _blurRadius = 1f;
[SerializeField] private Vector2 _referenceResolution = new Vector2(1920, 1080);
private void LateUpdate()
{
if (_blurMaterial)
{
Vector2 resolution = new Vector2(Screen.width, Screen.height);
float correction = resolution.y / _referenceResolution.y;
_blurMaterial.SetFloat("_Radius", _blurRadius);
_blurMaterial.SetFloat("_BlurMultiplier", correction);
}
}
}
}

View File

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

View File

@ -0,0 +1,68 @@
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace QFSW.QC.UI
{
[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
public class DraggableUI : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
[SerializeField] private RectTransform _dragRoot = null;
[SerializeField] private QuantumConsole _quantumConsole = null;
[SerializeField] private bool _lockInScreen = true;
[SerializeField] private UnityEvent _onBeginDrag = null;
[SerializeField] private UnityEvent _onDrag = null;
[SerializeField] private UnityEvent _onEndDrag = null;
private Vector2 _lastPos;
private bool _isDragging = false;
public void OnPointerDown(PointerEventData eventData)
{
_isDragging =
_quantumConsole &&
_quantumConsole.KeyConfig &&
_quantumConsole.KeyConfig.DragConsoleKey.IsHeld();
if (_isDragging)
{
_onBeginDrag.Invoke();
_lastPos = eventData.position;
}
}
public void LateUpdate()
{
if (_isDragging)
{
Transform root = _dragRoot;
if (!root) { root = transform as RectTransform; }
Vector2 pos = Input.mousePosition;
Vector2 delta = pos - _lastPos;
_lastPos = pos;
if (_lockInScreen)
{
Vector2 resolution = new Vector2(Screen.width, Screen.height);
if (pos.x <= 0 || pos.x >= resolution.x) { delta.x = 0; }
if (pos.y <= 0 || pos.y >= resolution.y) { delta.y = 0; }
}
root.Translate(delta);
_onDrag.Invoke();
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (_isDragging)
{
_isDragging = false;
_onEndDrag.Invoke();
}
}
}
}

View File

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

View File

@ -0,0 +1,71 @@
using UnityEngine;
using UnityEngine.UI;
namespace QFSW.QC.UI
{
[ExecuteInEditMode]
public class DynamicCanvasScaler : MonoBehaviour
{
public float RectMagnification
{
get => _rectMagnification;
set
{
if (value > 0)
{
_rectMagnification = value;
}
}
}
[Range(0.5f, 2f)]
[SerializeField] private float _rectMagnification = 1f;
public float ZoomMagnification
{
get => _zoomMagnification;
set
{
if (value > 0)
{
_zoomMagnification = value;
}
}
}
[Range(0.5f, 2f)]
[SerializeField] private float _zoomMagnification = 1f;
[SerializeField] private CanvasScaler _scaler = null;
[SerializeField] private RectTransform _uiRoot = null;
[SerializeField] private Vector2 _referenceResolution = new Vector2(1920, 1080);
private float RootScaler => _rectMagnification / _zoomMagnification;
private float _lastScaler;
private void OnEnable()
{
_lastScaler = RootScaler;
}
private void Update()
{
if (_scaler && _uiRoot)
{
if (RootScaler != _lastScaler)
{
Rect rootRect = new Rect(_uiRoot.offsetMin.x / _lastScaler, _uiRoot.offsetMin.y / _lastScaler, _uiRoot.offsetMax.x / _lastScaler, _uiRoot.offsetMax.y / _lastScaler);
_lastScaler = RootScaler;
_scaler.referenceResolution = _referenceResolution / _zoomMagnification;
_uiRoot.offsetMin = new Vector2(rootRect.x, rootRect.y) * RootScaler;
_uiRoot.offsetMax = new Vector2(rootRect.width, rootRect.height) * RootScaler;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(_uiRoot);
UnityEditor.EditorUtility.SetDirty(_scaler);
#endif
}
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 937bd4b48d20c51489879aabbe372231
timeCreated: 1568116289
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
{
"name": "QFSW.QC.UI",
"references": [
"QFSW.QC",
"Unity.TextMeshPro"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0ea4188915c00fb4688accb5ae29f133
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
using UnityEngine;
using UnityEngine.EventSystems;
namespace QFSW.QC.UI
{
[DisallowMultipleComponent]
public class ResizableUI : MonoBehaviour, IDragHandler
{
[SerializeField] private RectTransform _resizeRoot = null;
[SerializeField] private Canvas _resizeCanvas = null;
[SerializeField] private bool _lockInScreen = true;
[SerializeField] private Vector2 _minSize = new Vector2();
public void OnDrag(PointerEventData eventData)
{
Vector2 minBounds = (_resizeRoot.offsetMin + _minSize) * _resizeCanvas.scaleFactor;
Vector2 maxBounds = _lockInScreen
? new Vector2(Screen.width, Screen.height)
: new Vector2(Mathf.Infinity, Mathf.Infinity);
Vector2 delta = eventData.delta;
Vector2 posCurrent = eventData.position;
Vector2 posLast = posCurrent - delta;
Vector2 posCurrentBounded = new Vector2(
Mathf.Clamp(posCurrent.x, minBounds.x, maxBounds.x),
Mathf.Clamp(posCurrent.y, minBounds.y, maxBounds.y)
);
Vector2 posLastBounded = new Vector2(
Mathf.Clamp(posLast.x, minBounds.x, maxBounds.x),
Mathf.Clamp(posLast.y, minBounds.y, maxBounds.y)
);
Vector2 deltaBounded = posCurrentBounded - posLastBounded;
_resizeRoot.offsetMax += deltaBounded / _resizeCanvas.scaleFactor;
}
}
}

View File

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

View File

@ -0,0 +1,74 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace QFSW.QC.UI
{
[ExecuteInEditMode]
public class ZoomUIController : MonoBehaviour
{
[SerializeField] private float _zoomIncrement = 0.1f;
[SerializeField] private float _minZoom = 0.1f;
[SerializeField] private float _maxZoom = 2f;
[SerializeField] private Button _zoomDownBtn = null;
[SerializeField] private Button _zoomUpBtn = null;
[SerializeField] private DynamicCanvasScaler _scaler = null;
[SerializeField] private QuantumConsole _quantumConsole = null;
[SerializeField] private TextMeshProUGUI _text = null;
private float _lastZoom = -1;
private float ClampAndSnapZoom(float zoom)
{
float clampedZoom = Mathf.Min(_maxZoom, Mathf.Max(_minZoom, zoom));
float snappedZoom = Mathf.Round(clampedZoom / _zoomIncrement) * _zoomIncrement;
return snappedZoom;
}
public void ZoomUp()
{
_scaler.ZoomMagnification = ClampAndSnapZoom(_scaler.ZoomMagnification + _zoomIncrement);
}
public void ZoomDown()
{
_scaler.ZoomMagnification = ClampAndSnapZoom(_scaler.ZoomMagnification - _zoomIncrement);
}
private void Update()
{
if (_quantumConsole && _quantumConsole.KeyConfig)
{
if (_quantumConsole.KeyConfig.ZoomInKey.IsPressed()) { ZoomUp(); }
if (_quantumConsole.KeyConfig.ZoomOutKey.IsPressed()) { ZoomDown(); }
}
}
private void LateUpdate()
{
if (_scaler && _text)
{
float zoom = _scaler.ZoomMagnification;
if (zoom != _lastZoom)
{
_lastZoom = zoom;
int percentage = Mathf.RoundToInt(100 * zoom);
_text.text = $"{percentage}%";
}
}
if (_zoomDownBtn)
{
_zoomDownBtn.interactable = _lastZoom > _minZoom;
}
if (_zoomUpBtn)
{
_zoomUpBtn.interactable = _lastZoom < _maxZoom;
}
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0a3ab78ceb448994ba285874cb280c7b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC.Utilities
{
public static class CollectionExtensions
{
/// <summary>Inverts the key/value relationship between the items in the dictionary.</summary>
/// <returns>Dictionary with the inverted relationship.</returns>
public static Dictionary<TValue, TKey> Invert<TKey, TValue>(this IDictionary<TKey, TValue> source)
{
Dictionary<TValue, TKey> dictionary = new Dictionary<TValue, TKey>();
foreach (KeyValuePair<TKey, TValue> item in source)
{
if (!dictionary.ContainsKey(item.Value))
{
dictionary.Add(item.Value, item.Key);
}
}
return dictionary;
}
/// <summary>Gets a sub array of an existing array.</summary>
/// <param name="index">Index to take the sub array from.</param>
/// <param name="length">The length of the sub array.</param>
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
/// <summary>Skips the last element in the sequence.</summary>
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
using (IEnumerator<T> enumurator = source.GetEnumerator())
{
if (enumurator.MoveNext())
{
for (T value = enumurator.Current; enumurator.MoveNext(); value = enumurator.Current)
{
yield return value;
}
}
}
}
/// <summary>Reverses the order of the sequence.</summary>
public static IEnumerable<T> Reversed<T>(this IReadOnlyList<T> source)
{
for (int i = source.Count - 1; i >= 0; i--)
{
yield return source[i];
}
}
/// <summary>
/// Creates a distinct stream based on a custom predicate.
/// </summary>
/// <typeparam name="TValue">The type of the IEnumerable.</typeparam>
/// <typeparam name="TDistinct">The type of the value to test for distinctness.</typeparam>
/// <param name="source">The source IEnumerable.</param>
/// <param name="predicate">The custom distinct item producer.</param>
/// <returns>The distinct stream.</returns>
public static IEnumerable<TValue> DistinctBy<TValue, TDistinct>(this IEnumerable<TValue> source, Func<TValue, TDistinct> predicate)
{
HashSet<TDistinct> set = new HashSet<TDistinct>();
foreach (TValue value in source)
{
if (set.Add(predicate(value)))
{
yield return value;
}
}
}
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
public static T LastOr<T>(this IEnumerable<T> source, T value)
{
try
{
return source.Last();
}
catch (InvalidOperationException)
{
return value;
}
}
}
}

View File

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

View File

@ -0,0 +1,58 @@
using System.Collections.Concurrent;
using UnityEngine;
namespace QFSW.QC.Utilities
{
public static class ColorExtensions
{
/// <summary>Colors a string using rich formatting.</summary>
/// <returns>The formatted text.</returns>
/// <param name="text">The text to color.</param>
/// <param name="color">The color to add to the text.</param>
public static string ColorText(this string text, Color color)
{
if (string.IsNullOrWhiteSpace(text)) { return text; }
string hexColor = Color32ToStringNonAlloc(color);
return $"<color=#{hexColor}>{text}</color>";
}
private static readonly ConcurrentDictionary<int, string> _colorLookupTable = new ConcurrentDictionary<int, string>();
public static unsafe string Color32ToStringNonAlloc(Color32 color)
{
int colorKey = color.r << 24 | color.g << 16 | color.b << 8 | color.a;
if (_colorLookupTable.ContainsKey(colorKey))
{
return _colorLookupTable[colorKey];
}
char* buffer = stackalloc char[8];
Color32ToHexNonAlloc(color, buffer);
int bufferLength = color.a < 0xFF ? 8 : 6;
string colorText = new string(buffer, 0, bufferLength);
_colorLookupTable[colorKey] = colorText;
return colorText;
}
private static unsafe void Color32ToHexNonAlloc(Color32 color, char* buffer)
{
ByteToHex(color.r, out buffer[0], out buffer[1]);
ByteToHex(color.g, out buffer[2], out buffer[3]);
ByteToHex(color.b, out buffer[4], out buffer[5]);
ByteToHex(color.a, out buffer[6], out buffer[7]);
}
private static void ByteToHex(byte value, out char dig1, out char dig2)
{
dig1 = NibbleToHex((byte)(value >> 4));
dig2 = NibbleToHex((byte)(value & 0xF));
}
private static char NibbleToHex(byte nibble)
{
if (nibble < 10) { return (char)('0' + nibble); }
else { return (char)('A' + nibble - 10); }
}
}
}

View File

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

View File

@ -0,0 +1,84 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace QFSW.QC.Utilities
{
public static class GameObjectExtensions
{
private static readonly Dictionary<string, GameObject> GameObjectCache = new Dictionary<string, GameObject>();
private static readonly List<GameObject> RootGameObjectBuffer = new List<GameObject>();
public static GameObject Find(string name, bool includeInactive = false)
{
if (GameObjectCache.TryGetValue(name, out GameObject obj)
&& obj
&& obj.activeInHierarchy | includeInactive
&& obj.name == name)
{
return obj;
}
obj = GameObject.Find(name);
if (obj)
{
return GameObjectCache[name] = obj;
}
if (includeInactive)
{
int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++)
{
Scene scene = SceneManager.GetSceneByBuildIndex(i);
if (scene.isLoaded)
{
RootGameObjectBuffer.Clear();
scene.GetRootGameObjects(RootGameObjectBuffer);
foreach (GameObject root in RootGameObjectBuffer)
{
obj = Find(name, root);
if (obj)
{
return GameObjectCache[name] = obj;
}
}
}
}
obj = Resources
.FindObjectsOfTypeAll<GameObject>()
.Where(x => !x.hideFlags.HasFlag(HideFlags.HideInHierarchy))
.FirstOrDefault(x => x.name == name);
if (obj)
{
return GameObjectCache[name] = obj;
}
}
return null;
}
public static GameObject Find(string name, GameObject root)
{
if (root.name == name)
{
return root;
}
for (int i = 0; i < root.transform.childCount; i++)
{
GameObject obj = Find(name, root.transform.GetChild(i).gameObject);
if (obj)
{
return obj;
}
}
return null;
}
}
}

View File

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

View File

@ -0,0 +1,22 @@
using UnityEngine;
namespace QFSW.QC
{
public static class LogTypeExtensions
{
public static LoggingThreshold ToLoggingThreshold(this LogType logType)
{
LoggingThreshold severity = LoggingThreshold.Always;
switch (logType)
{
case LogType.Exception: severity = LoggingThreshold.Exception; break;
case LogType.Error: severity = LoggingThreshold.Error; break;
case LogType.Assert: severity = LoggingThreshold.Error; break;
case LogType.Warning: severity = LoggingThreshold.Warning; break;
case LogType.Log: severity = LoggingThreshold.Always; break;
}
return severity;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6173ce0a9ecacf0408e91b424d44ab09
timeCreated: 1554342642
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,370 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace QFSW.QC.Utilities
{
public static class ReflectionExtensions
{
#region Lookup Tables
private static readonly Dictionary<Type, string> _typeDisplayNames = new Dictionary<Type, string>
{
{ typeof(int), "int" },
{ typeof(float), "float" },
{ typeof(decimal), "decimal" },
{ typeof(double), "double" },
{ typeof(string), "string" },
{ typeof(bool), "bool" },
{ typeof(byte), "byte" },
{ typeof(sbyte), "sbyte" },
{ typeof(uint), "uint" },
{ typeof(short), "short" },
{ typeof(ushort), "ushort" },
{ typeof(long), "decimal" },
{ typeof(ulong), "ulong" },
{ typeof(char), "char" },
{ typeof(object), "object" }
};
private static readonly Type[] _valueTupleTypes =
{
typeof(ValueTuple<>),
typeof(ValueTuple<,>),
typeof(ValueTuple<,,>),
typeof(ValueTuple<,,,>),
typeof(ValueTuple<,,,,>),
typeof(ValueTuple<,,,,,>),
typeof(ValueTuple<,,,,,,>),
typeof(ValueTuple<,,,,,,,>)
};
private static readonly Type[][] _primitiveTypeCastHierarchy =
{
new[] { typeof(byte), typeof(sbyte), typeof(char) },
new[] { typeof(short), typeof(ushort) },
new[] { typeof(int), typeof(uint) },
new[] { typeof(long), typeof(ulong) },
new[] { typeof(float) },
new[] { typeof(double) }
};
#endregion
/// <summary>Determines if a type is a delegate.</summary>
/// <returns>If the type is a delegate.</returns>
public static bool IsDelegate(this Type type)
{
if (!typeof(Delegate).IsAssignableFrom(type)) { return false; }
return true;
}
/// <summary>Determines if a type is a strongly typed delegate.</summary>
/// <returns>If the type is a strongly typed delegate.</returns>
public static bool IsStrongDelegate(this Type type)
{
if (!type.IsDelegate()) { return false; }
if (type.IsAbstract) { return false; }
return true;
}
/// <summary>Determines if a field is a delegate.</summary>
/// <returns>If the field is a delegate.</returns>
public static bool IsDelegate(this FieldInfo fieldInfo)
{
return fieldInfo.FieldType.IsDelegate();
}
/// <summary>Determines if a field is a strongly typed delegate.</summary>
/// <param name="fieldInfo">The field to query.</param>
/// <returns>If the field is a strongly typed delegate.</returns>
public static bool IsStrongDelegate(this FieldInfo fieldInfo)
{
return fieldInfo.FieldType.IsStrongDelegate();
}
/// <summary>
/// Determines if the type is a generic type of the given non-generic type.
/// </summary>
/// <param name="nonGenericType">The non-generic type to test against.</param>
/// <returns>If the type is a generic type of the non-generic type.</returns>
public static bool IsGenericTypeOf(this Type genericType, Type nonGenericType)
{
if (!genericType.IsGenericType) { return false; }
return genericType.GetGenericTypeDefinition() == nonGenericType;
}
/// <summary>
/// Determines if the type is a derived type of the given base type.
/// </summary>
/// <param name="baseType">The base type to test against.</param>
/// <returns>If the type is a derived type of the base type.</returns>
public static bool IsDerivedTypeOf(this Type type, Type baseType)
{
return baseType.IsAssignableFrom(type);
}
/// <summary>
/// Determines if an object the given type can be casted to the specified type.
/// </summary>
/// <param name="to">The destination type of the cast.</param>
/// <param name="implicitly">If only implicit casts should be considered.</param>
/// <returns>If the cast can be performed.</returns>
public static bool IsCastableTo(this Type from, Type to, bool implicitly = false)
{
return to.IsAssignableFrom(from) || from.HasCastDefined(to, implicitly);
}
private static bool HasCastDefined(this Type from, Type to, bool implicitly)
{
if ((from.IsPrimitive || from.IsEnum) && (to.IsPrimitive || to.IsEnum))
{
if (!implicitly)
{
return from == to || (from != typeof(bool) && to != typeof(bool));
}
IEnumerable<Type> lowerTypes = Enumerable.Empty<Type>();
foreach (Type[] types in _primitiveTypeCastHierarchy)
{
if (types.Any(t => t == to))
{
return lowerTypes.Any(t => t == from);
}
lowerTypes = lowerTypes.Concat(types);
}
return false; // IntPtr, UIntPtr, Enum, Boolean
}
return IsCastDefined(to, m => m.GetParameters()[0].ParameterType, _ => from, implicitly, false)
|| IsCastDefined(from, _ => to, m => m.ReturnType, implicitly, true);
}
private static bool IsCastDefined(Type type, Func<MethodInfo, Type> baseType, Func<MethodInfo, Type> derivedType, bool implicitly, bool lookInBase)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.Static | (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
MethodInfo[] methods = type.GetMethods(flags);
return methods.Where(m => m.Name == "op_Implicit" || (!implicitly && m.Name == "op_Explicit"))
.Any(m => baseType(m).IsAssignableFrom(derivedType(m)));
}
/// <summary>
/// Dynamically casts an object to the specified type.
/// </summary>
/// <param name="type">The destination type of the cast.</param>
/// <param name="data">The object to cast.</param>
/// <returns>The dynamically casted object.</returns>
public static object Cast(this Type type, object data)
{
if (type.IsInstanceOfType(data))
{
return data;
}
try
{
return Convert.ChangeType(data, type);
}
catch (InvalidCastException)
{
Type srcType = data.GetType();
ParameterExpression dataParam = Expression.Parameter(srcType, "data");
Expression body = Expression.Convert(Expression.Convert(dataParam, srcType), type);
Delegate run = Expression.Lambda(body, dataParam).Compile();
return run.DynamicInvoke(data);
}
}
/// <summary>Determines if the given method is an override.</summary>
/// <returns>If the method is an override.</returns>
public static bool IsOverride(this MethodInfo methodInfo)
{
return methodInfo.GetBaseDefinition().DeclaringType != methodInfo.DeclaringType;
}
/// <summary>
/// Gets if the provider has the specified attribute.
/// </summary>
/// <typeparam name="T">The attribute to test.</typeparam>
/// <param name="provider">The attribute provider.</param>
/// <param name="searchInherited">If base declarations should be searched.</param>
/// <returns>If the attribute is present.</returns>
public static bool HasAttribute<T>(this ICustomAttributeProvider provider, bool searchInherited = true) where T : Attribute
{
try
{
return provider.IsDefined(typeof(T), searchInherited);
}
catch (MissingMethodException)
{
return false;
}
}
/// <summary>
/// Gets a formatted display name for a given type.
/// </summary>
/// <param name="type">The type to generate a display name for.</param>
/// <param name="includeNamespace">If the namespace should be included when generating the typename.</param>
/// <returns>The generated display name.</returns>
public static string GetDisplayName(this Type type, bool includeNamespace = false)
{
if (type.IsArray)
{
int rank = type.GetArrayRank();
string innerTypeName = GetDisplayName(type.GetElementType(), includeNamespace);
return $"{innerTypeName}[{new string(',', rank - 1)}]";
}
if (_typeDisplayNames.ContainsKey(type))
{
string baseName = _typeDisplayNames[type];
if (type.IsGenericType && !type.IsConstructedGenericType)
{
Type[] genericArgs = type.GetGenericArguments();
return $"{baseName}<{new string(',', genericArgs.Length - 1)}>";
}
return baseName;
}
if (type.IsGenericType)
{
Type baseType = type.GetGenericTypeDefinition();
Type[] genericArgs = type.GetGenericArguments();
if (_valueTupleTypes.Contains(baseType))
{
return GetTupleDisplayName(type, includeNamespace);
}
if (type.IsConstructedGenericType)
{
string[] genericNames = new string[genericArgs.Length];
for (int i = 0; i < genericArgs.Length; i++)
{
genericNames[i] = GetDisplayName(genericArgs[i], includeNamespace);
}
string baseName = GetDisplayName(baseType, includeNamespace).Split('<')[0];
return $"{baseName}<{string.Join(", ", genericNames)}>";
}
string typeName = includeNamespace
? type.FullName
: type.Name;
return $"{typeName.Split('`')[0]}<{new string(',', genericArgs.Length - 1)}>";
}
Type declaringType = type.DeclaringType;
if (declaringType != null)
{
string declaringName = GetDisplayName(declaringType, includeNamespace);
return $"{declaringName}.{type.Name}";
}
return includeNamespace
? type.FullName
: type.Name;
}
private static string GetTupleDisplayName(this Type type, bool includeNamespace = false)
{
IEnumerable<string> parts = type
.GetGenericArguments()
.Select(x => x.GetDisplayName(includeNamespace));
return $"({string.Join(", ", parts)})";
}
/// <summary>
/// Determines if two methods from different types have the same signature.
/// </summary>
/// <param name="a">First method</param>
/// <param name="b">Second method</param>
/// <returns><c>true</c> if they are equal</returns>
public static bool AreMethodsEqual(MethodInfo a, MethodInfo b)
{
if (a.Name != b.Name) return false;
ParameterInfo[] paramsA = a.GetParameters();
ParameterInfo[] paramsB = b.GetParameters();
if (paramsA.Length != paramsB.Length) return false;
for (int i = 0; i < paramsA.Length; i++)
{
ParameterInfo pa = paramsA[i];
ParameterInfo pb = paramsB[i];
if (pa.Name != pb.Name) return false;
if (pa.HasDefaultValue != pb.HasDefaultValue) return false;
Type ta = pa.ParameterType;
Type tb = pb.ParameterType;
if (!ta.ContainsGenericParameters && !tb.ContainsGenericParameters)
{
if (ta != tb) return false;
}
}
if (a.IsGenericMethod != b.IsGenericMethod) return false;
if (a.IsGenericMethod && b.IsGenericMethod)
{
Type[] genericA = a.GetGenericArguments();
Type[] genericB = b.GetGenericArguments();
if (genericA.Length != genericB.Length) return false;
for (int i = 0; i < genericA.Length; i++)
{
Type ga = genericA[i];
Type gb = genericB[i];
if (ga.Name != gb.Name) return false;
}
}
return true;
}
/// <summary>
/// Rebases a method onto a new type by finding the corresponding method with an equal signature.
/// </summary>
/// <param name="method">Method to rebase</param>
/// <param name="newBase">New type to rebase the method onto</param>
/// <returns>The rebased method</returns>
public static MethodInfo RebaseMethod(this MethodInfo method, Type newBase)
{
BindingFlags flags = BindingFlags.Default;
flags |= method.IsStatic
? BindingFlags.Static
: BindingFlags.Instance;
flags |= method.IsPublic
? BindingFlags.Public
: BindingFlags.NonPublic;
MethodInfo[] candidates = newBase.GetMethods(flags)
.Where(x => AreMethodsEqual(x, method))
.ToArray();
if (candidates.Length == 0)
{
throw new ArgumentException($"Could not rebase method {method} onto type {newBase} as no matching candidates were found");
}
if (candidates.Length > 1)
{
throw new ArgumentException($"Could not rebase method {method} onto type {newBase} as too many matching candidates were found");
}
return candidates[0];
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 095d8e0dd1a06544485e6498a6907792
timeCreated: 1544062910
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
using System;
namespace QFSW.QC.Utilities
{
public static class StringExtensions
{
public static bool ContainsCaseInsensitive(this string source, string value)
{
if (string.IsNullOrEmpty(source))
{
if (string.IsNullOrEmpty(value)) { return true; }
else { return false; }
}
#if UNITY_WEBGL
return source.ToLower().Contains(value.ToLower());
#else
return source.Contains(value, StringComparison.OrdinalIgnoreCase);
#endif
}
public static bool Contains(this string source, string value, StringComparison comp)
{
return source?.IndexOf(value, comp) >= 0;
}
public static int CountFromIndex(this string source, char target, int index)
{
int count = 0;
for (int i = index; i < source.Length; i++)
{
if (source[i] == target)
{
count++;
}
}
return count;
}
}
}

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ac9ccb14571900847893f62b5ebaa305
timeCreated: 1561417301
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,214 @@
using QFSW.QC.Containers;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC
{
public static class TextProcessing
{
public static readonly char[] DefaultLeftScopers = { '<', '[', '(', '{', '"' };
public static readonly char[] DefaultRightScopers = { '>', ']', ')', '}', '"' };
public static string ReduceScope(this string input, int maxReduction = -1)
{
return input.ReduceScope(DefaultLeftScopers, DefaultRightScopers, maxReduction);
}
public static string ReduceScope(this string input, char leftScoper, char rightScoper, int maxReduction = -1)
{
return input.ReduceScope(leftScoper.AsArraySingle(), rightScoper.AsArraySingle(), maxReduction);
}
public static string ReduceScope<T>(this string input, T leftScopers, T rightScopers, int maxReduction = -1)
where T : IReadOnlyList<char>
{
if (leftScopers.Count != rightScopers.Count)
{
throw new ArgumentException("There must be an equal number of corresponding left and right scopers");
}
if (string.IsNullOrWhiteSpace(input))
{
return string.Empty;
}
string trimmedInput = input.Trim();
if (maxReduction == 0)
{
return trimmedInput;
}
for (int i = 0; i < leftScopers.Count; i++)
{
char leftScoper = leftScopers[i];
char rightScoper = rightScopers[i];
if (leftScoper == rightScoper)
{
string descopedInput = trimmedInput;
bool descoped = false;
while (descopedInput[0] == leftScoper && descopedInput[descopedInput.Length - 1] == rightScoper)
{
descoped = true;
descopedInput = descopedInput.Substring(1, descopedInput.Length - 2).Trim();
if (descopedInput.Length == 0) { break; }
}
for (int j = 0; j < descopedInput.Length; j++)
{
if (descopedInput[j] == leftScoper && (j == 0 || descopedInput[j - 1] != '\\'))
{
descoped = false;
break;
}
}
if (descoped) { return descopedInput.ReduceScope(leftScopers, rightScopers, maxReduction - 1); }
}
else
{
if (trimmedInput[0] == leftScoper && trimmedInput[trimmedInput.Length - 1] == rightScoper)
{
int scope = 1;
for (int j = 1; j < trimmedInput.Length - 1; j++)
{
if (trimmedInput[j] == leftScoper) { scope++; }
else if (trimmedInput[j] == rightScoper) { scope--; }
if (scope == 0)
{
return trimmedInput;
}
}
return trimmedInput.Substring(1, trimmedInput.Length - 2).ReduceScope(leftScopers, rightScopers, maxReduction - 1);
}
}
}
return input;
}
public static string[] SplitScoped(this string input, char splitChar, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, -1, autoReduceScope);
}
public static string[] SplitScoped(this string input, char splitChar, int maxCount, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, DefaultLeftScopers, DefaultRightScopers, maxCount, autoReduceScope);
}
public static string[] SplitScoped(this string input, char splitChar, char leftScoper, char rightScoper, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, leftScoper, rightScoper, -1, autoReduceScope);
}
public static string[] SplitScoped(this string input, char splitChar, char leftScoper, char rightScoper, int maxCount, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, leftScoper.AsArraySingle(), rightScoper.AsArraySingle(), maxCount, autoReduceScope);
}
public static string[] SplitScoped<T>(this string input, char splitChar, T leftScopers, T rightScopers, bool autoReduceScope = false)
where T : IReadOnlyList<char>
{
return input.SplitScoped(splitChar, leftScopers, rightScopers, -1, autoReduceScope);
}
public static string[] SplitScoped<T>(this string input, char splitChar, T leftScopers, T rightScopers, int maxCount, bool autoReduceScope = false)
where T : IReadOnlyList<char>
{
if (autoReduceScope) { input = input.ReduceScope(leftScopers, rightScopers); }
if (string.IsNullOrWhiteSpace(input)) { return Array.Empty<string>(); }
IEnumerable<int> rawSplitIndices = GetScopedSplitPoints(input, splitChar, leftScopers, rightScopers);
int[] splitIndices;
if (maxCount > 0)
{
splitIndices = rawSplitIndices.Take(maxCount - 1).ToArray();
}
else
{
splitIndices = rawSplitIndices.ToArray();
}
// Return single array when no splits occurred
if (splitIndices.Length == 0)
{
return new[] { input };
}
string[] splitString = new string[splitIndices.Length + 1];
int lastSplitIndex = 0;
for (int i = 0; i < splitIndices.Length; i++)
{
splitString[i] = input.Substring(lastSplitIndex, splitIndices[i] - lastSplitIndex).Trim();
lastSplitIndex = splitIndices[i] + 1;
}
splitString[splitIndices.Length] = input.Substring(lastSplitIndex).Trim();
return splitString;
}
public static IEnumerable<int> GetScopedSplitPoints<T>(string input, char splitChar, T leftScopers, T rightScopers)
where T : IReadOnlyList<char>
{
if (leftScopers.Count != rightScopers.Count)
{
throw new ArgumentException("There must be an equal number of corresponding left and right scopers");
}
int[] scopes = new int[leftScopers.Count];
for (int i = 0; i < input.Length; i++)
{
if (i == 0 || input[i - 1] != '\\')
{
for (int j = 0; j < leftScopers.Count; j++)
{
char leftScoper = leftScopers[j];
char rightScoper = rightScopers[j];
if (input[i] == leftScoper && leftScoper == rightScoper) { scopes[j] = 1 - scopes[j]; }
else if (input[i] == leftScoper) { scopes[j]++; }
else if (input[i] == rightScoper) { scopes[j]--; }
}
}
if (input[i] == splitChar && scopes.All(x => x == 0))
{
yield return i;
}
}
}
public static bool CanSplitScoped(this string input, char splitChar)
{
return input.CanSplitScoped(splitChar, DefaultLeftScopers, DefaultRightScopers);
}
public static bool CanSplitScoped(this string input, char splitChar, char leftScoper, char rightScoper)
{
return input.CanSplitScoped(splitChar, leftScoper.AsArraySingle(), rightScoper.AsArraySingle());
}
public static bool CanSplitScoped<T>(this string input, char splitChar, T leftScopers, T rightScopers)
where T : IReadOnlyList<char>
{
return GetScopedSplitPoints(input, splitChar, leftScopers, rightScopers).Any();
}
public static string UnescapeText(this string input, char escapeChar) { return input.UnescapeText(escapeChar.AsArraySingle()); }
public static string UnescapeText<T>(this string input, T escapeChars)
where T : IReadOnlyCollection<char>
{
foreach (char escapeChar in escapeChars)
{
input = input.Replace($"\\{escapeChar}", escapeChar.ToString());
}
return input;
}
}
}

View File

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

View File

@ -0,0 +1,10 @@
<linker>
<assembly fullname="QFSW.QC" preserve="all"/>
<assembly fullname="QFSW.QC.Parsers" preserve="all"/>
<assembly fullname="QFSW.QC.Grammar" preserve="all"/>
<assembly fullname="QFSW.QC.Serializers" preserve="all"/>
<assembly fullname="QFSW.QC.Extras" preserve="all"/>
<assembly fullname="System.Core">
<type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
</assembly>
</linker>

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b3569c4d6f4f03e449d1e3afa1c8afd8
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 59dec0d3cfad221488e6b8ad38e6414d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,219 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "QFSW/Blur"
{
Properties
{
_Color("Main Color", Color) = (1,1,1,1)
_OverlayColor("Overlay Color", Color) = (1,1,1,1)
_MainTex("Tint Color (RGB)", 2D) = "white" {}
_Radius("Radius", Range(0, 20)) = 1
}
Category
{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }
Blend SrcAlpha OneMinusSrcAlpha
SubShader{
GrabPass{
Tags{ "LightMode" = "Always" }
}
Pass{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
fixed4 color : COLOR;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
o.color = v.color;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
uniform float _Radius;
uniform float _BlurMultiplier = 1;
half4 frag(v2f i) : COLOR
{
_Radius *= _BlurMultiplier;
_Radius *= i.color.a;
half4 sum = half4(0,0,0,0);
#define GRABPIXEL(weight, kernelx) tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx * _Radius, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight
sum += GRABPIXEL(0.05, -4.0);
sum += GRABPIXEL(0.09, -3.0);
sum += GRABPIXEL(0.12, -2.0);
sum += GRABPIXEL(0.15, -1.0);
sum += GRABPIXEL(0.18, 0.0);
sum += GRABPIXEL(0.15, +1.0);
sum += GRABPIXEL(0.12, +2.0);
sum += GRABPIXEL(0.09, +3.0);
sum += GRABPIXEL(0.05, +4.0);
return sum;
}
ENDCG
}
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f {
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
fixed4 color : COLOR;
};
v2f vert(appdata_t v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
o.color = v.color;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
uniform float _Radius;
uniform float _BlurMultiplier = 1;
half4 frag(v2f i) : COLOR{
_Radius *= _BlurMultiplier;
_Radius *= i.color.a;
half4 sum = half4(0,0,0,0);
#define GRABPIXEL(weight,kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely*_Radius, i.uvgrab.z, i.uvgrab.w))) * weight
sum += GRABPIXEL(0.05, -4.0);
sum += GRABPIXEL(0.09, -3.0);
sum += GRABPIXEL(0.12, -2.0);
sum += GRABPIXEL(0.15, -1.0);
sum += GRABPIXEL(0.18, 0.0);
sum += GRABPIXEL(0.15, +1.0);
sum += GRABPIXEL(0.12, +2.0);
sum += GRABPIXEL(0.09, +3.0);
sum += GRABPIXEL(0.05, +4.0);
return sum;
}
ENDCG
}
GrabPass{
Tags{ "LightMode" = "Always" }
}
Pass{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
float4 color: COLOR;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvmain : TEXCOORD1;
float4 color : COLOR;
};
float4 _MainTex_ST;
v2f vert(appdata_t v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
o.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);
o.color = v.color;
return o;
}
fixed4 _Color;
fixed4 _OverlayColor;
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
sampler2D _MainTex;
half4 frag(v2f i) : COLOR
{
half4 blurredCol = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab)); // Gets the color of what is behind it and blurred
half4 texCol = tex2D(_MainTex, i.uvmain); // Gets the color of the supplied texture
half4 tint = texCol * _Color; // Gets the tint color to apply
half4 col = blurredCol * tint; // Tints the color
col = col * (1 - _OverlayColor.a) + _OverlayColor * _OverlayColor.a; // Blends it with the overlay color
col *= i.color;
col = blurredCol * (1 - texCol.a) + col * texCol.a; // Blends it using the tex color so transparent regions stay transparent
return col;
}
ENDCG
}
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 3fba250d711269d47864fade9116867c
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4750aea94a3727649a4fd1df0cd87fc5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@ -0,0 +1,121 @@
fileFormatVersion: 2
guid: 0a00d33b88ebe3f4eb5dfb0d2a1c0726
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: 4
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 1
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: XboxOne
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: a493569414aca02479e5838bc4b201dc
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -0,0 +1,143 @@
fileFormatVersion: 2
guid: 3b4c5868913f036409451b4765150dd3
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 74a7715c93db7b740bb6fc2b674fb937
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,121 @@
fileFormatVersion: 2
guid: b4d81ddc1591c4948b549eda7f0e9c50
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: 4
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 1
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: XboxOne
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 01ef2571c3a7dca4c9d87e3445ea2964
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,143 @@
fileFormatVersion: 2
guid: 99f5a2cb8513e1a49819dc39f036320a
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 78f26b5a2fd9c8a449665effcf2d1a33
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,143 @@
fileFormatVersion: 2
guid: b765d10f7f039904ebfb9e4db1f949b0
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 700
spriteBorder: {x: 45, y: 45, z: 45, w: 45}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 9aadd7a7f818c2444a85fa992475615a
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
This asset is governed by the Asset Store EULA; however, the following components are governed by the licenses indicated below:
A. Office Code Pro
- OFL: see Fonts/LICENSE.txt
B. CSharpCompiler
- MIT: see Extras/exec/CSharpCompiler/LICENSE.txt

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c73db89ef64357640b17d95065ca2626
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,334 @@
V2.5.4
Addition 0121: Console zoom can now be triggered with hotkeys (default: ctrl+ and ctrl-)
Addition 0122: Hotkey for dragging the console is now configurable (default: shift click)
Addition 0123: AreActionsExecuting added to query if the console is currently executing actions
Change 0064: Optimised input handling under new input system
Bug Fix 0064: Fixed bug where speechmarks were not parsed properly for GameObject arguments
V2.5.3
Addition 0120: New core command: max-logs
Change 0063: QC will now ignore compiler generated types during table generation resulting in faster load times
Bug Fix 0063: Fixed a native crash that would occur under IL2CPP with GeNa installed
V2.5.2
Addition 0119: Added maximum log size setting to prevent huge logs from crashing the console
Change 0062: Default prefab now has a maximum log count of 1024 logs
Bug Fix 0062: Fixed grammar in error message for when there are no invocation targets
V2.5.1
Addition 0118: Included SRP friendly prefab and theme variants: 'Quantum Console (SRP)' and 'Default Theme (SRP)'
Bug Fix 0061: Fixed a case where loggers could initialize too late causing errors when initialize on startup is disabled
V2.5.0
Addition 0113: [CommandPrefix] can now be applied to entire assemblies
Addition 0114: New extra command: http.get
Addition 0115: New extra command: http.put
Addition 0116: New extra command: http.post
Addition 0117: New extra command: http.delete
Change 0058: Non static invocation will now throw an exception if no targets could be found
Change 0059: Non static non MonoBehaviour commands not using MonoTargetType.Registry are now explicitly rejected
Change 0060: call-instance now unwraps the inner exception
Change 0061: man now uses pretty printing for declaring type names
Bug Fix 0059: Fixed a bug where JSON strings would be parsed as expression bodies
Bug Fix 0060: Fixed nested type names not being serialized correctly
V2.4.7
Bug Fix 0057: Console display will no longer incorrectly parse rich tags from invoked command
Bug Fix 0058: Generic class commands now still work when the command method has overloads
V2.4.6
Addition 0110: Commands declared in generic classes are now supported
Addition 0111: New extra command: quit
Addition 0112: New extra command: capture-screenshot
Change 0057: Improved the default format for timestamps
Bug Fix 0055: Fixed issues with new input system when the device does not support a keyboard
Bug Fix 0056: Fixed false positives of the IL2CPP primitive operator warning
V2.4.5
Change 0056: The OnLog event now receives an ILog, containing both the log text and type
Bug Fix 0054: Fixed a bug where destroyed objects were not removed from the registry
V2.4.4
Bug Fix 0053: Fixed a bug where the max log lines setting would not work properly
V2.4.3
Bug Fix 0052: Fixed ReadKey action on new input system
V2.4.2
Note: In order to keep QC looking the same as before when using the included Blur material, set the Panel Color in the theme to white
Change 0055: The blur shader now responds to vertex colors, meaning it is affected by the color of the Image/Sprite renderer
Bug Fix 0051: Fixed the QC_DISABLED preprocessor
V2.4.1
Addition 0109: Command suggestions are now clickable
Change 0054: call-static now unwraps the inner exception
Bug Fix 0048: Fixed instances of the command name not including prefixes in its manual
Bug Fix 0049: Fixed an issue where changes to the console scaling in edit mode would be lost
Bug Fix 0050: Resolved an error that could occur during certain operator syntax checks
V2.4.0
Note: due to restructuring it is recommended that you remove your current installation before updating
Addition 0106: Added the Command Actions system
Addition 0107: Logs can now be made to the console without a leading newline
Addition 0108: Timestamp format can now be configured via the QuantumTheme
Change 0052: Blank log lines are now allowed
Change 0053: Hardcoded color formatting has been removed
Bug Fix 0047: Fixed the banner being rendered incorrectly on HighDPI displays
V2.3.7
Addition 0105: Native support for new input system
V2.3.6
Change 0051: Optimised text processing code to reduce allocations
Bug Fix 0046: Type parser/serializer now support tuple syntax
V2.3.5
Change 0050: Optimised get-object-info
Addition 0101: Console UI can now be resized at runtime
Addition 0102: New extra command: get-scene-hierarchy
Addition 0103: New extra command: write-file
Addition 0104: New extra command: read-file
V2.3.4
Change 0046: Improved hotkey handling so there are no longer false positives or collisions
Change 0047: Improved when the console steals input and no longer does it on mobile platforms
Change 0048: Improved performance of GameObject parser
Change 0049: Reverted the invocation message changes introduced in V2.3.3
Addition 0097: New user extendable preprocessor system
Addition 0098: New extra command: call-static
Addition 0099: New extra command: call-instance
Addition 0100: Addition of [NoInject] for all injection based systems
Bug Fix 0041: Fixed a singleton QC destroying itself if the gameobject is disabled then enabled
Bug Fix 0042: Fixed the GameObject parser being unable to parse inactive DontDestroyOnLoad objects
Bug Fix 0043: Fixed IL2CPP alloc crash that could be encountered in a multi target command invocation
Bug Fix 0044: Inner exceptions in binary operator invocation are now properly displayed in the console
Bug Fix 0045: The AutoScroll:Always option now works
V2.3.3
Brand new documentation: https://qfsw.co.uk/docs/QC/
Change 0045: Improved invocation messages for commands without a return
Addition 0093: New MonoTargetType: SingleInactive
Addition 0094: New MonoTargetType: AllInactive
Addition 0095: Added logging level option and command
Addition 0096: Added TryAddCommand to processor for runtime addition of commands
Bug Fix 0039: Primitive parser now behave correctly on non English locales
Bug Fix 0040: Fixed primitive operators with high stripping level enabled
V2.3.2
Change 0043: Optimised command table generation
Change 0044: Changed sort order so that it is higher than default
Bug Fix 0035: Fixed a bug where fuzzy case sensitive command suggestion sorting would not work
Bug Fix 0036: Primitive casts in expression bodies now work in IL2CPP
Bug Fix 0037: Fixed [Preserve] error reported in specific 2018.3 versions
Bug Fix 0038: Fixed a bug where the UI control panel would not receive theme updates
V2.3.1
Change 0043: Vectors and Quaternions now use recursive parsing for their constituents
Change 0044: Boolean parser now accepts yes and no values
Bug Fix 0035: Reworked scoping so that nested collections using different scope tokens works again e.g. [(1,2),(3,4)]
Bug Fix 0036: Fixed many stripping issues when high stripping level is enabled
V2.3.0
Upgrade Note: TMP and 2018.3+ are now required, full upgrade guide at https://www.qfsw.co.uk/docs/QC/Upgrade230/
Addition 0071: UI can now be scaled at runtime
Addition 0072: New user extendable serialization system
Addition 0073: ITuples can now be serialized (.NET 4.6 compatibility level only)
Addition 0074: Vector2Int/Vector3Int can now be serialized
Addition 0075: New user extendable parser system
Addition 0076: HashSets/LinkedList/ConcurrentStack/ConcurrentQueue/ConcurrentBags are now a parseable arguments
Addition 0077: IEnumerable/ICollection/IReadOnlyCollection/IList/IReadOnlyLists are now a parseable arguments
Addition 0078: Vector2Int/Vector3Ints are now a parseable arguments
Addition 0079: Tuple/ValueTuples are now parseable arguments
Addition 0080: New user extendable custom grammar construct system
Addition 0081: Expression bodies can now be used to use one command as an argument to another - {expr}
Addition 0082: Nullable expression bodies allow null values to pass through - {expr}?
Addition 0083: Boolean values/expressions can now be negated with !
Addition 0084: Binary operators can now be used in the console input (+ - * / %)
Addition 0085: QC now has a proper singleton mode
Addition 0086: New [QcIgnore] attribute which informs QC to ignore classes/assemblies
Addition 0087: New command: user-commands
Addition 0088: New command: qc-script-extern
Addition 0089: New extra command: instantiate-prefab
Addition 0090: New extra command: instantiate-model
Addition 0091: New extra command: destroy-component
Addition 0092: Stadia and Lumin platforms have been added to the command platforms
Change 0032: Visual theme of the UI has been greatly improved
Change 0033: Command table generation is now multithreaded and over 10x faster
Change 0034: Parsing and serialization is now significantly faster
Change 0035: Improved console text regeneration so that it happens at most once per frame
Change 0036: Internal naming conventions and APIs have been overhauled
Change 0037: Custom inspectors now work properly on 2019.3+
Change 0038: man command now displays the declaring type(s)
Change 0039: get-object-info command now displays direct children
Change 0040: Key configuration has been moved to QuantumKeyConfiguration
Change 0041: Increased the scroll sensitivity
Change 0042: [CommandPrefix] can now be used on structs
Bug Fix 0025: Fixed the drag not working
Bug Fix 0026: Fixed a bug where the targets of a multicast command would not be alphanumerically ordered
Bug Fix 0027: Multidimensional array type names are now serialized correctly
Bug Fix 0028: Multidimensional array type names are now parsed correctly
Bug Fix 0029: Fixed a concurrency bug with QC's async logging
Bug Fix 0030: Job counter UI now receives theme changes
Bug Fix 0031: Fixed a bug where generics could trigger rich formatting in the input field
Bug Fix 0032: Fixed a bug where ColorText would fail on IL2CPP with non opaque colors
Bug Fix 0033: BadImageFormatException issue has been tracked upstream to Mono and is now ignored
Bug Fix 0034: Removed leading blank line in get-object-info
V2.2.2
Addition 0064: Quantum Console now has a brand new look
Addition 0065: Non static commands can now be used on non-monobehaviours (Quantum Registry must be used)
Addition 0066: Formatting in registry errors is now greatly improved
Addition 0067: Quantum Theme can now take a custom material and color
Addition 0068: Quantum Console can now be dragged (default shift + click)
Addition 0069: New extra command: start-coroutine
Addition 0070: New extra command: msaa
Change 0029: Improved readability of collection formatters on dark theme
Change 0030: Improved readability Quantum Theme inspector on dark theme
Change 0031: Improved extra command get-object-info
Bug Fix 0022: Improved stability of TMP upgrader
Bug Fix 0023: Fixed stability issues with theme application
Bug Fix 0024: Fixed a bug where QC would complain about weak delegates even if they were not being used as a command
V2.2.1
Addition 0064: New MonoTargetType: Singleton
Addition 0065: New extra command: bind
Addition 0066: New extra command: unbind
Addition 0067: New extra command: unbind-all
Addition 0068: New extra command: display-bindings
Change 0029: Many parts of Quantum Console have been massively optimised
Bug Fix 0022: Fixed a bug where the input field would not focus the first time the console is opened
V2.2.0
Addition 0060: Added TMP support
Addition 0061: Added support for backwards command suggestion cycling
Addition 0062: New console command: verbose-errors
Addition 0063: New console command: verbose-logging
Change 0026: Improved bool parsing to support on/off and 1/0
Change 0027: Errors are now more user friendly when using enum arguments
Change 0028: Optimised text generation to reduce string size
V2.1.3
Addition 0057: Font can now be controlled from the Quantum Theme
Addition 0058: Added QC_DISABLE_BUILTIN_ALL to disable all built in commands
Addition 0059: Added QC_DISABLE_BUILTIN_EXTRA to disable all extra commands
Bug Fix 0021: Fixed a bug where abstract and virtual commands would cause duplicates to appear
V2.1.2
Addition 0039: Maximum number of logs can now be restricted
Addition 0040: New extra command: enum-info (added enum colouring to default theme)
Addition 0041: New extra command: all-scenes
Addition 0042: New extra command: loaded-scenes
Addition 0043: New extra command: active-scene
Addition 0044: New extra command: set-active-scene
Addition 0045: New extra command: unload-scene
Addition 0046: New extra command: unload-scene-index
Addition 0047: New extra command: max-fps
Addition 0048: New extra command: vsync
Addition 0049: New extra command: set-resolution
Addition 0050: New extra command: current-resolutin
Addition 0051: New extra command: supported-resolutions
Addition 0052: New extra command: fullscreen
Addition 0053: New extra command: screen-dpi
Addition 0054: New extra command: screen-orientation
Addition 0055: New extra command: time-scale
Addition 0056: Added MobilePlatforms shortcut to Platform
Change 0020: QC no longer needs the .NET 4.6 API compatability level and only the scripting backend
Change 0021: QC now internally uses string builders for improved performance
Change 0022: Default theme now has IEnumerators default to line seperation and ICollections to [a, b, c]
Change 0023: Extra commands now use their own assembly
Change 0024: Scene commands have been moved to their own file
Change 0025: Scene load/unload commands are now async
Bug Fix 0016: Fixed a bug where auto named commands and command prefixes would not work on fields or classes in Roslyn
Bug Fix 0017: Fixed a bug where initialize on startup option would not hide the console
Bug Fix 0018: Fixed a bug where whitespace would be treated as args
Bug Fix 0019: Fixed the Switch enum value having the incorrect bit value
Bug Fix 0020: Fixed .NET auto upgrader
V2.1.1
Addition 0037: Added [CommandPrefix] attribute. Adding this to a class will prepend its prefix to all commands created within the class
Addition 0038: Console will now automatically open when a log of the specified severity is encountered
V2.1.0
Addition 0036: Async commands are now fully supported
Change 0017: exec and exec-extern are now async commands
Change 0018: exec and all related code has been moved to Extras/exec for easy removal if desired
Change 0019: exec will no longer appear on iOS, PS4, Switch or Xbox One
Bug Fix 0013: Input text no longer becomes highlighted when using the command history
Bug Fix 0014: get-object-info command will now throw a proper error on failure
Bug Fix 0015: Fixed a bug where TypeFormatters and thus theme objects would be corrupted when moving across specific Unity versions
V2.0.2
Addition 0033: Added visibility toggle for scene view mode
Addition 0034: QC can now be easily disabled on release builds, builds etc.
Addition 0035: Added verbose modes to exception handling and log interception
V2.0.1
Addition 0030: Async and thread safe support for logs and Debug.Logs
Addition 0031: Option to initialise the console on startup without activating it
Addition 0032: Scene persistence option
Change 0016: Exposed the Toggle function to the public API
Bug Fix 0011: Fixed a bug where logs and Debug.Logs occuring before the console was initialised would be dropped
Bug Fix 0012: Stopped editor warnings on 2018.3+
V2.0.0
Note: It is recommended you remove Quantum Console from your project before downloading this update
Addition 0010: Generic commands are now supported
Addition 0011: Macros are now supported
Addition 0012: New Quantum Theme system; themes are fully customisable and control formatting of returns
Addition 0013: Case sensitivity is now an option for command autocompletion
Addition 0014: Optional popup display for suggested commands
Addition 0015: Namespace system has been added for type resolution
Addition 0016: Nested collections are now supported as arguments
Addition 0017: Stacks and Queues are now supported as arguments
Addition 0018: Type parser now supports primitives, arrays, generics and namespaces
Addition 0019: Type formatter has been massively improved
Addition 0020: Formatter now supports Dictionaries and KeyValuePairs
Addition 0021: 'null' is now supported as an argument for all reference types
Addition 0022: Toggleable timestamps for logs
Addition 0023: Autoscrolling feature for the Quantum Console
Addition 0024: Improved formatting for inputted commands in the console log
Addition 0025: New extra command: add-component
Addition 0026: New extra command: teleport-relative
Addition 0027: New extra command: set-parent
Addition 0028: New extra command: rotate
Addition 0029: Brand new demo scene
Change 0003: Return serialization has been massively improved
Change 0004: Invocation and serialiazation have been decoupled
Change 0005: Text processing has been hugely improved, properly supporting escape characters and scope control
Change 0006: Color and vector parsing has been improved
Change 0007: Scroll sensitivity has been increased
Change 0008: Source has been restructured
Change 0009: All parsing related functionality has been moved to QuantumParser
Change 0010: All registry related functionality has been moved to QuantumRegistry
Change 0011: Registry commands are now generic
Change 0012: Formatting in get-object-info has been improved
Change 0013: CTRL and CMD are now one option in keybindings, and SHIFT has been added as a modifier
Change 0014: Removed various command aliases
Change 0015: exec and exec-extern have been removed from WebGL
Bug Fix 0002: Autocompletion sort order for fuzzy searches has been improved
Bug Fix 0003: Command history is no longer cleared on console clear
Bug Fix 0004: Fixed a bug where 'double' type would be displayed as 'int'
Bug Fix 0005: Exception style logs are now formatted correctly
Bug Fix 0006: Fixed GetRegistryContents<T>
Bug Fix 0007: Fixed a bug where writer commands were generated for readonly/const fields
Bug Fix 0008: CloseOnSubmit now works
Bug Fix 0009: Fixed a bug where commands with unsupported array typed parameters would not be rejected
Bug Fix 0010: Fixed a bug where the inspector would throw errors during playmode
V1.0.2
Addition 0006: Arrays are now a supported parameter type
Addition 0007: Lists are now a supported paramater type
Addition 0008: Processor now properly formats generic types
Addition 0009: Arrays, Lists and all other IEnumerables will now be properly formatted when returned
Change 0002: Improved internal assemblies
V1.0.1
Addition 0002: Added support for delegate commands
Addition 0003: Enums are now a supported parameter type
Addition 0004: New extra command: load-scene
Addition 0005: New extra command: send-message
Change 0001: Improved internal code organisation
Bug Fix 0001: Better supports 2018.3b
V1.0.0
Initial release

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: da7b1060a39034f64b9568c74ba675d8
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ed61ebfbaaf591f40a51900ce1a5c898
timeCreated: 1541374714
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -231,6 +231,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: b64a96362efa9ba44802d57e2e074f27, type: 3} m_Script: {fileID: 11500000, guid: b64a96362efa9ba44802d57e2e074f27, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_defaultValue:
_prefix:
_postfix: _postfix:
--- !u!1 &9027889519720641281 --- !u!1 &9027889519720641281
GameObject: GameObject:
@ -438,8 +440,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 28b9e93c12a050746982d0ae2c8dab98, type: 3} m_Script: {fileID: 11500000, guid: 28b9e93c12a050746982d0ae2c8dab98, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_scoreAdd: 0
_timeBonus: 30 _timeBonus: 30
_selfDestroy: 0
--- !u!1 &9027889519819089751 --- !u!1 &9027889519819089751
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -752,37 +754,37 @@ PrefabInstance:
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalPosition.x propertyPath: m_LocalPosition.x
value: -577.1286 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalPosition.y propertyPath: m_LocalPosition.y
value: -183.81604 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalPosition.z propertyPath: m_LocalPosition.z
value: 932.67645 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalRotation.w propertyPath: m_LocalRotation.w
value: 0.6990287 value: 1
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalRotation.x propertyPath: m_LocalRotation.x
value: -0.17240688 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalRotation.y propertyPath: m_LocalRotation.y
value: -0.6825062 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
propertyPath: m_LocalRotation.z propertyPath: m_LocalRotation.z
value: -0.1257779 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159, - target: {fileID: 925482383945416140, guid: 12c9d9623955d4e48825c5b19ea0b159,
type: 3} type: 3}
@ -834,7 +836,8 @@ PrefabInstance:
propertyPath: m_Enabled propertyPath: m_Enabled
value: 0 value: 0
objectReference: {fileID: 0} objectReference: {fileID: 0}
m_RemovedComponents: [] m_RemovedComponents:
- {fileID: 925482383945416143, guid: 12c9d9623955d4e48825c5b19ea0b159, type: 3}
m_SourcePrefab: {fileID: 100100000, guid: 12c9d9623955d4e48825c5b19ea0b159, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 12c9d9623955d4e48825c5b19ea0b159, type: 3}
--- !u!4 &5145598549098378746 stripped --- !u!4 &5145598549098378746 stripped
Transform: Transform:

View File

@ -1138,7 +1138,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 4a14752bce1e85a47ad22bd4e89cbe2f, type: 3} m_Script: {fileID: 11500000, guid: 4a14752bce1e85a47ad22bd4e89cbe2f, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_postfix: _defaultValue:
_prefix:
_postfix: " \u044D\u043D."
--- !u!1 &1647452393 --- !u!1 &1647452393
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -3639,11 +3641,11 @@ MonoBehaviour:
targetRigidbody2D: {fileID: 0} targetRigidbody2D: {fileID: 0}
targetTransform: {fileID: 7985013476349946332} targetTransform: {fileID: 7985013476349946332}
_result: _result:
position: {x: 104.326294, y: -5.5460205, z: -1932.3633} position: {x: 0, y: 0, z: 0}
up: {x: 0, y: 1, z: 0} up: {x: 0, y: 0, z: 0}
forward: {x: -0.001450564, y: 0.002455365, z: 0.99999595} forward: {x: 0, y: 0, z: 0}
color: {r: 1, g: 1, b: 1, a: 1} color: {r: 0, g: 0, b: 0, a: 0}
size: 1 size: 0
percent: 0 percent: 0
_finalResult: _finalResult:
position: {x: 104.326294, y: -5.5460205, z: -1932.3633} position: {x: 104.326294, y: -5.5460205, z: -1932.3633}
@ -3749,7 +3751,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_mainPanel: {fileID: 2874212760557784321} _mainPanel: {fileID: 2874212760557784321}
_tutorPanel: {fileID: 1955516150} _tutorPanel: {fileID: 9202471761446870197}
_progressBarImage: {fileID: 3460062592487292032} _progressBarImage: {fileID: 3460062592487292032}
LeftTrigger: {fileID: -5982496924579745919, guid: e39f4b35a6db18348b41eb0262520e69, LeftTrigger: {fileID: -5982496924579745919, guid: e39f4b35a6db18348b41eb0262520e69,
type: 3} type: 3}
@ -3931,6 +3933,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: b64a96362efa9ba44802d57e2e074f27, type: 3} m_Script: {fileID: 11500000, guid: b64a96362efa9ba44802d57e2e074f27, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_defaultValue:
_prefix:
_postfix: _postfix:
--- !u!1 &7985013476380022744 --- !u!1 &7985013476380022744
GameObject: GameObject:
@ -4190,6 +4194,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 726321230e0043c409946c98a7055152, type: 3} m_Script: {fileID: 11500000, guid: 726321230e0043c409946c98a7055152, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_defaultValue:
_prefix:
_postfix: " \u043A\u043C/\u0447" _postfix: " \u043A\u043C/\u0447"
--- !u!1 &7985013476728618132 --- !u!1 &7985013476728618132
GameObject: GameObject:
@ -7506,201 +7512,6 @@ PrefabInstance:
m_Modification: m_Modification:
m_TransformParent: {fileID: 7185685602648263643} m_TransformParent: {fileID: 7185685602648263643}
m_Modifications: m_Modifications:
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedFill
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.x
value: 3.1465978e-13
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.z
value: 2.201165e-11
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.x
value: 0.00828664
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.y
value: 18.494493
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.z
value: -0.11507933
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.a
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.r
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedRectSize.x
value: 663.338
objectReference: {fileID: 0}
- target: {fileID: 2197034094981908278, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedRectSize.y
value: 63.013
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedFill
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.x
value: 3.1465978e-13
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.z
value: 2.201165e-11
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.x
value: 0.00828664
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.y
value: 18.494493
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.z
value: -0.11507933
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.a
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.r
value: 0.71158946
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedRectSize.x
value: 663.338
objectReference: {fileID: 0}
- target: {fileID: 3068211644373382748, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedRectSize.y
value: 63.013
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedFill
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.x
value: 3.1465978e-13
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedUp.z
value: 2.201165e-11
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.x
value: 0.009404147
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.y
value: -190.99933
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedPos.z
value: 0.14092928
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.a
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedColor.r
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedRectSize.x
value: 271.883
objectReference: {fileID: 0}
- target: {fileID: 4913003076036444960, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: savedRectSize.y
value: 271.883
objectReference: {fileID: 0}
- target: {fileID: 6365554433948213058, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: m_Alpha
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9202471761387014830, guid: 4a88f6f36bda305499bdcac5bcc22d90, - target: {fileID: 9202471761387014830, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3} type: 3}
propertyPath: m_Pivot.x propertyPath: m_Pivot.x
@ -7811,11 +7622,6 @@ PrefabInstance:
propertyPath: m_Name propertyPath: m_Name
value: VisorCanvas value: VisorCanvas
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 9202471761387014834, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
propertyPath: angle
value: 180
objectReference: {fileID: 0}
- target: {fileID: 9202471761387014835, guid: 4a88f6f36bda305499bdcac5bcc22d90, - target: {fileID: 9202471761387014835, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3} type: 3}
propertyPath: m_Camera propertyPath: m_Camera
@ -7823,24 +7629,6 @@ PrefabInstance:
objectReference: {fileID: 7185685602646741319} objectReference: {fileID: 7185685602646741319}
m_RemovedComponents: [] m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 4a88f6f36bda305499bdcac5bcc22d90, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 4a88f6f36bda305499bdcac5bcc22d90, type: 3}
--- !u!1 &1184396203059313786 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 8059874730754158137, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
m_PrefabInstance: {fileID: 9202471760028783171}
m_PrefabAsset: {fileID: 0}
--- !u!225 &1955516150
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1184396203059313786}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!225 &2874212760557784321 stripped --- !u!225 &2874212760557784321 stripped
CanvasGroup: CanvasGroup:
m_CorrespondingSourceObject: {fileID: 6365554433948213058, guid: 4a88f6f36bda305499bdcac5bcc22d90, m_CorrespondingSourceObject: {fileID: 6365554433948213058, guid: 4a88f6f36bda305499bdcac5bcc22d90,
@ -7859,3 +7647,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
--- !u!225 &9202471761446870197 stripped
CanvasGroup:
m_CorrespondingSourceObject: {fileID: 1955516150, guid: 4a88f6f36bda305499bdcac5bcc22d90,
type: 3}
m_PrefabInstance: {fileID: 9202471760028783171}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6c1eeffb375f85242b020d6da947ffc4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,131 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &3809675095417365283
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1011916610372698401, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: Prefix
value: '+ '
objectReference: {fileID: 0}
- target: {fileID: 1011916610372698401, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: Postfix
value: " \u043E\u0447\u043A\u043E\u0432"
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_SizeDelta.x
value: 209.39
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_SizeDelta.y
value: 100
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalPosition.z
value: -0.1
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchoredPosition.x
value: -54.7
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -82.3
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4969609539872308112, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_Name
value: UIPopup (Score)
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: d5c0d58890a7e7840b47863ed98e5c6e, type: 3}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 02053ceef6c8f96458984eefd26124b0
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,131 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &7864455548232232849
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1011916610372698401, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: Prefix
value: '+ '
objectReference: {fileID: 0}
- target: {fileID: 1011916610372698401, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: Postfix
value: " \u0441\u0435\u043A"
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_SizeDelta.x
value: 209.39
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_SizeDelta.y
value: 100
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalPosition.z
value: -0.1
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchoredPosition.x
value: -54.7
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -82.3
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2756876663177930824, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4969609539872308112, guid: d5c0d58890a7e7840b47863ed98e5c6e,
type: 3}
propertyPath: m_Name
value: UIPopup (Time)
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: d5c0d58890a7e7840b47863ed98e5c6e, type: 3}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c86fad07ffc84b14f854c246948dbfac
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,222 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &200318615579008512
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7333867837070813280}
- component: {fileID: 4997159387300029257}
- component: {fileID: 5337496564380876370}
- component: {fileID: 2004703880053495574}
- component: {fileID: 7234202513872361131}
m_Layer: 0
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7333867837070813280
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 200318615579008512}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2756876663177930824}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4997159387300029257
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 200318615579008512}
m_CullTransparentMesh: 1
--- !u!114 &5337496564380876370
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 200318615579008512}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: New Text
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 45.8
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 1
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &2004703880053495574
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 200318615579008512}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e62188adca544cf1b96ccf1630f15f9, type: 3}
m_Name:
m_EditorClassIdentifier:
DoNotTesselate: 0
savedPos: {x: 0, y: 0, z: 0}
savedUp: {x: 0, y: 0, z: 0}
savedRectSize: {x: 0, y: 0}
savedColor: {r: 0, g: 0, b: 0, a: 0}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 0
--- !u!114 &7234202513872361131
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 200318615579008512}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 004b8ec0c25535c409b1f6115963d476, type: 3}
m_Name:
m_EditorClassIdentifier:
Dirty: 0
--- !u!1 &4969609539872308112
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2756876663177930824}
- component: {fileID: 1011916610372698401}
m_Layer: 0
m_Name: UIPopup
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2756876663177930824
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4969609539872308112}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -0.1}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7333867837070813280}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -54.7, y: -82.3}
m_SizeDelta: {x: 209.39, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1011916610372698401
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4969609539872308112}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c3a122f9d31deb2449916718b05c92bc, type: 3}
m_Name:
m_EditorClassIdentifier:
_text: {fileID: 5337496564380876370}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d5c0d58890a7e7840b47863ed98e5c6e
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,5 +1,226 @@
%YAML 1.1 %YAML 1.1
%TAG !u! tag:unity3d.com,2011: %TAG !u! tag:unity3d.com,2011:
--- !u!1 &2146129770
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2146129771}
m_Layer: 0
m_Name: PopupSpawnPos
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2146129771
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2146129770}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1860358267194598677}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 244, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1564034533108096379
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4004537012386243882}
- component: {fileID: 1162760457737044675}
- component: {fileID: 7688394229909313368}
- component: {fileID: 3562044667756752820}
- component: {fileID: 5239063720710252651}
- component: {fileID: 1023336064}
m_Layer: 0
m_Name: BonusText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4004537012386243882
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1564034533108096379}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0.036112145}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1860358267194598677}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: -419}
m_SizeDelta: {x: 395.774, y: 129.583}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1162760457737044675
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1564034533108096379}
m_CullTransparentMesh: 1
--- !u!114 &7688394229909313368
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1564034533108096379}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: 10
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 83.91
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1
m_fontSizeMin: 18
m_fontSizeMax: 83.91
m_fontStyle: 1
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &3562044667756752820
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1564034533108096379}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e62188adca544cf1b96ccf1630f15f9, type: 3}
m_Name:
m_EditorClassIdentifier:
DoNotTesselate: 0
savedPos: {x: 0, y: 0, z: 0}
savedUp: {x: 0, y: 0, z: 0}
savedRectSize: {x: 0, y: 0}
savedColor: {r: 0, g: 0, b: 0, a: 0}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 0
--- !u!114 &5239063720710252651
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1564034533108096379}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 004b8ec0c25535c409b1f6115963d476, type: 3}
m_Name:
m_EditorClassIdentifier:
Dirty: 0
--- !u!114 &1023336064
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1564034533108096379}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 232c3975195049046b093176c334caab, type: 3}
m_Name:
m_EditorClassIdentifier:
_defaultValue:
_prefix: '(x '
_postfix: )
--- !u!1 &1607195224622154761 --- !u!1 &1607195224622154761
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -90,12 +311,12 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
DoNotTesselate: 0 DoNotTesselate: 0
savedPos: {x: 0, y: 0, z: 0} savedPos: {x: 0.000051498588, y: 18.492935, z: 0.0000001550396}
savedUp: {x: 0, y: 0, z: 0} savedUp: {x: 3.1465978e-13, y: 1, z: 2.201165e-11}
savedRectSize: {x: 0, y: 0} savedRectSize: {x: 663.338, y: 63.013}
savedColor: {r: 0, g: 0, b: 0, a: 0} savedColor: {r: 0.71158946, g: 1, b: 0, a: 1}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0} savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 0 savedFill: 1
--- !u!1 &2456473982007753813 --- !u!1 &2456473982007753813
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -134,7 +355,7 @@ RectTransform:
m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 117} m_AnchoredPosition: {x: 0, y: 117}
m_SizeDelta: {x: 367.076, y: 91.769} m_SizeDelta: {x: 632.123, y: 91.769}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6310987546111005199 --- !u!222 &6310987546111005199
CanvasRenderer: CanvasRenderer:
@ -356,12 +577,12 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
DoNotTesselate: 0 DoNotTesselate: 0
savedPos: {x: 0, y: 0, z: 0} savedPos: {x: 0.000051498537, y: -190.99998, z: -0.0003197979}
savedUp: {x: 0, y: 0, z: 0} savedUp: {x: 3.1465978e-13, y: 1, z: 2.201165e-11}
savedRectSize: {x: 0, y: 0} savedRectSize: {x: 271.883, y: 271.883}
savedColor: {r: 0, g: 0, b: 0, a: 0} savedColor: {r: 1, g: 1, b: 1, a: 1}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0} savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 0 savedFill: 1
--- !u!1 &3589229234049084828 --- !u!1 &3589229234049084828
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -394,6 +615,9 @@ RectTransform:
- {fileID: 9202471760983386593} - {fileID: 9202471760983386593}
- {fileID: 9202471760714427097} - {fileID: 9202471760714427097}
- {fileID: 9202471760488186011} - {fileID: 9202471760488186011}
- {fileID: 4004537012386243882}
- {fileID: 2146129771}
- {fileID: 326048764444127262}
m_Father: {fileID: 9202471761387014830} m_Father: {fileID: 9202471761387014830}
m_RootOrder: 0 m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -410,7 +634,7 @@ CanvasGroup:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3589229234049084828} m_GameObject: {fileID: 3589229234049084828}
m_Enabled: 1 m_Enabled: 1
m_Alpha: 1 m_Alpha: 0
m_Interactable: 1 m_Interactable: 1
m_BlocksRaycasts: 1 m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0 m_IgnoreParentGroups: 0
@ -505,12 +729,215 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
DoNotTesselate: 0 DoNotTesselate: 0
savedPos: {x: 0.000051498588, y: 18.492935, z: 0.0000001550396}
savedUp: {x: 3.1465978e-13, y: 1, z: 2.201165e-11}
savedRectSize: {x: 663.338, y: 63.013}
savedColor: {r: 1, g: 1, b: 1, a: 1}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 1
--- !u!1 &5910555295511923874
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 326048764444127262}
- component: {fileID: 6255781262072940109}
- component: {fileID: 8650261210416225506}
- component: {fileID: 7869725402744582542}
- component: {fileID: 8801838980126204425}
- component: {fileID: 4266446464926029223}
- component: {fileID: 6170361849501489470}
m_Layer: 0
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &326048764444127262
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1860358267194598677}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 305}
m_SizeDelta: {x: 200, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6255781262072940109
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_CullTransparentMesh: 1
--- !u!114 &8650261210416225506
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u0412\u0440\u0435\u043C\u044F:"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &7869725402744582542
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e62188adca544cf1b96ccf1630f15f9, type: 3}
m_Name:
m_EditorClassIdentifier:
DoNotTesselate: 0
savedPos: {x: 0, y: 0, z: 0} savedPos: {x: 0, y: 0, z: 0}
savedUp: {x: 0, y: 0, z: 0} savedUp: {x: 0, y: 0, z: 0}
savedRectSize: {x: 0, y: 0} savedRectSize: {x: 0, y: 0}
savedColor: {r: 0, g: 0, b: 0, a: 0} savedColor: {r: 0, g: 0, b: 0, a: 0}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0} savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 0 savedFill: 0
--- !u!114 &8801838980126204425
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 004b8ec0c25535c409b1f6115963d476, type: 3}
m_Name:
m_EditorClassIdentifier:
Dirty: 0
--- !u!114 &4266446464926029223
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e62188adca544cf1b96ccf1630f15f9, type: 3}
m_Name:
m_EditorClassIdentifier:
DoNotTesselate: 0
savedPos: {x: 0, y: 0, z: 0}
savedUp: {x: 0, y: 0, z: 0}
savedRectSize: {x: 0, y: 0}
savedColor: {r: 0, g: 0, b: 0, a: 0}
savedTextUV0: {x: 0, y: 0, z: 0, w: 0}
savedFill: 0
--- !u!114 &6170361849501489470
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5910555295511923874}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 004b8ec0c25535c409b1f6115963d476, type: 3}
m_Name:
m_EditorClassIdentifier:
Dirty: 0
--- !u!1 &8059874730754158137 --- !u!1 &8059874730754158137
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -520,6 +947,7 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 3341415872416724787} - component: {fileID: 3341415872416724787}
- component: {fileID: 1955516150}
m_Layer: 0 m_Layer: 0
m_Name: StartTutorial m_Name: StartTutorial
m_TagString: Untagged m_TagString: Untagged
@ -550,6 +978,18 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100} m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!225 &1955516150
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8059874730754158137}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!1 &9202471760488186004 --- !u!1 &9202471760488186004
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -563,9 +1003,9 @@ GameObject:
- component: {fileID: 9202471760488186015} - component: {fileID: 9202471760488186015}
- component: {fileID: 9202471760488186008} - component: {fileID: 9202471760488186008}
- component: {fileID: 9202471760488186009} - component: {fileID: 9202471760488186009}
- component: {fileID: 9202471760488186010} - component: {fileID: 1530766295}
m_Layer: 0 m_Layer: 0
m_Name: Text (TMP) (1) m_Name: ScoreText
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -720,7 +1160,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
Dirty: 0 Dirty: 0
--- !u!114 &9202471760488186010 --- !u!114 &1530766295
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -729,10 +1169,12 @@ MonoBehaviour:
m_GameObject: {fileID: 9202471760488186004} m_GameObject: {fileID: 9202471760488186004}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4a14752bce1e85a47ad22bd4e89cbe2f, type: 3} m_Script: {fileID: 11500000, guid: 5fac8287982008c4aad577d37f0e885c, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_postfix: " \u043E\u0447." _defaultValue: "0 \u043E\u0447."
_prefix:
_postfix: " \u043E\u0447\u043A\u043E\u0432"
--- !u!1 &9202471760714427098 --- !u!1 &9202471760714427098
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -748,7 +1190,7 @@ GameObject:
- component: {fileID: 9202471760714427103} - component: {fileID: 9202471760714427103}
- component: {fileID: 9202471760714427107} - component: {fileID: 9202471760714427107}
m_Layer: 0 m_Layer: 0
m_Name: Text (TMP) m_Name: TimerText
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -915,6 +1357,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: b64a96362efa9ba44802d57e2e074f27, type: 3} m_Script: {fileID: 11500000, guid: b64a96362efa9ba44802d57e2e074f27, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_defaultValue:
_prefix:
_postfix: _postfix:
--- !u!1 &9202471760983386594 --- !u!1 &9202471760983386594
GameObject: GameObject:
@ -1006,7 +1450,7 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
DoNotTesselate: 0 DoNotTesselate: 0
savedPos: {x: 0.00828664, y: -64.99654, z: -0.32008088} savedPos: {x: 0.000051498555, y: -64.99994, z: -0.15967491}
savedUp: {x: 1.12754275e-13, y: 1, z: 3.42218e-11} savedUp: {x: 1.12754275e-13, y: 1, z: 3.42218e-11}
savedRectSize: {x: 1932.7, y: 1329.5757} savedRectSize: {x: 1932.7, y: 1329.5757}
savedColor: {r: 1, g: 1, b: 1, a: 1} savedColor: {r: 1, g: 1, b: 1, a: 1}
@ -1132,7 +1576,7 @@ MonoBehaviour:
interactable: 1 interactable: 1
blocksRaycasts: 1 blocksRaycasts: 1
forceUseBoxCollider: 0 forceUseBoxCollider: 0
angle: 1 angle: 180
preserveAspect: 1 preserveAspect: 1
vertAngle: 90 vertAngle: 90
ringFill: 0.5 ringFill: 0.5

File diff suppressed because one or more lines are too long

View File

@ -8795,7 +8795,7 @@ PrefabInstance:
type: 3} type: 3}
propertyPath: OnSubmit.m_PersistentCalls.m_Calls.Array.data[0].m_Target propertyPath: OnSubmit.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value: value:
objectReference: {fileID: 0} objectReference: {fileID: 1586040768636592466}
- target: {fileID: 5385305708475918454, guid: 8a70b6ef2260a1848b78f80fbf4e786d, - target: {fileID: 5385305708475918454, guid: 8a70b6ef2260a1848b78f80fbf4e786d,
type: 3} type: 3}
propertyPath: OnSubmit.m_PersistentCalls.m_Calls.Array.data[1].m_Target propertyPath: OnSubmit.m_PersistentCalls.m_Calls.Array.data[1].m_Target
@ -9158,6 +9158,18 @@ PrefabInstance:
objectReference: {fileID: 1381913585} objectReference: {fileID: 1381913585}
m_RemovedComponents: [] m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 59bb54bf798778349a37c58fbf18880c, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 59bb54bf798778349a37c58fbf18880c, type: 3}
--- !u!114 &1586040768636592466 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 1586040770268846765, guid: 59bb54bf798778349a37c58fbf18880c,
type: 3}
m_PrefabInstance: {fileID: 1586040768636592465}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ea6843af62cab9c4b8dabeba902a4262, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &3804151737227041911 stripped --- !u!114 &3804151737227041911 stripped
MonoBehaviour: MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 5385305708475918454, guid: 8a70b6ef2260a1848b78f80fbf4e786d, m_CorrespondingSourceObject: {fileID: 5385305708475918454, guid: 8a70b6ef2260a1848b78f80fbf4e786d,

View File

@ -1,8 +1,92 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.Events;
public class ScoreController : MonoBehaviour public class ScoreController : MonoBehaviour, ITextChangable
{ {
public event Action<float> OnScoreChange;
private LeaderboardController _leaderboardController;
private float _currentScore = 0;
private bool _decreaseBonus;
private Coroutine _decreaseReloadCoroutine;
private UIPopupController _UIPopupController;
public UnityEvent<object> OnTextChange => _OnTextChange;
private UnityEvent<object> _OnTextChange = new UnityEvent<object>();
private BonusController _bonusController;
private void Awake()
{
_bonusController = FindObjectOfType<BonusController>();
_UIPopupController = FindObjectOfType<UIPopupController>();
_leaderboardController = FindObjectOfType<LeaderboardController>();
}
[ContextMenu("Debug add score")]
private void DebugAddScore()
{
AddScore(100, true);
}
[ContextMenu("Debug add score in time")]
private void DebugAddScoreInTime()
{
AddScoreInTime(100, 2, false);
}
public void AddScoreInTime(float ammount, float time, bool useBonus)
{
StartCoroutine(ScoreInTime_Coroutine(ammount,time,useBonus));
}
private IEnumerator ScoreInTime_Coroutine(float ammount, float time, bool useBonus)
{
var timeOffset = time / ammount;
for (int i = 0; i < ammount; i++)
{
AddScore(1, useBonus, false);
yield return new WaitForSeconds(timeOffset);
}
}
public void AddScore(float ammount, bool useBonus = false, bool usePopup = true)
{
float resScore = ammount;
if (useBonus)
{
_bonusController.DecreaseReload();
resScore *= _bonusController.BonusValue;
}
_currentScore += resScore;
PlayerSetup.Instance.SetPlayerScore(_currentScore);
OnScoreChange?.Invoke(_currentScore);
if (usePopup)
{
_UIPopupController.SpawnPopup
(
resScore.ToString(),
UIMagnetType.Score,
() => {
_OnTextChange?.Invoke(_currentScore);
_bonusController.UseBonus();
}
);
}
else
{
_OnTextChange?.Invoke(_currentScore);
}
}
} }

View File

@ -5,9 +5,18 @@ public class BaseItem : MonoBehaviour, IInteractable
[SerializeField] [SerializeField]
private float _scoreAdd = 0; private float _scoreAdd = 0;
protected ScoreController _scoreController;
protected virtual void Awake()
{
_scoreController = FindObjectOfType<ScoreController>();
}
public virtual void Interact() public virtual void Interact()
{ {
PlayerSetup.Instance.AddScore(_scoreAdd); if (_scoreAdd > 0)
_scoreController.AddScore(_scoreAdd, true);
Destroy(gameObject); Destroy(gameObject);
} }
} }

View File

@ -9,8 +9,9 @@ public class EnergyItem : BaseItem
private EnergyController _energyController; private EnergyController _energyController;
private void Awake() protected override void Awake()
{ {
base.Awake();
_energyController = FindObjectOfType<EnergyController>(); _energyController = FindObjectOfType<EnergyController>();
} }

View File

@ -20,7 +20,6 @@ public class GameManager : MonoBehaviour
private EnergyController _energyController; private EnergyController _energyController;
private vTimerCounter _timerCounter; private vTimerCounter _timerCounter;
private EndGameModule _endGameModule; private EndGameModule _endGameModule;
private LeaderboardController _leaderboardController;
private bool _successEnd; private bool _successEnd;
@ -61,7 +60,6 @@ public class GameManager : MonoBehaviour
private void InitReferences() private void InitReferences()
{ {
_leaderboardController = FindObjectOfType<LeaderboardController>();
_endGameModule = FindObjectOfType<EndGameModule>(); _endGameModule = FindObjectOfType<EndGameModule>();
_timerCounter = FindObjectOfType<vTimerCounter>(); _timerCounter = FindObjectOfType<vTimerCounter>();
} }
@ -79,14 +77,13 @@ public class GameManager : MonoBehaviour
{ {
case GameState.Started: case GameState.Started:
{ {
var player = PlayerSetup.Instance.CreateNewPlayer(); PlayerSetup.Instance.CreateNewPlayer();
_leaderboardController.InitPlayerInfo(player);
_UITextShow?.ShowTimer _UITextShow?.ShowTimer
( (
3, 3,
"ÑÒÀÐÒ!", "ÑÒÀÐÒ!",
0, 1,
null, null,
() => { OnGameStarted?.Invoke(); } () => { OnGameStarted?.Invoke(); }
); );

View File

@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI; using UnityEngine.UI;
public class LeaderboardController : MonoBehaviour public class LeaderboardController : MonoBehaviour
@ -19,10 +20,10 @@ public class LeaderboardController : MonoBehaviour
private void Start() private void Start()
{ {
UpdateLeaderboard(0); UpdateLeaderboard();
} }
private void UpdateLeaderboard(float newScore) private void UpdateLeaderboard()
{ {
_entries.ForEach(x => Destroy(x.gameObject)); _entries.ForEach(x => Destroy(x.gameObject));
_entries.Clear(); _entries.Clear();
@ -38,15 +39,10 @@ public class LeaderboardController : MonoBehaviour
} }
} }
[ContextMenu("Debug submit")]
public void SubmitNewEntry() public void SubmitNewEntry()
{ {
PlayerSetup.Instance.SetPlayerName(_nameInputField.text); PlayerSetup.Instance.SetPlayerName(_nameInputField.text);
PlayerSetup.Instance.SavePlayer(); UpdateLeaderboard();
UpdateLeaderboard(0);
}
public void InitPlayerInfo(Player player)
{
player.OnScoreChange += UpdateLeaderboard;
} }
} }

View File

@ -14,7 +14,7 @@ public class LeaderboardEntry : MonoBehaviour
[SerializeField] [SerializeField]
private List<GameObject> _medals = new List<GameObject>(); private List<GameObject> _medals = new List<GameObject>();
public void Init(Player player, int index) public void Init(Player player, int index, bool selected = false)
{ {
if (index < 3) if (index < 3)
{ {
@ -24,5 +24,10 @@ public class LeaderboardEntry : MonoBehaviour
_numText.SetText($"{index + 1}"); _numText.SetText($"{index + 1}");
_nameText.SetText(player.Name); _nameText.SetText(player.Name);
_scoreText.SetText($"{player.Score}"); _scoreText.SetText($"{player.Score}");
if (selected)
{
_nameText.SetText("GREEEEN");
}
} }
} }

View File

@ -7,20 +7,12 @@ using UnityEngine;
public class Player public class Player
{ {
public string Name; public string Name;
public float Score public float Score;
{
get => _score;
set
{
_score = value;
OnScoreChange?.Invoke(_score);
}
}
private float _score; private float _score;
public List<MonumentInfo> UnlockedMonumets = new List<MonumentInfo>(); public List<MonumentInfo> UnlockedMonumets = new List<MonumentInfo>();
public event Action<float> OnScoreChange;
} }
[CreateAssetMenu(fileName = "PlayerInfo")] [CreateAssetMenu(fileName = "PlayerInfo")]

View File

@ -10,6 +10,7 @@ public class PlayerSetup : MonoBehaviour
[SerializeField] [SerializeField]
private Player _currentPlayer; private Player _currentPlayer;
public Player CurrentPlayer => _currentPlayer;
public PlayerInfo PlayerInfo => _playerInfo; public PlayerInfo PlayerInfo => _playerInfo;
private void Awake() private void Awake()
@ -29,28 +30,23 @@ public class PlayerSetup : MonoBehaviour
public Player CreateNewPlayer() public Player CreateNewPlayer()
{ {
_currentPlayer = new Player(); _currentPlayer = new Player();
SavePlayer();
return _currentPlayer; return _currentPlayer;
} }
public void SetPlayerScore(float value)
{
_currentPlayer.Score = value;
}
public void AddScore(float ammount)
{
_currentPlayer.Score += ammount;
}
public void SetPlayerName(string name) public void SetPlayerName(string name)
{ {
_currentPlayer.Name = name; _currentPlayer.Name = name;
} }
public void SetPlayerScore(float score)
{
_currentPlayer.Score = score;
}
public void UnlockMonument(MonumentInfo info) public void UnlockMonument(MonumentInfo info)
{ {
_currentPlayer.UnlockedMonumets.Add(info); _currentPlayer.UnlockedMonumets.Add(info);
AddScore(info.Score);
} }
public bool TryFindMonument(MonumentInfo info) public bool TryFindMonument(MonumentInfo info)

View File

@ -9,8 +9,9 @@ public class TimeBonus : BaseItem
private vTimerCounter _timerCounter; private vTimerCounter _timerCounter;
private void Awake() protected override void Awake()
{ {
base.Awake();
_timerCounter = FindObjectOfType<vTimerCounter>(); _timerCounter = FindObjectOfType<vTimerCounter>();
} }

View File

@ -0,0 +1,8 @@
public class UIScoreText : UITextDisplayBase
{
protected override void Awake()
{
base.Awake();
_textChanger = FindObjectOfType<ScoreController>();
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 07bfafa14538ac741b2cb55975986490
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
{"Keys":["com.unity.services.core.cloud-environment","com.unity.services.core.version"],"Values":[{"m_Value":"production","m_IsReadOnly":false},{"m_Value":"1.4.3","m_IsReadOnly":true}]}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ed0a60712ef404f4b9e202287acbbd51
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

8
Assets/UIBonusText.cs Normal file
View File

@ -0,0 +1,8 @@
public class UIBonusText : UITextDisplayBase
{
protected override void Awake()
{
base.Awake();
_textChanger = FindObjectOfType<BonusController>();
}
}

View File

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

View File

@ -0,0 +1,8 @@
public class UILBPositionText : UITextDisplayBase
{
protected override void Awake()
{
base.Awake();
_textChanger = FindObjectOfType<DynamicLeaderboard>();
}
}

View File

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

17
Assets/UIPopup.cs Normal file
View File

@ -0,0 +1,17 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIPopup : MonoBehaviour
{
[SerializeField]
private TMPro.TextMeshProUGUI _text;
public string Prefix;
public string Postfix;
public void Init(string message)
{
_text.SetText(Prefix + message + Postfix);
}
}

11
Assets/UIPopup.cs.meta Normal file
View File

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

View File

@ -0,0 +1,27 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIPopupController : MonoBehaviour
{
[SerializeField]
private RectTransform _root;
[SerializeField]
private RectTransform _spawnPoint;
[SerializeField]
private List<UIPopupPair> _UIPairs = new List<UIPopupPair>();
public void SpawnPopup(string message, UIMagnetType type, Action onComplete)
{
var selectedPair = _UIPairs.Find(x => x.UIMagnetType == type);
var scorePoint = Instantiate(selectedPair.Popup, _root);
scorePoint.Init(message);
scorePoint.GetComponent<RectTransform>().anchoredPosition = _spawnPoint.anchoredPosition;
RectTransform target = selectedPair.MovePositon;
scorePoint.GetComponent<RectTransform>().LeanMoveLocal(target.anchoredPosition, 1).setOnComplete(onComplete).setEaseInExpo().setDestroyOnComplete(true);
}
}

View File

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

18
Assets/UIPopupPair.cs Normal file
View File

@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class UIPopupPair
{
public UIPopup Popup;
public RectTransform MovePositon;
public UIMagnetType UIMagnetType;
}
[System.Serializable]
public enum UIMagnetType
{
Score,
Time
}

View File

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

View File

@ -8,11 +8,16 @@ public class UITextDisplayBase : MonoBehaviour
protected TMPro.TextMeshProUGUI _text; protected TMPro.TextMeshProUGUI _text;
protected ITextChangable _textChanger; protected ITextChangable _textChanger;
[SerializeField] [SerializeField]
protected string _defaultValue = string.Empty;
[SerializeField]
protected string _prefix;
[SerializeField]
protected string _postfix; protected string _postfix;
protected virtual void Awake() protected virtual void Awake()
{ {
_text = GetComponent<TMPro.TextMeshProUGUI>(); _text = GetComponent<TMPro.TextMeshProUGUI>();
_text.SetText(_defaultValue);
} }
protected virtual void OnEnable() protected virtual void OnEnable()
@ -27,6 +32,6 @@ public class UITextDisplayBase : MonoBehaviour
private void UpdateText(object obj) private void UpdateText(object obj)
{ {
_text.SetText(obj.ToString() + _postfix); _text.SetText(_prefix + obj.ToString() + _postfix);
} }
} }

View File

@ -15,6 +15,7 @@ public class VisorUIModule : MonoBehaviour
[SerializeField] [SerializeField]
private Image _progressBarImage; private Image _progressBarImage;
public InputActionReference LeftTrigger; public InputActionReference LeftTrigger;
public InputActionReference RightTrigger; public InputActionReference RightTrigger;
@ -58,4 +59,4 @@ public class VisorUIModule : MonoBehaviour
_visorActivated = true; _visorActivated = true;
OnVisorActivated?.Invoke(); OnVisorActivated?.Invoke();
} }
} }

View File

@ -152,6 +152,10 @@ PlayerSettings:
- {fileID: 0} - {fileID: 0}
- {fileID: 0} - {fileID: 0}
- {fileID: 0} - {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: -6517218471499782410, guid: 1a4c68ca72a83449f938d669337cb305, type: 2}
- {fileID: 648089955447955448, guid: ac7df53da7627c941aa8b5303dd3d14f, type: 2}
metroInputSource: 0 metroInputSource: 0
wsaTransparentSwapchain: 0 wsaTransparentSwapchain: 0
m_HolographicPauseOnTrackingLoss: 1 m_HolographicPauseOnTrackingLoss: 1