175 lines
6.6 KiB
C#
175 lines
6.6 KiB
C#
|
|
// ===============================================================================
|
||
|
|
// AutoSaveTool - Persistent & Robust Auto-Saving for Unity Editor
|
||
|
|
//
|
||
|
|
// Creator: Scove
|
||
|
|
// Last Updated: 2024-05-08
|
||
|
|
// Version: 2.0
|
||
|
|
//
|
||
|
|
// Purpose:
|
||
|
|
// This tool provides a persistent, background auto-saving mechanism for the Unity Editor.
|
||
|
|
// It runs automatically when Unity starts and saves all open scenes and modified assets
|
||
|
|
// at a user-defined interval, even when the settings window is closed.
|
||
|
|
//
|
||
|
|
// Key Features:
|
||
|
|
// 1. Runs persistently in the background via [InitializeOnLoad].
|
||
|
|
// 2. Saves configuration (interval, status) using EditorPrefs, persisting across Unity sessions.
|
||
|
|
// 3. Uses System.DateTime for accurate time tracking, unaffected by Play Mode reloads.
|
||
|
|
// 4. Pauses counting down during Play Mode or compilation to prevent accidental saving.
|
||
|
|
//
|
||
|
|
// How to Use:
|
||
|
|
// 1. Place this script in an 'Editor' folder in your project.
|
||
|
|
// 2. Open the settings window via: Menu -> Tools -> Auto Save Settings.
|
||
|
|
// 3. Enable "Bật Auto Save" (Enable Auto Save).
|
||
|
|
// 4. Set the desired "Thời gian (phút)" (Interval in minutes).
|
||
|
|
// 5. The tool will now save automatically in the background according to the schedule.
|
||
|
|
// ===============================================================================
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditor.SceneManagement;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace Editor
|
||
|
|
{
|
||
|
|
[InitializeOnLoad] // Critical: Ensures the script runs in the background upon Unity startup
|
||
|
|
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()
|
||
|
|
{
|
||
|
|
// 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
[MenuItem("Tools/Auto Save Settings")]
|
||
|
|
public static void ShowWindow()
|
||
|
|
{
|
||
|
|
GetWindow<AutoSaveTool>("Auto Save");
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnGUI()
|
||
|
|
{
|
||
|
|
GUILayout.Label("Auto Save Configuration (Runs in Background)", EditorStyles.boldLabel);
|
||
|
|
EditorGUILayout.Space();
|
||
|
|
|
||
|
|
// 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
|
||
|
|
|
||
|
|
EditorPrefs.SetBool("AutoSave_Enabled", isAutoSaveEnabled);
|
||
|
|
EditorPrefs.SetFloat("AutoSave_Interval", saveIntervalMinutes);
|
||
|
|
EditorPrefs.SetBool("AutoSave_Log", showDebugLog);
|
||
|
|
|
||
|
|
ResetTimer(); // Reset timer based on new settings
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorGUILayout.Space();
|
||
|
|
|
||
|
|
if (isAutoSaveEnabled)
|
||
|
|
{
|
||
|
|
TimeSpan timeRemaining = nextSaveTime - DateTime.Now;
|
||
|
|
if (timeRemaining.TotalSeconds < 0) timeRemaining = TimeSpan.Zero;
|
||
|
|
|
||
|
|
// 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);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GUILayout.Button("Save Now", GUILayout.Height(30)))
|
||
|
|
{
|
||
|
|
SaveNow();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
EditorGUILayout.HelpBox("Auto Save System is currently DISABLED.", MessageType.Error);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 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()
|
||
|
|
{
|
||
|
|
nextSaveTime = DateTime.Now.AddMinutes(saveIntervalMinutes);
|
||
|
|
}
|
||
|
|
|
||
|
|
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;
|
||
|
|
|
||
|
|
if (isSaved && showDebugLog)
|
||
|
|
{
|
||
|
|
Debug.Log($"<color=#00FF00><b>[AutoSave]</b></color> Project saved automatically at {DateTime.Now.ToString("HH:mm:ss")}");
|
||
|
|
}
|
||
|
|
|
||
|
|
ResetTimer();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|