A game about forced loneliness, made by TACStudios
1using System;
2using System.ComponentModel;
3using System.Threading;
4using System.Threading.Tasks;
5
6using UnityEditor;
7using UnityEngine;
8
9using Codice.Client.Common.Connection;
10using Codice.CM.Common;
11using Codice.LogWrapper;
12using Unity.PlasticSCM.Editor.AssetMenu;
13using Unity.PlasticSCM.Editor.AssetsOverlays;
14using Unity.PlasticSCM.Editor.AssetsOverlays.Cache;
15using Unity.PlasticSCM.Editor.AssetUtils.Processor;
16using Unity.PlasticSCM.Editor.Hub;
17using Unity.PlasticSCM.Editor.Inspector;
18using Unity.PlasticSCM.Editor.SceneView;
19using Unity.PlasticSCM.Editor.UI;
20
21namespace Unity.PlasticSCM.Editor
22{
23 // Internal usage. This isn't a public API.
24 // It supports calls across two different modules "Unity.CollabProxy.Editor".ToolbarButton -> "Unity.PlasticSCM.Editor".PlasticPlugin.Xxx()
25 // and the "Unity.CollabProxy.Editor" is itself required as it is hard-coded by the Unity Editor code
26 [EditorBrowsable(EditorBrowsableState.Never)]
27 [InitializeOnLoad]
28 public static class PlasticPlugin
29 {
30 // Internal usage between two different modules of the package.
31 [EditorBrowsable(EditorBrowsableState.Never)]
32 public static event Action OnNotificationUpdated = delegate { };
33
34 // Internal usage between two different modules of the package.
35 // It's pending to rename the OpenPlasticWindowDisablingOfflineModeIfNeeded
36 // method to OpenPlasticWindowAndEnablePluginIfNeeded. We cannot do it now
37 // because it's a public method and this rename breaks the API validation
38 // check. We will do it when we change the major version number to v3.0.0
39 // (which is only allowed for a major new version of Unity)
40 [EditorBrowsable(EditorBrowsableState.Never)]
41 public static void OpenPlasticWindowDisablingOfflineModeIfNeeded()
42 {
43 if (!PlasticPluginIsEnabledPreference.IsEnabled())
44 {
45 PlasticPluginIsEnabledPreference.Enable();
46 Enable();
47 }
48
49 ShowWindow.Plastic();
50 }
51
52 // Internal usage between two different modules of the package.
53 [EditorBrowsable(EditorBrowsableState.Never)]
54 public static Texture GetPluginStatusIcon()
55 {
56 return PlasticNotification.GetIcon(mNotificationStatus);
57 }
58
59 internal static IAssetStatusCache AssetStatusCache
60 {
61 get { return mAssetStatusCache; }
62 }
63
64 internal static WorkspaceOperationsMonitor WorkspaceOperationsMonitor
65 {
66 get { return mWorkspaceOperationsMonitor; }
67 }
68
69 internal static PlasticConnectionMonitor ConnectionMonitor
70 {
71 get { return mPlasticConnectionMonitor; }
72 }
73
74 internal static bool IsUnitTesting { get; set; }
75
76 static PlasticPlugin()
77 {
78 EditorDispatcher.InitializeMainThreadIdAndContext(
79 Thread.CurrentThread.ManagedThreadId,
80 SynchronizationContext.Current);
81
82 ProcessHubCommand.Initialize();
83
84 if (!FindWorkspace.HasWorkspace(ApplicationDataPath.Get()))
85 return;
86
87 if (!PlasticPluginIsEnabledPreference.IsEnabled())
88 return;
89
90 CooldownWindowDelayer cooldownInitializeAction = new CooldownWindowDelayer(
91 Enable, UnityConstants.PLUGIN_DELAYED_INITIALIZE_INTERVAL);
92 cooldownInitializeAction.Ping();
93 }
94
95 internal static void Enable()
96 {
97 if (mIsEnabled)
98 return;
99
100 mIsEnabled = true;
101
102 PlasticApp.InitializeIfNeeded();
103
104 mLog.Debug("Enable");
105
106 PlasticApp.Enable();
107
108 WorkspaceInfo wkInfo = FindWorkspace.InfoForApplicationPath(
109 ApplicationDataPath.Get(), PlasticGui.Plastic.API);
110
111 if (wkInfo == null)
112 return;
113
114 EnableForWorkspace(wkInfo);
115 }
116
117 internal static void EnableForWorkspace(WorkspaceInfo wkInfo)
118 {
119 if (mIsEnabledForWorkspace)
120 return;
121
122 mIsEnabledForWorkspace = true;
123
124 mLog.Debug("EnableForWorkspace " + wkInfo.ClientPath);
125
126 PlasticGui.Plastic.API.UpgradeWorkspaceMetadataAfterOrgUnificationNeeded(wkInfo);
127
128 PlasticApp.SetWorkspace(wkInfo);
129
130 HandleCredsAliasAndServerCert.InitializeHostUnreachableExceptionListener(
131 mPlasticConnectionMonitor);
132
133 bool isGluonMode = PlasticGui.Plastic.API.IsGluonWorkspace(wkInfo);
134
135 mAssetStatusCache = new AssetStatusCache(wkInfo, isGluonMode);
136
137 PlasticAssetsProcessor plasticAssetsProcessor = new PlasticAssetsProcessor();
138
139 mWorkspaceOperationsMonitor = BuildWorkspaceOperationsMonitor(plasticAssetsProcessor, isGluonMode);
140 mWorkspaceOperationsMonitor.Start();
141
142 UnityCloudProjectLinkMonitor.CheckCloudProjectAlignmentAsync(wkInfo);
143
144 AssetsProcessors.Enable(
145 wkInfo.ClientPath, plasticAssetsProcessor, mAssetStatusCache);
146 AssetMenuItems.Enable(
147 wkInfo, PlasticGui.Plastic.API, mAssetStatusCache);
148 DrawAssetOverlay.Enable(
149 wkInfo.ClientPath, mAssetStatusCache);
150 DrawInspectorOperations.Enable(
151 wkInfo, PlasticGui.Plastic.API, mAssetStatusCache);
152 DrawSceneOperations.Enable(
153 wkInfo, PlasticGui.Plastic.API,
154 mWorkspaceOperationsMonitor, mAssetStatusCache);
155
156 Task.Run(() => EnsureServerConnection(wkInfo, mPlasticConnectionMonitor));
157 }
158
159 internal static void Shutdown()
160 {
161 mLog.Debug("Shutdown");
162
163 HandleCredsAliasAndServerCert.CleanHostUnreachableExceptionListener();
164 mPlasticConnectionMonitor.Stop();
165
166 Disable();
167 }
168
169 internal static void Disable()
170 {
171 if (!mIsEnabled)
172 return;
173
174 try
175 {
176 mLog.Debug("Disable");
177
178 DisableForWorkspace();
179
180 PlasticApp.Dispose();
181 }
182 finally
183 {
184 mIsEnabled = false;
185 }
186 }
187
188 internal static void SetNotificationStatus(
189 PlasticWindow plasticWindow,
190 PlasticNotification.Status status)
191 {
192 mNotificationStatus = status;
193
194 plasticWindow.UpdateWindowIcon(status);
195
196 if (OnNotificationUpdated != null)
197 OnNotificationUpdated.Invoke();
198 }
199
200 static void DisableForWorkspace()
201 {
202 if (!mIsEnabledForWorkspace)
203 return;
204
205 try
206 {
207 mWorkspaceOperationsMonitor.Stop();
208 mAssetStatusCache.Cancel();
209
210 AssetsProcessors.Disable();
211 AssetMenuItems.Disable();
212 DrawAssetOverlay.Disable();
213 DrawInspectorOperations.Disable();
214 DrawSceneOperations.Disable();
215
216 mAssetStatusCache.Clear();
217 }
218 finally
219 {
220 mIsEnabledForWorkspace = false;
221 }
222 }
223
224 internal static PlasticNotification.Status GetNotificationStatus()
225 {
226 return mNotificationStatus;
227 }
228
229 static WorkspaceOperationsMonitor BuildWorkspaceOperationsMonitor(
230 PlasticAssetsProcessor plasticAssetsProcessor,
231 bool isGluonMode)
232 {
233 WorkspaceOperationsMonitor result = new WorkspaceOperationsMonitor(
234 PlasticGui.Plastic.API, plasticAssetsProcessor, isGluonMode);
235 plasticAssetsProcessor.SetWorkspaceOperationsMonitor(result);
236 return result;
237 }
238
239 static void EnsureServerConnection(
240 WorkspaceInfo wkInfo,
241 PlasticConnectionMonitor plasticConnectionMonitor)
242 {
243 if (IsUnitTesting)
244 return;
245
246 RepositorySpec repSpec = PlasticGui.Plastic.API.GetRepositorySpec(wkInfo);
247
248 plasticConnectionMonitor.SetRepositorySpecForEventTracking(repSpec);
249
250 try
251 {
252 // set the PlasticConnectionMonitor initially to have a valid connection
253 // then check that the server connection is valid. If failed, we call
254 // PlasticConnectionMonitor.OnConnectionError that fires the Plugin disable
255 // and the reconnection mechanism
256
257 plasticConnectionMonitor.SetAsConnected();
258
259 if (!PlasticGui.Plastic.API.CheckServerConnection(repSpec.Server))
260 throw new Exception(string.Format("Failed to connect to {0}", repSpec.Server));
261 }
262 catch (Exception ex)
263 {
264 plasticConnectionMonitor.OnConnectionError(ex, repSpec.Server);
265 }
266 }
267
268 static PlasticNotification.Status mNotificationStatus;
269 static IAssetStatusCache mAssetStatusCache;
270 static WorkspaceOperationsMonitor mWorkspaceOperationsMonitor;
271 static PlasticConnectionMonitor mPlasticConnectionMonitor = new PlasticConnectionMonitor();
272 static bool mIsEnabled;
273 static bool mIsEnabledForWorkspace;
274
275 static readonly ILog mLog = PlasticApp.GetLogger("PlasticPlugin");
276 }
277}