ModernUO
ModernUO copied to clipboard
Replace resources w/ generic commodity object
- [ ] Replace all commodities (gold, logs, ore, ingots, etc) with a single Commodity type.
- [ ] Use an object pool to rent/return these objects.
- [ ] Replace Type arguments with Enum arguments for these commodities.
- [ ] Replace Activator.CreateInstance with Rent from the object pool.
- [ ] Replace getting items in a container by type with the enum.
- [ ] Update hold and stack methods to be aware of the new commodity object.
- [ ] Create a migration script from the old RunUO types.
- [ ] Update mobiles/loot to allocate gold and other items through the object pool.
Here could be an example implementation I made:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
namespace Server.Collections
{
public static class ObjectPool
{
private static class Pool<T>
{
private static readonly ConcurrentBag<T> pool = new ConcurrentBag<T>();
/// <summary>
/// Methode puts an object in pool. Furthermore methode does not need
/// a lock to be thread safe because of internal handling of ConcurrentBag.
/// </summary>
/// <param name="obj"></param>
public static void PutObject(T obj)
{
pool.Add(obj);
}
/// <summary>
/// Methode gets an object of pool. Furthermore methode does not need
/// a lock to be thread safe because of internal handling of ConcurrentBag.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static bool TryGetObject(out T obj)
{
if (pool.Count > 0)
{
pool.TryTake(out obj);
return true;
}
obj = default(T);
return false;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
public static void Put<T>(T obj)
{
Pool<T>.PutObject(obj);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
private static bool TryGet<T>(out T obj)
{
return Pool<T>.TryGetObject(out obj);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetOrDefault<T>()
{
T ret;
TryGet(out ret);
return ret;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Get<T>() where T : new()
{
T ret;
return TryGet(out ret) ? ret : new T();
}
}
}
That is a start but I think concurrent bags may not have great performance. We need to benchmark this.
Also needs to prefill it. Next needs a max size so you don't end up with 100mill objects lol. Next needs to be resizable (eventually will use ingame commands or a Gump to tweak)
That is a start but I think concurrent bags may not have great performance. We need to benchmark this.
Also needs to prefill it. Next needs a max size so you don't end up with 100mill objects lol. Next needs to be resizable (eventually will use ingame commands or a Gump to tweak)
I already have an alternative approach using Stack instead of ConcurrentBags. Just chosen it because the bags are thread safe. I wrote it yesterday in about 5 minutes and were just playing around with it. I gonna check this out later on.
Try using a ConcurrentQueue, it doesn't use locks, is thread-safe and it should be just as good as a Stack.
Skip doing this for now. We can look into it if it becomes a bottle neck.