Skip to content

Commit 773f3f5

Browse files
authored
Merge pull request #4 from TarasK8/feature/asset-references
Feature/asset references
2 parents 2c00199 + 28dc0b4 commit 773f3f5

11 files changed

+450
-2
lines changed

Editor/AssetsContainerEditor.cs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System;
2+
using System.IO;
3+
using TarasK8.SaveSystem;
4+
using UnityEditor;
5+
using UnityEngine;
6+
7+
namespace TarasK8.SaveSystemEditor
8+
{
9+
public class AssetsContainerEditor : EditorWindow
10+
{
11+
private AssetsContainer _container;
12+
private SerializedObject _serializedObject;
13+
private SerializedProperty _paths;
14+
private SerializedProperty _assets;
15+
16+
private Vector2 _assetsScroll;
17+
private Vector2 _pathsScroll;
18+
19+
[MenuItem("Window/Saveable References")]
20+
public static void ShowWindow()
21+
{
22+
GetWindow<AssetsContainerEditor>("Saveable References").Show();
23+
}
24+
25+
[MenuItem("Assets/Add to Saveable References")]
26+
public static void AddToContainer()
27+
{
28+
AssetsContainer container = GetOrCreateContainer();
29+
UnityEngine.Object[] objects = Selection.objects;
30+
if (objects.Length == 0)
31+
return;
32+
container.AddWithContextMenu(objects);
33+
}
34+
35+
private void Initialize()
36+
{
37+
_container = GetOrCreateContainer();
38+
_serializedObject = new SerializedObject(_container);
39+
_paths = _serializedObject.FindProperty("_paths");
40+
_assets = _serializedObject.FindProperty("_assets");
41+
}
42+
43+
private void OnEnable()
44+
{
45+
base.minSize = new Vector2(400f, 400f);
46+
Initialize();
47+
}
48+
49+
public void OnGUI()
50+
{
51+
if(_container == null)
52+
{
53+
if(GUILayout.Button("Create Assets Container"))
54+
{
55+
Initialize();
56+
}
57+
return;
58+
}
59+
_serializedObject.Update();
60+
DrawPaths();
61+
DrawAssetsList();
62+
_serializedObject.ApplyModifiedProperties();
63+
}
64+
65+
private void DrawPaths()
66+
{
67+
EditorGUILayout.BeginVertical("box");
68+
EditorGUILayout.BeginHorizontal();
69+
EditorGUILayout.LabelField($"Paths ({_paths.arraySize})", EditorStyles.boldLabel, GUILayout.MinWidth(120f));
70+
if (GUILayout.Button("Add", GUILayout.MinWidth(70f)))
71+
_paths.InsertArrayElementAtIndex(0);
72+
EditorGUILayout.EndHorizontal();
73+
_pathsScroll = EditorGUILayout.BeginScrollView(_pathsScroll, GUILayout.MaxHeight(160f), GUILayout.MinHeight(0f), GUILayout.Height(160f));
74+
for (int i = 0; i < _paths.arraySize; i++)
75+
{
76+
DrawPathElement(i);
77+
}
78+
EditorGUILayout.EndScrollView();
79+
EditorGUILayout.EndVertical();
80+
}
81+
82+
private void DrawPathElement(int index)
83+
{
84+
var element = _paths.GetArrayElementAtIndex(index);
85+
EditorGUILayout.BeginHorizontal();
86+
EditorGUILayout.LabelField($"Path {index}", GUILayout.Width(60f));
87+
EditorGUILayout.PropertyField(element, new GUIContent(string.Empty));
88+
if(GUILayout.Button("Select", GUILayout.Width(50f)))
89+
{
90+
string path = EditorUtility.OpenFolderPanel("Select path", "Assets", "");
91+
92+
if (path != "Assets" || path.Length != 0)
93+
path = path.Substring(path.IndexOf("Assets"));
94+
95+
if (AssetDatabase.IsValidFolder(path))
96+
element.stringValue = path;
97+
else
98+
_paths.DeleteArrayElementAtIndex(index);
99+
}
100+
DrawDeleteButton(_paths, index);
101+
EditorGUILayout.EndHorizontal();
102+
}
103+
104+
private void DrawAssetsList()
105+
{
106+
EditorGUILayout.BeginVertical("box");
107+
EditorGUILayout.BeginHorizontal();
108+
EditorGUILayout.LabelField($"Saved Assets ({_assets.arraySize})", EditorStyles.boldLabel, GUILayout.MinWidth(120f));
109+
if (GUILayout.Button("Load From Paths"))
110+
{
111+
_container.LoadAssets();
112+
}
113+
if (GUILayout.Button("Clear All"))
114+
{
115+
_container.ClearAll();
116+
}
117+
EditorGUILayout.EndHorizontal();
118+
_assetsScroll = EditorGUILayout.BeginScrollView(_assetsScroll, /*GUILayout.MaxHeight(200f), */GUILayout.MinHeight(0f));
119+
for (int i = 0; i < _assets.arraySize; i++)
120+
{
121+
DrawAssetElement(i);
122+
}
123+
EditorGUILayout.EndScrollView();
124+
EditorGUILayout.EndVertical();
125+
}
126+
127+
private void DrawAssetElement(int index)
128+
{
129+
var element = _assets.GetArrayElementAtIndex(index);
130+
EditorGUILayout.BeginHorizontal();
131+
EditorGUILayout.LabelField(new GUIContent($"Asset {index}"), GUILayout.Width(70f));
132+
GUI.enabled = false;
133+
EditorGUILayout.PropertyField(element.FindPropertyRelative("_asset"), new GUIContent(string.Empty));
134+
GUI.enabled = true;
135+
if(GUILayout.Button("Copy Ref", GUILayout.Width(70f)))
136+
{
137+
string reference = element.FindPropertyRelative("_guid").stringValue;
138+
EditorGUIUtility.systemCopyBuffer = reference;
139+
Debug.Log($"Copied Reference: {reference}");
140+
}
141+
DrawDeleteButton(_assets, index);
142+
EditorGUILayout.EndHorizontal();
143+
}
144+
145+
private void DrawDeleteButton(SerializedProperty array, int index)
146+
{
147+
if (GUILayout.Button("Remove", GUILayout.Width(60f)))
148+
{
149+
array.DeleteArrayElementAtIndex(index);
150+
}
151+
}
152+
153+
private static AssetsContainer GetOrCreateContainer()
154+
{
155+
var container = Resources.Load<AssetsContainer>(AssetsContainer.RESOURCES_PATH);
156+
157+
if (container)
158+
{
159+
return container;
160+
}
161+
162+
container = ScriptableObject.CreateInstance<AssetsContainer>();
163+
container.Initialize();
164+
165+
string directory = Path.GetDirectoryName(AssetsContainer.PATH);
166+
if (!Directory.Exists(directory))
167+
{
168+
Directory.CreateDirectory(directory);
169+
}
170+
171+
AssetDatabase.CreateAsset(container, AssetsContainer.PATH);
172+
AssetDatabase.SaveAssets();
173+
174+
return container;
175+
}
176+
}
177+
178+
[CustomEditor(typeof(AssetsContainer))]
179+
public class AssetsContainerEditorTemp : Editor
180+
{
181+
public override void OnInspectorGUI()
182+
{
183+
if (GUILayout.Button("Open Editor"))
184+
{
185+
AssetsContainerEditor.ShowWindow();
186+
}
187+
}
188+
}
189+
}

Editor/AssetsContainerEditor.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Assets References.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using UnityEngine;
2+
3+
namespace TarasK8.SaveSystem
4+
{
5+
[System.Serializable]
6+
public class AssetEntry
7+
{
8+
[SerializeField] private string _guid;
9+
[SerializeField] private Object _asset;
10+
11+
public string Guid => _guid;
12+
public Object Asset => _asset;
13+
14+
public AssetEntry(string guid, Object asset)
15+
{
16+
_guid = guid;
17+
_asset = asset;
18+
}
19+
}
20+
}

Runtime/Assets References/AssetEntry.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using UnityEditor;
5+
using UnityEngine;
6+
7+
namespace TarasK8.SaveSystem
8+
{
9+
public class AssetsContainer : ScriptableObject
10+
{
11+
public const string RESOURCES_PATH = "Main Asset Container";
12+
public const string PATH = "Assets/Resources/" + RESOURCES_PATH + ".asset";
13+
14+
private static AssetsContainer _instance;
15+
16+
[SerializeField] private string[] _paths;
17+
[SerializeField] private List<AssetEntry> _assets;
18+
19+
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
20+
private static void SetupInstance()
21+
{
22+
_instance = Resources.Load<AssetsContainer>(RESOURCES_PATH);
23+
}
24+
25+
public static bool CanReference(Object asset, out string guid)
26+
{
27+
if(_instance == null)
28+
{
29+
guid = null;
30+
return false;
31+
}
32+
33+
return _instance.TryGetGuid(asset, out guid);
34+
}
35+
36+
public static bool TryResolveReference(string guid, out Object asset)
37+
{
38+
if (_instance == null)
39+
{
40+
asset = null;
41+
return false;
42+
}
43+
44+
return _instance.TryGetAsset(guid, out asset);
45+
}
46+
47+
private bool TryGetGuid(Object asset, out string guid)
48+
{
49+
foreach (var entry in _assets)
50+
{
51+
if (ReferenceEquals(asset, entry.Asset))
52+
{
53+
guid = entry.Guid;
54+
return true;
55+
}
56+
}
57+
guid = null;
58+
return false;
59+
}
60+
61+
private bool TryGetAsset(string guid, out Object asset)
62+
{
63+
foreach (var entry in _assets)
64+
{
65+
if (guid == entry.Guid)
66+
{
67+
asset = entry.Asset;
68+
return true;
69+
}
70+
}
71+
asset = null;
72+
return false;
73+
}
74+
75+
#if UNITY_EDITOR
76+
public void Initialize() => _assets = new List<AssetEntry>();
77+
78+
public void ClearAll() => _assets.Clear();
79+
80+
public void LoadAssets()
81+
{
82+
var a = FindAssets(_paths);
83+
_assets.AddRange(a);
84+
}
85+
86+
public void AddWithContextMenu(IEnumerable<Object> assets)
87+
{
88+
var toAdd = Filter(assets);
89+
int addedCount = toAdd.Count();
90+
if (addedCount == 0)
91+
Debug.Log("These assets are already added");
92+
else
93+
Debug.Log($"Added {addedCount} assets");
94+
_assets.AddRange(toAdd);
95+
}
96+
97+
private IEnumerable<AssetEntry> Filter(IEnumerable<Object> assets)
98+
{
99+
foreach (var asset in assets)
100+
{
101+
if(TryGetGuid(asset, out _) == false)
102+
{
103+
string path = AssetDatabase.GetAssetPath(asset);
104+
string guid = AssetDatabase.GUIDToAssetPath(path);
105+
AssetEntry assetEntry = new AssetEntry(guid, asset);
106+
yield return assetEntry;
107+
}
108+
}
109+
}
110+
111+
public IEnumerable<AssetEntry> FindAssets(params string[] paths)
112+
{
113+
string[] filteredPaths = paths.Where(x => string.IsNullOrEmpty(x) == false).ToArray();
114+
115+
if(filteredPaths.Length == 0) yield break;
116+
117+
string[] guids = AssetDatabase.FindAssets("t:Object", filteredPaths);
118+
119+
foreach (string guid in guids)
120+
{
121+
string path = AssetDatabase.GUIDToAssetPath(guid);
122+
Object asset = AssetDatabase.LoadAssetAtPath<Object>(path);
123+
if (TryGetGuid(asset, out _) == false)
124+
{
125+
AssetEntry assetEntry = new AssetEntry(guid, asset);
126+
yield return assetEntry;
127+
}
128+
129+
}
130+
}
131+
#endif
132+
}
133+
}

Runtime/Assets References/AssetsContainer.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)