浏览代码

Merge branch 'main' into pr-bash

/main
Ciro Continisio 4 年前
当前提交
2a0d8691
共有 23 个文件被更改,包括 1087 次插入4 次删除
  1. 12
      UOP1_Project/Assets/Scripts/Editor/ReplaceTool.cs
  2. 8
      UOP1_Project/Assets/ScriptableObjects/SceneData/Resources.meta
  3. 113
      UOP1_Project/Assets/Scripts/Editor/GameObjectPreview.cs
  4. 3
      UOP1_Project/Assets/Scripts/Editor/GameObjectPreview.cs.meta
  5. 267
      UOP1_Project/Assets/Scripts/Editor/PrefabSelectionTreeView.cs
  6. 11
      UOP1_Project/Assets/Scripts/Editor/PrefabSelectionTreeView.cs.meta
  7. 69
      UOP1_Project/Assets/Scripts/Editor/ReplaceContextMenu.cs
  8. 3
      UOP1_Project/Assets/Scripts/Editor/ReplaceContextMenu.cs.meta
  9. 190
      UOP1_Project/Assets/Scripts/Editor/ReplacePrefabSearchPopup.cs
  10. 3
      UOP1_Project/Assets/Scripts/Editor/ReplacePrefabSearchPopup.cs.meta
  11. 38
      UOP1_Project/Assets/Scripts/Editor/ScriptableObjectHelper.cs
  12. 11
      UOP1_Project/Assets/Scripts/Editor/ScriptableObjectHelper.cs.meta
  13. 217
      UOP1_Project/Assets/Scripts/EditorTools/SceneAccessTool.cs
  14. 11
      UOP1_Project/Assets/Scripts/EditorTools/SceneAccessTool.cs.meta
  15. 8
      UOP1_Project/Assets/Scripts/Input/Editor.meta
  16. 51
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs
  17. 11
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs.meta
  18. 30
      UOP1_Project/Assets/ScriptableObjects/SceneData/Resources/SceneAccessHolder.asset
  19. 8
      UOP1_Project/Assets/ScriptableObjects/SceneData/Resources/SceneAccessHolder.asset.meta
  20. 16
      UOP1_Project/Assets/Scripts/Input/Editor/InputReaderEditor.cs
  21. 11
      UOP1_Project/Assets/Scripts/Input/Editor/InputReaderEditor.cs.meta

12
UOP1_Project/Assets/Scripts/Editor/ReplaceTool.cs


/// </summary>
/// <param name="objectToReplace">Game Objects to replace.</param>
/// <param name="replaceObject">Prefab that will be instantiated in place of the objects to replace.</param>
private void ReplaceSelectedObjects(GameObject[] objectToReplace, GameObject replaceObject)
internal static void ReplaceSelectedObjects(GameObject[] objectToReplace, GameObject replaceObject)
Debug.Log("[Replace Tool] Replace process");
//Debug.Log("[Replace Tool] Replace process");
var inst = Instantiate(replaceObject, go.transform.position, go.transform.rotation, go.transform.parent);
var inst = (GameObject)PrefabUtility.InstantiatePrefab(replaceObject);
inst.transform.position = go.transform.position;
inst.transform.rotation = go.transform.rotation;
inst.transform.parent = go.transform.parent;
inst.transform.localScale = go.transform.localScale;
Undo.RegisterCreatedObjectUndo(inst, "Replacement creation.");
foreach (Transform child in go.transform)

Undo.DestroyObjectImmediate(go);
}
Debug.LogFormat("[Replace Tool] {0} objects replaced on scene with {1}", objectToReplace.Length, replaceObject.name);
//Debug.LogFormat("[Replace Tool] {0} objects replaced on scene with {1}", objectToReplace.Length, replaceObject.name);
}
}

8
UOP1_Project/Assets/ScriptableObjects/SceneData/Resources.meta


fileFormatVersion: 2
guid: dd754fdc4b0731f4f9633351d8dcd5f3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

113
UOP1_Project/Assets/Scripts/Editor/GameObjectPreview.cs


using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UOP1.EditorTools
{
internal class GameObjectPreview
{
private static Type gameObjectInspectorType;
private static MethodInfo getPreviewDataMethod;
private static FieldInfo renderUtilityField;
private Rect renderRect;
private Color light0Color;
private Color light1Color;
private PreviewRenderUtility renderUtility;
private Editor cachedEditor;
public RenderTexture outputTexture;
[InitializeOnLoadMethod]
private static void OnInitialize()
{
gameObjectInspectorType = typeof(Editor).Assembly.GetType("UnityEditor.GameObjectInspector");
var previewDataType = gameObjectInspectorType.GetNestedType("PreviewData", BindingFlags.NonPublic);
getPreviewDataMethod = gameObjectInspectorType.GetMethod("GetPreviewData", BindingFlags.NonPublic | BindingFlags.Instance);
renderUtilityField = previewDataType.GetField("renderUtility", BindingFlags.Public | BindingFlags.Instance);
}
public void CreatePreviewForTarget(GameObject target)
{
if (!cachedEditor || cachedEditor.target != target)
{
renderUtility = null;
// There is a bug that breaks previews and Prefab mode after creating too many editors.
// Simply using CreateCachedEditor is fixing that problem.
Editor.CreateCachedEditor(target, gameObjectInspectorType, ref cachedEditor);
}
}
public void RenderInteractivePreview(Rect rect)
{
if (!cachedEditor)
return;
if (renderUtility == null || renderUtility.lights[0] == null)
{
var previewData = getPreviewDataMethod.Invoke(cachedEditor, null);
renderUtility = renderUtilityField.GetValue(previewData) as PreviewRenderUtility;
light0Color = renderUtility.lights[0].color;
light1Color = renderUtility.lights[1].color;
}
renderUtility.lights[0].color = light0Color * 1.6f;
renderUtility.lights[1].color = light1Color * 6f;
var backColor = renderUtility.camera.backgroundColor;
renderUtility.camera.backgroundColor = new Color(backColor.r, backColor.g, backColor.b, 0);
renderUtility.camera.clearFlags = CameraClearFlags.Depth;
var color = GUI.color;
// Hide default preview texture, since it has no alpha blending
GUI.color = new Color(1, 1, 1, 0);
cachedEditor.OnPreviewGUI(rect, null);
GUI.color = color;
outputTexture = renderUtility.camera.targetTexture;
}
public void DrawPreviewTexture(Rect rect)
{
GUI.DrawTexture(rect, outputTexture, ScaleMode.ScaleToFit, true, 0);
}
public static bool HasRenderableParts(GameObject go)
{
var renderers = go.GetComponentsInChildren<Renderer>();
foreach (var renderer in renderers)
{
switch (renderer)
{
case MeshRenderer _:
var filter = renderer.gameObject.GetComponent<MeshFilter>();
if (filter && filter.sharedMesh)
return true;
break;
case SkinnedMeshRenderer skinnedMesh:
if (skinnedMesh.sharedMesh)
return true;
break;
case SpriteRenderer sprite:
if (sprite.sprite)
return true;
break;
case BillboardRenderer billboard:
if (billboard.billboard && billboard.sharedMaterial)
return true;
break;
}
}
return false;
}
}
}

3
UOP1_Project/Assets/Scripts/Editor/GameObjectPreview.cs.meta


fileFormatVersion: 2
guid: bb1d562e678248bbb3b897536cf62c50
timeCreated: 1606495882

267
UOP1_Project/Assets/Scripts/Editor/PrefabSelectionTreeView.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UOP1.EditorTools.Replacer
{
internal class PrefabSelectionTreeView : TreeView
{
private static Texture2D prefabOnIcon = EditorGUIUtility.IconContent("Prefab On Icon").image as Texture2D;
private static Texture2D prefabVariantOnIcon = EditorGUIUtility.IconContent("PrefabVariant On Icon").image as Texture2D;
private static Texture2D folderIcon = EditorGUIUtility.IconContent("Folder Icon").image as Texture2D;
private static Texture2D folderOnIcon = EditorGUIUtility.IconContent("Folder On Icon").image as Texture2D;
private static GUIStyle whiteLabel;
private static GUIStyle foldout;
public int RowsCount => rows.Count;
private Event evt => Event.current;
public Action<GameObject> onSelectEntry;
private List<TreeViewItem> rows = new List<TreeViewItem>();
private HashSet<string> paths = new HashSet<string>();
private Dictionary<int, RenderTexture> previewCache = new Dictionary<int, RenderTexture>();
private HashSet<int> renderableItems = new HashSet<int>();
private GameObjectPreview itemPreview = new GameObjectPreview();
private GUIContent itemContent = new GUIContent();
private int selectedId;
public PrefabSelectionTreeView(TreeViewState state) : base(state)
{
foldoutOverride = FoldoutOverride;
Reload();
}
private bool FoldoutOverride(Rect position, bool expandedState, GUIStyle style)
{
position.width = Screen.width;
position.height = 20;
position.y -= 2;
expandedState = GUI.Toggle(position, expandedState, GUIContent.none, style);
return expandedState;
}
public void Cleanup()
{
foreach (var texture in previewCache.Values)
Object.DestroyImmediate(texture);
}
public bool IsRenderable(int id)
{
return renderableItems.Contains(id);
}
private void CachePreview(int itemId)
{
var copy = new RenderTexture(itemPreview.outputTexture);
var previous = RenderTexture.active;
Graphics.Blit(itemPreview.outputTexture, copy);
RenderTexture.active = previous;
previewCache.Add(itemId, copy);
}
protected override bool CanMultiSelect(TreeViewItem item)
{
return false;
}
private bool IsPrefabAsset(int id, out GameObject prefab)
{
var obj = EditorUtility.InstanceIDToObject(id);
if (obj is GameObject go)
{
prefab = go;
return true;
}
prefab = null;
return false;
}
protected override void DoubleClickedItem(int id)
{
if (IsPrefabAsset(id, out var prefab))
onSelectEntry(prefab);
else
SetExpanded(id, !IsExpanded(id));
}
protected override void KeyEvent()
{
var key = evt.keyCode;
if (key == KeyCode.KeypadEnter || key == KeyCode.Return)
DoubleClickedItem(selectedId);
}
protected override void SelectionChanged(IList<int> selectedIds)
{
if (selectedIds.Count > 0)
selectedId = selectedIds[0];
}
protected override TreeViewItem BuildRoot()
{
var root = new TreeViewItem(0, -1);
rows.Clear();
paths.Clear();
foreach (var guid in AssetDatabase.FindAssets("t:Prefab"))
{
var path = AssetDatabase.GUIDToAssetPath(guid);
var splits = path.Split('/');
var depth = splits.Length - 2;
if (splits[0] != "Assets")
break;
var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
AddFoldersItems(splits);
AddPrefabItem(asset, depth);
}
SetupParentsAndChildrenFromDepths(root, rows);
return root;
}
protected override float GetCustomRowHeight(int row, TreeViewItem item)
{
// Hide folders during search
if (!IsPrefabAsset(item.id, out _) && hasSearch)
return 0;
return 20;
}
public override void OnGUI(Rect rect)
{
if (whiteLabel == null)
whiteLabel = new GUIStyle(EditorStyles.label) { normal = { textColor = EditorStyles.whiteLabel.normal.textColor } };
base.OnGUI(rect);
}
protected override void RowGUI(RowGUIArgs args)
{
var rect = args.rowRect;
var item = args.item;
var isRenderable = IsRenderable(item.id);
var isSelected = IsSelected(item.id);
var isFocused = HasFocus() && isSelected;
var isPrefab = IsPrefabAsset(item.id, out var prefab);
var isFolder = !isPrefab;
if (isFolder && hasSearch)
return;
if (isFolder)
{
if (rect.Contains(evt.mousePosition) && evt.type == EventType.MouseUp)
{
SetSelection(new List<int> { item.id });
SetFocus();
}
}
var labelStyle = isFocused ? whiteLabel : EditorStyles.label;
var contentIndent = GetContentIndent(item);
customFoldoutYOffset = 2;
itemContent.text = item.displayName;
rect.x += contentIndent;
rect.width -= contentIndent;
var iconRect = new Rect(rect) { width = 20 };
if (isPrefab)
{
var type = PrefabUtility.GetPrefabAssetType(prefab);
var onIcon = type == PrefabAssetType.Regular ? prefabOnIcon : prefabVariantOnIcon;
var labelRect = new Rect(rect);
if (isRenderable)
{
var previewRect = new Rect(rect) { width = 32, height = 32 };
if (!previewCache.TryGetValue(item.id, out var previewTexture))
{
itemPreview.CreatePreviewForTarget(prefab);
itemPreview.RenderInteractivePreview(previewRect);
if (itemPreview.outputTexture)
CachePreview(item.id);
}
if (!previewTexture)
Repaint();
else
GUI.DrawTexture(iconRect, previewTexture, ScaleMode.ScaleAndCrop);
labelRect.x += iconRect.width;
labelRect.width -= iconRect.width + 24;
GUI.Label(labelRect, args.label, labelStyle);
if (isSelected)
{
var prefabIconRect = new Rect(iconRect) { x = rect.xMax - 24 };
GUI.Label(prefabIconRect, isFocused ? onIcon : item.icon);
}
}
else
{
itemContent.image = isSelected ? onIcon : item.icon;
GUI.Label(rect, itemContent, labelStyle);
}
}
else
{
itemContent.image = isFocused ? folderOnIcon : folderIcon;
GUI.Label(rect, itemContent, labelStyle);
}
}
private void AddFoldersItems(string[] splits)
{
for (int i = 1; i < splits.Length - 1; i++)
{
var split = splits[i];
if (!paths.Contains(split))
{
rows.Add(new TreeViewItem(split.GetHashCode(), i - 1, " " + split) { icon = folderIcon });
paths.Add(split);
}
}
}
private void AddPrefabItem(GameObject asset, int depth)
{
var id = asset.GetInstanceID();
var content = new GUIContent(EditorGUIUtility.ObjectContent(asset, asset.GetType()));
if (GameObjectPreview.HasRenderableParts(asset))
renderableItems.Add(id);
rows.Add(new TreeViewItem(id, depth, content.text)
{
icon = content.image as Texture2D
});
}
}
}

11
UOP1_Project/Assets/Scripts/Editor/PrefabSelectionTreeView.cs.meta


fileFormatVersion: 2
guid: 241edd7da6766964687c5bf319a6163f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

69
UOP1_Project/Assets/Scripts/Editor/ReplaceContextMenu.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace UOP1.EditorTools.Replacer
{
internal class ReplaceContextMenu
{
private static Type hierarchyType;
private static EditorWindow focusedWindow;
private static IMGUIContainer hierarchyGUI;
private static Vector2 mousePosition;
private static bool hasExecuted;
[InitializeOnLoadMethod]
private static void OnInitialize()
{
hierarchyType = typeof(Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
EditorApplication.update += TrackFocusedHierarchy;
}
private static void TrackFocusedHierarchy()
{
if (focusedWindow != EditorWindow.focusedWindow)
{
focusedWindow = EditorWindow.focusedWindow;
if (focusedWindow?.GetType() == hierarchyType)
{
if (hierarchyGUI != null)
hierarchyGUI.onGUIHandler -= OnFocusedHierarchyGUI;
hierarchyGUI = focusedWindow.rootVisualElement.parent.Query<IMGUIContainer>();
hierarchyGUI.onGUIHandler += OnFocusedHierarchyGUI;
}
}
}
private static void OnFocusedHierarchyGUI()
{
// As Event.current is null during context-menu callback, we need to track mouse position on hierarchy GUI
mousePosition = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
}
[MenuItem("GameObject/Replace", true, priority = 0)]
private static bool ReplaceSelectionValidate()
{
return Selection.gameObjects.Length > 0;
}
[MenuItem("GameObject/Replace", priority = 0)]
private static void ReplaceSelection()
{
if (hasExecuted)
return;
var rect = new Rect(mousePosition, new Vector2(240, 360));
ReplacePrefabSearchPopup.Show(rect);
EditorApplication.delayCall += () => hasExecuted = false;
}
}
}

3
UOP1_Project/Assets/Scripts/Editor/ReplaceContextMenu.cs.meta


fileFormatVersion: 2
guid: a36e948ccc254a1cbffab62792cda09d
timeCreated: 1606469766

190
UOP1_Project/Assets/Scripts/Editor/ReplacePrefabSearchPopup.cs


using System;
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using static UnityEditor.EditorGUIUtility;
using static UnityEditor.EditorJsonUtility;
using static UnityEngine.Application;
namespace UOP1.EditorTools.Replacer
{
internal class ReplacePrefabSearchPopup : EditorWindow
{
private const float previewHeight = 128;
private class ViewState : ScriptableObject
{
public TreeViewState treeViewState = new TreeViewState();
}
private static ReplacePrefabSearchPopup window;
private static Styles styles;
private static Event evt => Event.current;
private static string assetPath => Path.Combine(dataPath.Remove(dataPath.Length - 7, 7), "Library", "ReplacePrefabTreeState.asset");
private bool hasSelection => tree.state.selectedIDs.Count > 0;
private int selectedId => tree.state.selectedIDs[0];
private GameObject instance => EditorUtility.InstanceIDToObject(selectedId) as GameObject;
private SearchField searchField;
private PrefabSelectionTreeView tree;
private ViewState viewState;
private Vector2 startPos;
private Vector2 startSize;
private Vector2 lastSize;
private GameObjectPreview selectionPreview = new GameObjectPreview();
public static void Show(Rect rect)
{
var windows = Resources.FindObjectsOfTypeAll<ReplacePrefabSearchPopup>();
window = windows.Length != 0 ? windows[0] : CreateInstance<ReplacePrefabSearchPopup>();
window.Init();
window.startPos = rect.position;
window.startSize = rect.size;
window.position = new Rect(rect.position, rect.size);
// Need to predict start window size to avoid trash frame
window.SetInitialSize();
// This type of window supports resizing, but is also persistent, so we need to close it manually
window.ShowPopup();
//onSelectEntry += _ => window.Close();
}
private void Init()
{
viewState = CreateInstance<ViewState>();
if (File.Exists(assetPath))
FromJsonOverwrite(File.ReadAllText(assetPath), viewState);
tree = new PrefabSelectionTreeView(viewState.treeViewState);
tree.onSelectEntry += OnSelectEntry;
AssetPreview.SetPreviewTextureCacheSize(tree.RowsCount);
searchField = new SearchField();
searchField.downOrUpArrowKeyPressed += tree.SetFocusAndEnsureSelectedItem;
searchField.SetFocus();
}
private void OnSelectEntry(GameObject prefab)
{
ReplaceTool.ReplaceSelectedObjects(Selection.gameObjects, prefab);
}
private void OnEnable()
{
Init();
}
private void OnDisable()
{
tree.Cleanup();
}
public new void Close()
{
SaveState();
base.Close();
}
private void SaveState()
{
File.WriteAllText(assetPath, ToJson(viewState));
}
private void OnGUI()
{
if (evt.type == EventType.KeyDown && evt.keyCode == KeyCode.Escape)
{
if (tree.hasSearch)
tree.searchString = "";
else
Close();
}
if (focusedWindow != this)
Close();
if (styles == null)
styles = new Styles();
DoToolbar();
DoTreeView();
DoSelectionPreview();
}
void DoToolbar()
{
tree.searchString = searchField.OnToolbarGUI(tree.searchString);
GUILayout.Label("Replace With...", styles.headerLabel);
}
void DoTreeView()
{
var rect = GUILayoutUtility.GetRect(0, 10000, 0, 10000);
rect.x += 2;
rect.width -= 4;
rect.y += 2;
rect.height -= 4;
tree.OnGUI(rect);
}
void DoSelectionPreview()
{
if (hasSelection && tree.IsRenderable(selectedId))
{
SetSize(startSize.x, startSize.y + previewHeight);
var previewRect = GUILayoutUtility.GetRect(position.width, previewHeight);
selectionPreview.CreatePreviewForTarget(instance);
selectionPreview.RenderInteractivePreview(previewRect);
selectionPreview.DrawPreviewTexture(previewRect);
}
else
{
SetSize(startSize.x, startSize.y);
}
}
private void SetInitialSize()
{
if (hasSelection && tree.IsRenderable(selectedId))
SetSize(startSize.x, startSize.y + previewHeight);
else
SetSize(startSize.x, startSize.y);
}
private void SetSize(float width, float height)
{
var newSize = new Vector2(width, height);
if (newSize != lastSize)
{
lastSize = newSize;
position = new Rect(position.x, position.y, width, height);
}
}
private class Styles
{
public GUIStyle headerLabel = new GUIStyle(EditorStyles.centeredGreyMiniLabel)
{
fontSize = 11,
fontStyle = FontStyle.Bold
};
}
}
}

3
UOP1_Project/Assets/Scripts/Editor/ReplacePrefabSearchPopup.cs.meta


fileFormatVersion: 2
guid: 566745c65b224919bb9886aba499be67
timeCreated: 1606459889

38
UOP1_Project/Assets/Scripts/Editor/ScriptableObjectHelper.cs


using System;
using UnityEngine;
public static class ScriptableObjectHelper
{
public static void GenerateButtonsForEvents<T>(UnityEngine.Object target)
where T : ScriptableObject
{
var targetIr = target as T;
if (targetIr != null)
{
var typeIr = targetIr.GetType();
var events = typeIr.GetEvents();
foreach (var ev in events)
{
if (GUILayout.Button(ev.Name))
{
//Delegates doesn't support direct access to RaiseMethod, must use backing field
// https://stackoverflow.com/questions/14885325/eventinfo-getraisemethod-always-null
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/44b0d573-5c53-47b0-8e85-6056cbae95b0/raising-an-event-via-reflection
var eventDelagate = typeIr.GetField(ev.Name, System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic)
?.GetValue(targetIr) as MulticastDelegate;
try
{
eventDelagate?.DynamicInvoke();
}
catch
{
Debug.LogWarning($"Event '{ev.Name}' requires some arguments which weren't provided. Delegate cannot be invoked directly from UI.");
}
}
}
}
}
}

11
UOP1_Project/Assets/Scripts/Editor/ScriptableObjectHelper.cs.meta


fileFormatVersion: 2
guid: 0a7eba3a614f3d74fb12d27b80cd0597
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

217
UOP1_Project/Assets/Scripts/EditorTools/SceneAccessTool.cs


using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEditorInternal;
using UnityEditor.SceneManagement;
using System.Collections.Generic;
using System.Linq;
public class SceneAccessTool : EditorWindow, IHasCustomMenu
{
private SceneAccessHolderSO _inspected;
private SerializedObject _serializedObject;
private Editor _sceneAccessHolderSOEditor;
public enum Layout { List, Grid }
private Layout _layout;
private bool _showOptions = false;
private bool _editMode = false;
private ReorderableList list;
private void OnEnable()
{
_inspected = Resources.Load<SceneAccessHolderSO>("SceneAccessHolder");
SetUpList();
}
private void SetUpList()
{
_serializedObject = new SerializedObject(_inspected);
if (_editMode)
{
list = new ReorderableList(_serializedObject,
_serializedObject.FindProperty("sceneList"),
true, false, false, false);
list.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = list.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.PropertyField(
new Rect(rect.x, rect.y, rect.width - 30, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("name"), GUIContent.none);
EditorGUI.PropertyField(
new Rect(rect.x + rect.width - 25, rect.y, 25, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("visible"), GUIContent.none);
};
}
}
[MenuItem("Tools/SceneAccessTool")]
public static void ShowWindow()
{
GetWindow<SceneAccessTool>("SceneAccessTool");
}
private void OnGUI()
{
if (_inspected != null)
{
if (_showOptions)
ShowOptions();
ShowSceneList();
}
}
public void ShowOptions()
{
GUILayout.BeginHorizontal();
if (GUILayout.Button("Populate Scene List"))
{
PopulateSceneList();
}
if (GUILayout.Button("Clear List"))
{
ClearSceneList();
}
if (GUILayout.Button("Edit Mode"))
{
ToggleEditMode();
}
GUILayout.EndHorizontal();
}
public void ShowSceneList()
{
if (_editMode)
{
_serializedObject.Update();
list.DoLayoutList();
_serializedObject.ApplyModifiedProperties();
}
else
{
if (_layout == Layout.List)
{
for (int i = 0; i < _inspected.sceneList.Count; i++)
{
var sceneItem = _inspected.sceneList[i];
if (!sceneItem.visible)
{
continue;
}
if (GUILayout.Button(sceneItem.name))
{
EditorSceneManager.OpenScene(sceneItem.path);
}
}
}
else
{
int gridSize = 48;
int widthCount = gridSize;
GUILayout.BeginHorizontal();
for (int i = 0; i < _inspected.sceneList.Count; i++)
{
var sceneItem = _inspected.sceneList[i];
if (!sceneItem.visible)
{
continue;
}
GUIStyle customButton = new GUIStyle("button");
customButton.fontSize = 10;
customButton.alignment = TextAnchor.UpperLeft;
customButton.wordWrap = true;
GUIContent guiContent = new GUIContent(sceneItem.name);
if (GUILayout.Button(
guiContent,
customButton,
GUILayout.Width(gridSize),
GUILayout.Height(gridSize)))
{
EditorSceneManager.OpenScene(sceneItem.path);
}
widthCount += gridSize + 4;
if (widthCount > position.width)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
widthCount = gridSize;
}
}
GUILayout.EndHorizontal();
}
}
}
/// <summary>
/// Find all scenes in the project and put them in the list
/// </summary>
private void PopulateSceneList()
{
EditorBuildSettingsScene[] currentScenes = EditorBuildSettings.scenes;
EditorBuildSettingsScene[] filteredScenes = currentScenes.Where(ebss => File.Exists(ebss.path)).ToArray();
List<SceneAccessHolderSO.SceneInfo> allScene = new List<SceneAccessHolderSO.SceneInfo>();
for (int i = 0; i < filteredScenes.Length; i++)
{
allScene.Add(
new SceneAccessHolderSO.SceneInfo
{
name = Path.GetFileNameWithoutExtension(filteredScenes[i].path),
path = Path.GetFullPath(filteredScenes[i].path),
visible = true
});
}
//add the new scenes
foreach (SceneAccessHolderSO.SceneInfo sceneInfo in allScene)
{
if (!_inspected.sceneList.Contains(sceneInfo))
{
_inspected.sceneList.Add(sceneInfo);
}
}
//remove the deleted scenes
foreach (SceneAccessHolderSO.SceneInfo sceneInfo in _inspected.sceneList.ToList())
{
if (!allScene.Contains(sceneInfo))
{
_inspected.sceneList.Remove(sceneInfo);
}
}
}
private void ClearSceneList()
{
_inspected.sceneList.Clear();
}
public void AddItemsToMenu(GenericMenu menu)
{
menu.AddItem(new GUIContent("ToggleOptions"), false, ToggleOptions);
menu.AddItem(new GUIContent("ToggleLayout"), false, ToggleLayout);
}
private void ToggleOptions()
{
_showOptions = !_showOptions;
}
private void ToggleLayout()
{
if (_layout == Layout.List)
{
_layout = Layout.Grid;
}
else
{
_layout = Layout.List;
}
}
private void ToggleEditMode()
{
_editMode = !_editMode;
SetUpList();
}
}

11
UOP1_Project/Assets/Scripts/EditorTools/SceneAccessTool.cs.meta


fileFormatVersion: 2
guid: c8ba2b93ee72bce49aa87ecc1b52ea6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
UOP1_Project/Assets/Scripts/Input/Editor.meta


fileFormatVersion: 2
guid: 8aed24cb0c323134e96fb92cecbeafc4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

51
UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class ReadOnlyAttribute : PropertyAttribute
{
}
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property,
GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label, true);
}
public override void OnGUI(Rect position,
SerializedProperty property,
GUIContent label)
{
GUI.enabled = false;
EditorGUI.PropertyField(position, property, label, true);
GUI.enabled = true;
}
}
/// <summary>
/// It holds a list of scenes that's shown in the scene quick access tool
/// </summary>
[CreateAssetMenu(fileName = "SceneAccessHolder", menuName = "Scene Data/SceneAccessHolder")]
public class SceneAccessHolderSO : ScriptableObject
{
[Serializable]
public struct SceneInfo : IEquatable<SceneInfo>
{
[ReadOnly] public string name;
[ReadOnly] public string path;
public bool visible;
public bool Equals(SceneInfo other)
{
// Would still want to check for null etc. first.
return this.path == other.path;
}
}
[Header("List of Scenes")]
public List<SceneInfo> sceneList;
}

11
UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs.meta


fileFormatVersion: 2
guid: 041bdbf27ff47ea4586c6b730fc5114c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

30
UOP1_Project/Assets/ScriptableObjects/SceneData/Resources/SceneAccessHolder.asset


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 041bdbf27ff47ea4586c6b730fc5114c, type: 3}
m_Name: SceneAccessHolder
m_EditorClassIdentifier:
sceneList:
- name: MainMenu
path: D:\indie\_OnGoing\open-project-Unity\UOP1_Project\Assets\Scenes\Menus\MainMenu.unity
visible: 1
- name: Forest
path: D:\indie\_OnGoing\open-project-Unity\UOP1_Project\Assets\Scenes\Locations\Forest.unity
visible: 0
- name: Beach
path: D:\indie\_OnGoing\open-project-Unity\UOP1_Project\Assets\Scenes\Locations\Beach.unity
visible: 1
- name: TestingGround
path: D:\indie\_OnGoing\open-project-Unity\UOP1_Project\Assets\Scenes\TestingGround.unity
visible: 1
- name: Initialization
path: D:\indie\_OnGoing\open-project-Unity\UOP1_Project\Assets\Scenes\Initialization.unity
visible: 1

8
UOP1_Project/Assets/ScriptableObjects/SceneData/Resources/SceneAccessHolder.asset.meta


fileFormatVersion: 2
guid: 40fa063512d1a5b46a597c15c6160a5e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

16
UOP1_Project/Assets/Scripts/Input/Editor/InputReaderEditor.cs


using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(InputReader))]
public class InputReaderEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (!Application.isPlaying)
return;
ScriptableObjectHelper.GenerateButtonsForEvents<InputReader>(target);
}
}

11
UOP1_Project/Assets/Scripts/Input/Editor/InputReaderEditor.cs.meta


fileFormatVersion: 2
guid: 0e46e2d2cecfc354a8ac70cae65b2343
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存