update
This commit is contained in:
@@ -29,32 +29,30 @@ using System;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.UIElements;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
[InitializeOnLoad] // Critical: Ensures the script runs in the background upon Unity startup
|
||||
[InitializeOnLoad]
|
||||
public class AutoSaveTool : EditorWindow
|
||||
{
|
||||
// Static Configuration Variables (Persisted via EditorPrefs)
|
||||
private static bool isAutoSaveEnabled;
|
||||
private static float saveIntervalMinutes;
|
||||
private static bool showDebugLog;
|
||||
|
||||
// Time Tracking Variable
|
||||
private static DateTime nextSaveTime;
|
||||
|
||||
// Static Constructor: Runs when Unity starts or recompiles
|
||||
static AutoSaveTool()
|
||||
private Label statusLabel;
|
||||
private VisualElement progressBar;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
static void Init()
|
||||
{
|
||||
// 1. Load settings from EditorPrefs (persistent storage)
|
||||
isAutoSaveEnabled = EditorPrefs.GetBool("AutoSave_Enabled", false);
|
||||
saveIntervalMinutes = EditorPrefs.GetFloat("AutoSave_Interval", 5f);
|
||||
showDebugLog = EditorPrefs.GetBool("AutoSave_Log", true);
|
||||
|
||||
// 2. Initialize the timer
|
||||
ResetTimer();
|
||||
|
||||
// 3. Register the background update loop
|
||||
EditorApplication.update += OnEditorUpdate;
|
||||
}
|
||||
|
||||
@@ -64,83 +62,194 @@ namespace Editor
|
||||
GetWindow<AutoSaveTool>("Auto Save");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
public void CreateGUI()
|
||||
{
|
||||
GUILayout.Label("Auto Save Configuration (Runs in Background)", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
VisualElement root = rootVisualElement;
|
||||
root.style.paddingTop = 15;
|
||||
root.style.paddingBottom = 15;
|
||||
root.style.paddingLeft = 15;
|
||||
root.style.paddingRight = 15;
|
||||
|
||||
// Begin tracking changes on the GUI
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
isAutoSaveEnabled = EditorGUILayout.Toggle("Enable Auto Save", isAutoSaveEnabled);
|
||||
saveIntervalMinutes = EditorGUILayout.FloatField("Interval (Minutes)", saveIntervalMinutes);
|
||||
showDebugLog = EditorGUILayout.Toggle("Show Debug Log", showDebugLog);
|
||||
|
||||
// If any setting changed, save it immediately to EditorPrefs
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (saveIntervalMinutes < 0.5f) saveIntervalMinutes = 0.5f; // Minimum 30 seconds
|
||||
Label title = new Label("Auto Save Settings");
|
||||
title.style.fontSize = 22;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.color = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
title.style.marginBottom = 15;
|
||||
root.Add(title);
|
||||
|
||||
// Settings Card
|
||||
VisualElement settingsCard = CreateCard();
|
||||
|
||||
Toggle enableToggle = new Toggle("Enable Auto Save");
|
||||
enableToggle.value = isAutoSaveEnabled;
|
||||
enableToggle.RegisterValueChangedCallback(evt => {
|
||||
isAutoSaveEnabled = evt.newValue;
|
||||
EditorPrefs.SetBool("AutoSave_Enabled", isAutoSaveEnabled);
|
||||
ResetTimer();
|
||||
UpdateUIStatus();
|
||||
});
|
||||
enableToggle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
settingsCard.Add(enableToggle);
|
||||
|
||||
Slider intervalSlider = new Slider("Interval (Minutes)", 0.5f, 60f);
|
||||
intervalSlider.value = saveIntervalMinutes;
|
||||
intervalSlider.style.marginTop = 15;
|
||||
intervalSlider.RegisterValueChangedCallback(evt => {
|
||||
saveIntervalMinutes = evt.newValue;
|
||||
EditorPrefs.SetFloat("AutoSave_Interval", saveIntervalMinutes);
|
||||
ResetTimer();
|
||||
});
|
||||
|
||||
// Add a label to show exact slider value
|
||||
Label intervalLabel = new Label($"Current: {saveIntervalMinutes:F1} min");
|
||||
intervalLabel.style.alignSelf = Align.FlexEnd;
|
||||
intervalLabel.style.color = new StyleColor(new Color(0.7f, 0.7f, 0.7f));
|
||||
intervalSlider.RegisterValueChangedCallback(evt => {
|
||||
intervalLabel.text = $"Current: {evt.newValue:F1} min";
|
||||
});
|
||||
|
||||
settingsCard.Add(intervalSlider);
|
||||
settingsCard.Add(intervalLabel);
|
||||
|
||||
Toggle logToggle = new Toggle("Show Debug Log");
|
||||
logToggle.value = showDebugLog;
|
||||
logToggle.style.marginTop = 10;
|
||||
logToggle.RegisterValueChangedCallback(evt => {
|
||||
showDebugLog = evt.newValue;
|
||||
EditorPrefs.SetBool("AutoSave_Log", showDebugLog);
|
||||
});
|
||||
settingsCard.Add(logToggle);
|
||||
|
||||
root.Add(settingsCard);
|
||||
|
||||
ResetTimer(); // Reset timer based on new settings
|
||||
}
|
||||
// Status Card
|
||||
VisualElement statusCard = CreateCard();
|
||||
statusCard.style.marginTop = 15;
|
||||
|
||||
Label statusTitle = new Label("System Status");
|
||||
statusTitle.style.fontSize = 16;
|
||||
statusTitle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
statusTitle.style.marginBottom = 15;
|
||||
statusCard.Add(statusTitle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
statusLabel = new Label();
|
||||
statusLabel.style.fontSize = 15;
|
||||
statusLabel.style.marginBottom = 10;
|
||||
statusCard.Add(statusLabel);
|
||||
|
||||
if (isAutoSaveEnabled)
|
||||
{
|
||||
TimeSpan timeRemaining = nextSaveTime - DateTime.Now;
|
||||
if (timeRemaining.TotalSeconds < 0) timeRemaining = TimeSpan.Zero;
|
||||
// Progress bar
|
||||
VisualElement progressBg = new VisualElement();
|
||||
progressBg.style.height = 12;
|
||||
progressBg.style.backgroundColor = new StyleColor(new Color(0.1f, 0.1f, 0.1f));
|
||||
progressBg.style.borderTopLeftRadius = 6;
|
||||
progressBg.style.borderTopRightRadius = 6;
|
||||
progressBg.style.borderBottomLeftRadius = 6;
|
||||
progressBg.style.borderBottomRightRadius = 6;
|
||||
progressBg.style.marginBottom = 20;
|
||||
progressBg.style.overflow = Overflow.Hidden;
|
||||
|
||||
// Display warning if Play Mode or Compiling
|
||||
if (EditorApplication.isPlaying || EditorApplication.isCompiling)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Currently in Play Mode or Compiling. Saving is temporarily paused to prevent errors.", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
string timeStr = string.Format("{0:00}:{1:00}", timeRemaining.Minutes, timeRemaining.Seconds);
|
||||
EditorGUILayout.HelpBox($"System is running in background.\nAuto-saving in: {timeStr}", MessageType.Info);
|
||||
}
|
||||
progressBar = new VisualElement();
|
||||
progressBar.style.height = 12;
|
||||
progressBar.style.backgroundColor = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
progressBar.style.width = Length.Percent(0);
|
||||
progressBg.Add(progressBar);
|
||||
|
||||
if (GUILayout.Button("Save Now", GUILayout.Height(30)))
|
||||
{
|
||||
SaveNow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Auto Save System is currently DISABLED.", MessageType.Error);
|
||||
}
|
||||
statusCard.Add(progressBg);
|
||||
|
||||
Button saveNowBtn = new Button(() => SaveNow());
|
||||
saveNowBtn.text = "Force Save Now";
|
||||
saveNowBtn.style.height = 40;
|
||||
saveNowBtn.style.backgroundColor = new StyleColor(new Color(0.2f, 0.6f, 0.3f));
|
||||
saveNowBtn.style.color = new StyleColor(Color.white);
|
||||
saveNowBtn.style.fontSize = 14;
|
||||
saveNowBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
saveNowBtn.style.borderTopLeftRadius = 6;
|
||||
saveNowBtn.style.borderTopRightRadius = 6;
|
||||
saveNowBtn.style.borderBottomLeftRadius = 6;
|
||||
saveNowBtn.style.borderBottomRightRadius = 6;
|
||||
statusCard.Add(saveNowBtn);
|
||||
|
||||
root.Add(statusCard);
|
||||
|
||||
// Periodically update the countdown text and progress bar
|
||||
root.schedule.Execute(UpdateUIStatus).Every(100);
|
||||
UpdateUIStatus();
|
||||
|
||||
root.Add(ScovySignature.CreateSignatureBox());
|
||||
}
|
||||
|
||||
private VisualElement CreateCard()
|
||||
{
|
||||
VisualElement card = new VisualElement();
|
||||
card.style.backgroundColor = new StyleColor(new Color(0.18f, 0.18f, 0.18f, 0.9f));
|
||||
card.style.borderTopLeftRadius = 10;
|
||||
card.style.borderTopRightRadius = 10;
|
||||
card.style.borderBottomLeftRadius = 10;
|
||||
card.style.borderBottomRightRadius = 10;
|
||||
card.style.paddingTop = 15;
|
||||
card.style.paddingBottom = 15;
|
||||
card.style.paddingLeft = 15;
|
||||
card.style.paddingRight = 15;
|
||||
|
||||
card.style.borderTopWidth = 1;
|
||||
card.style.borderBottomWidth = 1;
|
||||
card.style.borderLeftWidth = 1;
|
||||
card.style.borderRightWidth = 1;
|
||||
card.style.borderTopColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderBottomColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderLeftColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderRightColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
return card;
|
||||
}
|
||||
|
||||
private void UpdateUIStatus()
|
||||
{
|
||||
if (statusLabel == null || progressBar == null) return;
|
||||
|
||||
if (!isAutoSaveEnabled)
|
||||
{
|
||||
statusLabel.text = "Auto Save is DISABLED.";
|
||||
statusLabel.style.color = new StyleColor(new Color(0.85f, 0.35f, 0.35f));
|
||||
progressBar.style.width = Length.Percent(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EditorApplication.isPlaying || EditorApplication.isCompiling)
|
||||
{
|
||||
statusLabel.text = "PAUSED (Play Mode / Compiling)";
|
||||
statusLabel.style.color = new StyleColor(new Color(0.9f, 0.75f, 0.2f));
|
||||
progressBar.style.backgroundColor = new StyleColor(new Color(0.9f, 0.75f, 0.2f));
|
||||
return;
|
||||
}
|
||||
|
||||
TimeSpan timeRemaining = nextSaveTime - DateTime.Now;
|
||||
if (timeRemaining.TotalSeconds < 0) timeRemaining = TimeSpan.Zero;
|
||||
|
||||
string timeStr = string.Format("{0:00}:{1:00}", timeRemaining.Minutes, timeRemaining.Seconds);
|
||||
statusLabel.text = $"Auto-saving in: {timeStr}";
|
||||
statusLabel.style.color = new StyleColor(new Color(0.6f, 0.8f, 1f));
|
||||
progressBar.style.backgroundColor = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
|
||||
float totalSeconds = saveIntervalMinutes * 60f;
|
||||
float elapsed = totalSeconds - (float)timeRemaining.TotalSeconds;
|
||||
float percent = Mathf.Clamp01(elapsed / totalSeconds) * 100f;
|
||||
progressBar.style.width = Length.Percent(percent);
|
||||
}
|
||||
|
||||
// This function runs continuously in the background
|
||||
private static void OnEditorUpdate()
|
||||
{
|
||||
if (!isAutoSaveEnabled) return;
|
||||
|
||||
// If playing or compiling -> PAUSE the countdown (do not reset)
|
||||
if (EditorApplication.isPlaying || EditorApplication.isCompiling)
|
||||
{
|
||||
// Add delta time to nextSaveTime to compensate for time elapsed while paused
|
||||
nextSaveTime = nextSaveTime.AddSeconds(Time.unscaledDeltaTime);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's time to save
|
||||
if (DateTime.Now >= nextSaveTime)
|
||||
{
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
// Repaint the GUI if the window is open to keep the countdown smooth
|
||||
if (HasOpenInstances<AutoSaveTool>())
|
||||
{
|
||||
GetWindow<AutoSaveTool>().Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResetTimer()
|
||||
@@ -151,17 +260,14 @@ namespace Editor
|
||||
private static void SaveNow()
|
||||
{
|
||||
var currentScene = EditorSceneManager.GetActiveScene();
|
||||
|
||||
bool isSaved = false;
|
||||
|
||||
// 1. Save Current Scene if it is dirty AND has a path (not Untitled)
|
||||
if (currentScene.isDirty && !string.IsNullOrEmpty(currentScene.path))
|
||||
{
|
||||
EditorSceneManager.SaveOpenScenes();
|
||||
isSaved = true;
|
||||
}
|
||||
|
||||
// 2. Always save Assets (Prefabs, ScriptableObjects, etc.)
|
||||
AssetDatabase.SaveAssets();
|
||||
isSaved = true;
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Globalization;
|
||||
using System;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.UIElements;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
@@ -33,8 +35,9 @@ namespace Editor
|
||||
private static EventModifiers loadModifier;
|
||||
private static KeyCode[] slotKeys = new KeyCode[9];
|
||||
|
||||
// Static constructor runs automatically when Unity loads or recompiles
|
||||
static CameraBookmarksTool()
|
||||
// Replaced static constructor with InitializeOnLoadMethod to avoid EditorPrefs exceptions
|
||||
[InitializeOnLoadMethod]
|
||||
static void Init()
|
||||
{
|
||||
LoadSettings();
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
@@ -69,52 +72,130 @@ namespace Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
public void CreateGUI()
|
||||
{
|
||||
GUILayout.Label("Shortcut Configuration", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
VisualElement root = rootVisualElement;
|
||||
root.style.paddingTop = 15;
|
||||
root.style.paddingBottom = 15;
|
||||
root.style.paddingLeft = 15;
|
||||
root.style.paddingRight = 15;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Label title = new Label("Shortcut Configuration");
|
||||
title.style.fontSize = 20;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.color = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
title.style.marginBottom = 15;
|
||||
root.Add(title);
|
||||
|
||||
// Modifier Keys Setup
|
||||
saveModifier = (EventModifiers)EditorGUILayout.EnumFlagsField("Save Modifier", saveModifier);
|
||||
loadModifier = (EventModifiers)EditorGUILayout.EnumFlagsField("Load Modifier", loadModifier);
|
||||
// Warning Box
|
||||
VisualElement warningBox = new VisualElement();
|
||||
warningBox.style.backgroundColor = new StyleColor(new Color(0.8f, 0.6f, 0.1f, 0.3f));
|
||||
warningBox.style.borderLeftWidth = 4;
|
||||
warningBox.style.borderLeftColor = new StyleColor(new Color(0.9f, 0.7f, 0.1f));
|
||||
warningBox.style.paddingTop = 10;
|
||||
warningBox.style.paddingBottom = 10;
|
||||
warningBox.style.paddingLeft = 10;
|
||||
warningBox.style.marginBottom = 15;
|
||||
warningBox.style.display = DisplayStyle.None;
|
||||
|
||||
Label warningLabel = new Label("Warning: Save and Load modifiers are the SAME! This will cause conflicts.");
|
||||
warningLabel.style.color = new StyleColor(new Color(0.9f, 0.8f, 0.5f));
|
||||
warningLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
warningBox.Add(warningLabel);
|
||||
root.Add(warningBox);
|
||||
|
||||
if (saveModifier == loadModifier)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Warning: Save and Load modifiers are the SAME! This will cause conflicts.", MessageType.Warning);
|
||||
}
|
||||
// Modifiers Card
|
||||
VisualElement modifiersCard = CreateCard();
|
||||
EnumFlagsField saveField = new EnumFlagsField("Save Modifier", saveModifier);
|
||||
saveField.RegisterValueChangedCallback(evt => {
|
||||
saveModifier = (EventModifiers)evt.newValue;
|
||||
SaveSettings();
|
||||
warningBox.style.display = (saveModifier == loadModifier) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
});
|
||||
modifiersCard.Add(saveField);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
GUILayout.Label("Slot Keys Assignment", EditorStyles.boldLabel);
|
||||
EnumFlagsField loadField = new EnumFlagsField("Load Modifier", loadModifier);
|
||||
loadField.RegisterValueChangedCallback(evt => {
|
||||
loadModifier = (EventModifiers)evt.newValue;
|
||||
SaveSettings();
|
||||
warningBox.style.display = (saveModifier == loadModifier) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
});
|
||||
loadField.style.marginTop = 10;
|
||||
modifiersCard.Add(loadField);
|
||||
|
||||
warningBox.style.display = (saveModifier == loadModifier) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
root.Add(modifiersCard);
|
||||
|
||||
// KeyCode Setup for 9 slots
|
||||
// Slots Section
|
||||
Label slotsTitle = new Label("Slot Keys Assignment");
|
||||
slotsTitle.style.fontSize = 16;
|
||||
slotsTitle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
slotsTitle.style.color = new StyleColor(new Color(0.8f, 0.8f, 0.8f));
|
||||
slotsTitle.style.marginTop = 15;
|
||||
slotsTitle.style.marginBottom = 10;
|
||||
root.Add(slotsTitle);
|
||||
|
||||
VisualElement slotsCard = CreateCard();
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label($"Slot {i + 1}", GUILayout.Width(100));
|
||||
slotKeys[i] = (KeyCode)EditorGUILayout.EnumPopup(slotKeys[i]);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
int index = i;
|
||||
EnumField slotField = new EnumField($"Slot {i + 1}", slotKeys[i]);
|
||||
slotField.RegisterValueChangedCallback(evt => {
|
||||
slotKeys[index] = (KeyCode)evt.newValue;
|
||||
SaveSettings();
|
||||
});
|
||||
if (i > 0) slotField.style.marginTop = 8;
|
||||
slotsCard.Add(slotField);
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
SaveSettings(); // Save immediately if anything changes
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
root.Add(slotsCard);
|
||||
|
||||
// Reset Button
|
||||
if (GUILayout.Button("Reset to Default Settings", GUILayout.Height(30)))
|
||||
{
|
||||
Button resetBtn = new Button(() => {
|
||||
saveModifier = EventModifiers.Control;
|
||||
loadModifier = EventModifiers.Shift;
|
||||
for (int i = 0; i < 9; i++) slotKeys[i] = KeyCode.Alpha1 + i;
|
||||
|
||||
SaveSettings();
|
||||
GUI.FocusControl(null); // Remove focus to refresh UI correctly
|
||||
}
|
||||
|
||||
root.Clear();
|
||||
CreateGUI(); // Rebuild
|
||||
});
|
||||
resetBtn.text = "Reset to Default Settings";
|
||||
resetBtn.style.height = 40;
|
||||
resetBtn.style.marginTop = 20;
|
||||
resetBtn.style.backgroundColor = new StyleColor(new Color(0.7f, 0.3f, 0.3f));
|
||||
resetBtn.style.color = new StyleColor(Color.white);
|
||||
resetBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
resetBtn.style.borderTopLeftRadius = 6;
|
||||
resetBtn.style.borderTopRightRadius = 6;
|
||||
resetBtn.style.borderBottomLeftRadius = 6;
|
||||
resetBtn.style.borderBottomRightRadius = 6;
|
||||
root.Add(resetBtn);
|
||||
|
||||
root.Add(ScovySignature.CreateSignatureBox());
|
||||
}
|
||||
|
||||
private VisualElement CreateCard()
|
||||
{
|
||||
VisualElement card = new VisualElement();
|
||||
card.style.backgroundColor = new StyleColor(new Color(0.18f, 0.18f, 0.18f, 0.9f));
|
||||
card.style.borderTopLeftRadius = 8;
|
||||
card.style.borderTopRightRadius = 8;
|
||||
card.style.borderBottomLeftRadius = 8;
|
||||
card.style.borderBottomRightRadius = 8;
|
||||
card.style.paddingTop = 15;
|
||||
card.style.paddingBottom = 15;
|
||||
card.style.paddingLeft = 15;
|
||||
card.style.paddingRight = 15;
|
||||
|
||||
card.style.borderTopWidth = 1;
|
||||
card.style.borderBottomWidth = 1;
|
||||
card.style.borderLeftWidth = 1;
|
||||
card.style.borderRightWidth = 1;
|
||||
card.style.borderTopColor = new StyleColor(new Color(0.25f, 0.25f, 0.25f));
|
||||
card.style.borderBottomColor = new StyleColor(new Color(0.25f, 0.25f, 0.25f));
|
||||
card.style.borderLeftColor = new StyleColor(new Color(0.25f, 0.25f, 0.25f));
|
||||
card.style.borderRightColor = new StyleColor(new Color(0.25f, 0.25f, 0.25f));
|
||||
return card;
|
||||
}
|
||||
|
||||
static void OnSceneGUI(SceneView view)
|
||||
|
||||
454
Assets/Editors/CameraJumpPointsEditor.cs
Normal file
454
Assets/Editors/CameraJumpPointsEditor.cs
Normal file
@@ -0,0 +1,454 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.UIElements;
|
||||
|
||||
[CustomEditor(typeof(CameraJumpPoints))]
|
||||
public class CameraJumpPointsEditor : UnityEditor.Editor
|
||||
{
|
||||
private static CameraJumpPoints[] allPoints;
|
||||
|
||||
// Store previous pose
|
||||
private static Vector3 previousPosition;
|
||||
private static Quaternion previousRotation;
|
||||
private static bool hasPreviousPose = false;
|
||||
private static Transform currentJumpTarget = null;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
static void Init()
|
||||
{
|
||||
SceneView.duringSceneGui += OnSceneGUIStatic;
|
||||
EditorApplication.hierarchyChanged += OnHierarchyChanged;
|
||||
}
|
||||
|
||||
static void OnHierarchyChanged()
|
||||
{
|
||||
allPoints = Object.FindObjectsOfType<CameraJumpPoints>();
|
||||
}
|
||||
|
||||
static void OnSceneGUIStatic(SceneView sceneView)
|
||||
{
|
||||
Event e = Event.current;
|
||||
if (e.type == EventType.KeyDown && e.keyCode != KeyCode.None)
|
||||
{
|
||||
if (allPoints == null)
|
||||
{
|
||||
allPoints = Object.FindObjectsOfType<CameraJumpPoints>();
|
||||
}
|
||||
|
||||
bool needsRefresh = false;
|
||||
|
||||
foreach (var cp in allPoints)
|
||||
{
|
||||
if (cp == null)
|
||||
{
|
||||
needsRefresh = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var pt in cp.points)
|
||||
{
|
||||
if (pt.key == e.keyCode && pt.ctrl == e.control && pt.alt == e.alt && pt.shift == e.shift)
|
||||
{
|
||||
if (pt.target == null) continue;
|
||||
|
||||
if (currentJumpTarget == pt.target && hasPreviousPose)
|
||||
{
|
||||
// Jump back
|
||||
sceneView.pivot = previousPosition;
|
||||
sceneView.rotation = previousRotation;
|
||||
currentJumpTarget = null;
|
||||
hasPreviousPose = false;
|
||||
sceneView.Repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save previous pose
|
||||
previousPosition = sceneView.pivot;
|
||||
previousRotation = sceneView.rotation;
|
||||
hasPreviousPose = true;
|
||||
currentJumpTarget = pt.target;
|
||||
|
||||
// Jump to target exactly matching camera position
|
||||
sceneView.rotation = pt.target.rotation;
|
||||
sceneView.pivot = pt.target.position + pt.target.forward * sceneView.cameraDistance;
|
||||
sceneView.Repaint();
|
||||
}
|
||||
|
||||
e.Use();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsRefresh)
|
||||
{
|
||||
allPoints = Object.FindObjectsOfType<CameraJumpPoints>();
|
||||
}
|
||||
}
|
||||
|
||||
// Lock camera movement when in View Mode
|
||||
if (hasPreviousPose && currentJumpTarget != null)
|
||||
{
|
||||
bool isNavigating = false;
|
||||
|
||||
if (e.type == EventType.KeyDown)
|
||||
{
|
||||
if (e.keyCode == KeyCode.W || e.keyCode == KeyCode.A || e.keyCode == KeyCode.S || e.keyCode == KeyCode.D ||
|
||||
e.keyCode == KeyCode.Q || e.keyCode == KeyCode.E ||
|
||||
e.keyCode == KeyCode.UpArrow || e.keyCode == KeyCode.DownArrow ||
|
||||
e.keyCode == KeyCode.LeftArrow || e.keyCode == KeyCode.RightArrow)
|
||||
{
|
||||
isNavigating = true;
|
||||
}
|
||||
}
|
||||
else if (e.type == EventType.MouseDown || e.type == EventType.MouseDrag)
|
||||
{
|
||||
// Right click (1), Middle click (2), or Alt+Left click (orbit)
|
||||
if (e.button == 1 || e.button == 2 || (e.button == 0 && e.alt))
|
||||
{
|
||||
isNavigating = true;
|
||||
}
|
||||
}
|
||||
else if (e.type == EventType.ScrollWheel)
|
||||
{
|
||||
isNavigating = true;
|
||||
}
|
||||
|
||||
if (isNavigating)
|
||||
{
|
||||
string hotkeyStr = "your shortcut";
|
||||
if (allPoints != null)
|
||||
{
|
||||
foreach (var cp in allPoints)
|
||||
{
|
||||
if (cp == null) continue;
|
||||
foreach (var pt in cp.points)
|
||||
{
|
||||
if (pt.target == currentJumpTarget)
|
||||
{
|
||||
hotkeyStr = pt.GetKeyString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sceneView.ShowNotification(new GUIContent($"View Mode Locked. Press {hotkeyStr} again to escape."));
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
VisualElement root = new VisualElement();
|
||||
root.style.paddingTop = 15;
|
||||
root.style.paddingBottom = 15;
|
||||
root.style.paddingLeft = 10;
|
||||
root.style.paddingRight = 10;
|
||||
|
||||
// Title
|
||||
Label title = new Label("Camera Bookmarks");
|
||||
title.style.fontSize = 22;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.marginBottom = 15;
|
||||
title.style.color = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
root.Add(title);
|
||||
|
||||
// Help Box Custom
|
||||
VisualElement helpBox = new VisualElement();
|
||||
helpBox.style.backgroundColor = new StyleColor(new Color(0.15f, 0.15f, 0.15f, 0.8f));
|
||||
helpBox.style.borderLeftWidth = 4;
|
||||
helpBox.style.borderLeftColor = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
helpBox.style.borderTopRightRadius = 6;
|
||||
helpBox.style.borderBottomRightRadius = 6;
|
||||
helpBox.style.paddingTop = 12;
|
||||
helpBox.style.paddingBottom = 12;
|
||||
helpBox.style.paddingLeft = 12;
|
||||
helpBox.style.paddingRight = 12;
|
||||
helpBox.style.marginBottom = 20;
|
||||
|
||||
Label helpText = new Label("• Jump instantly via hotkeys in Scene View.\n• Press the exact same hotkey again to return.\n• Use 'Capture Current View' for quick setup.");
|
||||
helpText.style.whiteSpace = WhiteSpace.Normal;
|
||||
helpText.style.color = new StyleColor(new Color(0.85f, 0.85f, 0.85f));
|
||||
helpBox.Add(helpText);
|
||||
root.Add(helpBox);
|
||||
|
||||
// List Container
|
||||
VisualElement listContainer = new VisualElement();
|
||||
root.Add(listContainer);
|
||||
|
||||
SerializedProperty pointsProp = serializedObject.FindProperty("points");
|
||||
System.Action rebuildList = null;
|
||||
|
||||
rebuildList = () => {
|
||||
listContainer.Clear();
|
||||
serializedObject.Update();
|
||||
|
||||
for (int i = 0; i < pointsProp.arraySize; i++)
|
||||
{
|
||||
int index = i;
|
||||
SerializedProperty pointProp = pointsProp.GetArrayElementAtIndex(index);
|
||||
|
||||
// Card UI
|
||||
VisualElement card = new VisualElement();
|
||||
card.style.backgroundColor = new StyleColor(new Color(0.2f, 0.2f, 0.2f, 0.9f));
|
||||
card.style.borderTopLeftRadius = 8;
|
||||
card.style.borderTopRightRadius = 8;
|
||||
card.style.borderBottomLeftRadius = 8;
|
||||
card.style.borderBottomRightRadius = 8;
|
||||
card.style.paddingTop = 15;
|
||||
card.style.paddingBottom = 15;
|
||||
card.style.paddingLeft = 15;
|
||||
card.style.paddingRight = 15;
|
||||
card.style.marginBottom = 12;
|
||||
|
||||
// Subtle shadow/border
|
||||
card.style.borderTopWidth = 1;
|
||||
card.style.borderBottomWidth = 1;
|
||||
card.style.borderLeftWidth = 1;
|
||||
card.style.borderRightWidth = 1;
|
||||
card.style.borderTopColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderBottomColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderLeftColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderRightColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
|
||||
// Header
|
||||
VisualElement header = new VisualElement();
|
||||
header.style.flexDirection = FlexDirection.Row;
|
||||
header.style.justifyContent = Justify.SpaceBetween;
|
||||
header.style.marginBottom = 12;
|
||||
|
||||
PropertyField nameField = new PropertyField(pointProp.FindPropertyRelative("name"), "");
|
||||
nameField.style.flexGrow = 1;
|
||||
nameField.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
|
||||
Button deleteBtn = new Button(() => {
|
||||
pointsProp.DeleteArrayElementAtIndex(index);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
rebuildList();
|
||||
});
|
||||
deleteBtn.text = "✕";
|
||||
deleteBtn.style.backgroundColor = new StyleColor(new Color(0.8f, 0.25f, 0.25f, 0.9f));
|
||||
deleteBtn.style.color = new StyleColor(Color.white);
|
||||
deleteBtn.style.borderTopLeftRadius = 4;
|
||||
deleteBtn.style.borderTopRightRadius = 4;
|
||||
deleteBtn.style.borderBottomLeftRadius = 4;
|
||||
deleteBtn.style.borderBottomRightRadius = 4;
|
||||
deleteBtn.style.width = 24;
|
||||
deleteBtn.style.height = 24;
|
||||
deleteBtn.style.marginLeft = 15;
|
||||
deleteBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
|
||||
header.Add(nameField);
|
||||
header.Add(deleteBtn);
|
||||
card.Add(header);
|
||||
|
||||
// Target Row with Sync button
|
||||
VisualElement targetRow = new VisualElement();
|
||||
targetRow.style.flexDirection = FlexDirection.Row;
|
||||
targetRow.style.marginBottom = 12;
|
||||
|
||||
PropertyField targetField = new PropertyField(pointProp.FindPropertyRelative("target"), "Target Object");
|
||||
targetField.style.flexGrow = 1;
|
||||
targetRow.Add(targetField);
|
||||
|
||||
Button syncBtn = new Button(() => {
|
||||
SceneView sv = SceneView.lastActiveSceneView;
|
||||
if (sv != null && sv.camera != null) {
|
||||
Transform t = (Transform)pointProp.FindPropertyRelative("target").objectReferenceValue;
|
||||
if (t != null) {
|
||||
Undo.RecordObject(t, "Sync Target View");
|
||||
t.position = sv.camera.transform.position;
|
||||
t.rotation = sv.camera.transform.rotation;
|
||||
}
|
||||
}
|
||||
});
|
||||
syncBtn.text = "Sync to Scene";
|
||||
syncBtn.tooltip = "Updates this object's transform to match your current Scene View.";
|
||||
syncBtn.style.marginLeft = 10;
|
||||
syncBtn.style.paddingLeft = 8;
|
||||
syncBtn.style.paddingRight = 8;
|
||||
syncBtn.style.borderTopLeftRadius = 4;
|
||||
syncBtn.style.borderTopRightRadius = 4;
|
||||
syncBtn.style.borderBottomLeftRadius = 4;
|
||||
syncBtn.style.borderBottomRightRadius = 4;
|
||||
syncBtn.style.backgroundColor = new StyleColor(new Color(0.3f, 0.3f, 0.3f));
|
||||
targetRow.Add(syncBtn);
|
||||
|
||||
card.Add(targetRow);
|
||||
|
||||
// Key binding Row
|
||||
VisualElement keyRow = new VisualElement();
|
||||
keyRow.style.flexDirection = FlexDirection.Row;
|
||||
keyRow.style.alignItems = Align.Center;
|
||||
|
||||
Label keyLabel = new Label("Shortcut Key");
|
||||
keyLabel.style.width = 120;
|
||||
keyRow.Add(keyLabel);
|
||||
|
||||
Button recordBtn = new Button();
|
||||
recordBtn.style.flexGrow = 1;
|
||||
recordBtn.style.height = 30;
|
||||
recordBtn.style.borderTopLeftRadius = 6;
|
||||
recordBtn.style.borderTopRightRadius = 6;
|
||||
recordBtn.style.borderBottomLeftRadius = 6;
|
||||
recordBtn.style.borderBottomRightRadius = 6;
|
||||
recordBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
|
||||
System.Action updateBtnText = () => {
|
||||
SerializedProperty keyP = pointProp.FindPropertyRelative("key");
|
||||
SerializedProperty cP = pointProp.FindPropertyRelative("ctrl");
|
||||
SerializedProperty aP = pointProp.FindPropertyRelative("alt");
|
||||
SerializedProperty sP = pointProp.FindPropertyRelative("shift");
|
||||
|
||||
if ((KeyCode)keyP.intValue == KeyCode.None) {
|
||||
recordBtn.text = "Not Set (Click to Record)";
|
||||
recordBtn.style.backgroundColor = new StyleColor(new Color(0.3f, 0.3f, 0.3f));
|
||||
} else {
|
||||
string s = "";
|
||||
if (cP.boolValue) s += "Ctrl + ";
|
||||
if (aP.boolValue) s += "Alt + ";
|
||||
if (sP.boolValue) s += "Shift + ";
|
||||
s += ((KeyCode)keyP.intValue).ToString();
|
||||
recordBtn.text = s;
|
||||
recordBtn.style.backgroundColor = new StyleColor(new Color(0.15f, 0.45f, 0.8f));
|
||||
}
|
||||
};
|
||||
|
||||
updateBtnText();
|
||||
bool isRecording = false;
|
||||
|
||||
recordBtn.clicked += () => {
|
||||
if (isRecording) {
|
||||
isRecording = false;
|
||||
updateBtnText();
|
||||
return;
|
||||
}
|
||||
isRecording = true;
|
||||
recordBtn.text = "Press any key... (ESC to cancel)";
|
||||
recordBtn.style.backgroundColor = new StyleColor(new Color(0.8f, 0.4f, 0.1f));
|
||||
recordBtn.Focus();
|
||||
};
|
||||
|
||||
recordBtn.RegisterCallback<KeyDownEvent>((evt) => {
|
||||
if (!isRecording) return;
|
||||
|
||||
if (evt.keyCode == KeyCode.Escape) {
|
||||
isRecording = false;
|
||||
updateBtnText();
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode != KeyCode.None &&
|
||||
evt.keyCode != KeyCode.LeftAlt && evt.keyCode != KeyCode.RightAlt &&
|
||||
evt.keyCode != KeyCode.LeftControl && evt.keyCode != KeyCode.RightControl &&
|
||||
evt.keyCode != KeyCode.LeftShift && evt.keyCode != KeyCode.RightShift &&
|
||||
evt.keyCode != KeyCode.LeftCommand && evt.keyCode != KeyCode.RightCommand)
|
||||
{
|
||||
pointProp.FindPropertyRelative("key").intValue = (int)evt.keyCode;
|
||||
pointProp.FindPropertyRelative("ctrl").boolValue = evt.ctrlKey;
|
||||
pointProp.FindPropertyRelative("alt").boolValue = evt.altKey;
|
||||
pointProp.FindPropertyRelative("shift").boolValue = evt.shiftKey;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
isRecording = false;
|
||||
updateBtnText();
|
||||
evt.StopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
recordBtn.focusable = true;
|
||||
keyRow.Add(recordBtn);
|
||||
card.Add(keyRow);
|
||||
|
||||
listContainer.Add(card);
|
||||
}
|
||||
|
||||
// Buttons layout
|
||||
VisualElement buttonsRow = new VisualElement();
|
||||
buttonsRow.style.flexDirection = FlexDirection.Row;
|
||||
buttonsRow.style.marginTop = 15;
|
||||
|
||||
// Capture Current View Button
|
||||
Button captureBtn = new Button(() => {
|
||||
SceneView sv = SceneView.lastActiveSceneView;
|
||||
if (sv != null && sv.camera != null) {
|
||||
GameObject go = new GameObject("Camera Point " + (pointsProp.arraySize + 1));
|
||||
CameraJumpPoints tgt = (CameraJumpPoints)target;
|
||||
go.transform.SetParent(tgt.transform);
|
||||
go.transform.position = sv.camera.transform.position;
|
||||
go.transform.rotation = sv.camera.transform.rotation;
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(go, "Capture Camera Point");
|
||||
|
||||
pointsProp.arraySize++;
|
||||
SerializedProperty newElem = pointsProp.GetArrayElementAtIndex(pointsProp.arraySize - 1);
|
||||
newElem.FindPropertyRelative("name").stringValue = go.name;
|
||||
newElem.FindPropertyRelative("target").objectReferenceValue = go.transform;
|
||||
newElem.FindPropertyRelative("key").intValue = (int)KeyCode.None;
|
||||
newElem.FindPropertyRelative("ctrl").boolValue = false;
|
||||
newElem.FindPropertyRelative("alt").boolValue = false;
|
||||
newElem.FindPropertyRelative("shift").boolValue = false;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
rebuildList();
|
||||
} else {
|
||||
Debug.LogWarning("No active Scene View found to capture.");
|
||||
}
|
||||
});
|
||||
captureBtn.text = "+ Capture Scene View";
|
||||
captureBtn.style.flexGrow = 1;
|
||||
captureBtn.style.height = 40;
|
||||
captureBtn.style.fontSize = 14;
|
||||
captureBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
captureBtn.style.backgroundColor = new StyleColor(new Color(0.25f, 0.65f, 0.4f));
|
||||
captureBtn.style.color = new StyleColor(Color.white);
|
||||
captureBtn.style.borderTopLeftRadius = 8;
|
||||
captureBtn.style.borderTopRightRadius = 8;
|
||||
captureBtn.style.borderBottomLeftRadius = 8;
|
||||
captureBtn.style.borderBottomRightRadius = 8;
|
||||
captureBtn.style.marginRight = 5;
|
||||
|
||||
// Add Empty Button
|
||||
Button addEmptyBtn = new Button(() => {
|
||||
pointsProp.arraySize++;
|
||||
SerializedProperty newElem = pointsProp.GetArrayElementAtIndex(pointsProp.arraySize - 1);
|
||||
newElem.FindPropertyRelative("name").stringValue = "New Empty " + pointsProp.arraySize;
|
||||
newElem.FindPropertyRelative("target").objectReferenceValue = null;
|
||||
newElem.FindPropertyRelative("key").intValue = (int)KeyCode.None;
|
||||
newElem.FindPropertyRelative("ctrl").boolValue = false;
|
||||
newElem.FindPropertyRelative("alt").boolValue = false;
|
||||
newElem.FindPropertyRelative("shift").boolValue = false;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
rebuildList();
|
||||
});
|
||||
addEmptyBtn.text = "Add Empty";
|
||||
addEmptyBtn.style.width = 100;
|
||||
addEmptyBtn.style.height = 40;
|
||||
addEmptyBtn.style.borderTopLeftRadius = 8;
|
||||
addEmptyBtn.style.borderTopRightRadius = 8;
|
||||
addEmptyBtn.style.borderBottomLeftRadius = 8;
|
||||
addEmptyBtn.style.borderBottomRightRadius = 8;
|
||||
|
||||
buttonsRow.Add(captureBtn);
|
||||
buttonsRow.Add(addEmptyBtn);
|
||||
|
||||
listContainer.Add(buttonsRow);
|
||||
};
|
||||
|
||||
rebuildList();
|
||||
|
||||
// Listen for Unity serialization changes (e.g. Undo/Redo)
|
||||
root.TrackPropertyValue(pointsProp, (prop) => {
|
||||
rebuildList();
|
||||
});
|
||||
|
||||
root.Add(Editor.ScovySignature.CreateSignatureBox());
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
2
Assets/Editors/CameraJumpPointsEditor.cs.meta
Normal file
2
Assets/Editors/CameraJumpPointsEditor.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6418c2e4db0af4342add5271469ded58
|
||||
@@ -37,7 +37,7 @@ namespace Editor
|
||||
private float maxTilt = 5f;
|
||||
private bool uniformScale = true;
|
||||
|
||||
[MenuItem("Tools/Level Decorator (Chaos Maker)")]
|
||||
[MenuItem("Tools/Level Decorator")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GetWindow<LevelDecorator>("Chaos Maker");
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.UIElements;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
@@ -40,8 +42,8 @@ namespace Editor
|
||||
private static EventModifiers playModifier;
|
||||
private static KeyCode playKey;
|
||||
|
||||
// Static constructor runs automatically when Unity loads or recompiles
|
||||
static PlayFromHereTool()
|
||||
[InitializeOnLoadMethod]
|
||||
static void Init()
|
||||
{
|
||||
LoadSettings();
|
||||
// Subscribe to SceneView GUI to listen for keyboard inputs
|
||||
@@ -72,52 +74,149 @@ namespace Editor
|
||||
EditorPrefs.SetInt("PFH_PlayKey", (int)playKey);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
public void CreateGUI()
|
||||
{
|
||||
GUILayout.Label("Shortcut Configuration", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
VisualElement root = rootVisualElement;
|
||||
root.style.paddingTop = 15;
|
||||
root.style.paddingBottom = 15;
|
||||
root.style.paddingLeft = 15;
|
||||
root.style.paddingRight = 15;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Label title = new Label("Shortcut Configuration");
|
||||
title.style.fontSize = 22;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.color = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
title.style.marginBottom = 15;
|
||||
root.Add(title);
|
||||
|
||||
// Section for Mode 1
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
GUILayout.Label("Mode 1: Teleport Only", EditorStyles.boldLabel);
|
||||
teleportModifier = (EventModifiers)EditorGUILayout.EnumFlagsField("Modifier Keys", teleportModifier);
|
||||
teleportKey = (KeyCode)EditorGUILayout.EnumPopup("Main Key", teleportKey);
|
||||
EditorGUILayout.EndVertical();
|
||||
// Warning Box for Conflicts
|
||||
VisualElement warningBox = new VisualElement();
|
||||
warningBox.style.backgroundColor = new StyleColor(new Color(0.8f, 0.2f, 0.2f, 0.3f));
|
||||
warningBox.style.borderLeftWidth = 4;
|
||||
warningBox.style.borderLeftColor = new StyleColor(new Color(0.9f, 0.3f, 0.3f));
|
||||
warningBox.style.paddingTop = 10;
|
||||
warningBox.style.paddingBottom = 10;
|
||||
warningBox.style.paddingLeft = 10;
|
||||
warningBox.style.marginBottom = 15;
|
||||
warningBox.style.display = DisplayStyle.None;
|
||||
|
||||
Label warningLabel = new Label("Conflict: Mode 1 and Mode 2 have the same hotkey!");
|
||||
warningLabel.style.color = new StyleColor(new Color(0.9f, 0.5f, 0.5f));
|
||||
warningLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
warningBox.Add(warningLabel);
|
||||
root.Add(warningBox);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
System.Action checkConflicts = () => {
|
||||
bool conflict = (teleportModifier == playModifier && teleportKey == playKey);
|
||||
warningBox.style.display = conflict ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
};
|
||||
|
||||
// Section for Mode 2
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
GUILayout.Label("Mode 2: Play From Here (Teleport + Play)", EditorStyles.boldLabel);
|
||||
playModifier = (EventModifiers)EditorGUILayout.EnumFlagsField("Modifier Keys", playModifier);
|
||||
playKey = (KeyCode)EditorGUILayout.EnumPopup("Main Key", playKey);
|
||||
EditorGUILayout.EndVertical();
|
||||
// Mode 1 Card
|
||||
Label mode1Title = new Label("Mode 1: Teleport Only");
|
||||
mode1Title.style.fontSize = 16;
|
||||
mode1Title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
mode1Title.style.color = new StyleColor(new Color(0.8f, 0.8f, 0.8f));
|
||||
mode1Title.style.marginBottom = 10;
|
||||
root.Add(mode1Title);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
VisualElement card1 = CreateCard();
|
||||
EnumFlagsField tMod = new EnumFlagsField("Modifier Keys", teleportModifier);
|
||||
tMod.RegisterValueChangedCallback(evt => {
|
||||
teleportModifier = (EventModifiers)evt.newValue;
|
||||
SaveSettings();
|
||||
}
|
||||
checkConflicts();
|
||||
});
|
||||
card1.Add(tMod);
|
||||
|
||||
// Conflict warning
|
||||
if (teleportModifier == playModifier && teleportKey == playKey)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Conflict: Mode 1 and Mode 2 have the same hotkey!", MessageType.Error);
|
||||
}
|
||||
EnumField tKey = new EnumField("Main Key", teleportKey);
|
||||
tKey.RegisterValueChangedCallback(evt => {
|
||||
teleportKey = (KeyCode)evt.newValue;
|
||||
SaveSettings();
|
||||
checkConflicts();
|
||||
});
|
||||
tKey.style.marginTop = 10;
|
||||
card1.Add(tKey);
|
||||
root.Add(card1);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
// Mode 2 Card
|
||||
Label mode2Title = new Label("Mode 2: Play From Here (Teleport + Play)");
|
||||
mode2Title.style.fontSize = 16;
|
||||
mode2Title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
mode2Title.style.color = new StyleColor(new Color(0.8f, 0.8f, 0.8f));
|
||||
mode2Title.style.marginTop = 15;
|
||||
mode2Title.style.marginBottom = 10;
|
||||
root.Add(mode2Title);
|
||||
|
||||
if (GUILayout.Button("Reset to Defaults", GUILayout.Height(30)))
|
||||
{
|
||||
VisualElement card2 = CreateCard();
|
||||
EnumFlagsField pMod = new EnumFlagsField("Modifier Keys", playModifier);
|
||||
pMod.RegisterValueChangedCallback(evt => {
|
||||
playModifier = (EventModifiers)evt.newValue;
|
||||
SaveSettings();
|
||||
checkConflicts();
|
||||
});
|
||||
card2.Add(pMod);
|
||||
|
||||
EnumField pKey = new EnumField("Main Key", playKey);
|
||||
pKey.RegisterValueChangedCallback(evt => {
|
||||
playKey = (KeyCode)evt.newValue;
|
||||
SaveSettings();
|
||||
checkConflicts();
|
||||
});
|
||||
pKey.style.marginTop = 10;
|
||||
card2.Add(pKey);
|
||||
root.Add(card2);
|
||||
|
||||
checkConflicts();
|
||||
|
||||
// Reset Button
|
||||
Button resetBtn = new Button(() => {
|
||||
teleportModifier = EventModifiers.Control | EventModifiers.Alt;
|
||||
teleportKey = KeyCode.P;
|
||||
playModifier = EventModifiers.Control | EventModifiers.Alt | EventModifiers.Shift;
|
||||
playKey = KeyCode.P;
|
||||
SaveSettings();
|
||||
GUI.FocusControl(null);
|
||||
}
|
||||
|
||||
root.Clear();
|
||||
CreateGUI(); // Rebuild
|
||||
});
|
||||
resetBtn.text = "Reset to Defaults";
|
||||
resetBtn.style.height = 40;
|
||||
resetBtn.style.marginTop = 20;
|
||||
resetBtn.style.backgroundColor = new StyleColor(new Color(0.7f, 0.3f, 0.3f));
|
||||
resetBtn.style.color = new StyleColor(Color.white);
|
||||
resetBtn.style.fontSize = 14;
|
||||
resetBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
resetBtn.style.borderTopLeftRadius = 6;
|
||||
resetBtn.style.borderTopRightRadius = 6;
|
||||
resetBtn.style.borderBottomLeftRadius = 6;
|
||||
resetBtn.style.borderBottomRightRadius = 6;
|
||||
root.Add(resetBtn);
|
||||
|
||||
root.Add(ScovySignature.CreateSignatureBox());
|
||||
}
|
||||
|
||||
private VisualElement CreateCard()
|
||||
{
|
||||
VisualElement card = new VisualElement();
|
||||
card.style.backgroundColor = new StyleColor(new Color(0.18f, 0.18f, 0.18f, 0.9f));
|
||||
card.style.borderTopLeftRadius = 10;
|
||||
card.style.borderTopRightRadius = 10;
|
||||
card.style.borderBottomLeftRadius = 10;
|
||||
card.style.borderBottomRightRadius = 10;
|
||||
card.style.paddingTop = 15;
|
||||
card.style.paddingBottom = 15;
|
||||
card.style.paddingLeft = 15;
|
||||
card.style.paddingRight = 15;
|
||||
|
||||
card.style.borderTopWidth = 1;
|
||||
card.style.borderBottomWidth = 1;
|
||||
card.style.borderLeftWidth = 1;
|
||||
card.style.borderRightWidth = 1;
|
||||
card.style.borderTopColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderBottomColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderLeftColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderRightColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
return card;
|
||||
}
|
||||
|
||||
private static void OnSceneGUI(SceneView view)
|
||||
|
||||
@@ -26,6 +26,8 @@ using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor.SceneManagement;
|
||||
using System.IO;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.UIElements;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
@@ -41,55 +43,69 @@ namespace Editor
|
||||
window.minSize = new Vector2(300, 450);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
public void CreateGUI()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
VisualElement root = rootVisualElement;
|
||||
root.style.paddingTop = 15;
|
||||
root.style.paddingBottom = 15;
|
||||
root.style.paddingLeft = 15;
|
||||
root.style.paddingRight = 15;
|
||||
|
||||
DrawPlaySection();
|
||||
EditorGUILayout.Space(15);
|
||||
|
||||
DrawSceneNavigation();
|
||||
EditorGUILayout.Space(15);
|
||||
|
||||
DrawDataManagement();
|
||||
}
|
||||
// Header
|
||||
Label title = new Label("Project Dashboard");
|
||||
title.style.fontSize = 22;
|
||||
title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
title.style.color = new StyleColor(new Color(0.3f, 0.7f, 1f));
|
||||
title.style.marginBottom = 15;
|
||||
root.Add(title);
|
||||
|
||||
private void DrawPlaySection()
|
||||
{
|
||||
GUILayout.Label("QUICK PLAY", EditorStyles.boldLabel);
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
// Quick Play Card
|
||||
VisualElement playCard = CreateCard();
|
||||
Label playTitle = new Label("QUICK PLAY");
|
||||
playTitle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
playTitle.style.marginBottom = 10;
|
||||
playCard.Add(playTitle);
|
||||
|
||||
// Green Play Button
|
||||
Color oldColor = GUI.backgroundColor;
|
||||
GUI.backgroundColor = new Color(0.4f, 1f, 0.4f); // Light Green
|
||||
Button playBtn = new Button(() => PlayFromBootScene());
|
||||
playBtn.text = "▶ PLAY GAME (From Boot Scene)";
|
||||
playBtn.style.height = 40;
|
||||
playBtn.style.backgroundColor = new StyleColor(new Color(0.2f, 0.6f, 0.3f));
|
||||
playBtn.style.color = new StyleColor(Color.white);
|
||||
playBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
playBtn.style.borderTopLeftRadius = 6;
|
||||
playBtn.style.borderTopRightRadius = 6;
|
||||
playBtn.style.borderBottomLeftRadius = 6;
|
||||
playBtn.style.borderBottomRightRadius = 6;
|
||||
playCard.Add(playBtn);
|
||||
|
||||
if (GUILayout.Button("▶ PLAY GAME (From Boot Scene)", GUILayout.Height(40)))
|
||||
{
|
||||
PlayFromBootScene();
|
||||
}
|
||||
Label helpText = new Label("Automatically saves, loads the first scene in Build Settings, and presses Play.");
|
||||
helpText.style.color = new StyleColor(new Color(0.6f, 0.6f, 0.6f));
|
||||
helpText.style.marginTop = 10;
|
||||
helpText.style.whiteSpace = WhiteSpace.Normal;
|
||||
playCard.Add(helpText);
|
||||
|
||||
GUI.backgroundColor = oldColor;
|
||||
|
||||
EditorGUILayout.HelpBox("Automatically saves your current scene, loads the first scene in Build Settings, and presses Play.", MessageType.Info);
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
root.Add(playCard);
|
||||
|
||||
private void DrawSceneNavigation()
|
||||
{
|
||||
GUILayout.Label("SCENE NAVIGATION (Build Settings)", EditorStyles.boldLabel);
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
// Scene Navigation
|
||||
VisualElement navCard = CreateCard();
|
||||
navCard.style.marginTop = 15;
|
||||
Label navTitle = new Label("SCENE NAVIGATION (Build Settings)");
|
||||
navTitle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
navTitle.style.marginBottom = 10;
|
||||
navCard.Add(navTitle);
|
||||
|
||||
// Fetch scenes dynamically from Build Settings
|
||||
ScrollView scrollView = new ScrollView();
|
||||
scrollView.style.maxHeight = 200;
|
||||
EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes;
|
||||
|
||||
if (scenes.Length == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No scenes found in Build Settings! Please go to File -> Build Settings and add your scenes.", MessageType.Warning);
|
||||
Label warn = new Label("No scenes found in Build Settings! Please go to File -> Build Settings.");
|
||||
warn.style.color = new StyleColor(new Color(0.9f, 0.7f, 0.2f));
|
||||
warn.style.whiteSpace = WhiteSpace.Normal;
|
||||
navCard.Add(warn);
|
||||
}
|
||||
else
|
||||
{
|
||||
sceneScrollPos = EditorGUILayout.BeginScrollView(sceneScrollPos, GUILayout.MaxHeight(200));
|
||||
|
||||
for (int i = 0; i < scenes.Length; i++)
|
||||
{
|
||||
if (scenes[i].enabled)
|
||||
@@ -97,41 +113,51 @@ namespace Editor
|
||||
string scenePath = scenes[i].path;
|
||||
string sceneName = Path.GetFileNameWithoutExtension(scenePath);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label($"[{i}]", GUILayout.Width(25));
|
||||
VisualElement row = new VisualElement();
|
||||
row.style.flexDirection = FlexDirection.Row;
|
||||
row.style.marginBottom = 5;
|
||||
row.style.alignItems = Align.Center;
|
||||
|
||||
Label indexLbl = new Label($"[{i}]");
|
||||
indexLbl.style.width = 30;
|
||||
indexLbl.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
|
||||
Button loadBtn = new Button(() => OpenScene(scenePath));
|
||||
loadBtn.text = $"Load {sceneName}";
|
||||
loadBtn.style.flexGrow = 1;
|
||||
loadBtn.style.height = 25;
|
||||
loadBtn.style.borderTopLeftRadius = 4;
|
||||
loadBtn.style.borderTopRightRadius = 4;
|
||||
loadBtn.style.borderBottomLeftRadius = 4;
|
||||
loadBtn.style.borderBottomRightRadius = 4;
|
||||
|
||||
if (GUILayout.Button($"Load {sceneName}", GUILayout.Height(25)))
|
||||
{
|
||||
OpenScene(scenePath);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
row.Add(indexLbl);
|
||||
row.Add(loadBtn);
|
||||
scrollView.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
navCard.Add(scrollView);
|
||||
}
|
||||
root.Add(navCard);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
// Data Management
|
||||
VisualElement dataCard = CreateCard();
|
||||
dataCard.style.marginTop = 15;
|
||||
Label dataTitle = new Label("DATA MANAGEMENT");
|
||||
dataTitle.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
dataTitle.style.marginBottom = 10;
|
||||
dataCard.Add(dataTitle);
|
||||
|
||||
private void DrawDataManagement()
|
||||
{
|
||||
GUILayout.Label("DATA MANAGEMENT", EditorStyles.boldLabel);
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
Button folderBtn = new Button(() => EditorUtility.RevealInFinder(Application.persistentDataPath));
|
||||
folderBtn.text = "Open Save Folder (Explorer/Finder)";
|
||||
folderBtn.style.height = 30;
|
||||
folderBtn.style.borderTopLeftRadius = 4;
|
||||
folderBtn.style.borderTopRightRadius = 4;
|
||||
folderBtn.style.borderBottomLeftRadius = 4;
|
||||
folderBtn.style.borderBottomRightRadius = 4;
|
||||
dataCard.Add(folderBtn);
|
||||
|
||||
if (GUILayout.Button("Open Save Folder (Explorer/Finder)", GUILayout.Height(30)))
|
||||
{
|
||||
EditorUtility.RevealInFinder(Application.persistentDataPath);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
// Red Delete Button
|
||||
Color oldColor = GUI.backgroundColor;
|
||||
GUI.backgroundColor = new Color(1f, 0.4f, 0.4f); // Light Red
|
||||
|
||||
if (GUILayout.Button("⚠ Clear PlayerPrefs & Save Data", GUILayout.Height(35)))
|
||||
{
|
||||
Button clearBtn = new Button(() => {
|
||||
if (EditorUtility.DisplayDialog(
|
||||
"Clear All Data?",
|
||||
"Are you sure you want to delete all PlayerPrefs and JSON save files?\nThis action cannot be undone.",
|
||||
@@ -140,10 +166,46 @@ namespace Editor
|
||||
{
|
||||
ClearAllData();
|
||||
}
|
||||
}
|
||||
});
|
||||
clearBtn.text = "⚠ Clear PlayerPrefs & Save Data";
|
||||
clearBtn.style.height = 35;
|
||||
clearBtn.style.marginTop = 10;
|
||||
clearBtn.style.backgroundColor = new StyleColor(new Color(0.7f, 0.3f, 0.3f));
|
||||
clearBtn.style.color = new StyleColor(Color.white);
|
||||
clearBtn.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
clearBtn.style.borderTopLeftRadius = 6;
|
||||
clearBtn.style.borderTopRightRadius = 6;
|
||||
clearBtn.style.borderBottomLeftRadius = 6;
|
||||
clearBtn.style.borderBottomRightRadius = 6;
|
||||
dataCard.Add(clearBtn);
|
||||
|
||||
GUI.backgroundColor = oldColor;
|
||||
EditorGUILayout.EndVertical();
|
||||
root.Add(dataCard);
|
||||
|
||||
root.Add(ScovySignature.CreateSignatureBox());
|
||||
}
|
||||
|
||||
private VisualElement CreateCard()
|
||||
{
|
||||
VisualElement card = new VisualElement();
|
||||
card.style.backgroundColor = new StyleColor(new Color(0.18f, 0.18f, 0.18f, 0.9f));
|
||||
card.style.borderTopLeftRadius = 10;
|
||||
card.style.borderTopRightRadius = 10;
|
||||
card.style.borderBottomLeftRadius = 10;
|
||||
card.style.borderBottomRightRadius = 10;
|
||||
card.style.paddingTop = 15;
|
||||
card.style.paddingBottom = 15;
|
||||
card.style.paddingLeft = 15;
|
||||
card.style.paddingRight = 15;
|
||||
|
||||
card.style.borderTopWidth = 1;
|
||||
card.style.borderBottomWidth = 1;
|
||||
card.style.borderLeftWidth = 1;
|
||||
card.style.borderRightWidth = 1;
|
||||
card.style.borderTopColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderBottomColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderLeftColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
card.style.borderRightColor = new StyleColor(new Color(0.12f, 0.12f, 0.12f));
|
||||
return card;
|
||||
}
|
||||
|
||||
private void PlayFromBootScene()
|
||||
|
||||
82
Assets/Editors/ScovySignature.cs
Normal file
82
Assets/Editors/ScovySignature.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using System.IO;
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
public static class ScovySignature
|
||||
{
|
||||
public static VisualElement CreateSignatureBox()
|
||||
{
|
||||
VisualElement signatureBox = new VisualElement();
|
||||
signatureBox.style.marginTop = 25;
|
||||
signatureBox.style.paddingTop = 15;
|
||||
signatureBox.style.paddingBottom = 10;
|
||||
signatureBox.style.borderTopWidth = 1;
|
||||
signatureBox.style.borderTopColor = new StyleColor(new Color(0.25f, 0.25f, 0.25f));
|
||||
signatureBox.style.alignItems = Align.Center;
|
||||
|
||||
Label creatorLabel = new Label("Created by Scovy");
|
||||
creatorLabel.style.fontSize = 14;
|
||||
creatorLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
creatorLabel.style.color = new StyleColor(new Color(0.4f, 0.8f, 1f));
|
||||
signatureBox.Add(creatorLabel);
|
||||
|
||||
// Load ascii art from catgirl.txt
|
||||
string asciiText = " /\\_/\\ \n ( o.o ) \n > ^ < "; // Fallback
|
||||
|
||||
// Search for the text asset anywhere in the project
|
||||
string[] guids = AssetDatabase.FindAssets("catgirl t:TextAsset");
|
||||
if (guids.Length > 0)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
TextAsset txtAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
|
||||
if (txtAsset != null)
|
||||
{
|
||||
asciiText = txtAsset.text;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback attempt to read directly if Unity hasn't indexed it yet
|
||||
string directPath = Path.Combine(Application.dataPath, "Editors/catgirl.txt");
|
||||
if (File.Exists(directPath))
|
||||
{
|
||||
asciiText = File.ReadAllText(directPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent Unity from stripping leading spaces by replacing them with non-breaking spaces
|
||||
asciiText = asciiText.Replace(" ", "\u00A0");
|
||||
|
||||
Label asciiArt = new Label(asciiText);
|
||||
asciiArt.style.whiteSpace = WhiteSpace.Pre;
|
||||
asciiArt.style.color = new StyleColor(new Color(0.5f, 0.5f, 0.5f));
|
||||
asciiArt.style.marginTop = 5;
|
||||
asciiArt.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||
|
||||
// Increased font size based on feedback
|
||||
asciiArt.style.fontSize = 10;
|
||||
|
||||
// Attempt to load an OS system font that supports Braille characters (like MS Gothic or Segoe UI Symbol)
|
||||
Font osFont = Font.CreateDynamicFontFromOSFont(new string[] { "MS Gothic", "Segoe UI Symbol", "Consolas", "Arial" }, 10);
|
||||
if (osFont != null)
|
||||
{
|
||||
// In newer Unity versions unityFontDefinition is preferred
|
||||
asciiArt.style.unityFontDefinition = new StyleFontDefinition(osFont);
|
||||
}
|
||||
|
||||
// Also add a scrollview wrapper just in case it's still too large
|
||||
ScrollView scrollWrapper = new ScrollView();
|
||||
scrollWrapper.style.maxHeight = 250; // Increased height to accommodate larger font
|
||||
scrollWrapper.style.marginTop = 5;
|
||||
scrollWrapper.contentContainer.style.alignItems = Align.Center;
|
||||
scrollWrapper.Add(asciiArt);
|
||||
|
||||
signatureBox.Add(scrollWrapper);
|
||||
|
||||
return signatureBox;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Editors/ScovySignature.cs.meta
Normal file
2
Assets/Editors/ScovySignature.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e111b033e887ade4b8a2459210a0df00
|
||||
@@ -45,80 +45,74 @@ namespace Editor
|
||||
|
||||
private static void OnSceneGUI(SceneView sceneView)
|
||||
{
|
||||
// Only display the panel when the game is actually running
|
||||
if (!Application.isPlaying) return;
|
||||
|
||||
Handles.BeginGUI();
|
||||
|
||||
// Calculate center-top position dynamically based on current Scene View size
|
||||
float posX = (sceneView.position.width - PANEL_WIDTH) / 2f;
|
||||
float posY = 15f;
|
||||
Rect panelRect = new Rect(posX, posY, PANEL_WIDTH, PANEL_HEIGHT);
|
||||
float panelWidth = 460f;
|
||||
float panelHeight = 40f;
|
||||
float posX = (sceneView.position.width - panelWidth) / 2f;
|
||||
float posY = 20f;
|
||||
Rect panelRect = new Rect(posX, posY, panelWidth, panelHeight);
|
||||
|
||||
// Draw the main background box
|
||||
GUI.Box(panelRect, GUIContent.none, EditorStyles.helpBox);
|
||||
|
||||
GUILayout.BeginArea(new Rect(posX + 10, posY + 10, PANEL_WIDTH - 20, PANEL_HEIGHT - 20));
|
||||
|
||||
// --- 1. HEADER (Title & Current Speed) ---
|
||||
GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel)
|
||||
{
|
||||
richText = true,
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = 13
|
||||
};
|
||||
// Sleek semi-transparent dark background
|
||||
EditorGUI.DrawRect(panelRect, new Color(0.1f, 0.1f, 0.1f, 0.85f));
|
||||
|
||||
// Format the time scale to show 2 decimal places
|
||||
// Thin accent line at the top
|
||||
EditorGUI.DrawRect(new Rect(posX, posY, panelWidth, 2), new Color(0.3f, 0.7f, 1f, 0.8f));
|
||||
|
||||
GUILayout.BeginArea(new Rect(posX + 10, posY + 8, panelWidth - 20, panelHeight - 16));
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
// --- 1. HEADER (Current Speed) ---
|
||||
string currentSpeedText = EditorApplication.isPaused ? "<color=#FF6B6B>PAUSED</color>" : $"<color=#4ECDC4>{Time.timeScale:F2}x</color>";
|
||||
GUILayout.Label($"⏳ <b>TIME LORD</b> | Current: {currentSpeedText}", headerStyle);
|
||||
GUILayout.Space(5);
|
||||
GUILayout.Label($"⏳ {currentSpeedText}", new GUIStyle(EditorStyles.boldLabel) { richText = true, fontSize = 13, alignment = TextAnchor.MiddleLeft }, GUILayout.Width(80));
|
||||
|
||||
// --- 2. TIME SLIDER (Fine-tune control) ---
|
||||
EditorGUI.BeginChangeCheck();
|
||||
float newTimeScale = GUILayout.HorizontalSlider(Time.timeScale, 0f, 10f);
|
||||
float newTimeScale = GUILayout.HorizontalSlider(Time.timeScale, 0f, 10f, GUILayout.Width(80), GUILayout.Height(20));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Time.timeScale = newTimeScale;
|
||||
// Auto-resume if adjusting slider while paused
|
||||
if (EditorApplication.isPaused && newTimeScale > 0f)
|
||||
{
|
||||
EditorApplication.isPaused = false;
|
||||
}
|
||||
}
|
||||
GUILayout.Space(5);
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
// --- 3. PRESET SPEED BUTTONS ---
|
||||
GUILayout.BeginHorizontal();
|
||||
DrawSpeedButton("0.1x", 0.1f);
|
||||
DrawSpeedButton("0.5x", 0.5f);
|
||||
DrawSpeedButton("1x", 1f);
|
||||
DrawSpeedButton("2x", 2f);
|
||||
DrawSpeedButton("5x", 5f);
|
||||
GUILayout.EndHorizontal();
|
||||
DrawSpeedButton("0.5x", 0.5f, 35);
|
||||
DrawSpeedButton("1x", 1f, 30);
|
||||
DrawSpeedButton("2x", 2f, 30);
|
||||
DrawSpeedButton("5x", 5f, 30);
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// --- 4. PAUSE / RESUME BUTTON ---
|
||||
Color oldBgColor = GUI.backgroundColor;
|
||||
GUI.backgroundColor = EditorApplication.isPaused ? new Color(1f, 0.4f, 0.4f) : new Color(0.9f, 0.9f, 0.9f);
|
||||
GUI.backgroundColor = EditorApplication.isPaused ? new Color(1f, 0.4f, 0.4f) : new Color(0.8f, 0.8f, 0.8f);
|
||||
|
||||
string pauseLabel = EditorApplication.isPaused ? "▶ RESUME GAME" : "⏸ PAUSE GAME";
|
||||
string pauseLabel = EditorApplication.isPaused ? "▶ RESUME" : "⏸ PAUSE";
|
||||
GUIStyle pauseStyle = new GUIStyle(GUI.skin.button) { fontStyle = FontStyle.Bold };
|
||||
|
||||
if (GUILayout.Button(pauseLabel, pauseStyle, GUILayout.Height(25)))
|
||||
if (GUILayout.Button(pauseLabel, pauseStyle, GUILayout.Width(80), GUILayout.Height(24)))
|
||||
{
|
||||
EditorApplication.isPaused = !EditorApplication.isPaused;
|
||||
}
|
||||
GUI.backgroundColor = oldBgColor;
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndArea();
|
||||
|
||||
Handles.EndGUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a preset button that automatically highlights green if it matches the current time scale.
|
||||
/// </summary>
|
||||
private static void DrawSpeedButton(string label, float targetSpeed)
|
||||
private static void DrawSpeedButton(string label, float targetSpeed, float width)
|
||||
{
|
||||
Color oldBgColor = GUI.backgroundColor;
|
||||
|
||||
@@ -129,7 +123,7 @@ namespace Editor
|
||||
GUI.backgroundColor = new Color(0.4f, 1f, 0.4f); // Light Green
|
||||
}
|
||||
|
||||
if (GUILayout.Button(label, GUILayout.Height(22)))
|
||||
if (GUILayout.Button(label, GUILayout.Width(width), GUILayout.Height(24)))
|
||||
{
|
||||
Time.timeScale = targetSpeed;
|
||||
|
||||
|
||||
4
Assets/Editors/catgirl.txt
Normal file
4
Assets/Editors/catgirl.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
╱|、
|
||||
(˚ˎ 。7
|
||||
|、˜〵
|
||||
じしˍ,)ノ
|
||||
7
Assets/Editors/catgirl.txt.meta
Normal file
7
Assets/Editors/catgirl.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1243462c0117614cba30fe64aa5d2b0
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user