Files
BABA_YAGA/Assets/Editor/CameraBookmarksTool.cs

226 lines
8.9 KiB
C#
Raw Normal View History

2026-03-26 20:27:19 +07:00
// ===============================================================================
// CameraBookmarksTool - Configurable Scene View Camera Save & Load
//
// Creator: Scove
// Last Updated: 2024-05-08
// Version: 3.0
//
// Purpose:
// Allows saving and loading specific Scene View camera angles and positions.
// Includes an Editor Window interface to completely customize the keyboard shortcuts.
//
// How to Use:
// 1. Place this script in an 'Editor' folder in your project.
// 2. Open Settings: Menu -> Tools -> Camera Bookmarks Settings.
// 3. Customize your Save/Load modifiers (e.g., Control, Shift, Alt).
// 4. Customize the shortcut keys for Slot 1 to 9.
// 5. Focus the Scene View and use your assigned shortcuts to Save/Load camera angles.
// ===============================================================================
using UnityEditor;
using UnityEngine;
using System.Globalization;
using System;
namespace Editor
{
[InitializeOnLoad]
public class CameraBookmarksTool : EditorWindow
{
// Customizable Shortcut Keys
private static EventModifiers saveModifier;
private static EventModifiers loadModifier;
private static KeyCode[] slotKeys = new KeyCode[9];
// Static constructor runs automatically when Unity loads or recompiles
static CameraBookmarksTool()
{
LoadSettings();
SceneView.duringSceneGui += OnSceneGUI;
}[MenuItem("Tools/Camera Bookmarks Settings")]
public static void ShowWindow()
{
GetWindow<CameraBookmarksTool>("Cam Bookmarks");
}
private static void LoadSettings()
{
// Load settings from EditorPrefs, fallback to Control/Shift if not found
saveModifier = (EventModifiers)EditorPrefs.GetInt("CamBM_SaveMod", (int)EventModifiers.Control);
loadModifier = (EventModifiers)EditorPrefs.GetInt("CamBM_LoadMod", (int)EventModifiers.Shift);
// Load key bindings for 9 slots, fallback to Alpha1-Alpha9
for (int i = 0; i < 9; i++)
{
int defaultKey = (int)(KeyCode.Alpha1 + i);
slotKeys[i] = (KeyCode)EditorPrefs.GetInt($"CamBM_Key_{i}", defaultKey);
}
}
private static void SaveSettings()
{
EditorPrefs.SetInt("CamBM_SaveMod", (int)saveModifier);
EditorPrefs.SetInt("CamBM_LoadMod", (int)loadModifier);
for (int i = 0; i < 9; i++)
{
EditorPrefs.SetInt($"CamBM_Key_{i}", (int)slotKeys[i]);
}
}
private void OnGUI()
{
GUILayout.Label("Shortcut Configuration", EditorStyles.boldLabel);
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
// Modifier Keys Setup
saveModifier = (EventModifiers)EditorGUILayout.EnumFlagsField("Save Modifier", saveModifier);
loadModifier = (EventModifiers)EditorGUILayout.EnumFlagsField("Load Modifier", loadModifier);
if (saveModifier == loadModifier)
{
EditorGUILayout.HelpBox("Warning: Save and Load modifiers are the SAME! This will cause conflicts.", MessageType.Warning);
}
EditorGUILayout.Space();
GUILayout.Label("Slot Keys Assignment", EditorStyles.boldLabel);
// KeyCode Setup for 9 slots
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();
}
if (EditorGUI.EndChangeCheck())
{
SaveSettings(); // Save immediately if anything changes
}
EditorGUILayout.Space();
EditorGUILayout.Space();
// Reset Button
if (GUILayout.Button("Reset to Default Settings", GUILayout.Height(30)))
{
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
}
}
static void OnSceneGUI(SceneView view)
{
Event e = Event.current;
if (e.type == EventType.KeyDown)
{
// Mask out CapsLock, NumLock, and Function keys. We only care about main modifiers.
EventModifiers currentMods = e.modifiers & (EventModifiers.Shift | EventModifiers.Control | EventModifiers.Alt | EventModifiers.Command);
// Check if the pressed key matches any of our custom assigned slot keys
int pressedSlotIndex = -1;
for (int i = 0; i < 9; i++)
{
if (e.keyCode == slotKeys[i] && e.keyCode != KeyCode.None)
{
pressedSlotIndex = i + 1;
break;
}
}
if (pressedSlotIndex != -1)
{
string prefsKey = $"CamBookmark_Slot_{pressedSlotIndex}";
// SAVE ACTION
if (currentMods == saveModifier)
{
SaveBookmark(view, prefsKey, pressedSlotIndex);
e.Use(); // Consume the event
}
// LOAD ACTION
else if (currentMods == loadModifier)
{
LoadBookmark(view, prefsKey, pressedSlotIndex);
e.Use(); // Consume the event
}
}
}
}
private static void SaveBookmark(SceneView view, string key, int slotIndex)
{
Transform camTransform = view.camera.transform;
float size = view.size;
// Use InvariantCulture to ensure dot (.) is used for decimals, preventing regional bugs
string data = string.Format(CultureInfo.InvariantCulture,
"{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}",
camTransform.position.x, camTransform.position.y, camTransform.position.z,
camTransform.rotation.x, camTransform.rotation.y, camTransform.rotation.z, camTransform.rotation.w,
size);
EditorPrefs.SetString(key, data);
// Show feedback in Scene View
string message = $"Saved Camera Bookmark to Slot {slotIndex}";
view.ShowNotification(new GUIContent(message));
Debug.Log($"<color=#00FF00><b>[CameraBookmarks]</b></color> {message}");
}
private static void LoadBookmark(SceneView view, string key, int slotIndex)
{
if (!EditorPrefs.HasKey(key))
{
string emptyMsg = $"Slot {slotIndex} is empty!";
view.ShowNotification(new GUIContent(emptyMsg));
Debug.LogWarning($"<b>[CameraBookmarks]</b> {emptyMsg}");
return;
}
string[] parts = EditorPrefs.GetString(key).Split('|');
if (parts.Length == 8)
{
try
{
// Parse data back to floats using InvariantCulture
Vector3 pos = new Vector3(
float.Parse(parts[0], CultureInfo.InvariantCulture),
float.Parse(parts[1], CultureInfo.InvariantCulture),
float.Parse(parts[2], CultureInfo.InvariantCulture)
);
Quaternion rot = new Quaternion(
float.Parse(parts[3], CultureInfo.InvariantCulture),
float.Parse(parts[4], CultureInfo.InvariantCulture),
float.Parse(parts[5], CultureInfo.InvariantCulture),
float.Parse(parts[6], CultureInfo.InvariantCulture)
);
float size = float.Parse(parts[7], CultureInfo.InvariantCulture);
// Apply the saved transform to the Scene View camera
view.LookAtDirect(pos, rot, size);
// Show feedback in Scene View
string message = $"Loaded Camera Bookmark from Slot {slotIndex}";
view.ShowNotification(new GUIContent(message));
Debug.Log($"<color=#00FFFF><b>[CameraBookmarks]</b></color> {message}");
}
catch (Exception ex)
{
Debug.LogError($"<b>[CameraBookmarks]</b> Failed to parse data for Slot {slotIndex}. Error: {ex.Message}");
}
}
}
}
}