Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MemoryPool doesn't allow to use backing factory with multiple params, e.g. PrefabResourceFactory #16

Open
waitxd opened this issue Jun 7, 2019 · 3 comments

Comments

@waitxd
Copy link

waitxd commented Jun 7, 2019

In current implementation it seems impossible to create MonoMemoryPool and provide the prefab to use for the new object (like with PrefabResourceFactory or PrefabFactory).
Even when you are instantiating memory pool directly.

@waitxd
Copy link
Author

waitxd commented Jun 7, 2019

Spent some time to solve this problem.

Right now in Extenject each of MonoMemoryPool<TParam1..TParam5,TContract> (one till five parameters) classes is using MemoryPoolBase<TContract> with only one parameter, which holds IFactory<TContract> (no parameters in Create method). So there is no way to pass additional parameters to the factrory. This might be a good place for further improvements.

However, I came to the conclusion that the idea of using MonoMemoryPool with Prefab[Resource]Factory is broken by design. If you pass different prefabs to the MonoMemoryPool.Spawn, the pool will contain different prefabs after MonoMemoryPool.Despawn. This can lead to the undefined behaviour when someone will reuse them.

But if someone really need to pass parameters from memory pool to underlaying factory you can use something like that.

@svermeulen
Copy link

Yep, that all makes sense. You can't use the same memory pool to share instances that are created using multiple different prefabs. One issue I see with your solution is that using code could pass different prefabs. Which might not be an issue if you're injecting it AsTransient but worth pointing out. Another solution would be to use a dictionary like this:

    public class BulletFactory 
    {
        readonly Dictionary<GameObject, IMemoryPool<Bullet>> _pools =
            new Dictionary<GameObject, IMemoryPool<Bullet>>();

        readonly DiContainer _container;
        readonly MemoryPoolSettings _settings;

        public BulletFactory(DiContainer container, MemoryPoolSettings settings)
        {
            _container = container;
            _settings = settings;
        }

        public void Despawn(GameObject prefab, Bullet bullet)
        {
            _pools[prefab].Despawn(bullet);
        }

        public Bullet Spawn(GameObject prefab) 
        {
            IMemoryPool<Bullet> pool;

            if (!_pools.TryGetValue(prefab, out pool)) 
            {
                pool = _container.Instantiate<MonoMemoryPool<Bullet>>(
                    new object[] { _settings,  new FuncFactory<Bullet>(() => _container.InstantiatePrefabForComponent<Bullet>(prefab))});
                _pools.Add(prefab, pool);
            }

            return pool.Spawn();
        }
    }

    public class FuncFactory<T> : IFactory<T>
    {
        readonly Func<T> _factoryMethod;

        public FuncFactory(Func<T> factoryMethod)
        {
            _factoryMethod = factoryMethod;
        }

        public T Create() 
        {
            return _factoryMethod();
        }
    }

@kennir
Copy link

kennir commented Jun 20, 2020

@svermeulen Hi , Can you explain how to use BulletFactory ? I can not use BindFactory<Bullet, BulletFactory> because BulletFactory is not inherit from PlaceholdFactory?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants