Created unity project
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Codice.Client.Common;
|
||||
using Codice.Utils;
|
||||
using PlasticGui;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class AssetsPath
|
||||
{
|
||||
internal static class GetFullPath
|
||||
{
|
||||
internal static string ForObject(Object obj)
|
||||
{
|
||||
string relativePath = AssetDatabase.GetAssetPath(obj);
|
||||
|
||||
if (string.IsNullOrEmpty(relativePath))
|
||||
return null;
|
||||
|
||||
return Path.GetFullPath(relativePath);
|
||||
}
|
||||
|
||||
internal static string ForGuid(string guid)
|
||||
{
|
||||
string relativePath = GetAssetPath(guid);
|
||||
|
||||
if (string.IsNullOrEmpty(relativePath))
|
||||
return null;
|
||||
|
||||
return Path.GetFullPath(relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class GetFullPathUnderWorkspace
|
||||
{
|
||||
internal static string ForAsset(
|
||||
string wkPath,
|
||||
string assetPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetPath))
|
||||
return null;
|
||||
|
||||
string fullPath = Path.GetFullPath(assetPath);
|
||||
|
||||
if (!PathHelper.IsContainedOn(fullPath, wkPath))
|
||||
return null;
|
||||
|
||||
if (!fullPath.StartsWith("/"))
|
||||
fullPath = fullPath.Substring(0, 1).ToLowerInvariant() + fullPath.Substring(1);
|
||||
return fullPath.TrimEnd('/', '\\');
|
||||
}
|
||||
|
||||
internal static string ForGuid(
|
||||
string wkPath,
|
||||
string guid)
|
||||
{
|
||||
return ForAsset(wkPath, GetAssetPath(guid));
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetLayoutsFolderRelativePath()
|
||||
{
|
||||
return string.Concat(mAssetsFolderLocation, "/Layouts");
|
||||
}
|
||||
|
||||
internal static string GetStylesFolderRelativePath()
|
||||
{
|
||||
return string.Concat(mAssetsFolderLocation, "/Styles");
|
||||
}
|
||||
|
||||
internal static string GetImagesFolderRelativePath()
|
||||
{
|
||||
return string.Concat(mAssetsFolderLocation, "/Images");
|
||||
}
|
||||
|
||||
internal static string GetRelativePath(string fullPath)
|
||||
{
|
||||
return PathHelper.GetRelativePath(
|
||||
mProjectFullPath, fullPath).Substring(1);
|
||||
}
|
||||
|
||||
internal static bool IsRunningAsUPMPackage()
|
||||
{
|
||||
string unityPlasticDllPath = Path.GetFullPath(
|
||||
AssemblyLocation.GetAssemblyDirectory(
|
||||
Assembly.GetAssembly(typeof(PlasticLocalization))));
|
||||
|
||||
// The Plastic Dll path when running as a UPM package is either
|
||||
// "Packages/com.unity.collab-proxy@xxx/Lib/Editor/unityplastic.dll" when running as an UPM package
|
||||
// "Assets/Plugins/PlasticSCM/Lib/Editor/unityplastic.dll" in the development environment
|
||||
return unityPlasticDllPath.Contains("com.unity.collab-proxy");
|
||||
}
|
||||
|
||||
static string GetAssetPath(string guid)
|
||||
{
|
||||
if (string.IsNullOrEmpty(guid))
|
||||
return null;
|
||||
|
||||
return AssetDatabase.GUIDToAssetPath(guid);
|
||||
}
|
||||
|
||||
internal static bool IsPackagesRootElement(string path)
|
||||
{
|
||||
return PathHelper.IsSamePath(mProjectPackagesFullPath, PathHelper.GetParentPath(path));
|
||||
}
|
||||
|
||||
internal static bool IsScript(string path)
|
||||
{
|
||||
return Path.GetExtension(path).Equals(".cs");
|
||||
}
|
||||
|
||||
static AssetsPath()
|
||||
{
|
||||
mAssetsFolderLocation = (IsRunningAsUPMPackage()) ?
|
||||
"Packages/com.unity.collab-proxy/Editor/Assets" :
|
||||
"Assets/Plugins/PlasticSCM/Editor/Assets";
|
||||
}
|
||||
|
||||
static readonly string mProjectFullPath = ProjectPath.FromApplicationDataPath(ApplicationDataPath.Get());
|
||||
static readonly string mProjectPackagesFullPath = Path.Combine(mProjectFullPath, "Packages");
|
||||
|
||||
static string mAssetsFolderLocation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a077a49d9db9de74f827f0568f6e65c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Unity.PlasticSCM.Editor.AssetMenu;
|
||||
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
|
||||
using UnityEditor.VersionControl;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class GetSelectedPaths
|
||||
{
|
||||
internal static List<string> ForOperation(
|
||||
string wkPath,
|
||||
AssetList assetList,
|
||||
IAssetStatusCache assetStatusCache,
|
||||
AssetMenuOperations operation,
|
||||
bool includeMetaFiles = true)
|
||||
{
|
||||
List<string> selectedPaths = AssetsSelection.
|
||||
GetSelectedPaths(wkPath, assetList);
|
||||
|
||||
List<string> result = new List<string>(selectedPaths);
|
||||
|
||||
if (!includeMetaFiles)
|
||||
return result;
|
||||
|
||||
foreach (string path in selectedPaths)
|
||||
{
|
||||
if (MetaPath.IsMetaPath(path))
|
||||
continue;
|
||||
|
||||
string metaPath = MetaPath.GetMetaPath(path);
|
||||
|
||||
if (!File.Exists(metaPath))
|
||||
continue;
|
||||
|
||||
if (result.Contains(metaPath))
|
||||
continue;
|
||||
|
||||
if (!IsApplicableForOperation(
|
||||
metaPath, false, operation, assetStatusCache))
|
||||
continue;
|
||||
|
||||
result.Add(metaPath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool IsApplicableForOperation(
|
||||
string path,
|
||||
bool isDirectory,
|
||||
AssetMenuOperations operation,
|
||||
IAssetStatusCache assetStatusCache)
|
||||
{
|
||||
SelectedAssetGroupInfo info = SelectedAssetGroupInfo.BuildFromSingleFile(
|
||||
path, isDirectory, assetStatusCache);
|
||||
|
||||
return AssetMenuUpdater.GetAvailableMenuOperations(info).HasFlag(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9369fa547ca81b4fafa42a3e74c1b7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
using Codice.Client.BaseCommands;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class LoadAsset
|
||||
{
|
||||
internal static UnityEngine.Object FromChangeInfo(ChangeInfo changeInfo)
|
||||
{
|
||||
string changeFullPath = changeInfo.GetFullPath();
|
||||
|
||||
if (MetaPath.IsMetaPath(changeFullPath))
|
||||
changeFullPath = MetaPath.GetPathFromMetaPath(changeFullPath);
|
||||
|
||||
return FromFullPath(changeFullPath);
|
||||
}
|
||||
|
||||
static UnityEngine.Object FromFullPath(string fullPath)
|
||||
{
|
||||
if (!IsPathUnderProject(fullPath))
|
||||
return null;
|
||||
|
||||
return AssetDatabase.LoadMainAssetAtPath(
|
||||
AssetsPath.GetRelativePath(fullPath));
|
||||
}
|
||||
|
||||
static bool IsPathUnderProject(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return false;
|
||||
|
||||
var fullPath = Path.GetFullPath(path).Replace('\\', '/');
|
||||
|
||||
return fullPath.StartsWith(
|
||||
mProjectRelativePath,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
static string mProjectRelativePath =
|
||||
Directory.GetCurrentDirectory().Replace('\\', '/') + '/';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91f74d588534bef42ac4b919a2ece84a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5a9787c5ed94504798db0c3330424fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,106 @@
|
||||
using UnityEditor;
|
||||
|
||||
using Codice.LogWrapper;
|
||||
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
|
||||
using Unity.PlasticSCM.Editor.UI;
|
||||
using AssetOverlays = Unity.PlasticSCM.Editor.AssetsOverlays;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
|
||||
{
|
||||
class AssetModificationProcessor : UnityEditor.AssetModificationProcessor
|
||||
{
|
||||
internal static bool ForceCheckout { get; private set; }
|
||||
|
||||
/* We need to do a checkout, verifying that the content/date or size has changed.
|
||||
* In order to do this checkout we need the changes to have reached the disk.
|
||||
* That's why we save the changed files in this array, and when they are reloaded
|
||||
* in AssetPostprocessor.OnPostprocessAllAssets we process them. */
|
||||
internal static string[] ModifiedAssets { get; set; }
|
||||
|
||||
static AssetModificationProcessor()
|
||||
{
|
||||
ForceCheckout = EditorPrefs.GetBool(
|
||||
UnityConstants.FORCE_CHECKOUT_KEY_NAME);
|
||||
}
|
||||
|
||||
internal static void Enable(
|
||||
string wkPath,
|
||||
IAssetStatusCache assetStatusCache)
|
||||
{
|
||||
mLog.Debug("Enable");
|
||||
|
||||
mWkPath = wkPath;
|
||||
mAssetStatusCache = assetStatusCache;
|
||||
|
||||
mIsEnabled = true;
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
{
|
||||
mLog.Debug("Disable");
|
||||
|
||||
mIsEnabled = false;
|
||||
|
||||
mWkPath = null;
|
||||
mAssetStatusCache = null;
|
||||
}
|
||||
|
||||
internal static void SetForceCheckoutOption(bool isEnabled)
|
||||
{
|
||||
ForceCheckout = isEnabled;
|
||||
|
||||
EditorPrefs.SetBool(
|
||||
UnityConstants.FORCE_CHECKOUT_KEY_NAME,
|
||||
isEnabled);
|
||||
}
|
||||
|
||||
static string[] OnWillSaveAssets(string[] paths)
|
||||
{
|
||||
if (!mIsEnabled)
|
||||
return paths;
|
||||
|
||||
ModifiedAssets = (string[])paths.Clone();
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static bool IsOpenForEdit(string assetPath, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
|
||||
if (!mIsEnabled)
|
||||
return true;
|
||||
|
||||
if (!ForceCheckout)
|
||||
return true;
|
||||
|
||||
if (assetPath.StartsWith("ProjectSettings/"))
|
||||
return true;
|
||||
|
||||
string assetFullPath = AssetsPath.GetFullPathUnderWorkspace.
|
||||
ForAsset(mWkPath, assetPath);
|
||||
|
||||
if (assetFullPath == null)
|
||||
return true;
|
||||
|
||||
if (MetaPath.IsMetaPath(assetFullPath))
|
||||
assetFullPath = MetaPath.GetPathFromMetaPath(assetFullPath);
|
||||
|
||||
AssetOverlays.AssetStatus status = mAssetStatusCache.
|
||||
GetStatus(assetFullPath);
|
||||
|
||||
if (AssetOverlays.ClassifyAssetStatus.IsAdded(status) ||
|
||||
AssetOverlays.ClassifyAssetStatus.IsCheckedOut(status))
|
||||
return true;
|
||||
|
||||
return !AssetOverlays.ClassifyAssetStatus.IsControlled(status);
|
||||
}
|
||||
|
||||
static bool mIsEnabled;
|
||||
|
||||
static IAssetStatusCache mAssetStatusCache;
|
||||
static string mWkPath;
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("AssetModificationProcessor");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c53c624438663f74ab67fbdf8869ae18
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,199 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
using Codice.Client.Common;
|
||||
using Codice.Client.Common.FsNodeReaders.Watcher;
|
||||
using Codice.LogWrapper;
|
||||
using Unity.PlasticSCM.Editor.UI;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
|
||||
{
|
||||
class AssetPostprocessor : UnityEditor.AssetPostprocessor
|
||||
{
|
||||
internal static bool AutomaticAdd { get; private set; }
|
||||
|
||||
static AssetPostprocessor()
|
||||
{
|
||||
AutomaticAdd = BoolSetting.Load(UnityConstants.AUTOMATIC_ADD_KEY_NAME, true);
|
||||
}
|
||||
|
||||
internal static void SetAutomaticAddOption(bool isEnabled)
|
||||
{
|
||||
if (AutomaticAdd != isEnabled)
|
||||
{
|
||||
AutomaticAdd = isEnabled;
|
||||
|
||||
BoolSetting.Save(isEnabled, UnityConstants.AUTOMATIC_ADD_KEY_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
internal struct PathToMove
|
||||
{
|
||||
internal readonly string SrcPath;
|
||||
internal readonly string DstPath;
|
||||
|
||||
internal PathToMove(string srcPath, string dstPath)
|
||||
{
|
||||
SrcPath = srcPath;
|
||||
DstPath = dstPath;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Enable(
|
||||
string wkPath,
|
||||
PlasticAssetsProcessor plasticAssetsProcessor)
|
||||
{
|
||||
mLog.Debug("Enable");
|
||||
|
||||
mWkPath = wkPath;
|
||||
mPlasticAssetsProcessor = plasticAssetsProcessor;
|
||||
|
||||
mIsEnabled = true;
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
{
|
||||
mLog.Debug("Disable");
|
||||
|
||||
mIsEnabled = false;
|
||||
|
||||
mWkPath = null;
|
||||
mPlasticAssetsProcessor = null;
|
||||
}
|
||||
|
||||
internal static void SetIsRepaintNeededAfterAssetDatabaseRefresh()
|
||||
{
|
||||
mIsRepaintNeededAfterAssetDatabaseRefresh = true;
|
||||
}
|
||||
|
||||
static void OnPostprocessAllAssets(
|
||||
string[] importedAssets,
|
||||
string[] deletedAssets,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
if (!mIsEnabled)
|
||||
return;
|
||||
|
||||
if (mIsRepaintNeededAfterAssetDatabaseRefresh)
|
||||
{
|
||||
mIsRepaintNeededAfterAssetDatabaseRefresh = false;
|
||||
|
||||
ProjectWindow.Repaint();
|
||||
RepaintInspector.All();
|
||||
}
|
||||
|
||||
// We need to ensure that the MonoFSWatcher is enabled before processing Plastic operations
|
||||
// It fixes the following scenario:
|
||||
// 1. Close PlasticSCM window
|
||||
// 2. Create an asset, it appears with the added overlay
|
||||
// 3. Open PlasticSCM window, the asset should appear as added instead of deleted locally
|
||||
PlasticApp.EnableMonoFsWatcherIfNeeded();
|
||||
|
||||
mPlasticAssetsProcessor.MoveOnSourceControl(
|
||||
ExtractPathsToMove(movedAssets, movedFromAssetPaths));
|
||||
|
||||
mPlasticAssetsProcessor.DeleteFromSourceControl(
|
||||
GetPathsContainedOnWorkspace(mWkPath, deletedAssets));
|
||||
|
||||
if (AutomaticAdd)
|
||||
{
|
||||
mPlasticAssetsProcessor.AddToSourceControl(
|
||||
GetPathsContainedOnWorkspace(mWkPath, importedAssets));
|
||||
}
|
||||
|
||||
// We expect modified assets to go through AssetModificationProcessor.OnWillSaveAssets before getting here.
|
||||
// To fix: there is a known limitation of renamed prefabs not triggering OnWillSaveAssets method.
|
||||
if (AssetModificationProcessor.ModifiedAssets == null)
|
||||
return;
|
||||
|
||||
mPlasticAssetsProcessor.CheckoutOnSourceControl(
|
||||
GetPathsContainedOnWorkspace(
|
||||
mWkPath, AssetModificationProcessor.ModifiedAssets));
|
||||
|
||||
AssetModificationProcessor.ModifiedAssets = null;
|
||||
}
|
||||
|
||||
static List<PathToMove> ExtractPathsToMove(string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
List<PathToMove> proposedPathsToMove = GetPathsToMoveContainedOnWorkspace(mWkPath, movedAssets, movedFromAssetPaths);
|
||||
|
||||
// Unity doesn't provide the moved paths ordered.
|
||||
// We want to enqueue the batched movements in hierarchical order to avoid plastic considering assets as locally moved.
|
||||
// It also avoid unnecessary children movements when their parents are also moved.
|
||||
proposedPathsToMove.Sort((x, y) => PathHelper.GetPathMatchSorter().Compare(x.SrcPath, y.SrcPath));
|
||||
|
||||
List<PathToMove> pathsToMove = new List<PathToMove>();
|
||||
|
||||
foreach (PathToMove proposedPathToMove in proposedPathsToMove)
|
||||
{
|
||||
if (pathsToMove.Any(pathToMove => PathHelper.IsContainedOn(proposedPathToMove.SrcPath, pathToMove.SrcPath)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pathsToMove.Add(proposedPathToMove);
|
||||
}
|
||||
|
||||
return pathsToMove;
|
||||
}
|
||||
|
||||
static List<PathToMove> GetPathsToMoveContainedOnWorkspace(
|
||||
string wkPath,
|
||||
string[] movedAssets,
|
||||
string[] movedFromAssetPaths)
|
||||
{
|
||||
List<PathToMove> result = new List<PathToMove>(movedAssets.Length);
|
||||
|
||||
for (int i = 0; i < movedAssets.Length; i++)
|
||||
{
|
||||
string fullSrcPath = AssetsPath.GetFullPathUnderWorkspace.
|
||||
ForAsset(wkPath, movedFromAssetPaths[i]);
|
||||
|
||||
if (fullSrcPath == null)
|
||||
continue;
|
||||
|
||||
string fullDstPath = AssetsPath.GetFullPathUnderWorkspace.
|
||||
ForAsset(wkPath, movedAssets[i]);
|
||||
|
||||
if (fullDstPath == null)
|
||||
continue;
|
||||
|
||||
result.Add(new PathToMove(
|
||||
fullSrcPath, fullDstPath));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<string> GetPathsContainedOnWorkspace(
|
||||
string wkPath, string[] assets)
|
||||
{
|
||||
List<string> result = new List<string>(
|
||||
assets.Length);
|
||||
|
||||
foreach (string asset in assets)
|
||||
{
|
||||
string fullPath = AssetsPath.GetFullPathUnderWorkspace.
|
||||
ForAsset(wkPath, asset);
|
||||
|
||||
if (fullPath == null)
|
||||
continue;
|
||||
|
||||
result.Add(fullPath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool mIsEnabled;
|
||||
static bool mIsRepaintNeededAfterAssetDatabaseRefresh;
|
||||
|
||||
static PlasticAssetsProcessor mPlasticAssetsProcessor;
|
||||
static string mWkPath;
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("AssetPostprocessor");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9ffdef169b1cbb4e9910671a9ee83bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
|
||||
{
|
||||
internal static class AssetsProcessors
|
||||
{
|
||||
internal static void Enable(
|
||||
string wkPath,
|
||||
PlasticAssetsProcessor plasticAssetsProcessor,
|
||||
IAssetStatusCache assetStatusCache)
|
||||
{
|
||||
AssetPostprocessor.Enable(wkPath, plasticAssetsProcessor);
|
||||
AssetModificationProcessor.Enable(wkPath, assetStatusCache);
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
{
|
||||
AssetPostprocessor.Disable();
|
||||
AssetModificationProcessor.Disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71cb30384b5f8d64ea7df220cff88d0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Codice.LogWrapper;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
|
||||
{
|
||||
internal class PlasticAssetsProcessor : WorkspaceOperationsMonitor.IDisableAssetsProcessor
|
||||
{
|
||||
internal void SetWorkspaceOperationsMonitor(
|
||||
WorkspaceOperationsMonitor workspaceOperationsMonitor)
|
||||
{
|
||||
mWorkspaceOperationsMonitor = workspaceOperationsMonitor;
|
||||
}
|
||||
|
||||
internal void AddToSourceControl(List<string> paths)
|
||||
{
|
||||
if (paths.Count == 0)
|
||||
return;
|
||||
|
||||
if (IsDisableBecauseExceptionHappened(DateTime.Now))
|
||||
{
|
||||
mLog.Warn(
|
||||
"PlasticAssetsProcessor skipping AddToSourceControl operation " +
|
||||
"because an exception happened in the last 60 seconds");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string path in paths)
|
||||
mLog.DebugFormat("AddToSourceControl: {0}", path);
|
||||
|
||||
mWorkspaceOperationsMonitor.AddAssetsProcessorPathsToAdd(paths);
|
||||
}
|
||||
|
||||
internal void DeleteFromSourceControl(List<string> paths)
|
||||
{
|
||||
if (paths.Count == 0)
|
||||
return;
|
||||
|
||||
if (IsDisableBecauseExceptionHappened(DateTime.Now))
|
||||
{
|
||||
mLog.Warn(
|
||||
"PlasticAssetsProcessor skipping DeleteFromSourceControl operation " +
|
||||
"because an exception happened in the last 60 seconds");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string path in paths)
|
||||
mLog.DebugFormat("DeleteFromSourceControl: {0}", path);
|
||||
|
||||
mWorkspaceOperationsMonitor.AddAssetsProcessorPathsToDelete(paths);
|
||||
}
|
||||
|
||||
internal void MoveOnSourceControl(List<AssetPostprocessor.PathToMove> paths)
|
||||
{
|
||||
if (paths.Count == 0)
|
||||
return;
|
||||
|
||||
if (IsDisableBecauseExceptionHappened(DateTime.Now))
|
||||
{
|
||||
mLog.Warn(
|
||||
"PlasticAssetsProcessor skipping MoveOnSourceControl operation " +
|
||||
"because an exception happened in the last 60 seconds");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (AssetPostprocessor.PathToMove path in paths)
|
||||
mLog.DebugFormat("MoveOnSourceControl: {0} to {1}", path.SrcPath, path.DstPath);
|
||||
|
||||
mWorkspaceOperationsMonitor.AddAssetsProcessorPathsToMove(paths);
|
||||
}
|
||||
|
||||
internal void CheckoutOnSourceControl(List<string> paths)
|
||||
{
|
||||
if (paths.Count == 0)
|
||||
return;
|
||||
|
||||
if (IsDisableBecauseExceptionHappened(DateTime.Now))
|
||||
{
|
||||
mLog.Warn(
|
||||
"PlasticAssetsProcessor skipping CheckoutOnSourceControl operation " +
|
||||
"because an exception happened in the last 60 seconds");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string path in paths)
|
||||
mLog.DebugFormat("CheckoutOnSourceControl: {0}", path);
|
||||
|
||||
mWorkspaceOperationsMonitor.AddAssetsProcessorPathsToCheckout(paths);
|
||||
}
|
||||
|
||||
void WorkspaceOperationsMonitor.IDisableAssetsProcessor.Disable()
|
||||
{
|
||||
mLastExceptionDateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
bool IsDisableBecauseExceptionHappened(DateTime now)
|
||||
{
|
||||
return (now - mLastExceptionDateTime).TotalSeconds < 5;
|
||||
}
|
||||
|
||||
DateTime mLastExceptionDateTime = DateTime.MinValue;
|
||||
WorkspaceOperationsMonitor mWorkspaceOperationsMonitor;
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("PlasticAssetsProcessor");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3daa94b5fca9a648b12f6ef2aae752f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Codice.Client.Common;
|
||||
using Codice.Client.Common.Threading;
|
||||
using Codice.CM.Common;
|
||||
using Codice.LogWrapper;
|
||||
using PlasticGui.WorkspaceWindow.Home;
|
||||
using PlasticGui;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
|
||||
{
|
||||
internal class UnityCloudProjectLinkMonitor : AssetModificationProcessor
|
||||
{
|
||||
internal class CloudSettings
|
||||
{
|
||||
internal string OrganizationId;
|
||||
internal string OrganizationName;
|
||||
internal string ProjectId;
|
||||
internal string ProjectName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory class to retrieve the cloud settings for the current project.
|
||||
/// </summary>
|
||||
internal static Func<CloudSettings> CloudSettingsFactory = () => new CloudSettings()
|
||||
{
|
||||
OrganizationId = CloudProjectSettings.organizationId,
|
||||
OrganizationName = CloudProjectSettings.organizationName,
|
||||
ProjectId = CloudProjectSettings.projectId,
|
||||
ProjectName = CloudProjectSettings.projectName
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the workspace project is aligned with the linked project in the cloud settings (if any).
|
||||
/// If not, logs a warning message for users to inform about the issue and give indications on how to re-link.
|
||||
/// </summary>
|
||||
internal static void CheckCloudProjectAlignmentAsync(WorkspaceInfo wkInfo)
|
||||
{
|
||||
mLog.Debug("Checking for cloud project alignment...");
|
||||
|
||||
mCachedWkInfo = wkInfo;
|
||||
|
||||
CloudSettings cloudSettings = CloudSettingsFactory();
|
||||
|
||||
if (string.IsNullOrEmpty(cloudSettings.OrganizationId) || string.IsNullOrEmpty(cloudSettings.ProjectId))
|
||||
{
|
||||
mCachedCloudSettings = cloudSettings;
|
||||
|
||||
mLog.Debug("The project is not connected to Unity Cloud");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cloudSettings.OrganizationId.Equals(mCachedCloudSettings.OrganizationId) &&
|
||||
cloudSettings.ProjectId.Equals(mCachedCloudSettings.ProjectId))
|
||||
{
|
||||
mLog.Debug("The linked project didn't change");
|
||||
return;
|
||||
}
|
||||
|
||||
mCachedCloudSettings = cloudSettings;
|
||||
|
||||
CheckCloudProjectAlignmentAsync();
|
||||
}
|
||||
|
||||
static void CheckCloudProjectAlignmentAsync()
|
||||
{
|
||||
PlasticThreadPool.Run(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
RepositorySpec repSpec = PlasticGui.Plastic.API.GetRepositorySpec(mCachedWkInfo);
|
||||
if (repSpec == null || !OrganizationsInformation.IsUnityOrganization(repSpec.Server))
|
||||
{
|
||||
mLog.Debug("Skipping check for not covered organization");
|
||||
return;
|
||||
}
|
||||
|
||||
RepositoryInfo repositoryProject = ProjectInfo.ForRepSpec(repSpec);
|
||||
|
||||
if (repositoryProject == null || !repositoryProject.GUID.ToString().Equals(mCachedCloudSettings.ProjectId))
|
||||
{
|
||||
string repositoryOrganizationName = CloudServer.GetOrganizationName(ResolveServer.ToDisplayString(repSpec.Server));
|
||||
string repositoryProjectName = CloudProject.GetProjectName(repSpec.Name);
|
||||
|
||||
LogMismatchingProject(
|
||||
mCachedCloudSettings.OrganizationName, mCachedCloudSettings.ProjectName,
|
||||
repositoryOrganizationName, repositoryProjectName);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.Debug("The linked cloud project is properly aligned");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionsHandler.LogException(typeof(UnityCloudProjectLinkMonitor).Name, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void LogMismatchingProject(string cloudOrganization, string cloudProject, string repoOrganization, string repoProject)
|
||||
{
|
||||
string localOrganizationAndProject = string.Format("{0}/{1}", repoOrganization, repoProject);
|
||||
string cloudOrganizationAndProject = string.Format("{0}/{1}", cloudOrganization, cloudProject);
|
||||
|
||||
string mismatchingProjectMessage = string.Format(
|
||||
PlasticLocalization.Name.MismatchingRepositoryProjectMessage.GetString(),
|
||||
cloudOrganizationAndProject,
|
||||
localOrganizationAndProject,
|
||||
localOrganizationAndProject,
|
||||
repoOrganization,
|
||||
localOrganizationAndProject,
|
||||
cloudOrganizationAndProject
|
||||
);
|
||||
|
||||
Debug.LogWarning(mismatchingProjectMessage);
|
||||
mLog.Warn(mismatchingProjectMessage);
|
||||
}
|
||||
|
||||
static string[] OnWillSaveAssets(string[] paths)
|
||||
{
|
||||
if (mCachedWkInfo != null && paths.Any(path => path.Equals(ProjectSettingsAsset)))
|
||||
{
|
||||
CheckCloudProjectAlignmentAsync(mCachedWkInfo);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static WorkspaceInfo mCachedWkInfo;
|
||||
static CloudSettings mCachedCloudSettings = new CloudSettings();
|
||||
|
||||
static readonly string ProjectSettingsAsset = "ProjectSettings/ProjectSettings.asset";
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("UnityCloudProjectLinkMonitor");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b77071fd36e946809b40d79e6ba9fe8a
|
||||
timeCreated: 1728894821
|
||||
@@ -0,0 +1,805 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
using Codice;
|
||||
using Codice.Client.BaseCommands;
|
||||
using Codice.Client.Commands;
|
||||
using Codice.Client.Commands.WkTree;
|
||||
using Codice.LogWrapper;
|
||||
using Codice.Utils;
|
||||
using GluonGui;
|
||||
using PlasticGui;
|
||||
using PlasticGui.WorkspaceWindow;
|
||||
using Unity.PlasticSCM.Editor.UI;
|
||||
using Unity.PlasticSCM.Editor.Views.Merge;
|
||||
using Unity.PlasticSCM.Editor.Views.PendingChanges;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
|
||||
{
|
||||
internal class WorkspaceOperationsMonitor
|
||||
{
|
||||
// Internal usage. This isn't a public API.
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public interface IDisableAssetsProcessor
|
||||
{
|
||||
void Disable();
|
||||
}
|
||||
|
||||
internal WorkspaceOperationsMonitor(
|
||||
IPlasticAPI plasticApi,
|
||||
IDisableAssetsProcessor disableAssetsProcessor,
|
||||
bool isGluonMode)
|
||||
{
|
||||
mPlasticAPI = plasticApi;
|
||||
mDisableAssetsProcessor = disableAssetsProcessor;
|
||||
mIsGluonMode = isGluonMode;
|
||||
}
|
||||
|
||||
internal void RegisterWindow(
|
||||
IWorkspaceWindow workspaceWindow,
|
||||
ViewHost viewHost,
|
||||
NewIncomingChangesUpdater incomingChangesUpdater)
|
||||
{
|
||||
mWorkspaceWindow = workspaceWindow;
|
||||
mViewHost = viewHost;
|
||||
mNewIncomingChangesUpdater = incomingChangesUpdater;
|
||||
}
|
||||
|
||||
internal void UnRegisterWindow()
|
||||
{
|
||||
mWorkspaceWindow = null;
|
||||
mViewHost = null;
|
||||
mNewIncomingChangesUpdater = null;
|
||||
}
|
||||
|
||||
internal void RegisterPendingChangesView(
|
||||
PendingChangesTab pendingChangesTab)
|
||||
{
|
||||
mPendingChangesTab = pendingChangesTab;
|
||||
}
|
||||
|
||||
internal void RegisterIncomingChangesView(
|
||||
IIncomingChangesTab incomingChangesTab)
|
||||
{
|
||||
mIncomingChangesTab = incomingChangesTab;
|
||||
}
|
||||
|
||||
internal void UnRegisterViews()
|
||||
{
|
||||
mPendingChangesTab = null;
|
||||
mIncomingChangesTab = null;
|
||||
}
|
||||
|
||||
internal void Start()
|
||||
{
|
||||
mLog.Debug("Start");
|
||||
|
||||
mCancelToken = new CancelToken();
|
||||
mIsEnabled = true;
|
||||
|
||||
Thread thread = new Thread(TaskLoopThread);
|
||||
thread.IsBackground = true;
|
||||
thread.Name = "Plastic SCM Workspace Operations Monitor thread";
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
internal void Stop()
|
||||
{
|
||||
mLog.Debug("Stop");
|
||||
|
||||
SetAsFinished();
|
||||
}
|
||||
|
||||
internal void Disable()
|
||||
{
|
||||
mIsEnabled = false;
|
||||
|
||||
mLog.Debug("Disabled");
|
||||
}
|
||||
|
||||
internal void Enable()
|
||||
{
|
||||
mIsEnabled = true;
|
||||
|
||||
mLog.Debug("Enabled");
|
||||
}
|
||||
|
||||
internal void AddAssetsProcessorPathsToAdd(
|
||||
List<string> paths)
|
||||
{
|
||||
AddPathsToProcess(
|
||||
mAssetsProcessorPathsToAdd, paths,
|
||||
mLock, mResetEvent, mIsEnabled);
|
||||
}
|
||||
|
||||
internal void AddAssetsProcessorPathsToDelete(
|
||||
List<string> paths)
|
||||
{
|
||||
AddPathsToProcess(
|
||||
mAssetsProcessorPathsToDelete, paths,
|
||||
mLock, mResetEvent, mIsEnabled);
|
||||
}
|
||||
|
||||
internal void AddAssetsProcessorPathsToCheckout(
|
||||
List<string> paths)
|
||||
{
|
||||
AddPathsToProcess(
|
||||
mAssetsProcessorPathsToCheckout, paths,
|
||||
mLock, mResetEvent, mIsEnabled);
|
||||
}
|
||||
|
||||
internal void AddAssetsProcessorPathsToMove(
|
||||
List<AssetPostprocessor.PathToMove> paths)
|
||||
{
|
||||
AddPathsToMoveToProcess(
|
||||
mAssetsProcessorPathsToMove, paths,
|
||||
mLock, mResetEvent, mIsEnabled);
|
||||
}
|
||||
|
||||
internal void AddPathsToCheckout(
|
||||
List<string> paths)
|
||||
{
|
||||
AddPathsToProcess(
|
||||
mPathsToCheckout, paths,
|
||||
mLock, mResetEvent, mIsEnabled);
|
||||
}
|
||||
|
||||
void TaskLoopThread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mCancelToken.IsCancelled())
|
||||
break;
|
||||
|
||||
if (!mIsEnabled)
|
||||
{
|
||||
SleepUntilNextWorkload();
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasAssetProcessorOpsPending = false;
|
||||
bool hasCheckoutOpsPending = false;
|
||||
ProcessOperations(
|
||||
mPlasticAPI,
|
||||
mAssetsProcessorPathsToAdd,
|
||||
mAssetsProcessorPathsToDelete,
|
||||
mAssetsProcessorPathsToCheckout,
|
||||
mAssetsProcessorPathsToMove,
|
||||
mPathsToCheckout,
|
||||
mCancelToken,
|
||||
mLock,
|
||||
mDisableAssetsProcessor,
|
||||
out hasAssetProcessorOpsPending,
|
||||
out hasCheckoutOpsPending);
|
||||
|
||||
if (mCancelToken.IsCancelled())
|
||||
break;
|
||||
|
||||
if (hasAssetProcessorOpsPending ||
|
||||
hasCheckoutOpsPending)
|
||||
continue;
|
||||
|
||||
SleepUntilNextWorkload();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
mLog.ErrorFormat(
|
||||
"Error running the tasks loop : {0}", e.Message);
|
||||
mLog.DebugFormat(
|
||||
"Stacktrace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessOperations(
|
||||
IPlasticAPI plasticApi,
|
||||
List<string> assetsProcessorPathsToAdd,
|
||||
List<string> assetsProcessorPathsToDelete,
|
||||
List<string> assetsProcessorPathsToCheckout,
|
||||
List<AssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
|
||||
List<string> pathsToCheckout,
|
||||
CancelToken cancelToken,
|
||||
object lockObj,
|
||||
IDisableAssetsProcessor disableAssetsProcessor,
|
||||
out bool hasAssetProcessorOpsPending,
|
||||
out bool hasCheckoutOpsPending)
|
||||
{
|
||||
hasAssetProcessorOpsPending = false;
|
||||
hasCheckoutOpsPending = false;
|
||||
|
||||
mLog.Debug("Starting process operations...");
|
||||
|
||||
bool hasAssetProcessorOpsProcessed =
|
||||
ProcessAssetProcessorOperations(
|
||||
plasticApi,
|
||||
assetsProcessorPathsToAdd,
|
||||
assetsProcessorPathsToDelete,
|
||||
assetsProcessorPathsToCheckout,
|
||||
assetsProcessorPathsToMove,
|
||||
cancelToken,
|
||||
lockObj,
|
||||
disableAssetsProcessor);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
bool hasCheckoutOpsProcessed =
|
||||
ProcessCheckoutOperation(
|
||||
plasticApi,
|
||||
pathsToCheckout,
|
||||
cancelToken,
|
||||
lockObj);
|
||||
|
||||
mLog.Debug("ProcessOperations - Processed paths ? " +
|
||||
(hasAssetProcessorOpsProcessed || hasCheckoutOpsProcessed));
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
HasPendingOperationsToProcess(
|
||||
assetsProcessorPathsToAdd,
|
||||
assetsProcessorPathsToDelete,
|
||||
assetsProcessorPathsToCheckout,
|
||||
assetsProcessorPathsToMove,
|
||||
pathsToCheckout,
|
||||
lockObj,
|
||||
out hasAssetProcessorOpsPending,
|
||||
out hasCheckoutOpsPending);
|
||||
|
||||
bool isAfterAssetProcessorOpNeeded =
|
||||
hasAssetProcessorOpsProcessed &&
|
||||
!hasAssetProcessorOpsPending;
|
||||
|
||||
bool isAfterCheckoutOpNeeded =
|
||||
hasCheckoutOpsProcessed &&
|
||||
!hasCheckoutOpsPending;
|
||||
|
||||
if (!isAfterAssetProcessorOpNeeded &&
|
||||
!isAfterCheckoutOpNeeded)
|
||||
return;
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
EditorDispatcher.Dispatch(() =>
|
||||
{
|
||||
mLog.Debug("AfterProcessOperations");
|
||||
|
||||
RefreshAsset.VersionControlCache();
|
||||
|
||||
if (isAfterAssetProcessorOpNeeded)
|
||||
AfterAssetProcessorOperation();
|
||||
|
||||
if (isAfterCheckoutOpNeeded)
|
||||
AfterCheckoutOperation();
|
||||
});
|
||||
}
|
||||
|
||||
void AfterAssetProcessorOperation()
|
||||
{
|
||||
AutoRefresh.PendingChangesView(mPendingChangesTab);
|
||||
|
||||
AutoRefresh.IncomingChangesView(mIncomingChangesTab);
|
||||
|
||||
if (mIsGluonMode)
|
||||
{
|
||||
RefreshViewsAfterAssetProcessorForGluon(mViewHost);
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshViewsAfterAssetProcessorForDeveloper(mWorkspaceWindow);
|
||||
}
|
||||
|
||||
void AfterCheckoutOperation()
|
||||
{
|
||||
if (mIsGluonMode)
|
||||
{
|
||||
RefreshViewsAfterCheckoutForGluon(mViewHost);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNewIncomingChangesUpdater != null)
|
||||
mNewIncomingChangesUpdater.Update(DateTime.Now);
|
||||
|
||||
RefreshViewsAfterCheckoutForDeveloper(mWorkspaceWindow);
|
||||
}
|
||||
|
||||
void SetAsFinished()
|
||||
{
|
||||
if (mCancelToken.IsCancelled())
|
||||
return;
|
||||
|
||||
mCancelToken.Cancel();
|
||||
mResetEvent.Set();
|
||||
}
|
||||
|
||||
void SleepUntilNextWorkload()
|
||||
{
|
||||
mLog.Debug("SleepUntilNextWorkload");
|
||||
|
||||
mResetEvent.Reset();
|
||||
mResetEvent.WaitOne();
|
||||
}
|
||||
|
||||
static bool ProcessAssetProcessorOperations(
|
||||
IPlasticAPI plasticApi,
|
||||
List<string> assetsProcessorPathsToAdd,
|
||||
List<string> assetsProcessorPathsToDelete,
|
||||
List<string> assetsProcessorPathsToCheckout,
|
||||
List<AssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
|
||||
CancelToken cancelToken,
|
||||
object lockObj,
|
||||
IDisableAssetsProcessor disableAssetsProcessor)
|
||||
{
|
||||
bool hasProcessedPaths = false;
|
||||
|
||||
try
|
||||
{
|
||||
hasProcessedPaths = AssetsProcessorOperations.
|
||||
AddIfNotControlled(
|
||||
plasticApi,
|
||||
ExtractPathsToProcess(assetsProcessorPathsToAdd, lockObj),
|
||||
cancelToken);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
hasProcessedPaths |= AssetsProcessorOperations.
|
||||
DeleteIfControlled(
|
||||
plasticApi,
|
||||
ExtractPathsToProcess(assetsProcessorPathsToDelete, lockObj),
|
||||
cancelToken);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
hasProcessedPaths |= AssetsProcessorOperations.
|
||||
CheckoutIfControlledAndChanged(
|
||||
plasticApi,
|
||||
ExtractPathsToProcess(assetsProcessorPathsToCheckout, lockObj),
|
||||
cancelToken);
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
hasProcessedPaths |= AssetsProcessorOperations.
|
||||
MoveIfControlled(
|
||||
plasticApi,
|
||||
ExtractPathsToMoveToProcess(assetsProcessorPathsToMove, lockObj).AsReadOnly(),
|
||||
cancelToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ex);
|
||||
|
||||
disableAssetsProcessor.Disable();
|
||||
}
|
||||
|
||||
return hasProcessedPaths;
|
||||
}
|
||||
|
||||
static bool ProcessCheckoutOperation(
|
||||
IPlasticAPI plasticApi,
|
||||
List<string> pathsToProcess,
|
||||
CancelToken cancelToken,
|
||||
object lockObj)
|
||||
{
|
||||
List<string> paths = ExtractPathsToProcess(
|
||||
pathsToProcess, lockObj);
|
||||
|
||||
List<string> result = new List<string>();
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
WorkspaceTreeNode node =
|
||||
plasticApi.GetWorkspaceTreeNode(path);
|
||||
|
||||
if (node != null &&
|
||||
!CheckWorkspaceTreeNodeStatus.IsCheckedOut(node))
|
||||
result.Add(path);
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
bool hasPathsToProcess = result.Count > 0;
|
||||
|
||||
if (hasPathsToProcess)
|
||||
{
|
||||
plasticApi.Checkout(
|
||||
result.ToArray(),
|
||||
CheckoutModifiers.ProcessSymlinks);
|
||||
}
|
||||
|
||||
LogProcessedPaths("ProcessCheckoutOperation", result);
|
||||
|
||||
return hasPathsToProcess;
|
||||
}
|
||||
|
||||
static void AddPathsToProcess(
|
||||
List<string> pathsToProcess,
|
||||
List<string> paths,
|
||||
object lockObj,
|
||||
ManualResetEvent resetEvent,
|
||||
bool isEnabled)
|
||||
{
|
||||
if (!isEnabled)
|
||||
return;
|
||||
|
||||
lock (lockObj)
|
||||
{
|
||||
pathsToProcess.AddRange(paths);
|
||||
}
|
||||
|
||||
resetEvent.Set();
|
||||
}
|
||||
|
||||
static void AddPathsToMoveToProcess(
|
||||
List<AssetPostprocessor.PathToMove> pathsToProcess,
|
||||
List<AssetPostprocessor.PathToMove> paths,
|
||||
object lockObj,
|
||||
ManualResetEvent resetEvent,
|
||||
bool isEnabled)
|
||||
{
|
||||
if (!isEnabled)
|
||||
return;
|
||||
|
||||
lock (lockObj)
|
||||
{
|
||||
pathsToProcess.AddRange(paths);
|
||||
}
|
||||
|
||||
resetEvent.Set();
|
||||
}
|
||||
|
||||
static List<string> ExtractPathsToProcess(
|
||||
List<string> pathsToProcess,
|
||||
object lockObj)
|
||||
{
|
||||
List<string> result;
|
||||
|
||||
lock (lockObj)
|
||||
{
|
||||
result = new List<string>(pathsToProcess);
|
||||
pathsToProcess.Clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<AssetPostprocessor.PathToMove> ExtractPathsToMoveToProcess(
|
||||
List<AssetPostprocessor.PathToMove> pathsToProcess,
|
||||
object lockObj)
|
||||
{
|
||||
List<AssetPostprocessor.PathToMove> result;
|
||||
|
||||
lock (lockObj)
|
||||
{
|
||||
result = new List<AssetPostprocessor.PathToMove>(pathsToProcess);
|
||||
pathsToProcess.Clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void HasPendingOperationsToProcess(
|
||||
List<string> assetsProcessorPathsToAdd,
|
||||
List<string> assetsProcessorPathsToDelete,
|
||||
List<string> assetsProcessorPathsToCheckout,
|
||||
List<AssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
|
||||
List<string> pathsToCheckout,
|
||||
object lockObj,
|
||||
out bool hasAssetProcessorOperations,
|
||||
out bool hasCheckoutOperations)
|
||||
{
|
||||
lock (lockObj)
|
||||
{
|
||||
hasAssetProcessorOperations =
|
||||
assetsProcessorPathsToAdd.Count > 0 ||
|
||||
assetsProcessorPathsToDelete.Count > 0 ||
|
||||
assetsProcessorPathsToCheckout.Count > 0 ||
|
||||
assetsProcessorPathsToMove.Count > 0;
|
||||
|
||||
hasCheckoutOperations =
|
||||
pathsToCheckout.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void RefreshViewsAfterAssetProcessorForGluon(ViewHost viewHost)
|
||||
{
|
||||
if (viewHost == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
viewHost.RefreshView(ViewType.LocksView);
|
||||
}
|
||||
|
||||
static void RefreshViewsAfterAssetProcessorForDeveloper(IWorkspaceWindow workspaceWindow)
|
||||
{
|
||||
if (workspaceWindow == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
workspaceWindow.RefreshView(ViewType.LocksView);
|
||||
}
|
||||
|
||||
static void RefreshViewsAfterCheckoutForDeveloper(
|
||||
IWorkspaceWindow workspaceWindow)
|
||||
{
|
||||
if (workspaceWindow == null)
|
||||
return;
|
||||
|
||||
workspaceWindow.RefreshView(ViewType.BranchExplorerView);
|
||||
workspaceWindow.RefreshView(ViewType.PendingChangesView);
|
||||
workspaceWindow.RefreshView(ViewType.HistoryView);
|
||||
workspaceWindow.RefreshView(ViewType.LocksView);
|
||||
}
|
||||
|
||||
static void RefreshViewsAfterCheckoutForGluon(
|
||||
ViewHost viewHost)
|
||||
{
|
||||
if (viewHost == null)
|
||||
return;
|
||||
|
||||
viewHost.RefreshView(ViewType.WorkspaceExplorerView);
|
||||
viewHost.RefreshView(ViewType.CheckinView);
|
||||
viewHost.RefreshView(ViewType.IncomingChangesView);
|
||||
viewHost.RefreshView(ViewType.SearchView);
|
||||
viewHost.RefreshView(ViewType.LocksView);
|
||||
}
|
||||
|
||||
static void LogProcessedPaths(
|
||||
string operation,
|
||||
List<string> paths)
|
||||
{
|
||||
if (paths.Count == 0)
|
||||
{
|
||||
mLog.DebugFormat(
|
||||
"{0} - There are no processed paths.",
|
||||
operation);
|
||||
return;
|
||||
}
|
||||
|
||||
mLog.DebugFormat(
|
||||
"{0} - Processed paths: {1}{2}",
|
||||
operation, Environment.NewLine,
|
||||
string.Join(Environment.NewLine, paths));
|
||||
}
|
||||
|
||||
static void LogException(Exception ex)
|
||||
{
|
||||
mLog.WarnFormat("Message: {0}", ex.Message);
|
||||
|
||||
mLog.DebugFormat(
|
||||
"StackTrace:{0}{1}",
|
||||
Environment.NewLine, ex.StackTrace);
|
||||
}
|
||||
|
||||
internal static class AssetsProcessorOperations
|
||||
{
|
||||
internal static bool AddIfNotControlled(
|
||||
IPlasticAPI plasticApi,
|
||||
List<string> paths,
|
||||
CancelToken cancelToken)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
|
||||
IgnoredFilesFilter ignoredFilter = plasticApi.GetIgnoredFilter();
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
string metaPath = MetaPath.GetMetaPath(path);
|
||||
|
||||
if (plasticApi.GetWorkspaceFromPath(path) == null)
|
||||
return false;
|
||||
|
||||
if (plasticApi.GetWorkspaceTreeNode(path) == null &&
|
||||
!ignoredFilter.IsIgnored(path))
|
||||
{
|
||||
result.Add(path);
|
||||
}
|
||||
|
||||
if (File.Exists(metaPath) &&
|
||||
plasticApi.GetWorkspaceTreeNode(metaPath) == null &&
|
||||
!ignoredFilter.IsIgnored(path))
|
||||
{
|
||||
result.Add(metaPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
bool hasPathsToProcess = result.Count > 0;
|
||||
|
||||
if (hasPathsToProcess)
|
||||
{
|
||||
IList checkouts;
|
||||
plasticApi.Add(result.ToArray(), GetDefaultAddOptions(), out checkouts);
|
||||
}
|
||||
|
||||
LogProcessedPaths("AddIfNotControlled", result);
|
||||
|
||||
return hasPathsToProcess;
|
||||
}
|
||||
|
||||
internal static bool DeleteIfControlled(
|
||||
IPlasticAPI plasticApi,
|
||||
List<string> paths,
|
||||
CancelToken cancelToken)
|
||||
{
|
||||
List<string> processedPaths = new List<string>(paths.Count);
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
string metaPath = MetaPath.GetMetaPath(path);
|
||||
|
||||
if (plasticApi.GetWorkspaceTreeNode(path) != null)
|
||||
{
|
||||
processedPaths.Add(path);
|
||||
}
|
||||
|
||||
if (plasticApi.GetWorkspaceTreeNode(metaPath) != null)
|
||||
{
|
||||
processedPaths.Add(metaPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
plasticApi.DeleteControlled(
|
||||
processedPaths.ToArray(), DeleteModifiers.None, null);
|
||||
|
||||
LogProcessedPaths("DeleteIfControlled", processedPaths);
|
||||
|
||||
return processedPaths.Count > 0;
|
||||
}
|
||||
|
||||
internal static bool MoveIfControlled(
|
||||
IPlasticAPI plasticApi,
|
||||
ReadOnlyCollection<AssetPostprocessor.PathToMove> paths,
|
||||
CancelToken cancelToken)
|
||||
{
|
||||
List<string> processedPaths = new List<string>(paths.Count);
|
||||
|
||||
foreach (AssetPostprocessor.PathToMove pathToMove in paths)
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
if (plasticApi.GetWorkspaceTreeNode(pathToMove.SrcPath) != null)
|
||||
{
|
||||
plasticApi.Move(
|
||||
pathToMove.SrcPath, pathToMove.DstPath,
|
||||
MoveModifiers.None);
|
||||
|
||||
processedPaths.Add(string.Format("{0} to {1}",
|
||||
pathToMove.SrcPath, pathToMove.DstPath));
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
string srcMetaPath = MetaPath.GetMetaPath(pathToMove.SrcPath);
|
||||
string dstMetaPath = MetaPath.GetMetaPath(pathToMove.DstPath);
|
||||
|
||||
if (plasticApi.GetWorkspaceTreeNode(srcMetaPath) != null)
|
||||
{
|
||||
plasticApi.Move(
|
||||
srcMetaPath, dstMetaPath,
|
||||
MoveModifiers.None);
|
||||
|
||||
processedPaths.Add(string.Format("{0} to {1}",
|
||||
srcMetaPath, dstMetaPath));
|
||||
}
|
||||
}
|
||||
|
||||
LogProcessedPaths("MoveIfControlled", processedPaths);
|
||||
|
||||
return processedPaths.Count > 0;
|
||||
}
|
||||
|
||||
internal static bool CheckoutIfControlledAndChanged(
|
||||
IPlasticAPI plasticApi,
|
||||
List<string> paths,
|
||||
CancelToken cancelToken)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
|
||||
HiddenChangesFilesFilter hiddenChangesFilter = plasticApi.GetHiddenChangesFilter();
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
string metaPath = MetaPath.GetMetaPath(path);
|
||||
|
||||
WorkspaceTreeNode node = plasticApi.GetWorkspaceTreeNode(path);
|
||||
WorkspaceTreeNode nodeMeta = plasticApi.GetWorkspaceTreeNode(metaPath);
|
||||
|
||||
if (node != null &&
|
||||
!CheckWorkspaceTreeNodeStatus.IsCheckedOut(node) &&
|
||||
!hiddenChangesFilter.IsHiddenChanged(path) &&
|
||||
ChangedFileChecker.IsChanged(node.LocalInfo, path, false))
|
||||
{
|
||||
result.Add(path);
|
||||
}
|
||||
|
||||
if (nodeMeta != null &&
|
||||
!CheckWorkspaceTreeNodeStatus.IsCheckedOut(nodeMeta) &&
|
||||
!hiddenChangesFilter.IsHiddenChanged(path) &&
|
||||
ChangedFileChecker.IsChanged(nodeMeta.LocalInfo, metaPath, false))
|
||||
{
|
||||
result.Add(metaPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelToken.IsCancelled())
|
||||
return false;
|
||||
|
||||
bool hasPathsToProcess = result.Count > 0;
|
||||
|
||||
if (hasPathsToProcess)
|
||||
{
|
||||
plasticApi.Checkout(result.ToArray(), CheckoutModifiers.None);
|
||||
}
|
||||
|
||||
LogProcessedPaths("CheckoutIfControlledAndChanged", result);
|
||||
|
||||
return hasPathsToProcess;
|
||||
}
|
||||
|
||||
static AddOptions GetDefaultAddOptions()
|
||||
{
|
||||
AddOptions options = new AddOptions();
|
||||
options.AddPrivateParents = true;
|
||||
options.NeedCheckPlatformPath = true;
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
object mLock = new object();
|
||||
|
||||
List<string> mAssetsProcessorPathsToAdd = new List<string>();
|
||||
List<string> mAssetsProcessorPathsToDelete = new List<string>();
|
||||
List<string> mAssetsProcessorPathsToCheckout = new List<string>();
|
||||
List<AssetPostprocessor.PathToMove> mAssetsProcessorPathsToMove = new List<AssetPostprocessor.PathToMove>();
|
||||
List<string> mPathsToCheckout = new List<string>();
|
||||
|
||||
PendingChangesTab mPendingChangesTab;
|
||||
IIncomingChangesTab mIncomingChangesTab;
|
||||
IWorkspaceWindow mWorkspaceWindow;
|
||||
ViewHost mViewHost;
|
||||
NewIncomingChangesUpdater mNewIncomingChangesUpdater;
|
||||
|
||||
volatile bool mIsEnabled;
|
||||
volatile ManualResetEvent mResetEvent = new ManualResetEvent(false);
|
||||
CancelToken mCancelToken = new CancelToken();
|
||||
|
||||
readonly bool mIsGluonMode = false;
|
||||
readonly IDisableAssetsProcessor mDisableAssetsProcessor;
|
||||
readonly IPlasticAPI mPlasticAPI;
|
||||
|
||||
static readonly ILog mLog = PlasticApp.GetLogger("WorkspaceOperationsMonitor");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdec637f96aaa6546ad88a90cae5dcf1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class ProjectPath
|
||||
{
|
||||
internal static string FromApplicationDataPath(string dataPath)
|
||||
{
|
||||
return Path.GetDirectoryName(Path.GetFullPath(dataPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6cad902920d2d0e448b4a307b199d8fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
using UnityEditor;
|
||||
using UnityEditor.PackageManager;
|
||||
using Unity.PlasticSCM.Editor.UI;
|
||||
|
||||
using AssetPostprocessor = Unity.PlasticSCM.Editor.AssetUtils.Processor.AssetPostprocessor;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class RefreshAsset
|
||||
{
|
||||
internal static void BeforeLongAssetOperation()
|
||||
{
|
||||
AssetDatabase.DisallowAutoRefresh();
|
||||
}
|
||||
|
||||
internal static void AfterLongAssetOperation()
|
||||
{
|
||||
AfterLongAssetOperation(true);
|
||||
}
|
||||
|
||||
internal static void AfterLongAssetOperation(bool isPackagesReimportNeeded)
|
||||
{
|
||||
AssetDatabase.AllowAutoRefresh();
|
||||
|
||||
if (isPackagesReimportNeeded)
|
||||
{
|
||||
UnityAssetDatabaseAndPackageManagerAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshUnityAssetDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UnityAssetDatabase()
|
||||
{
|
||||
RefreshUnityAssetDatabase();
|
||||
}
|
||||
|
||||
internal static void UnityAssetDatabaseAndPackageManagerAsync()
|
||||
{
|
||||
// Client.Resolve() will resolve any pending packages added or removed from the project
|
||||
// VCS-1004718 - This is important so the domain gets reloaded first if needed
|
||||
Client.Resolve();
|
||||
|
||||
mCooldownRefreshAssetsAction.Ping();
|
||||
}
|
||||
|
||||
internal static void VersionControlCache()
|
||||
{
|
||||
ClearVersionControlCaches();
|
||||
|
||||
ProjectWindow.Repaint();
|
||||
RepaintInspector.All();
|
||||
}
|
||||
|
||||
static void ClearVersionControlCaches()
|
||||
{
|
||||
UnityEditor.VersionControl.Provider.ClearCache();
|
||||
|
||||
if (PlasticPlugin.AssetStatusCache != null)
|
||||
PlasticPlugin.AssetStatusCache.Clear();
|
||||
}
|
||||
|
||||
static void RefreshUnityAssetDatabase()
|
||||
{
|
||||
AssetDatabase.Refresh(ImportAssetOptions.Default);
|
||||
|
||||
ClearVersionControlCaches();
|
||||
|
||||
AssetPostprocessor.SetIsRepaintNeededAfterAssetDatabaseRefresh();
|
||||
}
|
||||
|
||||
static CooldownWindowDelayer mCooldownRefreshAssetsAction = new CooldownWindowDelayer(
|
||||
RefreshUnityAssetDatabase,
|
||||
UnityConstants.REFRESH_ASSET_DATABASE_DELAYED_INTERVAL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7495e44f1cb132745a310485807e68f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class RepaintInspector
|
||||
{
|
||||
internal static void All()
|
||||
{
|
||||
UnityEditor.Editor[] editors =
|
||||
Resources.FindObjectsOfTypeAll<UnityEditor.Editor>();
|
||||
|
||||
foreach (UnityEditor.Editor editor in editors)
|
||||
editor.Repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9203e3f44c0ecfd42953709384a56c4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,159 @@
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
using Codice.Client.BaseCommands;
|
||||
using Codice.Client.Common;
|
||||
using Unity.PlasticSCM.Editor.AssetUtils.Processor;
|
||||
|
||||
namespace Unity.PlasticSCM.Editor.AssetUtils
|
||||
{
|
||||
internal static class SaveAssets
|
||||
{
|
||||
internal static void ForChangesWithConfirmation(
|
||||
List<ChangeInfo> changes,
|
||||
WorkspaceOperationsMonitor workspaceOperationsMonitor,
|
||||
out bool isCancelled)
|
||||
{
|
||||
ForPaths(
|
||||
GetPaths(changes), true,
|
||||
workspaceOperationsMonitor,
|
||||
out isCancelled);
|
||||
}
|
||||
|
||||
internal static void ForPathsWithConfirmation(
|
||||
List<string> paths,
|
||||
WorkspaceOperationsMonitor workspaceOperationsMonitor,
|
||||
out bool isCancelled)
|
||||
{
|
||||
ForPaths(
|
||||
paths, true,
|
||||
workspaceOperationsMonitor,
|
||||
out isCancelled);
|
||||
}
|
||||
|
||||
internal static void ForChangesWithoutConfirmation(
|
||||
List<ChangeInfo> changes,
|
||||
WorkspaceOperationsMonitor workspaceOperationsMonitor)
|
||||
{
|
||||
bool isCancelled;
|
||||
ForPaths(
|
||||
GetPaths(changes), false,
|
||||
workspaceOperationsMonitor,
|
||||
out isCancelled);
|
||||
}
|
||||
|
||||
internal static void ForPathsWithoutConfirmation(
|
||||
List<string> paths,
|
||||
WorkspaceOperationsMonitor workspaceOperationsMonitor)
|
||||
{
|
||||
bool isCancelled;
|
||||
ForPaths(
|
||||
paths, false,
|
||||
workspaceOperationsMonitor,
|
||||
out isCancelled);
|
||||
}
|
||||
|
||||
static void ForPaths(
|
||||
List<string> paths,
|
||||
bool askForUserConfirmation,
|
||||
WorkspaceOperationsMonitor workspaceOperationsMonitor,
|
||||
out bool isCancelled)
|
||||
{
|
||||
workspaceOperationsMonitor.Disable();
|
||||
try
|
||||
{
|
||||
SaveDirtyScenes(
|
||||
paths,
|
||||
askForUserConfirmation,
|
||||
out isCancelled);
|
||||
|
||||
if (isCancelled)
|
||||
return;
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
finally
|
||||
{
|
||||
workspaceOperationsMonitor.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveDirtyScenes(
|
||||
List<string> paths,
|
||||
bool askForUserConfirmation,
|
||||
out bool isCancelled)
|
||||
{
|
||||
isCancelled = false;
|
||||
|
||||
List<Scene> scenesToSave = new List<Scene>();
|
||||
|
||||
foreach (Scene dirtyScene in GetDirtyScenes())
|
||||
{
|
||||
if (Contains(paths, dirtyScene))
|
||||
scenesToSave.Add(dirtyScene);
|
||||
}
|
||||
|
||||
if (scenesToSave.Count == 0)
|
||||
return;
|
||||
|
||||
if (askForUserConfirmation)
|
||||
{
|
||||
isCancelled = !EditorSceneManager.
|
||||
SaveModifiedScenesIfUserWantsTo(
|
||||
scenesToSave.ToArray());
|
||||
return;
|
||||
}
|
||||
|
||||
EditorSceneManager.SaveScenes(
|
||||
scenesToSave.ToArray());
|
||||
}
|
||||
|
||||
static List<Scene> GetDirtyScenes()
|
||||
{
|
||||
List<Scene> dirtyScenes = new List<Scene>();
|
||||
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
|
||||
if (!scene.isDirty)
|
||||
continue;
|
||||
|
||||
dirtyScenes.Add(scene);
|
||||
}
|
||||
|
||||
return dirtyScenes;
|
||||
}
|
||||
|
||||
static bool Contains(
|
||||
List<string> paths,
|
||||
Scene scene)
|
||||
{
|
||||
if (string.IsNullOrEmpty(scene.path))
|
||||
return false;
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (PathHelper.IsSamePath(
|
||||
path,
|
||||
Path.GetFullPath(scene.path)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static List<string> GetPaths(
|
||||
List<ChangeInfo> changeInfos)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
foreach (ChangeInfo change in changeInfos)
|
||||
result.Add(change.GetFullPath());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 802adf99bdbb1a3439a0a09ae5664192
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user