Skip to content

Commit

Permalink
Merge pull request #2 from Brian-Jiang/v0.8
Browse files Browse the repository at this point in the history
V0.8
  • Loading branch information
Brian-Jiang committed Jun 26, 2023
2 parents 552ce46 + 96fd8a7 commit 7e9fd4f
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 33 deletions.
60 changes: 39 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,51 @@
# Smart Reference
#### version 0.7.0
#### version 0.8.0

## Summary
Smart Reference is a Unity plugin that allows you to lazy load references to other objects in ScriptableObject and MonoBehaviour.
We use ScriptableObject to store data, but when you reference other objects, they will be treated as dependencies and will be loaded when the ScriptableObject is loaded.
This could be slow if you have a lot of references. Smart Reference allows you to load references only when you need them at runtime with same workflow in editor.
You may be familiar to use ScriptableObject store data, but when you reference other objects,
they will be treated as dependencies and will be loaded when the ScriptableObject is loaded. This could be slow if you have a lot of references.
For details, see [this article](https://medium.com/@bjjx1999/3-ways-to-reduce-load-time-in-runtime-for-unity-15d33003eb79).
Smart Reference allows you to load references only when you need them at runtime with same workflow in editor.

## Quick Start
1. Use SmartReference instead of Object. See how they look exactly same in the inspector.
```csharp
public class MonsterData : ScriptableObject {
public SmartReference<GameObject> prefab;
public SmartReference<Sprite> icon;
public string description;
}
```
```csharp
public class MonsterData : ScriptableObject {
public SmartReference<GameObject> prefab;
public SmartReference<Sprite> icon;
public string description;
}
```

2. In your start up script, call SmartReference.Init() to initialize the SmartReference system with your load and async load functions.
```csharp
SmartReference.Runtime.SmartReference.Init((path, type) => {
return MyLoadFunction.Load(path, type);
}, (path, type, callback) => {
MyLoadFunction.LoadAsync(path, type, obj => {
callback(obj);
2. Initialize smart reference when your game start
- If you use Unity Addressables, you need to add USE_UNITY_ADDRESSABLES symbol to your player settings, then call
```csharp
SmartReference.Runtime.SmartReference.InitWithAddressablesLoader();
```
- If you use your own custom loader, call
```csharp
SmartReference.Runtime.SmartReference.Init((path, type) => {
return MyLoadFunction.Load(path, type);
}, (path, type, callback) => {
MyLoadFunction.LoadAsync(path, type, obj => {
callback(obj);
});
});
});
```
```
or
```csharp
var loader = new CustomLoader {
loader = MyLoadFunction,
loaderAsync = MyAsyncLoadFunction,
};
SmartReference.Runtime.SmartReference.Init(loader);
```
- If you use Unity Resources(not recommended, see [why](https://medium.com/@bjjx1999/3-ways-to-reduce-load-time-in-runtime-for-unity-15d33003eb79)), call
```csharp
SmartReference.Runtime.SmartReference.InitWithResourcesLoader();
```

## Supports
If you have any questions, please comment at [Asset Store](https://u3d.as/35Sh)
Or email me directly at: [bjjx1999@live.com](mailto:bjjx1999@live.com)
If you have any questions, please leave an issue at [GitHub](https://github.com/Brian-Jiang/SmartReference/issues).
Thank you for your support!
36 changes: 36 additions & 0 deletions Runtime/AddressablesLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#if USE_UNITY_ADDRESSABLES

using System;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Object = UnityEngine.Object;

namespace SmartReference.Runtime {
public class AddressablesLoader: ISmartReferenceLoader {
public Object Load(string path, Type type) {
Object result = null;
var handle = Addressables.LoadAssetAsync<Object>(path);
handle.Completed += operation => {
if (operation.Status == AsyncOperationStatus.Succeeded) {
result = operation.Result;
}
};

#if !UNITY_WEBGL
handle.WaitForCompletion();
#endif
return result;
}

public void LoadAsync(string path, Type type, Action<Object> callback) {
var handle = Addressables.LoadAssetAsync<Object>(path);
handle.Completed += operation => {
if (operation.Status == AsyncOperationStatus.Succeeded) {
callback?.Invoke(operation.Result);
}
};
}
}
}

#endif
3 changes: 3 additions & 0 deletions Runtime/AddressablesLoader.cs.meta

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

20 changes: 20 additions & 0 deletions Runtime/CustomLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using Object = UnityEngine.Object;

namespace SmartReference.Runtime {
public delegate Object SmartReferenceLoader(string path, Type type);
public delegate void SmartReferenceLoaderAsync(string path, Type type, Action<Object> callback);

public class CustomLoader: ISmartReferenceLoader {
public SmartReferenceLoader loader;
public SmartReferenceLoaderAsync loaderAsync;

public Object Load(string path, Type type) {
return loader(path, type);
}

public void LoadAsync(string path, Type type, Action<Object> callback) {
loaderAsync(path, type, callback);
}
}
}
3 changes: 3 additions & 0 deletions Runtime/CustomLoader.cs.meta

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

9 changes: 9 additions & 0 deletions Runtime/ISmartReferenceLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;
using Object = UnityEngine.Object;

namespace SmartReference.Runtime {
public interface ISmartReferenceLoader {
public Object Load(string path, Type type);
public void LoadAsync(string path, Type type, Action<Object> callback);
}
}
3 changes: 3 additions & 0 deletions Runtime/ISmartReferenceLoader.cs.meta

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

16 changes: 16 additions & 0 deletions Runtime/ResourcesLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using UnityEngine;
using Object = UnityEngine.Object;

namespace SmartReference.Runtime {
public class ResourcesLoader: ISmartReferenceLoader {
public Object Load(string path, Type type) {
return Resources.Load(path, type);
}

public void LoadAsync(string path, Type type, Action<Object> callback) {
var request = Resources.LoadAsync(path, type);
request.completed += operation => callback?.Invoke(request.asset);
}
}
}
3 changes: 3 additions & 0 deletions Runtime/ResourcesLoader.cs.meta

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

6 changes: 5 additions & 1 deletion Runtime/SmartReference.Runtime.asmdef
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"name": "SmartReference.Runtime",
"rootNamespace": "SmartReference.Runtime"
"rootNamespace": "SmartReference.Runtime",
"references": [
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:84651a3751eca9349aac36a66bba901b"
]
}
50 changes: 39 additions & 11 deletions Runtime/SmartReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,48 @@
// ReSharper disable NotAccessedField.Global used in serialization

namespace SmartReference.Runtime {
public delegate Object SmartReferenceLoader(string path, Type type);
public delegate void SmartReferenceLoaderAsync(string path, Type type, Action<Object> callback);

[Serializable]
public abstract class SmartReference {
public string guid;
public long fileID;
public string path;

protected static SmartReferenceLoader loader;
protected static SmartReferenceLoaderAsync loaderAsync;
public static void Init(SmartReferenceLoader mLoader, SmartReferenceLoaderAsync mLoaderAsync) {
loader = mLoader;
loaderAsync = mLoaderAsync;
protected static ISmartReferenceLoader loader;

/// <summary>
/// Use this method to initialize the loader if you want to use Resources for loading assets.
/// </summary>
public static void InitWithResourcesLoader() {
loader = new ResourcesLoader();
}

#if USE_UNITY_ADDRESSABLES
/// <summary>
/// Use this method to initialize the loader if you want to use Unity Addressables for loading assets.
/// </summary>
public static void InitWithAddressablesLoader() {
loader = new AddressablesLoader();
}
#endif

/// <summary>
/// Use this method to initialize the loader if you want to use a custom loader.
/// </summary>
/// <param name="loader">Loader that load and return asset synchronously.</param>
/// <param name="loaderAsync">Loader that load and return asset asynchronously.</param>
public static void InitWithCustomLoader(SmartReferenceLoader loader, SmartReferenceLoaderAsync loaderAsync) {
SmartReference.loader = new CustomLoader {
loader = loader,
loaderAsync = loaderAsync,
};
}

/// <summary>
/// Use this method to initialize the loader if you want to use a custom loader.
/// </summary>
/// <param name="loader">The custom loader that you create.</param>
public static void InitWithCustomLoader(CustomLoader loader) {
SmartReference.loader = loader;
}
}

Expand Down Expand Up @@ -55,7 +83,7 @@ public void Load() {
return;
}

value = (T) loader(path, typeof(T));
value = (T) loader.Load(path, typeof(T));
if (value == null) {
Debug.LogWarning($"[SmartReference] load failed, path: {path}");
}
Expand All @@ -67,12 +95,12 @@ public void Load() {
public void LoadAsync() {
if (string.IsNullOrEmpty(path)) return;

if (loaderAsync == null) {
if (loader == null) {
Debug.LogError($"[SmartReference] loaderAsync is null, path: {path}");
return;
}

loaderAsync(path, typeof(T), obj => {
loader.LoadAsync(path, typeof(T), obj => {
if (obj == null) {
Debug.LogWarning($"[SmartReference] loadAsync failed, path: {path}");
}
Expand Down

0 comments on commit 7e9fd4f

Please sign in to comment.