UnioGame / UniGame.CoreModules

Base Modules Collection

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Getting Started

How to Install

Add to your project manifiest by path [%UnityProject%]/Packages/manifiest.json new dependency:

{
  "dependencies": {
    "com.unigame.coremodules": "https://github.com/UnioGame/UniGame.CoreModules.git",
  }
}

Modules

LifeTime

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.

Base API

    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; }
    }
    

LifeTime Creation

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

LifeTime Methods

  • 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(){
    
    }
    
  }
  

LifeTime Extensions

LifeTime ScriptableObjects

Context

Context is Reactive Container of strong typed data and Resolving them dynamicaly with support async operations

Base Context API

  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>();
  }

Resolve dependencies with Context

    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>();
    }

Scene Context

Additional API for Content that allow you register data into Scene Scoped Context container

Context Data Sources

Async Data Sources of data with registration into target Context

Game Services

Addressables Tools

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

How to Load

Load AssetReference with LifeTime

  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);
  }

Load Same Reference

  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
  }

Load Component from AssetReference

  AssetReference gameObjectReference;

  private async UniTask LoadReferences()
  {
      Transform objectTransform = await gameObjectReference.LoadAssetTaskAsync<Transform>(LifeTime);
  }

Load Interface from AssetReference

  • 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);
}
  

Load Collections of References

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);
}
  

Addressables Sprite Atlases

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

Editor Tools

Api References

  • 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.

License

MIT

About

Base Modules Collection

License:MIT License


Languages

Language:C# 100.0%