Skip to content

Commit

Permalink
Merge pull request #4 from Brian-Jiang/v0.9
Browse files Browse the repository at this point in the history
v0.9
  • Loading branch information
Brian-Jiang committed Sep 2, 2023
2 parents 7e9fd4f + 7721e67 commit b2d7161
Show file tree
Hide file tree
Showing 46 changed files with 15,444 additions and 19 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

## 0.9.0
- Auto update path or guid when the referenced asset is moved or renamed
- Add prebuild script to update all references in the project
- Add simple demo

## 0.8.0
- Add scene reference field
- Simplify initialization

## 0.7.0
- First release
3 changes: 3 additions & 0 deletions CHANGELOG.md.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 15 additions & 14 deletions Editor/SmartReferenceEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ internal class SmartReferenceEditor: PropertyDrawer {
private SerializedProperty guidProp;
private SerializedProperty fileIDProp;
private SerializedProperty pathProp;
private SerializedProperty typeProp;

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
if (!SerializedProperty.EqualContents(property, cacheProperty)) {
cacheProperty = property;
referencedObject = null;
guidProp = property.FindPropertyRelative("guid");
fileIDProp = property.FindPropertyRelative("fileID");
pathProp = property.FindPropertyRelative("path");
typeProp = property.FindPropertyRelative("type");
SmartReferenceUtils.UpdateReferenceWithProperty(property);
if (!string.IsNullOrEmpty(guidProp.stringValue)) {
var guid = guidProp.stringValue;
var fileID = fileIDProp.longValue;
Expand All @@ -31,33 +35,30 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten
}
}
}

}

// var objectArray = property.serializedObject.targetObjects;
// var sType = objectArray[0].GetType();
// var oType = sType.GetField(property.propertyPath).FieldType.GenericTypeArguments[0];
var type = Type.GetType(property.FindPropertyRelative("type").stringValue);
// var type = GetNestedObjectType(property, property.propertyPath, property.depth);
var type = Type.GetType(typeProp.stringValue);
var referenced = EditorGUI.ObjectField(position, label, referencedObject, type, false);
if (referencedObject != referenced) {
if (referenced == null) {
guidProp.stringValue = string.Empty;
fileIDProp.longValue = 0;
pathProp.stringValue = string.Empty;
return;
}

if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(referenced, out var guid, out long fileID)) {
Debug.LogError($"[SmartReferenceEditor] failed to get guid and fileID, path: {AssetDatabase.GetAssetPath(referenced)}");
Debug.LogError(
$"[SmartReferenceEditor] Failed to get guid and fileID, path: {AssetDatabase.GetAssetPath(referenced)}");
return;
}

guidProp.stringValue = guid;
fileIDProp.longValue = fileID;
pathProp.stringValue = AssetDatabase.GetAssetPath(referenced);

// property.FindPropertyRelative("type").stringValue = oType.FullName;
referencedObject = referenced;
}

pathProp.stringValue = AssetDatabase.GetAssetPath(referenced);

// if (referencedObject != null) {
// EditorGUI.bo
// }
}
}
}
14 changes: 14 additions & 0 deletions Editor/SmartReferencePreBuildProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

namespace SmartReference.Editor {
public class SmartReferencePreBuildProcessor: IPreprocessBuildWithReport {
public int callbackOrder => 0;

public void OnPreprocessBuild(BuildReport report) {
Debug.Log("[SmartReference] Prebuild - Updating all references...");
SmartReferenceUtils.UpdateAllReferences();
}
}
}
3 changes: 3 additions & 0 deletions Editor/SmartReferencePreBuildProcessor.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

149 changes: 149 additions & 0 deletions Editor/SmartReferenceUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace SmartReference.Editor {
public static class SmartReferenceUtils {
[MenuItem("Tools/SmartReference/Update All References", priority = 100)]
public static void UpdateAllReferences() {
EditorUtility.DisplayProgressBar("SmartReference", "Updating all references...", 0);

try {
var typeList = GetTypesWithSpecificField(typeof(Runtime.SmartReference));
foreach (var type in typeList) {
var guids = AssetDatabase.FindAssets($"t:{type.Name}");
foreach (var guid in guids) {
var path = AssetDatabase.GUIDToAssetPath(guid);
var asset = AssetDatabase.LoadAssetAtPath(path, type);
var serializedObject = new SerializedObject(asset);
var fields = type.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields) {
if (!typeof(Runtime.SmartReference).IsAssignableFrom(field.FieldType)) continue;

var property = serializedObject.FindProperty(field.Name);
UpdateReferenceWithProperty(property);
}

serializedObject.ApplyModifiedProperties();
}
}
}
finally {
EditorUtility.ClearProgressBar();
AssetDatabase.SaveAssets();
}
}

public static void UpdateReference(this Runtime.SmartReference smartReference) {
if (smartReference == null || string.IsNullOrEmpty(smartReference.guid)) return;

var succeed = false;
// Update path with guid and fileID
var objects = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GUIDToAssetPath(smartReference.guid));
foreach (var obj in objects) {
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out _, out long objFileID) &&
smartReference.fileID == objFileID) {
smartReference.path = AssetDatabase.GetAssetPath(obj);
succeed = true;
break;
}
}

// if failed, try to update guid and fileID with path
if (!succeed) {
var obj = AssetDatabase.LoadAssetAtPath(smartReference.path, Type.GetType(smartReference.type));
if (obj != null && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long objFileID)) {
smartReference.guid = AssetDatabase.AssetPathToGUID(smartReference.path);
smartReference.fileID = objFileID;
Debug.LogWarning("[SmartReference] The object referenced is missing, try to update guid and fileID with path");
succeed = true;
}
}

if (!succeed) {
Debug.LogError($"[SmartReference] Failed to update smart reference, path: {smartReference.path}");
}
}

internal static void UpdateReferenceWithProperty(SerializedProperty property) {
if (property == null) return;

var guidProp = property.FindPropertyRelative("guid");
if (string.IsNullOrEmpty(guidProp.stringValue)) return;

var fileIDProp = property.FindPropertyRelative("fileID");
var pathProp = property.FindPropertyRelative("path");
var typeProp = property.FindPropertyRelative("type");
var succeed = false;
// Update path with guid and fileID
var objects = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GUIDToAssetPath(guidProp.stringValue));
foreach (var obj in objects) {
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out _, out long objFileID) &&
fileIDProp.longValue == objFileID) {
pathProp.stringValue = AssetDatabase.GetAssetPath(obj);
succeed = true;
break;
}
}

// if failed, try to update guid and fileID with path
if (!succeed) {
var obj = AssetDatabase.LoadAssetAtPath(pathProp.stringValue, Type.GetType(typeProp.stringValue));
if (obj != null && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long objFileID)) {
guidProp.stringValue = AssetDatabase.AssetPathToGUID(pathProp.stringValue);
fileIDProp.longValue = objFileID;
Debug.LogWarning("[SmartReference] The object referenced is missing, try to update guid and fileID with path");
succeed = true;
}
}

if (!succeed) {
Debug.LogError($"[SmartReference] Failed to update smart reference, path: {pathProp.stringValue}");
}
}

private static List<Type> GetTypesWithSpecificField(Type fieldType)
{
List<Type> result = new List<Type>();

// Iterating over all assemblies
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
// Optional: Filter the assemblies by name if necessary
var fullName = assembly.FullName;
if (fullName.StartsWith("UnityEngine.") || fullName.StartsWith("UnityEditor.") ||
fullName.StartsWith("Unity.") || fullName.StartsWith("Bee.") ||
fullName.StartsWith("System.") || fullName.StartsWith("Mono.")) continue;

foreach (Type type in assembly.GetTypes())
{
// Safeguard against types that might throw exceptions
try
{
if (type.IsSubclassOf(typeof(UnityEngine.Object)))
{
foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
{
if (fieldType.IsAssignableFrom(field.FieldType))
{
result.Add(type);
break;
}
}
}
}
catch
{
// In some cases, attempting to inspect a type might throw an exception.
// Just catch and ignore.
}
}
}

return result;
}
}
}
3 changes: 3 additions & 0 deletions Editor/SmartReferenceUtils.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Xiao Jiang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3 changes: 3 additions & 0 deletions LICENSE.md.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Smart Reference
#### version 0.8.0
#### version 0.9.0

## Summary
Smart Reference is a Unity plugin that allows you to lazy load references to other objects in ScriptableObject and MonoBehaviour.
Expand Down Expand Up @@ -45,6 +45,9 @@ Smart Reference allows you to load references only when you need them at runtime
```csharp
SmartReference.Runtime.SmartReference.InitWithResourcesLoader();
```
3. SmartReference will automatically update paths before player build in case you move or rename the referenced asset.
If you want to manually update all references in the project, go to `Tools/SmartReference/Update All References` to update all references in the project.

## Supports
If you have any questions, please leave an issue at [GitHub](https://github.com/Brian-Jiang/SmartReference/issues).
Expand Down
3 changes: 3 additions & 0 deletions Runtime/Loaders.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 1 addition & 3 deletions Runtime/SmartReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public abstract class SmartReference {
public string guid;
public long fileID;
public string path;
public string type;

protected static ISmartReferenceLoader loader;

Expand Down Expand Up @@ -51,9 +52,6 @@ public static void InitWithCustomLoader(CustomLoader loader) {

[Serializable]
public class SmartReference<T>: SmartReference, ISerializationCallbackReceiver where T: Object {
[SerializeField]
private string type;

private T value;
/// <summary>
/// Get the asset. If the asset is not loaded, it will be loaded automatically.
Expand Down
Loading

0 comments on commit b2d7161

Please sign in to comment.