Add to your project manifiest by path [%UnityProject%]/Packages/manifiest.json new dependency:
{
"dependencies": {
"com.unigame.coremodules": "https://github.com/UnioGame/UniGame.CoreModules.git",
}
}
Main idea based on JetBrains LifeTime pattern.
Any shared resource/service MUST have single owner. main rule for fluent resources managment: One resource - One owner That rule make make all resource management pretty straightforward and allow to construct hierarchical dependencies.
public interface ILifeTime
{
/// <summary>
/// cleanup action, call when life time terminated
/// </summary>
ILifeTime AddCleanUpAction(Action cleanAction);
/// <summary>
/// add child disposable object
/// </summary>
ILifeTime AddDispose(IDisposable item);
/// <summary>
/// save object from GC
/// </summary>
ILifeTime AddRef(object o);
/// <summary>
/// is lifetime terminated
/// </summary>
bool IsTerminated { get; }
}
you can't create instance of LifeTime class directly, but there is easy way to achieve it
LifeTimeDefinition lifeTime = new LifeTimeDefinition();
LifeTime lifeTime = LifeTime.Create();
every instance of LifeTime has unique runtime Id.
you must always share only interface "LifeTime" where it needed for resources management and never allow direct access to LifeTime instance. That's guarantee that only owner can Terminate your resources
LifeTime.Terminate() cleanup all registered IDisposable, Actions, Object in inverted registration order. After that lifeTime.IsTerminated will return TRUE.
LifeTime lifeTime = LifeTime.Create();
lifeTime.Terminate();
All registered actions, disposables on Terminated LifeTime will execute immediately
LifeTime lifeTime = LifeTime.Create();
lifeTime.Terminate();
LifeTime.Release() cleanup all registered objects and mark
LifeTime lifeTime = LifeTime.Create();
lifeTime.Terminate();
IDisposable disposable1 = new Disposable1();
lifeTime.AddDisposable(disposable1);// Dispose method call immediately
- IDisposable cleanup
public class Foo : IDisposable
{
private LifeTime lifeTime = LifeTime.Create();
public Foo(){
var disposable1 = new Disposable1().AddTo(lifeTime);
var disposable2 = new Disposable2().AddTo(lifeTime);
var disposable3 = new Disposable3().AddTo(lifeTime);
var disposable4 = new Disposable4();
lifeTime.AddDisposable(disposable4);
}
public void Dispose() => lifeTime.Terminate();
}
- Cleanup Action
public class Foo : IDisposable
{
private LifeTime lifeTime = LifeTime.Create();
public Foo(){
lifeTime.AddCleanUpAction(CleanUp1);
lifeTime.AddCleanUpAction(() => CleanUp2());
}
public void Dispose() => lifeTime.Terminate();
public void CleanUp1(){
}
pulic void CleanUp2(){
}
}
Context is Reactive Container of strong typed data and Resolving them dynamicaly with support async operations
public interface IContext
{
/// <summary>
/// Subscribe typed message.
/// </summary>
IObservable<T> Receive<T>();
/// <summary>
/// Send Message to all receiver.
/// </summary>
void Publish<T>(T message);
/// Try to remove data of TData type
bool Remove<TData>();
/// Get registered data by TData Type or return default
TData Get<TData>();
/// Is Data wuth TData type registered
bool Contains<TData>();
}
public ILifeTime LifeTime { get; }
public async void Resolve(IContext context)
{
//async await of value from context with context lifetime
var asyncFooValue = await context.ReceiveFirstAsync<IFoo>();
//async await of value from context with direct lifetime
var asyncLifeTimeFooValue = await context.ReceiveFirstAsync<IFoo>(LifeTime);
//observable value
context.Receive<IFoo>()
.Subscribe(x => SomeAction(x))
.AddTo(LifeTime);
//sync value acquire
var syncValue = context.Get<IFoo>();
}
Additional API for Content that allow you register data into Scene Scoped Context container
Async Data Sources of data with registration into target Context
Toolset for easy and painless usage of Unity Addressables Package
The main problem of unity package usage is no easy control on assets references lifetime. Where is no way to bind lifetime of references to game state or objects Our toolset contains serveral helpful extensions that simplify your workflow
base extensions methods for Addressable System can be found at AddressableExtensions
ILifeTime LifeTime = new LifeTimeDefinition();
private async UniTask LoadReferences()
{
_goldResource = await _goldReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_starsResource = await _starsReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_diamondsResource = await _diamondsReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_energyResource = await _energyReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_boostTimeHintResource = await _boostTimeHintReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_highlightHintResource = await _highlightHintReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_searchHintResource = await _searchHintReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_realMoneyResource = await _realMoneyReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
_multiSearchHintResource = await _multiSearchHintReference.LoadAssetTaskAsync<GameResourceData>(LifeTime);
}
LifeTimeDefinition LifeTime1 = new LifeTimeDefinition();
LifeTimeDefinition LifeTime2 = new LifeTimeDefinition();
private async UniTask LoadReferences()
{
_goldResource1 = await _goldReference.LoadAssetTaskAsync<GameResourceData>(LifeTime1);
_goldResource2 = await _goldReference.LoadAssetTaskAsync<GameResourceData>(LifeTime2);
LifeTime1.Release(); // _goldReference still valid because of _goldResource2 has active reference and alive lifetime
LifeTime2.Release(); // all lifetime's terminated. _goldReference will be unloaded
}
AssetReference gameObjectReference;
private async UniTask LoadReferences()
{
Transform objectTransform = await gameObjectReference.LoadAssetTaskAsync<Transform>(LifeTime);
}
- Let's load some interface of MonoBehaviour from GameObject
AssetReference gameObjectReference;
private async UniTask LoadReferences()
{
var assetResult = await gameObjectReference.LoadAssetTaskAsync<GameObject,IFoo>(LifeTime);
IFoo = assetResult.result;
}
AssetReference gameObjectReference;
AssetReference soReference;
private async UniTask LoadReferences()
{
IFoo assetResult = await gameObjectReference.LoadAssetTaskApiAsync<GameObject,IFoo>(LifeTime);
ISomeScriptableObject assetResult = await soReference.LoadAssetTaskApiAsync<ScriptableObject,ISomeScriptableObject>(LifeTime);
}
or you can use GameObjectAssetReference
AssetReferenceGameObject gameObjectReference;
private async UniTask LoadReferences()
{
IFoo assetResult = await gameObjectReference.LoadAssetTaskAsync<IFoo>(LifeTime);
}
private readonly IReadOnlyList<AssetReference> resources;
private readonly List<IFoo> sources = new List<IFoo>();
public async UniTask<IReadOnlyList<SomeScriptableObject>> Execute(ILifeTime lifeTime)
{
return await resources.LoadAssetsTaskAsync<ScriptableObject, IFoo, AssetReference>(sources,lifeTime);
}
First of all. Create Sprite Atlas configuration asset
Create -> UniGame -> Addressables -> SpriteAtlasConfiguration
- create sprite atlas
- mark atlas as addressables
- disable "include in build"
- apply atlas reimport
Now if you will be use sprite reference by direct link from any addressables prefab all spirce shown correctly
- UniRx - Reactive Extensions for Unity
- UniTask - Provides an efficient allocation free async/await integration for Unity
- ZSting - Zero Allocation StringBuilder for .NET Core and Unity.
- Addressables Importer - A simple rule-based addressable asset importer. The importer marks assets as addressable, by applying to files having a path matching the rule pattern.
MIT