This commit is contained in:
2024-09-20 20:30:10 +02:00
commit 4fabf1a6fd
29169 changed files with 1706941 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
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))));
return Directory.Exists(
Path.GetFullPath(Path.Combine(
unityPlasticDllPath,
// assets relative path when running as a UPM package
"../../../Editor/PlasticSCM/Assets")));
}
static string GetAssetPath(string guid)
{
if (string.IsNullOrEmpty(guid))
return null;
return AssetDatabase.GUIDToAssetPath(guid);
}
static AssetsPath()
{
mAssetsFolderLocation = (IsRunningAsUPMPackage()) ?
"Packages/com.unity.collab-proxy/Editor/PlasticSCM/Assets" :
"Assets/Plugins/PlasticSCM/Editor/Assets";
}
static string mProjectFullPath = ProjectPath.
FromApplicationDataPath(ApplicationDataPath.Get());
static string mAssetsFolderLocation;
}
}

View File

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

View File

@@ -0,0 +1,58 @@
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)
{
List<string> selectedPaths = AssetsSelection.
GetSelectedPaths(wkPath, assetList);
List<string> result = new List<string>(selectedPaths);
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);
}
}
}

View File

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

View File

@@ -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('\\', '/') + '/';
}
}

View File

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

View File

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

View File

@@ -0,0 +1,99 @@
using UnityEditor;
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)
{
mWkPath = wkPath;
mAssetStatusCache = assetStatusCache;
mIsEnabled = true;
}
internal static void 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;
}
}

View File

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

View File

@@ -0,0 +1,143 @@
using System.Collections.Generic;
using Codice.Client.Common.FsNodeReaders.Watcher;
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
{
class AssetPostprocessor : UnityEditor.AssetPostprocessor
{
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)
{
mWkPath = wkPath;
mPlasticAssetsProcessor = plasticAssetsProcessor;
mIsEnabled = true;
}
internal static void 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 FSWatcher 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
MonoFileSystemWatcher.IsEnabled = true;
mPlasticAssetsProcessor.MoveOnSourceControl(
GetPathsToMoveContainedOnWorkspace(
mWkPath, movedAssets, movedFromAssetPaths));
mPlasticAssetsProcessor.DeleteFromSourceControl(
GetPathsContainedOnWorkspace(mWkPath, deletedAssets));
mPlasticAssetsProcessor.AddToSourceControl(
GetPathsContainedOnWorkspace(mWkPath, importedAssets));
if (AssetModificationProcessor.ModifiedAssets == null)
return;
mPlasticAssetsProcessor.CheckoutOnSourceControl(
GetPathsContainedOnWorkspace(
mWkPath, AssetModificationProcessor.ModifiedAssets));
AssetModificationProcessor.ModifiedAssets = null;
}
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;
}
}

View File

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

View File

@@ -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();
}
}
}

View File

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

View File

@@ -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 = LogManager.GetLogger("PlasticAssetsProcessor");
}
}

View File

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

View File

@@ -0,0 +1,714 @@
using System;
using System.Collections;
using System.Collections.Generic;
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 GluonGui;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.Views.IncomingChanges;
using Unity.PlasticSCM.Editor.Views.PendingChanges;
namespace Unity.PlasticSCM.Editor.AssetUtils.Processor
{
internal class WorkspaceOperationsMonitor
{
public interface IDisableAssetsProcessor
{
void Disable();
}
internal WorkspaceOperationsMonitor(
IPlasticAPI plasticApi,
IDisableAssetsProcessor disableAssetsProcessor,
bool isGluonMode)
{
mPlasticAPI = plasticApi;
mDisableAssetsProcessor = disableAssetsProcessor;
mIsGluonMode = isGluonMode;
}
internal void RegisterWindow(
WorkspaceWindow 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()
{
mIsRunning = true;
mIsEnabled = true;
Thread thread = new Thread(TaskLoopThread);
thread.IsBackground = true;
thread.Start();
}
internal void 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 (!mIsRunning)
break;
if (!mIsEnabled)
{
SleepUntilNextWorkload();
continue;
}
bool hasAssetProcessorOpsPending = false;
bool hasCheckoutOpsPending = false;
ProcessOperations(
mPlasticAPI,
mAssetsProcessorPathsToAdd,
mAssetsProcessorPathsToDelete,
mAssetsProcessorPathsToCheckout,
mAssetsProcessorPathsToMove,
mPathsToCheckout,
mLock,
mDisableAssetsProcessor,
out hasAssetProcessorOpsPending,
out hasCheckoutOpsPending);
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,
object lockObj,
IDisableAssetsProcessor disableAssetsProcessor,
out bool hasAssetProcessorOpsPending,
out bool hasCheckoutOpsPending)
{
bool hasAssetProcessorOpsProcessed =
ProcessAssetProcessorOperations(
plasticApi,
assetsProcessorPathsToAdd,
assetsProcessorPathsToDelete,
assetsProcessorPathsToCheckout,
assetsProcessorPathsToMove,
lockObj,
disableAssetsProcessor);
bool hasCheckoutOpsProcessed =
ProcessCheckoutOperation(
plasticApi,
pathsToCheckout,
lockObj);
HasPendingOperationsToProcess(
assetsProcessorPathsToAdd,
assetsProcessorPathsToDelete,
assetsProcessorPathsToCheckout,
assetsProcessorPathsToMove,
pathsToCheckout,
lockObj,
out hasAssetProcessorOpsPending,
out hasCheckoutOpsPending);
bool isAfterAssetProcessorOpNeeded =
hasAssetProcessorOpsProcessed &&
!hasAssetProcessorOpsPending;
bool isAfterCheckoutOpNeeded =
hasCheckoutOpsProcessed &&
!hasCheckoutOpsPending;
if (!isAfterAssetProcessorOpNeeded &&
!isAfterCheckoutOpNeeded)
return;
EditorDispatcher.Dispatch(() =>
{
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 (!mIsRunning)
return;
mIsRunning = false;
mResetEvent.Set();
}
void SleepUntilNextWorkload()
{
mResetEvent.Reset();
mResetEvent.WaitOne();
}
static bool ProcessAssetProcessorOperations(
IPlasticAPI plasticApi,
List<string> assetsProcessorPathsToAdd,
List<string> assetsProcessorPathsToDelete,
List<string> assetsProcessorPathsToCheckout,
List<AssetPostprocessor.PathToMove> assetsProcessorPathsToMove,
object lockObj,
IDisableAssetsProcessor disableAssetsProcessor)
{
bool hasProcessedPaths = false;
try
{
hasProcessedPaths = AssetsProcessorOperations.
AddIfNotControlled(
plasticApi, ExtractPathsToProcess(
assetsProcessorPathsToAdd, lockObj),
FilterManager.Get().GetIgnoredFilter());
hasProcessedPaths |= AssetsProcessorOperations.
DeleteIfControlled(
plasticApi, ExtractPathsToProcess(
assetsProcessorPathsToDelete, lockObj));
hasProcessedPaths |= AssetsProcessorOperations.
CheckoutIfControlledAndChanged(
plasticApi, ExtractPathsToProcess(
assetsProcessorPathsToCheckout, lockObj));
hasProcessedPaths |= AssetsProcessorOperations.
MoveIfControlled(
plasticApi, ExtractPathsToMoveToProcess(
assetsProcessorPathsToMove, lockObj));
}
catch (Exception ex)
{
LogException(ex);
disableAssetsProcessor.Disable();
}
return hasProcessedPaths;
}
static bool ProcessCheckoutOperation(
IPlasticAPI plasticApi,
List<string> pathsToProcess,
object lockObj)
{
List<string> paths = ExtractPathsToProcess(
pathsToProcess, lockObj);
List<string> result = new List<string>();
foreach (string path in paths)
{
WorkspaceTreeNode node =
plasticApi.GetWorkspaceTreeNode(path);
if (node != null &&
!CheckWorkspaceTreeNodeStatus.IsCheckedOut(node))
result.Add(path);
}
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);
}
static class AssetsProcessorOperations
{
internal static bool AddIfNotControlled(
IPlasticAPI plasticApi,
List<string> paths,
IgnoredFilesFilter ignoredFilter)
{
List<string> result = new List<string>();
foreach (string path in paths)
{
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);
}
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)
{
List<string> processedPaths = new List<string>(paths.Count);
foreach (string path in paths)
{
string metaPath = MetaPath.GetMetaPath(path);
if (plasticApi.GetWorkspaceTreeNode(path) != null)
{
processedPaths.Add(path);
}
if (plasticApi.GetWorkspaceTreeNode(metaPath) != null)
{
processedPaths.Add(metaPath);
}
}
plasticApi.DeleteControlled(
processedPaths.ToArray(), DeleteModifiers.None, null);
LogProcessedPaths("DeleteIfControlled", processedPaths);
return processedPaths.Count > 0;
}
internal static bool MoveIfControlled(
IPlasticAPI plasticApi,
List<AssetPostprocessor.PathToMove> paths)
{
List<string> processedPaths = new List<string>(paths.Count);
foreach (AssetPostprocessor.PathToMove pathToMove in paths)
{
string srcMetaPath = MetaPath.GetMetaPath(pathToMove.SrcPath);
string dstMetaPath = MetaPath.GetMetaPath(pathToMove.DstPath);
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 (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)
{
List<string> result = new List<string>();
foreach (string path in paths)
{
string metaPath = MetaPath.GetMetaPath(path);
WorkspaceTreeNode node =
plasticApi.GetWorkspaceTreeNode(path);
WorkspaceTreeNode nodeMeta =
plasticApi.GetWorkspaceTreeNode(metaPath);
if (node != null &&
!CheckWorkspaceTreeNodeStatus.IsCheckedOut(node) &&
ChangedFileChecker.IsChanged(node.LocalInfo, path, false))
result.Add(path);
if (nodeMeta != null &&
!CheckWorkspaceTreeNodeStatus.IsCheckedOut(nodeMeta) &&
ChangedFileChecker.IsChanged(nodeMeta.LocalInfo, metaPath, false))
result.Add(metaPath);
}
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();
volatile bool mIsRunning;
volatile bool mIsEnabled;
volatile ManualResetEvent mResetEvent = new ManualResetEvent(false);
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;
NewIncomingChangesUpdater mNewIncomingChangesUpdater;
ViewHost mViewHost;
IWorkspaceWindow mWorkspaceWindow;
readonly bool mIsGluonMode = false;
readonly IDisableAssetsProcessor mDisableAssetsProcessor;
readonly IPlasticAPI mPlasticAPI;
static readonly ILog mLog = LogManager.GetLogger("WorkspaceOperationsMonitor");
}
}

View File

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

View File

@@ -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));
}
}
}

View File

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

View File

@@ -0,0 +1,50 @@
using UnityEditor.PackageManager;
using Unity.PlasticSCM.Editor.AssetUtils.Processor;
namespace Unity.PlasticSCM.Editor.AssetUtils
{
internal static class RefreshAsset
{
internal static void BeforeLongAssetOperation()
{
UnityEditor.AssetDatabase.DisallowAutoRefresh();
}
internal static void AfterLongAssetOperation()
{
UnityEditor.AssetDatabase.AllowAutoRefresh();
UnityAssetDatabase();
// Client is an API to interact with package manager
// Client.Resolve() will resolve any pending packages added or removed from the project.
// https://docs.unity3d.com/ScriptReference/PackageManager.Client.html
Client.Resolve();
}
internal static void UnityAssetDatabase()
{
UnityEditor.AssetDatabase.Refresh(
UnityEditor.ImportAssetOptions.Default);
UnityEditor.VersionControl.Provider.ClearCache();
if (PlasticPlugin.AssetStatusCache != null)
PlasticPlugin.AssetStatusCache.Clear();
AssetPostprocessor.SetIsRepaintNeededAfterAssetDatabaseRefresh();
}
internal static void VersionControlCache()
{
UnityEditor.VersionControl.Provider.ClearCache();
if (PlasticPlugin.AssetStatusCache != null)
PlasticPlugin.AssetStatusCache.Clear();
ProjectWindow.Repaint();
RepaintInspector.All();
}
}
}

View File

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

View File

@@ -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();
}
}
}

View File

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

View File

@@ -0,0 +1,156 @@
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)
{
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;
}
}
}

View File

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