Created unity project

This commit is contained in:
2024-12-07 20:55:50 +01:00
parent 539250d964
commit 54fe327198
13758 changed files with 865324 additions and 0 deletions

View File

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

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

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,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");
}
}

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,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");
}
}

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 = PlasticApp.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,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");
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b77071fd36e946809b40d79e6ba9fe8a
timeCreated: 1728894821

View File

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

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

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,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;
}
}
}

View File

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