VersionControlConflictResolver.cs 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. namespace UnityVersionControl
  7. {
  8. /// <summary>
  9. /// Enhanced Visual Conflict Resolution Window for Unity Version Control
  10. /// Provides rich visual comparison and resolution for different asset types
  11. /// </summary>
  12. public class VersionControlConflictResolver : EditorWindow
  13. {
  14. #region Fields
  15. private Vector2 conflictListScrollPosition;
  16. private Vector2 viewerScrollPosition;
  17. private Vector2 leftScrollPosition;
  18. private Vector2 rightScrollPosition;
  19. private int selectedConflictIndex = 0;
  20. private readonly List<MockConflictInfo> mockConflicts = new List<MockConflictInfo>();
  21. private ConflictViewer currentViewer;
  22. // Enhanced visual comparison
  23. private int selectedViewMode = 0;
  24. private readonly string[] viewModeNames = { "Side by Side", "3D Preview", "Properties", "Overlay" };
  25. private float splitRatio = 0.5f;
  26. private bool isDraggingSplitter = false;
  27. // 3D Preview system
  28. private Camera previewCameraLeft;
  29. private Camera previewCameraRight;
  30. private RenderTexture leftRenderTexture;
  31. private RenderTexture rightRenderTexture;
  32. private GameObject leftPreviewObject;
  33. private GameObject rightPreviewObject;
  34. private GameObject previewEnvironment;
  35. private Light previewLight;
  36. // UI State
  37. private bool showLineNumbers = true;
  38. private bool showWhitespace = false;
  39. private bool wordWrap = false;
  40. private string searchText = "";
  41. private Vector3 cameraRotation = new Vector3(15f, -30f, 0f);
  42. private float cameraDistance = 3f;
  43. // Static callback for when conflicts are resolved
  44. private static System.Action onConflictsResolved;
  45. // Visual constants
  46. private static readonly Color backgroundColor = new Color(0.22f, 0.22f, 0.22f);
  47. private static readonly Color cardColor = new Color(0.28f, 0.28f, 0.28f);
  48. private static readonly Color accentColor = new Color(0.3f, 0.7f, 1f);
  49. private static readonly Color successColor = new Color(0.3f, 0.8f, 0.3f);
  50. private static readonly Color warningColor = new Color(1f, 0.8f, 0.2f);
  51. private static readonly Color errorColor = new Color(1f, 0.4f, 0.4f);
  52. private static readonly Color localColor = new Color(0.4f, 0.8f, 0.4f);
  53. private static readonly Color remoteColor = new Color(0.4f, 0.6f, 1f);
  54. private static readonly Color conflictColor = new Color(1f, 0.6f, 0.2f);
  55. private static readonly Color selectedColor = new Color(0.2f, 0.5f, 0.8f, 0.3f);
  56. // Caches
  57. private readonly Dictionary<string, Texture2D> textureCache = new Dictionary<string, Texture2D>();
  58. private readonly Dictionary<string, Material> materialCache = new Dictionary<string, Material>();
  59. private readonly Dictionary<string, GameObject> prefabCache = new Dictionary<string, GameObject>();
  60. private readonly List<PropertyDifference> currentPropertyDifferences = new List<PropertyDifference>();
  61. #endregion
  62. #region Unity Lifecycle
  63. [MenuItem("Window/Version Control/Conflict Resolver", false, 1)]
  64. public static void ShowWindow()
  65. {
  66. var window = GetWindow<VersionControlConflictResolver>();
  67. window.minSize = new Vector2(1000, 700);
  68. window.Initialize();
  69. }
  70. public static void ShowWindow(System.Action onResolved)
  71. {
  72. onConflictsResolved = onResolved;
  73. var window = GetWindow<VersionControlConflictResolver>("Visual Conflict Resolver");
  74. window.minSize = new Vector2(1000, 700);
  75. window.Initialize();
  76. }
  77. private void OnEnable()
  78. {
  79. Initialize();
  80. Setup3DPreviewSystem();
  81. }
  82. private void OnDisable()
  83. {
  84. CleanupTextures();
  85. Cleanup3DPreviewSystem();
  86. // Clean up callback to prevent memory leaks
  87. if (onConflictsResolved != null)
  88. {
  89. Debug.LogWarning("Conflict resolver closed without resolving conflicts - cleaning up callback");
  90. onConflictsResolved = null;
  91. }
  92. }
  93. private void OnGUI()
  94. {
  95. try
  96. {
  97. HandleEvents();
  98. DrawBackground();
  99. DrawEnhancedHeader();
  100. DrawMainLayout();
  101. }
  102. catch (Exception ex)
  103. {
  104. Debug.LogError($"Error in ConflictResolver OnGUI: {ex.Message}");
  105. DrawFallbackUI();
  106. }
  107. }
  108. #endregion
  109. #region Initialization
  110. private void Initialize()
  111. {
  112. CreateMockConflicts();
  113. if (mockConflicts.Count > 0)
  114. {
  115. SelectConflict(0);
  116. }
  117. }
  118. private void CreateMockConflicts()
  119. {
  120. try
  121. {
  122. mockConflicts.Clear();
  123. // Script conflict
  124. mockConflicts.Add(new MockConflictInfo
  125. {
  126. fileName = "PlayerController.cs",
  127. assetType = ConflictAssetType.Script,
  128. conflictType = ConflictType.PropertyValueDifference,
  129. description = "Method implementation differs",
  130. localVersion = "public float speed = 5.0f;\npublic void Move() {\n // Local implementation\n transform.Translate(Vector3.forward * speed);\n}",
  131. remoteVersion = "public float speed = 7.0f;\npublic void Move() {\n // Remote implementation\n rb.velocity = Vector3.forward * speed;\n}",
  132. resolution = ConflictResolution.Unresolved
  133. });
  134. // Prefab conflict
  135. mockConflicts.Add(new MockConflictInfo
  136. {
  137. fileName = "PlayerPrefab.prefab",
  138. assetType = ConflictAssetType.Prefab,
  139. conflictType = ConflictType.ComponentAdded,
  140. description = "Components differ between versions",
  141. localVersion = "Components: Transform, MeshRenderer, Rigidbody, BoxCollider",
  142. remoteVersion = "Components: Transform, MeshRenderer, Rigidbody, AudioSource, ParticleSystem",
  143. resolution = ConflictResolution.Unresolved
  144. });
  145. // Material conflict
  146. mockConflicts.Add(new MockConflictInfo
  147. {
  148. fileName = "PlayerMaterial.mat",
  149. assetType = ConflictAssetType.Material,
  150. conflictType = ConflictType.PropertyValueDifference,
  151. description = "Material properties have different values",
  152. localVersion = "Albedo: Red (1,0,0), Metallic: 0.5, Smoothness: 0.8",
  153. remoteVersion = "Albedo: Blue (0,0,1), Metallic: 0.2, Smoothness: 0.6",
  154. resolution = ConflictResolution.Unresolved
  155. });
  156. // Scene conflict
  157. mockConflicts.Add(new MockConflictInfo
  158. {
  159. fileName = "MainScene.unity",
  160. assetType = ConflictAssetType.Scene,
  161. conflictType = ConflictType.GameObjectMoved,
  162. description = "GameObject positions and lighting differ",
  163. localVersion = "Camera: (0,10,0), Lighting: Realtime GI",
  164. remoteVersion = "Camera: (5,10,-5), Lighting: Baked GI",
  165. resolution = ConflictResolution.Unresolved
  166. });
  167. // Texture conflict
  168. mockConflicts.Add(new MockConflictInfo
  169. {
  170. fileName = "CharacterTexture.png",
  171. assetType = ConflictAssetType.Texture,
  172. conflictType = ConflictType.AssetReplaced,
  173. description = "Different texture versions",
  174. localVersion = "Local texture: 512x512, RGB format",
  175. remoteVersion = "Remote texture: 1024x1024, RGBA format",
  176. resolution = ConflictResolution.Unresolved
  177. });
  178. }
  179. catch (Exception ex)
  180. {
  181. Debug.LogError($"Error creating mock conflicts: {ex.Message}");
  182. }
  183. }
  184. private void CleanupTextures()
  185. {
  186. foreach (var texture in textureCache.Values)
  187. {
  188. if (texture != null) DestroyImmediate(texture);
  189. }
  190. textureCache.Clear();
  191. }
  192. #endregion
  193. #region 3D Preview System
  194. private void Setup3DPreviewSystem()
  195. {
  196. try
  197. {
  198. // Create preview environment
  199. previewEnvironment = new GameObject("ConflictResolver_PreviewEnvironment");
  200. previewEnvironment.hideFlags = HideFlags.HideAndDontSave;
  201. // Setup lighting
  202. var lightGO = new GameObject("PreviewLight");
  203. lightGO.transform.SetParent(previewEnvironment.transform);
  204. lightGO.hideFlags = HideFlags.HideAndDontSave;
  205. previewLight = lightGO.AddComponent<Light>();
  206. previewLight.type = LightType.Directional;
  207. previewLight.intensity = 1.0f;
  208. previewLight.color = Color.white;
  209. previewLight.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
  210. // Setup left camera
  211. var leftCameraGO = new GameObject("PreviewCamera_Left");
  212. leftCameraGO.transform.SetParent(previewEnvironment.transform);
  213. leftCameraGO.hideFlags = HideFlags.HideAndDontSave;
  214. previewCameraLeft = leftCameraGO.AddComponent<Camera>();
  215. previewCameraLeft.clearFlags = CameraClearFlags.SolidColor;
  216. previewCameraLeft.backgroundColor = new Color(0.1f, 0.1f, 0.1f);
  217. previewCameraLeft.cullingMask = 1 << 30; // Layer 30 for left previews
  218. // Setup right camera
  219. var rightCameraGO = new GameObject("PreviewCamera_Right");
  220. rightCameraGO.transform.SetParent(previewEnvironment.transform);
  221. rightCameraGO.hideFlags = HideFlags.HideAndDontSave;
  222. previewCameraRight = rightCameraGO.AddComponent<Camera>();
  223. previewCameraRight.clearFlags = CameraClearFlags.SolidColor;
  224. previewCameraRight.backgroundColor = new Color(0.1f, 0.1f, 0.1f);
  225. previewCameraRight.cullingMask = 1 << 31; // Layer 31 for right previews
  226. // Create render textures
  227. leftRenderTexture = new RenderTexture(256, 256, 16);
  228. rightRenderTexture = new RenderTexture(256, 256, 16);
  229. previewCameraLeft.targetTexture = leftRenderTexture;
  230. previewCameraRight.targetTexture = rightRenderTexture;
  231. // Position cameras
  232. UpdateCameraPositions();
  233. }
  234. catch (Exception ex)
  235. {
  236. Debug.LogError($"Failed to setup 3D preview system: {ex.Message}");
  237. }
  238. }
  239. private void UpdateCameraPositions()
  240. {
  241. if (previewCameraLeft != null && previewCameraRight != null)
  242. {
  243. var position = Quaternion.Euler(cameraRotation) * Vector3.back * cameraDistance;
  244. previewCameraLeft.transform.position = position + Vector3.left * 2f;
  245. previewCameraLeft.transform.LookAt(Vector3.left * 2f);
  246. previewCameraRight.transform.position = position + Vector3.right * 2f;
  247. previewCameraRight.transform.LookAt(Vector3.right * 2f);
  248. }
  249. }
  250. private void Cleanup3DPreviewSystem()
  251. {
  252. try
  253. {
  254. if (leftRenderTexture != null)
  255. {
  256. leftRenderTexture.Release();
  257. DestroyImmediate(leftRenderTexture);
  258. leftRenderTexture = null;
  259. }
  260. if (rightRenderTexture != null)
  261. {
  262. rightRenderTexture.Release();
  263. DestroyImmediate(rightRenderTexture);
  264. rightRenderTexture = null;
  265. }
  266. if (leftPreviewObject != null)
  267. {
  268. DestroyImmediate(leftPreviewObject);
  269. leftPreviewObject = null;
  270. }
  271. if (rightPreviewObject != null)
  272. {
  273. DestroyImmediate(rightPreviewObject);
  274. rightPreviewObject = null;
  275. }
  276. if (previewEnvironment != null)
  277. {
  278. DestroyImmediate(previewEnvironment);
  279. previewEnvironment = null;
  280. }
  281. previewCameraLeft = null;
  282. previewCameraRight = null;
  283. previewLight = null;
  284. }
  285. catch (Exception ex)
  286. {
  287. Debug.LogError($"Failed to cleanup 3D preview system: {ex.Message}");
  288. }
  289. }
  290. private void RefreshPreviewObjects()
  291. {
  292. if (selectedViewMode == 1 && selectedConflictIndex >= 0 && selectedConflictIndex < mockConflicts.Count)
  293. {
  294. var conflict = mockConflicts[selectedConflictIndex];
  295. LoadPreviewObjects(conflict);
  296. }
  297. }
  298. private void LoadPreviewObjects(MockConflictInfo conflict)
  299. {
  300. try
  301. {
  302. // Clean up existing preview objects
  303. if (leftPreviewObject != null)
  304. DestroyImmediate(leftPreviewObject);
  305. if (rightPreviewObject != null)
  306. DestroyImmediate(rightPreviewObject);
  307. if (conflict.assetType == ConflictAssetType.Prefab)
  308. {
  309. leftPreviewObject = CreateMockPrefab(true);
  310. rightPreviewObject = CreateMockPrefab(false);
  311. // Position objects
  312. leftPreviewObject.transform.position = Vector3.left * 2f;
  313. rightPreviewObject.transform.position = Vector3.right * 2f;
  314. // Set layers
  315. SetLayerRecursively(leftPreviewObject, 30);
  316. SetLayerRecursively(rightPreviewObject, 31);
  317. }
  318. else if (conflict.assetType == ConflictAssetType.Material)
  319. {
  320. // Create sphere previews for materials
  321. leftPreviewObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  322. rightPreviewObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  323. leftPreviewObject.hideFlags = HideFlags.HideAndDontSave;
  324. rightPreviewObject.hideFlags = HideFlags.HideAndDontSave;
  325. leftPreviewObject.transform.position = Vector3.left * 2f;
  326. rightPreviewObject.transform.position = Vector3.right * 2f;
  327. // Apply different materials
  328. var leftRenderer = leftPreviewObject.GetComponent<Renderer>();
  329. var rightRenderer = rightPreviewObject.GetComponent<Renderer>();
  330. leftRenderer.material.color = Color.red;
  331. rightRenderer.material.color = Color.blue;
  332. SetLayerRecursively(leftPreviewObject, 30);
  333. SetLayerRecursively(rightPreviewObject, 31);
  334. }
  335. }
  336. catch (Exception ex)
  337. {
  338. Debug.LogError($"Failed to load preview objects: {ex.Message}");
  339. }
  340. }
  341. private GameObject CreateMockPrefab(bool isLocal)
  342. {
  343. var prefab = GameObject.CreatePrimitive(PrimitiveType.Cube);
  344. prefab.hideFlags = HideFlags.HideAndDontSave;
  345. prefab.name = isLocal ? "LocalPrefab" : "RemotePrefab";
  346. if (isLocal)
  347. {
  348. prefab.transform.localScale = Vector3.one;
  349. var renderer = prefab.GetComponent<Renderer>();
  350. renderer.material.color = Color.red;
  351. }
  352. else
  353. {
  354. prefab.transform.localScale = Vector3.one * 1.2f;
  355. var renderer = prefab.GetComponent<Renderer>();
  356. renderer.material.color = Color.blue;
  357. // Add additional component to show difference
  358. var audioSource = prefab.AddComponent<AudioSource>();
  359. }
  360. return prefab;
  361. }
  362. private void SetLayerRecursively(GameObject obj, int layer)
  363. {
  364. obj.layer = layer;
  365. foreach (Transform child in obj.transform)
  366. {
  367. SetLayerRecursively(child.gameObject, layer);
  368. }
  369. }
  370. #endregion
  371. #region Enhanced GUI Drawing
  372. private void DrawBackground()
  373. {
  374. var rect = new Rect(0, 0, position.width, position.height);
  375. EditorGUI.DrawRect(rect, backgroundColor);
  376. }
  377. private void DrawEnhancedHeader()
  378. {
  379. DrawCard(() =>
  380. {
  381. using (new EditorGUILayout.HorizontalScope())
  382. {
  383. var iconRect = GUILayoutUtility.GetRect(24, 24);
  384. var iconTexture = CreateRoundedTexture(errorColor, 24, 4);
  385. GUI.DrawTexture(iconRect, iconTexture);
  386. GUILayout.Space(8);
  387. using (new EditorGUILayout.VerticalScope())
  388. {
  389. var titleStyle = new GUIStyle(EditorStyles.boldLabel);
  390. titleStyle.fontSize = 14;
  391. titleStyle.normal.textColor = Color.white;
  392. EditorGUILayout.LabelField("Visual Conflict Resolution", titleStyle);
  393. var subtitleStyle = new GUIStyle(EditorStyles.label);
  394. subtitleStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
  395. subtitleStyle.fontSize = 11;
  396. EditorGUILayout.LabelField($"Resolve {mockConflicts.Count(c => c.resolution == ConflictResolution.Unresolved)} conflicts to continue", subtitleStyle);
  397. }
  398. GUILayout.FlexibleSpace();
  399. DrawViewModeSelector();
  400. GUILayout.Space(8);
  401. DrawResolutionButtons();
  402. }
  403. }, 12);
  404. }
  405. private void DrawViewModeSelector()
  406. {
  407. using (new EditorGUILayout.VerticalScope())
  408. {
  409. EditorGUILayout.LabelField("View Mode:", EditorStyles.miniLabel);
  410. var newViewMode = GUILayout.Toolbar(selectedViewMode, viewModeNames, GUILayout.Width(300));
  411. if (newViewMode != selectedViewMode)
  412. {
  413. selectedViewMode = newViewMode;
  414. RefreshPreviewObjects();
  415. GenerateCurrentPropertyDifferences();
  416. Repaint();
  417. }
  418. }
  419. }
  420. private void DrawResolutionButtons()
  421. {
  422. var unresolvedCount = mockConflicts.Count(c => c.resolution == ConflictResolution.Unresolved);
  423. var canProceed = unresolvedCount == 0;
  424. using (new EditorGUI.DisabledScope(!canProceed))
  425. {
  426. var proceedStyle = new GUIStyle(GUI.skin.button);
  427. proceedStyle.normal.textColor = Color.white;
  428. proceedStyle.fixedHeight = 28;
  429. proceedStyle.fontStyle = FontStyle.Bold;
  430. if (canProceed)
  431. {
  432. proceedStyle.normal.background = CreateRoundedTexture(successColor, 28, 4);
  433. }
  434. if (GUILayout.Button("✓ APPLY RESOLUTIONS", proceedStyle, GUILayout.Width(140)))
  435. {
  436. ApplyResolutions();
  437. }
  438. }
  439. GUILayout.Space(8);
  440. var cancelStyle = new GUIStyle(GUI.skin.button);
  441. cancelStyle.normal.textColor = errorColor;
  442. cancelStyle.fixedHeight = 28;
  443. if (GUILayout.Button("✕ CANCEL PULL", cancelStyle, GUILayout.Width(100)))
  444. {
  445. Close();
  446. }
  447. }
  448. private void DrawMainLayout()
  449. {
  450. EditorGUILayout.Space(8);
  451. using (new EditorGUILayout.HorizontalScope())
  452. {
  453. // Left panel - Conflict list
  454. DrawConflictList();
  455. GUILayout.Space(8);
  456. // Right panel - Conflict viewer
  457. DrawConflictViewer();
  458. }
  459. }
  460. private void DrawConflictList()
  461. {
  462. using (new EditorGUILayout.VerticalScope(GUILayout.Width(280)))
  463. {
  464. DrawCard(() =>
  465. {
  466. DrawSectionHeader("Conflicting Files", $"{mockConflicts.Count} files need resolution");
  467. EditorGUILayout.Space(8);
  468. using (var scrollView = new EditorGUILayout.ScrollViewScope(conflictListScrollPosition))
  469. {
  470. conflictListScrollPosition = scrollView.scrollPosition;
  471. for (int i = 0; i < mockConflicts.Count; i++)
  472. {
  473. DrawConflictListItem(mockConflicts[i], i);
  474. if (i < mockConflicts.Count - 1)
  475. EditorGUILayout.Space(4);
  476. }
  477. }
  478. }, 12);
  479. }
  480. }
  481. private void DrawConflictListItem(MockConflictInfo conflict, int index)
  482. {
  483. var isSelected = selectedConflictIndex == index;
  484. var itemRect = EditorGUILayout.BeginVertical();
  485. if (isSelected)
  486. {
  487. EditorGUI.DrawRect(itemRect, selectedColor);
  488. }
  489. if (GUI.Button(itemRect, "", GUIStyle.none))
  490. {
  491. SelectConflict(index);
  492. }
  493. GUILayout.Space(8);
  494. using (new EditorGUILayout.HorizontalScope())
  495. {
  496. GUILayout.Space(8);
  497. // Asset type icon
  498. var iconSize = 20;
  499. var iconRect = GUILayoutUtility.GetRect(iconSize, iconSize);
  500. var iconColor = GetAssetTypeColor(conflict.assetType);
  501. var iconTexture = CreateRoundedTexture(iconColor, iconSize, iconSize / 2);
  502. GUI.DrawTexture(iconRect, iconTexture);
  503. var iconStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
  504. iconStyle.normal.textColor = Color.white;
  505. iconStyle.fontSize = 8;
  506. iconStyle.fontStyle = FontStyle.Bold;
  507. GUI.Label(iconRect, GetAssetTypeIcon(conflict.assetType), iconStyle);
  508. GUILayout.Space(8);
  509. using (new EditorGUILayout.VerticalScope())
  510. {
  511. var fileNameStyle = new GUIStyle(EditorStyles.boldLabel);
  512. fileNameStyle.fontSize = 12;
  513. fileNameStyle.normal.textColor = Color.white;
  514. EditorGUILayout.LabelField(conflict.fileName, fileNameStyle);
  515. var descStyle = new GUIStyle(EditorStyles.label);
  516. descStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f);
  517. descStyle.fontSize = 10;
  518. descStyle.wordWrap = true;
  519. EditorGUILayout.LabelField(conflict.description, descStyle);
  520. }
  521. GUILayout.FlexibleSpace();
  522. // Resolution status
  523. var statusSize = 16;
  524. var statusRect = GUILayoutUtility.GetRect(statusSize, statusSize);
  525. var statusColor = conflict.resolution switch
  526. {
  527. ConflictResolution.Unresolved => errorColor,
  528. ConflictResolution.UseLocal => localColor,
  529. ConflictResolution.UseRemote => remoteColor,
  530. _ => warningColor
  531. };
  532. var statusTexture = CreateRoundedTexture(statusColor, statusSize, statusSize / 2);
  533. GUI.DrawTexture(statusRect, statusTexture);
  534. var statusIcon = conflict.resolution switch
  535. {
  536. ConflictResolution.Unresolved => "!",
  537. ConflictResolution.UseLocal => "L",
  538. ConflictResolution.UseRemote => "R",
  539. _ => "?"
  540. };
  541. var statusStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
  542. statusStyle.normal.textColor = Color.white;
  543. statusStyle.fontSize = 8;
  544. statusStyle.fontStyle = FontStyle.Bold;
  545. GUI.Label(statusRect, statusIcon, statusStyle);
  546. GUILayout.Space(8);
  547. }
  548. GUILayout.Space(8);
  549. EditorGUILayout.EndVertical();
  550. }
  551. private void DrawConflictViewer()
  552. {
  553. using (new EditorGUILayout.VerticalScope())
  554. {
  555. if (selectedConflictIndex >= 0 && selectedConflictIndex < mockConflicts.Count)
  556. {
  557. var selectedConflict = mockConflicts[selectedConflictIndex];
  558. DrawCard(() =>
  559. {
  560. DrawConflictViewerContent(selectedConflict);
  561. }, 12);
  562. }
  563. else
  564. {
  565. DrawCard(() =>
  566. {
  567. var emptyStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
  568. emptyStyle.normal.textColor = new Color(0.6f, 0.6f, 0.6f);
  569. emptyStyle.fontSize = 14;
  570. EditorGUILayout.LabelField("Select a conflict to view details", emptyStyle);
  571. }, 32);
  572. }
  573. }
  574. }
  575. private void DrawConflictViewerContent(MockConflictInfo conflict)
  576. {
  577. DrawSectionHeader($"{conflict.fileName} Conflict", $"{conflict.assetType} • {conflict.conflictType}");
  578. EditorGUILayout.Space(8);
  579. // Enhanced conflict viewer based on selected mode
  580. switch (selectedViewMode)
  581. {
  582. case 0: DrawSideBySideComparison(conflict); break;
  583. case 1: Draw3DPreviewComparison(conflict); break;
  584. case 2: DrawPropertiesComparison(conflict); break;
  585. case 3: DrawOverlayComparison(conflict); break;
  586. }
  587. EditorGUILayout.Space(16);
  588. DrawResolutionControls(conflict);
  589. }
  590. private void DrawSideBySideComparison(MockConflictInfo conflict)
  591. {
  592. var viewerRect = EditorGUILayout.BeginHorizontal(GUILayout.Height(400));
  593. // Left panel
  594. var leftWidth = viewerRect.width * splitRatio;
  595. using (new EditorGUILayout.VerticalScope(GUILayout.Width(leftWidth)))
  596. {
  597. DrawVersionPanel(conflict, true, "LOCAL VERSION");
  598. }
  599. // Splitter
  600. DrawSplitter();
  601. // Right panel
  602. using (new EditorGUILayout.VerticalScope())
  603. {
  604. DrawVersionPanel(conflict, false, "REMOTE VERSION");
  605. }
  606. EditorGUILayout.EndHorizontal();
  607. }
  608. private void DrawVersionPanel(MockConflictInfo conflict, bool isLocal, string title)
  609. {
  610. var headerColor = isLocal ? localColor : remoteColor;
  611. var content = isLocal ? conflict.localVersion : conflict.remoteVersion;
  612. var headerStyle = new GUIStyle(EditorStyles.boldLabel);
  613. headerStyle.normal.textColor = headerColor;
  614. headerStyle.alignment = TextAnchor.MiddleCenter;
  615. EditorGUILayout.LabelField(title, headerStyle);
  616. EditorGUILayout.Space(4);
  617. // Enhanced content based on asset type
  618. switch (conflict.assetType)
  619. {
  620. case ConflictAssetType.Material:
  621. DrawMaterialPreview(conflict, isLocal);
  622. break;
  623. case ConflictAssetType.Prefab:
  624. DrawPrefabPreview(conflict, isLocal);
  625. break;
  626. case ConflictAssetType.Texture:
  627. DrawTexturePreview(conflict, isLocal);
  628. break;
  629. case ConflictAssetType.Scene:
  630. DrawScenePreview(conflict, isLocal);
  631. break;
  632. case ConflictAssetType.Script:
  633. DrawScriptPreview(conflict, isLocal);
  634. break;
  635. default:
  636. DrawGenericPreview(content, headerColor);
  637. break;
  638. }
  639. }
  640. private void DrawMaterialPreview(MockConflictInfo conflict, bool isLocal)
  641. {
  642. // Material sphere preview
  643. var previewRect = GUILayoutUtility.GetRect(200, 150);
  644. EditorGUI.DrawRect(previewRect, new Color(0.1f, 0.1f, 0.1f));
  645. // Mock material sphere
  646. var centerRect = new Rect(previewRect.x + 50, previewRect.y + 25, 100, 100);
  647. var sphereColor = isLocal ? new Color(0.8f, 0.2f, 0.2f) : new Color(0.2f, 0.2f, 0.8f);
  648. // Draw gradient to simulate sphere lighting
  649. for (int i = 0; i < 50; i++)
  650. {
  651. var t = i / 50f;
  652. var currentColor = Color.Lerp(sphereColor * 1.5f, sphereColor * 0.3f, t);
  653. var rect = new Rect(centerRect.x + i, centerRect.y + i * 0.5f, centerRect.width - i * 2, centerRect.height - i);
  654. EditorGUI.DrawRect(rect, currentColor);
  655. }
  656. // Material properties
  657. EditorGUILayout.Space(8);
  658. var materialData = isLocal ?
  659. "Albedo: Red (1,0,0)\nMetallic: 0.5\nSmoothness: 0.8\nEmission: Off" :
  660. "Albedo: Blue (0,0,1)\nMetallic: 0.2\nSmoothness: 0.6\nEmission: On";
  661. var propStyle = new GUIStyle(EditorStyles.textArea);
  662. propStyle.fontSize = 10;
  663. propStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
  664. EditorGUILayout.TextArea(materialData, propStyle, GUILayout.Height(60));
  665. }
  666. private void DrawPrefabPreview(MockConflictInfo conflict, bool isLocal)
  667. {
  668. // Hierarchy view
  669. var hierarchyRect = GUILayoutUtility.GetRect(200, 200);
  670. EditorGUI.DrawRect(hierarchyRect, new Color(0.15f, 0.15f, 0.15f));
  671. GUILayout.BeginArea(hierarchyRect);
  672. GUILayout.Space(8);
  673. if (isLocal)
  674. {
  675. DrawHierarchyItem("Player", 0, true);
  676. DrawHierarchyItem("Mesh Renderer", 1, false);
  677. DrawHierarchyItem("Box Collider", 1, false);
  678. DrawHierarchyItem("Rigidbody", 1, false);
  679. DrawHierarchyItem("Player Controller", 1, false);
  680. }
  681. else
  682. {
  683. DrawHierarchyItem("Player", 0, true);
  684. DrawHierarchyItem("Mesh Renderer", 1, false);
  685. DrawHierarchyItem("Box Collider", 1, false);
  686. DrawHierarchyItem("Rigidbody", 1, false);
  687. DrawHierarchyItem("Audio Source", 1, true); // New component
  688. DrawHierarchyItem("Particle System", 1, true); // New component
  689. DrawHierarchyItem("Player Controller", 1, false);
  690. }
  691. GUILayout.EndArea();
  692. }
  693. private void DrawHierarchyItem(string name, int indent, bool isHighlighted)
  694. {
  695. using (new EditorGUILayout.HorizontalScope())
  696. {
  697. GUILayout.Space(indent * 16 + 8);
  698. var itemStyle = new GUIStyle(EditorStyles.label);
  699. itemStyle.fontSize = 10;
  700. itemStyle.normal.textColor = isHighlighted ? conflictColor : Color.white;
  701. var icon = indent == 0 ? "🎮" : "⚙️";
  702. EditorGUILayout.LabelField($"{icon} {name}", itemStyle, GUILayout.Height(16));
  703. }
  704. }
  705. private void DrawTexturePreview(MockConflictInfo conflict, bool isLocal)
  706. {
  707. var previewRect = GUILayoutUtility.GetRect(200, 150);
  708. EditorGUI.DrawRect(previewRect, new Color(0.1f, 0.1f, 0.1f));
  709. // Mock texture preview with checkerboard pattern
  710. var textureRect = new Rect(previewRect.x + 25, previewRect.y + 25, 150, 100);
  711. var textureColor = isLocal ?
  712. new Color(0.8f, 0.6f, 0.4f) : // Brown texture
  713. new Color(0.4f, 0.6f, 0.8f); // Blue texture
  714. // Draw checkerboard pattern
  715. for (int x = 0; x < 15; x++)
  716. {
  717. for (int y = 0; y < 10; y++)
  718. {
  719. var checkerColor = ((x + y) % 2 == 0) ? textureColor : textureColor * 0.7f;
  720. var checkerRect = new Rect(textureRect.x + x * 10, textureRect.y + y * 10, 10, 10);
  721. EditorGUI.DrawRect(checkerRect, checkerColor);
  722. }
  723. }
  724. // Texture info
  725. EditorGUILayout.Space(8);
  726. var textureInfo = isLocal ?
  727. "Size: 512x512\nFormat: RGB24\nMipmaps: Yes\nFilter: Bilinear" :
  728. "Size: 1024x1024\nFormat: RGBA32\nMipmaps: Yes\nFilter: Trilinear";
  729. var infoStyle = new GUIStyle(EditorStyles.textArea);
  730. infoStyle.fontSize = 10;
  731. infoStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
  732. EditorGUILayout.TextArea(textureInfo, infoStyle, GUILayout.Height(60));
  733. }
  734. private void DrawScenePreview(MockConflictInfo conflict, bool isLocal)
  735. {
  736. var previewRect = GUILayoutUtility.GetRect(200, 150);
  737. EditorGUI.DrawRect(previewRect, new Color(0.05f, 0.05f, 0.1f)); // Dark blue background
  738. // Mock scene elements
  739. var cameraPos = isLocal ? new Vector2(50, 50) : new Vector2(100, 80);
  740. var lightPos = isLocal ? new Vector2(150, 30) : new Vector2(120, 40);
  741. // Draw ground plane
  742. var groundRect = new Rect(previewRect.x + 20, previewRect.y + 120, previewRect.width - 40, 20);
  743. EditorGUI.DrawRect(groundRect, new Color(0.3f, 0.5f, 0.3f));
  744. // Draw camera
  745. var cameraRect = new Rect(previewRect.x + cameraPos.x, previewRect.y + cameraPos.y, 20, 20);
  746. EditorGUI.DrawRect(cameraRect, Color.yellow);
  747. // Draw light
  748. var lightRect = new Rect(previewRect.x + lightPos.x, previewRect.y + lightPos.y, 15, 15);
  749. EditorGUI.DrawRect(lightRect, Color.white);
  750. // Scene info
  751. EditorGUILayout.Space(8);
  752. var sceneInfo = isLocal ?
  753. "Camera: (0,10,0)\nLighting: Realtime GI\nSkybox: Default\nFog: Disabled" :
  754. "Camera: (5,10,-5)\nLighting: Baked GI\nSkybox: Procedural\nFog: Enabled";
  755. var infoStyle = new GUIStyle(EditorStyles.textArea);
  756. infoStyle.fontSize = 10;
  757. infoStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
  758. EditorGUILayout.TextArea(sceneInfo, infoStyle, GUILayout.Height(60));
  759. }
  760. private void DrawScriptPreview(MockConflictInfo conflict, bool isLocal)
  761. {
  762. var content = isLocal ? conflict.localVersion : conflict.remoteVersion;
  763. using (var scrollView = new EditorGUILayout.ScrollViewScope(isLocal ? leftScrollPosition : rightScrollPosition, GUILayout.Height(200)))
  764. {
  765. if (isLocal) leftScrollPosition = scrollView.scrollPosition;
  766. else rightScrollPosition = scrollView.scrollPosition;
  767. var codeStyle = new GUIStyle(EditorStyles.textArea);
  768. codeStyle.wordWrap = wordWrap;
  769. codeStyle.richText = false;
  770. codeStyle.font = EditorGUIUtility.Load("Consolas") as Font ?? GUI.skin.font;
  771. codeStyle.fontSize = 10;
  772. var lines = content.Split('\n');
  773. for (int i = 0; i < lines.Length; i++)
  774. {
  775. using (new EditorGUILayout.HorizontalScope())
  776. {
  777. if (showLineNumbers)
  778. {
  779. var lineNumStyle = new GUIStyle(EditorStyles.label);
  780. lineNumStyle.normal.textColor = new Color(0.5f, 0.5f, 0.5f);
  781. lineNumStyle.fontSize = 9;
  782. lineNumStyle.alignment = TextAnchor.MiddleRight;
  783. EditorGUILayout.LabelField((i + 1).ToString(), lineNumStyle, GUILayout.Width(30));
  784. }
  785. EditorGUILayout.LabelField(lines[i], codeStyle, GUILayout.Height(16));
  786. }
  787. }
  788. }
  789. // Code options
  790. EditorGUILayout.Space(4);
  791. using (new EditorGUILayout.HorizontalScope())
  792. {
  793. showLineNumbers = EditorGUILayout.Toggle("Lines", showLineNumbers, GUILayout.Width(60));
  794. wordWrap = EditorGUILayout.Toggle("Wrap", wordWrap, GUILayout.Width(60));
  795. }
  796. }
  797. private void DrawGenericPreview(string content, Color borderColor)
  798. {
  799. var rect = EditorGUILayout.BeginVertical();
  800. EditorGUI.DrawRect(rect, new Color(borderColor.r, borderColor.g, borderColor.b, 0.1f));
  801. GUILayout.Space(8);
  802. using (new EditorGUILayout.HorizontalScope())
  803. {
  804. GUILayout.Space(8);
  805. using (new EditorGUILayout.VerticalScope())
  806. {
  807. var contentStyle = new GUIStyle(EditorStyles.textArea);
  808. contentStyle.wordWrap = true;
  809. contentStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
  810. EditorGUILayout.TextArea(content, contentStyle, GUILayout.Height(200));
  811. }
  812. GUILayout.Space(8);
  813. }
  814. GUILayout.Space(8);
  815. EditorGUILayout.EndVertical();
  816. }
  817. private void Draw3DPreviewComparison(MockConflictInfo conflict)
  818. {
  819. if (conflict.assetType == ConflictAssetType.Prefab || conflict.assetType == ConflictAssetType.Scene || conflict.assetType == ConflictAssetType.Material)
  820. {
  821. EditorGUILayout.LabelField("3D Preview Comparison", EditorStyles.boldLabel);
  822. EditorGUILayout.Space(8);
  823. using (new EditorGUILayout.HorizontalScope())
  824. {
  825. // Left 3D preview
  826. using (new EditorGUILayout.VerticalScope())
  827. {
  828. EditorGUILayout.LabelField("LOCAL VERSION", EditorStyles.centeredGreyMiniLabel);
  829. Draw3DPreviewPanel(true);
  830. }
  831. GUILayout.Space(8);
  832. // Right 3D preview
  833. using (new EditorGUILayout.VerticalScope())
  834. {
  835. EditorGUILayout.LabelField("REMOTE VERSION", EditorStyles.centeredGreyMiniLabel);
  836. Draw3DPreviewPanel(false);
  837. }
  838. }
  839. // 3D Controls
  840. EditorGUILayout.Space(8);
  841. Draw3DControls();
  842. }
  843. else
  844. {
  845. EditorGUILayout.HelpBox("3D Preview is only available for Prefabs, Scenes, and Materials.", MessageType.Info);
  846. DrawSideBySideComparison(conflict);
  847. }
  848. }
  849. private void Draw3DPreviewPanel(bool isLocal)
  850. {
  851. var previewRect = GUILayoutUtility.GetRect(300, 200);
  852. EditorGUI.DrawRect(previewRect, new Color(0.1f, 0.1f, 0.1f));
  853. // Draw render texture if available
  854. var renderTexture = isLocal ? leftRenderTexture : rightRenderTexture;
  855. if (renderTexture != null)
  856. {
  857. GUI.DrawTexture(previewRect, renderTexture, ScaleMode.ScaleToFit);
  858. }
  859. else
  860. {
  861. // Fallback: mock 3D preview
  862. var centerX = previewRect.x + previewRect.width * 0.5f;
  863. var centerY = previewRect.y + previewRect.height * 0.5f;
  864. var cubeSize = isLocal ? 40 : 50;
  865. var cubeColor = isLocal ? new Color(0.8f, 0.2f, 0.2f) : new Color(0.2f, 0.2f, 0.8f);
  866. var cubeRect = new Rect(centerX - cubeSize/2, centerY - cubeSize/2, cubeSize, cubeSize);
  867. EditorGUI.DrawRect(cubeRect, cubeColor);
  868. // Draw simple perspective lines to simulate 3D
  869. var offset = 10;
  870. var topRect = new Rect(centerX - cubeSize/2 + offset, centerY - cubeSize/2 - offset, cubeSize, cubeSize);
  871. EditorGUI.DrawRect(topRect, new Color(cubeColor.r + 0.2f, cubeColor.g + 0.2f, cubeColor.b + 0.2f));
  872. }
  873. // Preview info
  874. var infoStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
  875. infoStyle.normal.textColor = Color.white;
  876. infoStyle.fontSize = 10;
  877. var infoRect = new Rect(previewRect.x, previewRect.y + previewRect.height - 20, previewRect.width, 20);
  878. GUI.Label(infoRect, isLocal ? "Local 3D Preview" : "Remote 3D Preview", infoStyle);
  879. }
  880. private void Draw3DControls()
  881. {
  882. using (new EditorGUILayout.HorizontalScope())
  883. {
  884. if (GUILayout.Button("Reset Camera", GUILayout.Width(100)))
  885. {
  886. cameraRotation = new Vector3(15f, -30f, 0f);
  887. cameraDistance = 3f;
  888. UpdateCameraPositions();
  889. }
  890. GUILayout.Space(8);
  891. if (GUILayout.Button("Focus on Differences", GUILayout.Width(150)))
  892. {
  893. // Focus camera on differences
  894. Debug.Log("Focusing on differences");
  895. }
  896. GUILayout.FlexibleSpace();
  897. EditorGUILayout.LabelField("Wireframe:", GUILayout.Width(70));
  898. var showWireframe = EditorGUILayout.Toggle(false, GUILayout.Width(20));
  899. }
  900. EditorGUILayout.Space(4);
  901. // Camera controls
  902. using (new EditorGUILayout.HorizontalScope())
  903. {
  904. EditorGUILayout.LabelField("Camera:", GUILayout.Width(60));
  905. cameraDistance = EditorGUILayout.Slider("Distance", cameraDistance, 1f, 10f);
  906. var newRotationY = EditorGUILayout.Slider("Rotation", cameraRotation.y, -180f, 180f);
  907. if (Math.Abs(newRotationY - cameraRotation.y) > 0.1f)
  908. {
  909. cameraRotation.y = newRotationY;
  910. UpdateCameraPositions();
  911. }
  912. }
  913. }
  914. private void DrawPropertiesComparison(MockConflictInfo conflict)
  915. {
  916. EditorGUILayout.LabelField("Property-by-Property Comparison", EditorStyles.boldLabel);
  917. EditorGUILayout.Space(8);
  918. // Search bar
  919. using (new EditorGUILayout.HorizontalScope())
  920. {
  921. EditorGUILayout.LabelField("Search:", GUILayout.Width(50));
  922. searchText = EditorGUILayout.TextField(searchText);
  923. if (GUILayout.Button("Clear", GUILayout.Width(50)))
  924. searchText = "";
  925. }
  926. EditorGUILayout.Space(4);
  927. using (var scrollView = new EditorGUILayout.ScrollViewScope(viewerScrollPosition, GUILayout.Height(300)))
  928. {
  929. viewerScrollPosition = scrollView.scrollPosition;
  930. var properties = currentPropertyDifferences;
  931. if (!string.IsNullOrEmpty(searchText))
  932. {
  933. properties = properties.Where(p => p.propertyName.ToLower().Contains(searchText.ToLower())).ToList();
  934. }
  935. foreach (var prop in properties)
  936. {
  937. DrawPropertyDifference(prop);
  938. EditorGUILayout.Space(4);
  939. }
  940. if (properties.Count == 0)
  941. {
  942. EditorGUILayout.LabelField("No properties found", EditorStyles.centeredGreyMiniLabel);
  943. }
  944. }
  945. }
  946. private void DrawPropertyDifference(PropertyDifference prop)
  947. {
  948. var propRect = EditorGUILayout.BeginHorizontal();
  949. // Background color based on change type
  950. Color bgColor = prop.changeType switch
  951. {
  952. PropertyChangeType.Added => new Color(0.2f, 0.6f, 0.2f, 0.3f),
  953. PropertyChangeType.Removed => new Color(0.6f, 0.2f, 0.2f, 0.3f),
  954. PropertyChangeType.Modified => new Color(0.6f, 0.4f, 0.2f, 0.3f),
  955. _ => Color.clear
  956. };
  957. if (bgColor != Color.clear)
  958. {
  959. EditorGUI.DrawRect(propRect, bgColor);
  960. }
  961. GUILayout.Space(8);
  962. // Property name
  963. var nameStyle = new GUIStyle(EditorStyles.boldLabel);
  964. nameStyle.normal.textColor = Color.white;
  965. nameStyle.fontSize = 11;
  966. EditorGUILayout.LabelField(prop.propertyName, nameStyle, GUILayout.Width(200));
  967. // Change type icon
  968. var changeIcon = prop.changeType switch
  969. {
  970. PropertyChangeType.Added => "+",
  971. PropertyChangeType.Removed => "-",
  972. PropertyChangeType.Modified => "⟳",
  973. _ => "?"
  974. };
  975. var iconStyle = new GUIStyle(EditorStyles.label);
  976. iconStyle.normal.textColor = prop.changeType switch
  977. {
  978. PropertyChangeType.Added => Color.green,
  979. PropertyChangeType.Removed => Color.red,
  980. PropertyChangeType.Modified => Color.yellow,
  981. _ => Color.white
  982. };
  983. EditorGUILayout.LabelField(changeIcon, iconStyle, GUILayout.Width(20));
  984. // Values comparison
  985. using (new EditorGUILayout.VerticalScope())
  986. {
  987. if (!string.IsNullOrEmpty(prop.localValue))
  988. {
  989. var localStyle = new GUIStyle(EditorStyles.label);
  990. localStyle.normal.textColor = localColor;
  991. localStyle.fontSize = 10;
  992. EditorGUILayout.LabelField($"Local: {prop.localValue}", localStyle);
  993. }
  994. if (!string.IsNullOrEmpty(prop.remoteValue))
  995. {
  996. var remoteStyle = new GUIStyle(EditorStyles.label);
  997. remoteStyle.normal.textColor = remoteColor;
  998. remoteStyle.fontSize = 10;
  999. EditorGUILayout.LabelField($"Remote: {prop.remoteValue}", remoteStyle);
  1000. }
  1001. }
  1002. GUILayout.FlexibleSpace();
  1003. // Individual resolution choice
  1004. if (prop.changeType == PropertyChangeType.Modified)
  1005. {
  1006. using (new EditorGUILayout.VerticalScope(GUILayout.Width(100)))
  1007. {
  1008. var localSelected = prop.resolution == ConflictResolution.UseLocal;
  1009. var remoteSelected = prop.resolution == ConflictResolution.UseRemote;
  1010. var localStyle = new GUIStyle(GUI.skin.button);
  1011. if (localSelected) localStyle.normal.background = CreateRoundedTexture(localColor, 18, 4);
  1012. if (GUILayout.Button("Use Local", localStyle, GUILayout.Height(18)))
  1013. {
  1014. prop.resolution = ConflictResolution.UseLocal;
  1015. Debug.Log($"Using local value for {prop.propertyName}");
  1016. }
  1017. var remoteStyle = new GUIStyle(GUI.skin.button);
  1018. if (remoteSelected) remoteStyle.normal.background = CreateRoundedTexture(remoteColor, 18, 4);
  1019. if (GUILayout.Button("Use Remote", remoteStyle, GUILayout.Height(18)))
  1020. {
  1021. prop.resolution = ConflictResolution.UseRemote;
  1022. Debug.Log($"Using remote value for {prop.propertyName}");
  1023. }
  1024. }
  1025. }
  1026. GUILayout.Space(8);
  1027. EditorGUILayout.EndHorizontal();
  1028. }
  1029. private void DrawOverlayComparison(MockConflictInfo conflict)
  1030. {
  1031. if (conflict.assetType == ConflictAssetType.Texture)
  1032. {
  1033. DrawTextureOverlay(conflict);
  1034. }
  1035. else if (conflict.assetType == ConflictAssetType.Material)
  1036. {
  1037. DrawMaterialOverlay(conflict);
  1038. }
  1039. else
  1040. {
  1041. EditorGUILayout.HelpBox("Overlay comparison is only available for Textures and Materials.", MessageType.Info);
  1042. DrawSideBySideComparison(conflict);
  1043. }
  1044. }
  1045. private void DrawTextureOverlay(MockConflictInfo conflict)
  1046. {
  1047. EditorGUILayout.LabelField("Texture Overlay Comparison", EditorStyles.boldLabel);
  1048. EditorGUILayout.Space(8);
  1049. var overlayRect = GUILayoutUtility.GetRect(400, 300);
  1050. EditorGUI.DrawRect(overlayRect, new Color(0.1f, 0.1f, 0.1f));
  1051. // Mock overlay - checkerboard showing differences
  1052. for (int x = 0; x < 40; x++)
  1053. {
  1054. for (int y = 0; y < 30; y++)
  1055. {
  1056. var isLocalPixel = (x + y) % 3 == 0;
  1057. var isDifferent = (x + y) % 7 == 0;
  1058. Color pixelColor;
  1059. if (isDifferent)
  1060. {
  1061. pixelColor = conflictColor; // Show differences
  1062. }
  1063. else if (isLocalPixel)
  1064. {
  1065. pixelColor = new Color(0.8f, 0.2f, 0.2f, 0.7f); // Local
  1066. }
  1067. else
  1068. {
  1069. pixelColor = new Color(0.2f, 0.2f, 0.8f, 0.7f); // Remote
  1070. }
  1071. var pixelRect = new Rect(overlayRect.x + x * 10, overlayRect.y + y * 10, 10, 10);
  1072. EditorGUI.DrawRect(pixelRect, pixelColor);
  1073. }
  1074. }
  1075. // Overlay controls
  1076. EditorGUILayout.Space(8);
  1077. using (new EditorGUILayout.HorizontalScope())
  1078. {
  1079. EditorGUILayout.LabelField("Blend Mode:", GUILayout.Width(80));
  1080. var blendMode = EditorGUILayout.Popup(0, new[] { "Normal", "Difference", "Overlay" }, GUILayout.Width(100));
  1081. GUILayout.Space(16);
  1082. EditorGUILayout.LabelField("Opacity:", GUILayout.Width(60));
  1083. var opacity = EditorGUILayout.Slider(0.5f, 0f, 1f, GUILayout.Width(100));
  1084. }
  1085. }
  1086. private void DrawMaterialOverlay(MockConflictInfo conflict)
  1087. {
  1088. EditorGUILayout.LabelField("Material Property Overlay", EditorStyles.boldLabel);
  1089. EditorGUILayout.Space(8);
  1090. // Side-by-side material spheres with difference highlighting
  1091. using (new EditorGUILayout.HorizontalScope())
  1092. {
  1093. // Local material sphere
  1094. var leftRect = GUILayoutUtility.GetRect(150, 150);
  1095. EditorGUI.DrawRect(leftRect, new Color(0.1f, 0.1f, 0.1f));
  1096. var leftSphere = new Rect(leftRect.x + 25, leftRect.y + 25, 100, 100);
  1097. EditorGUI.DrawRect(leftSphere, new Color(0.8f, 0.2f, 0.2f));
  1098. GUILayout.Space(16);
  1099. // Remote material sphere
  1100. var rightRect = GUILayoutUtility.GetRect(150, 150);
  1101. EditorGUI.DrawRect(rightRect, new Color(0.1f, 0.1f, 0.1f));
  1102. var rightSphere = new Rect(rightRect.x + 25, rightRect.y + 25, 100, 100);
  1103. EditorGUI.DrawRect(rightSphere, new Color(0.2f, 0.2f, 0.8f));
  1104. }
  1105. // Property differences highlight
  1106. EditorGUILayout.Space(8);
  1107. EditorGUILayout.LabelField("Differences:", EditorStyles.boldLabel);
  1108. DrawPropertyDifference(new PropertyDifference
  1109. {
  1110. propertyName = "Albedo Color",
  1111. localValue = "Red (1,0,0)",
  1112. remoteValue = "Blue (0,0,1)",
  1113. changeType = PropertyChangeType.Modified
  1114. });
  1115. }
  1116. private void DrawSplitter()
  1117. {
  1118. var splitterRect = GUILayoutUtility.GetRect(4, 400);
  1119. EditorGUI.DrawRect(splitterRect, new Color(0.5f, 0.5f, 0.5f, 0.5f));
  1120. EditorGUIUtility.AddCursorRect(splitterRect, MouseCursor.ResizeHorizontal);
  1121. if (Event.current.type == EventType.MouseDown && splitterRect.Contains(Event.current.mousePosition))
  1122. {
  1123. isDraggingSplitter = true;
  1124. Event.current.Use();
  1125. }
  1126. if (isDraggingSplitter)
  1127. {
  1128. if (Event.current.type == EventType.MouseDrag)
  1129. {
  1130. splitRatio = Mathf.Clamp(Event.current.mousePosition.x / position.width, 0.2f, 0.8f);
  1131. Event.current.Use();
  1132. Repaint();
  1133. }
  1134. else if (Event.current.type == EventType.MouseUp)
  1135. {
  1136. isDraggingSplitter = false;
  1137. Event.current.Use();
  1138. }
  1139. }
  1140. }
  1141. private void DrawResolutionControls(MockConflictInfo conflict)
  1142. {
  1143. using (new EditorGUILayout.HorizontalScope())
  1144. {
  1145. GUILayout.FlexibleSpace();
  1146. var localButtonStyle = new GUIStyle(GUI.skin.button);
  1147. localButtonStyle.normal.textColor = Color.white;
  1148. localButtonStyle.fixedHeight = 32;
  1149. localButtonStyle.fontSize = 12;
  1150. localButtonStyle.fontStyle = FontStyle.Bold;
  1151. if (conflict.resolution == ConflictResolution.UseLocal)
  1152. {
  1153. localButtonStyle.normal.background = CreateRoundedTexture(localColor, 32, 4);
  1154. }
  1155. if (GUILayout.Button("◀ USE LOCAL", localButtonStyle, GUILayout.Width(120)))
  1156. {
  1157. SetConflictResolution(selectedConflictIndex, ConflictResolution.UseLocal);
  1158. }
  1159. GUILayout.Space(8);
  1160. var remoteButtonStyle = new GUIStyle(GUI.skin.button);
  1161. remoteButtonStyle.normal.textColor = Color.white;
  1162. remoteButtonStyle.fixedHeight = 32;
  1163. remoteButtonStyle.fontSize = 12;
  1164. remoteButtonStyle.fontStyle = FontStyle.Bold;
  1165. if (conflict.resolution == ConflictResolution.UseRemote)
  1166. {
  1167. remoteButtonStyle.normal.background = CreateRoundedTexture(remoteColor, 32, 4);
  1168. }
  1169. if (GUILayout.Button("USE REMOTE ▶", remoteButtonStyle, GUILayout.Width(120)))
  1170. {
  1171. SetConflictResolution(selectedConflictIndex, ConflictResolution.UseRemote);
  1172. }
  1173. GUILayout.FlexibleSpace();
  1174. }
  1175. }
  1176. #endregion
  1177. #region Helper Methods
  1178. private void DrawCard(System.Action content, int padding = 12)
  1179. {
  1180. var rect = EditorGUILayout.BeginVertical();
  1181. EditorGUI.DrawRect(rect, cardColor);
  1182. GUILayout.Space(padding);
  1183. EditorGUILayout.BeginHorizontal();
  1184. GUILayout.Space(padding);
  1185. EditorGUILayout.BeginVertical();
  1186. content?.Invoke();
  1187. EditorGUILayout.EndVertical();
  1188. GUILayout.Space(padding);
  1189. EditorGUILayout.EndHorizontal();
  1190. GUILayout.Space(padding);
  1191. EditorGUILayout.EndVertical();
  1192. }
  1193. private void DrawSectionHeader(string title, string subtitle = "", Color? color = null)
  1194. {
  1195. var headerStyle = new GUIStyle(EditorStyles.boldLabel);
  1196. headerStyle.fontSize = 13;
  1197. headerStyle.normal.textColor = color ?? Color.white;
  1198. EditorGUILayout.LabelField(title, headerStyle);
  1199. if (!string.IsNullOrEmpty(subtitle))
  1200. {
  1201. var subtitleStyle = new GUIStyle(EditorStyles.label);
  1202. subtitleStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f);
  1203. subtitleStyle.fontSize = 10;
  1204. EditorGUILayout.LabelField(subtitle, subtitleStyle);
  1205. }
  1206. }
  1207. private Texture2D CreateRoundedTexture(Color color, int size = 64, int cornerRadius = 8)
  1208. {
  1209. var key = $"{color}_{size}_{cornerRadius}";
  1210. if (textureCache.TryGetValue(key, out var cachedTexture) && cachedTexture != null)
  1211. return cachedTexture;
  1212. var texture = new Texture2D(size, size);
  1213. var pixels = new Color[size * size];
  1214. for (int y = 0; y < size; y++)
  1215. {
  1216. for (int x = 0; x < size; x++)
  1217. {
  1218. float distanceToCorner = float.MaxValue;
  1219. if (x < cornerRadius && y < cornerRadius)
  1220. distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(cornerRadius, cornerRadius));
  1221. else if (x >= size - cornerRadius && y < cornerRadius)
  1222. distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(size - cornerRadius - 1, cornerRadius));
  1223. else if (x < cornerRadius && y >= size - cornerRadius)
  1224. distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(cornerRadius, size - cornerRadius - 1));
  1225. else if (x >= size - cornerRadius && y >= size - cornerRadius)
  1226. distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(size - cornerRadius - 1, size - cornerRadius - 1));
  1227. pixels[y * size + x] = (distanceToCorner <= cornerRadius ||
  1228. (x >= cornerRadius && x < size - cornerRadius) ||
  1229. (y >= cornerRadius && y < size - cornerRadius)) ? color : Color.clear;
  1230. }
  1231. }
  1232. texture.SetPixels(pixels);
  1233. texture.Apply();
  1234. textureCache[key] = texture;
  1235. return texture;
  1236. }
  1237. private Color GetAssetTypeColor(ConflictAssetType assetType)
  1238. {
  1239. return assetType switch
  1240. {
  1241. ConflictAssetType.Script => new Color(0.2f, 0.6f, 0.9f),
  1242. ConflictAssetType.Prefab => new Color(0.3f, 0.7f, 0.9f),
  1243. ConflictAssetType.Material => new Color(0.8f, 0.4f, 0.8f),
  1244. ConflictAssetType.Scene => new Color(0.9f, 0.3f, 0.3f),
  1245. ConflictAssetType.Texture => new Color(0.3f, 0.8f, 0.3f),
  1246. ConflictAssetType.ScriptableObject => new Color(0.9f, 0.7f, 0.2f),
  1247. ConflictAssetType.Animation => new Color(1f, 0.6f, 0.2f),
  1248. _ => new Color(0.6f, 0.6f, 0.6f)
  1249. };
  1250. }
  1251. private string GetAssetTypeIcon(ConflictAssetType assetType)
  1252. {
  1253. return assetType switch
  1254. {
  1255. ConflictAssetType.Script => "C#",
  1256. ConflictAssetType.Prefab => "PF",
  1257. ConflictAssetType.Material => "MT",
  1258. ConflictAssetType.Scene => "SC",
  1259. ConflictAssetType.Texture => "TX",
  1260. ConflictAssetType.ScriptableObject => "SO",
  1261. ConflictAssetType.Animation => "AN",
  1262. _ => "??"
  1263. };
  1264. }
  1265. private void SelectConflict(int index)
  1266. {
  1267. selectedConflictIndex = index;
  1268. GenerateCurrentPropertyDifferences();
  1269. RefreshPreviewObjects();
  1270. Repaint();
  1271. }
  1272. private void SetConflictResolution(int conflictIndex, ConflictResolution resolution)
  1273. {
  1274. try
  1275. {
  1276. if (conflictIndex >= 0 && conflictIndex < mockConflicts.Count)
  1277. {
  1278. mockConflicts[conflictIndex].resolution = resolution;
  1279. Debug.Log($"Set resolution for {mockConflicts[conflictIndex].fileName}: {resolution}");
  1280. Repaint();
  1281. }
  1282. else
  1283. {
  1284. Debug.LogError($"Invalid conflict index: {conflictIndex}");
  1285. }
  1286. }
  1287. catch (Exception ex)
  1288. {
  1289. Debug.LogError($"Error setting conflict resolution: {ex.Message}");
  1290. }
  1291. }
  1292. private void GenerateCurrentPropertyDifferences()
  1293. {
  1294. currentPropertyDifferences.Clear();
  1295. if (selectedConflictIndex >= 0 && selectedConflictIndex < mockConflicts.Count)
  1296. {
  1297. var conflict = mockConflicts[selectedConflictIndex];
  1298. currentPropertyDifferences.AddRange(GeneratePropertyDifferences(conflict));
  1299. }
  1300. }
  1301. private List<PropertyDifference> GeneratePropertyDifferences(MockConflictInfo conflict)
  1302. {
  1303. return conflict.assetType switch
  1304. {
  1305. ConflictAssetType.Material => GenerateMaterialProperties(),
  1306. ConflictAssetType.Prefab => GeneratePrefabProperties(),
  1307. ConflictAssetType.Texture => GenerateTextureProperties(),
  1308. ConflictAssetType.Scene => GenerateSceneProperties(),
  1309. ConflictAssetType.Script => GenerateScriptProperties(),
  1310. _ => GenerateGenericProperties()
  1311. };
  1312. }
  1313. private List<PropertyDifference> GenerateMaterialProperties()
  1314. {
  1315. return new List<PropertyDifference>
  1316. {
  1317. new PropertyDifference
  1318. {
  1319. propertyName = "Albedo Color",
  1320. localValue = "Red (1.0, 0.0, 0.0, 1.0)",
  1321. remoteValue = "Blue (0.0, 0.0, 1.0, 1.0)",
  1322. changeType = PropertyChangeType.Modified
  1323. },
  1324. new PropertyDifference
  1325. {
  1326. propertyName = "Metallic",
  1327. localValue = "0.5",
  1328. remoteValue = "0.2",
  1329. changeType = PropertyChangeType.Modified
  1330. },
  1331. new PropertyDifference
  1332. {
  1333. propertyName = "Smoothness",
  1334. localValue = "0.8",
  1335. remoteValue = "0.6",
  1336. changeType = PropertyChangeType.Modified
  1337. },
  1338. new PropertyDifference
  1339. {
  1340. propertyName = "Emission",
  1341. localValue = "",
  1342. remoteValue = "Enabled",
  1343. changeType = PropertyChangeType.Added
  1344. }
  1345. };
  1346. }
  1347. private List<PropertyDifference> GeneratePrefabProperties()
  1348. {
  1349. return new List<PropertyDifference>
  1350. {
  1351. new PropertyDifference
  1352. {
  1353. propertyName = "Transform.Scale",
  1354. localValue = "(1.0, 1.0, 1.0)",
  1355. remoteValue = "(1.2, 1.2, 1.2)",
  1356. changeType = PropertyChangeType.Modified
  1357. },
  1358. new PropertyDifference
  1359. {
  1360. propertyName = "BoxCollider.Size",
  1361. localValue = "(1.0, 1.0, 1.0)",
  1362. remoteValue = "(1.1, 1.1, 1.1)",
  1363. changeType = PropertyChangeType.Modified
  1364. },
  1365. new PropertyDifference
  1366. {
  1367. propertyName = "AudioSource",
  1368. localValue = "",
  1369. remoteValue = "Component Added",
  1370. changeType = PropertyChangeType.Added
  1371. },
  1372. new PropertyDifference
  1373. {
  1374. propertyName = "ParticleSystem",
  1375. localValue = "",
  1376. remoteValue = "Component Added",
  1377. changeType = PropertyChangeType.Added
  1378. }
  1379. };
  1380. }
  1381. private List<PropertyDifference> GenerateTextureProperties()
  1382. {
  1383. return new List<PropertyDifference>
  1384. {
  1385. new PropertyDifference
  1386. {
  1387. propertyName = "Texture Size",
  1388. localValue = "512x512",
  1389. remoteValue = "1024x1024",
  1390. changeType = PropertyChangeType.Modified
  1391. },
  1392. new PropertyDifference
  1393. {
  1394. propertyName = "Format",
  1395. localValue = "RGB24",
  1396. remoteValue = "RGBA32",
  1397. changeType = PropertyChangeType.Modified
  1398. },
  1399. new PropertyDifference
  1400. {
  1401. propertyName = "Filter Mode",
  1402. localValue = "Bilinear",
  1403. remoteValue = "Trilinear",
  1404. changeType = PropertyChangeType.Modified
  1405. }
  1406. };
  1407. }
  1408. private List<PropertyDifference> GenerateSceneProperties()
  1409. {
  1410. return new List<PropertyDifference>
  1411. {
  1412. new PropertyDifference
  1413. {
  1414. propertyName = "Camera Position",
  1415. localValue = "(0, 10, 0)",
  1416. remoteValue = "(5, 10, -5)",
  1417. changeType = PropertyChangeType.Modified
  1418. },
  1419. new PropertyDifference
  1420. {
  1421. propertyName = "Lighting Mode",
  1422. localValue = "Realtime GI",
  1423. remoteValue = "Baked GI",
  1424. changeType = PropertyChangeType.Modified
  1425. },
  1426. new PropertyDifference
  1427. {
  1428. propertyName = "Skybox",
  1429. localValue = "Default",
  1430. remoteValue = "Procedural",
  1431. changeType = PropertyChangeType.Modified
  1432. },
  1433. new PropertyDifference
  1434. {
  1435. propertyName = "Fog",
  1436. localValue = "",
  1437. remoteValue = "Enabled",
  1438. changeType = PropertyChangeType.Added
  1439. }
  1440. };
  1441. }
  1442. private List<PropertyDifference> GenerateScriptProperties()
  1443. {
  1444. return new List<PropertyDifference>
  1445. {
  1446. new PropertyDifference
  1447. {
  1448. propertyName = "speed variable",
  1449. localValue = "5.0f",
  1450. remoteValue = "7.0f",
  1451. changeType = PropertyChangeType.Modified
  1452. },
  1453. new PropertyDifference
  1454. {
  1455. propertyName = "Move() method",
  1456. localValue = "transform.Translate()",
  1457. remoteValue = "rb.velocity =",
  1458. changeType = PropertyChangeType.Modified
  1459. }
  1460. };
  1461. }
  1462. private List<PropertyDifference> GenerateGenericProperties()
  1463. {
  1464. return new List<PropertyDifference>
  1465. {
  1466. new PropertyDifference
  1467. {
  1468. propertyName = "Generic Property",
  1469. localValue = "Local Value",
  1470. remoteValue = "Remote Value",
  1471. changeType = PropertyChangeType.Modified
  1472. }
  1473. };
  1474. }
  1475. private void HandleEvents()
  1476. {
  1477. if (Event.current.type == EventType.Repaint)
  1478. {
  1479. // Handle any repaint-related operations
  1480. if (selectedViewMode == 1 && previewCameraLeft != null && previewCameraRight != null)
  1481. {
  1482. // Render 3D previews if needed
  1483. previewCameraLeft.Render();
  1484. previewCameraRight.Render();
  1485. }
  1486. }
  1487. }
  1488. private void ApplyResolutions()
  1489. {
  1490. try
  1491. {
  1492. Debug.Log("Applying conflict resolutions:");
  1493. foreach (var conflict in mockConflicts)
  1494. {
  1495. Debug.Log($" {conflict.fileName}: {conflict.resolution}");
  1496. }
  1497. EditorUtility.DisplayDialog("Resolutions Applied",
  1498. "All conflicts have been resolved. Pull operation will now continue.",
  1499. "OK");
  1500. // Call the callback to notify the main window that conflicts are resolved
  1501. var callback = onConflictsResolved;
  1502. onConflictsResolved = null; // Clear the callback first to prevent issues
  1503. callback?.Invoke();
  1504. Close();
  1505. }
  1506. catch (Exception ex)
  1507. {
  1508. Debug.LogError($"Error applying resolutions: {ex.Message}");
  1509. EditorUtility.DisplayDialog("Error",
  1510. $"Failed to apply resolutions: {ex.Message}",
  1511. "OK");
  1512. }
  1513. }
  1514. private void DrawFallbackUI()
  1515. {
  1516. EditorGUILayout.LabelField("Visual Conflict Resolver - Error State", EditorStyles.boldLabel);
  1517. if (GUILayout.Button("Restart"))
  1518. {
  1519. Close();
  1520. ShowWindow();
  1521. }
  1522. }
  1523. #endregion
  1524. #region Data Models
  1525. [Serializable]
  1526. public class MockConflictInfo
  1527. {
  1528. public string fileName;
  1529. public ConflictAssetType assetType;
  1530. public ConflictType conflictType;
  1531. public string description;
  1532. public string localVersion;
  1533. public string remoteVersion;
  1534. public ConflictResolution resolution;
  1535. }
  1536. [Serializable]
  1537. public class PropertyDifference
  1538. {
  1539. public string propertyName;
  1540. public string localValue;
  1541. public string remoteValue;
  1542. public PropertyChangeType changeType;
  1543. public ConflictResolution resolution = ConflictResolution.Unresolved;
  1544. }
  1545. public enum PropertyChangeType
  1546. {
  1547. Added,
  1548. Removed,
  1549. Modified
  1550. }
  1551. public enum ConflictAssetType
  1552. {
  1553. Script,
  1554. Prefab,
  1555. Material,
  1556. Scene,
  1557. Texture,
  1558. ScriptableObject,
  1559. Animation,
  1560. Audio,
  1561. Model,
  1562. Unknown
  1563. }
  1564. public enum ConflictType
  1565. {
  1566. PropertyValueDifference,
  1567. PropertyAdded,
  1568. PropertyRemoved,
  1569. ComponentAdded,
  1570. ComponentRemoved,
  1571. ComponentPropertyChanged,
  1572. ChildObjectAdded,
  1573. ChildObjectRemoved,
  1574. ChildObjectReordered,
  1575. GameObjectMoved,
  1576. GameObjectRenamed,
  1577. SceneSettingsChanged,
  1578. AssetReplaced,
  1579. AssetMetadataChanged
  1580. }
  1581. public enum ConflictResolution
  1582. {
  1583. Unresolved,
  1584. UseLocal,
  1585. UseRemote,
  1586. Manual,
  1587. Merged
  1588. }
  1589. public abstract class ConflictViewer
  1590. {
  1591. public abstract bool CanHandle(ConflictAssetType assetType);
  1592. public abstract void DrawConflictView(Rect area, MockConflictInfo conflict);
  1593. public abstract ConflictResolution GetUserChoice();
  1594. }
  1595. #endregion
  1596. }
  1597. }