mirror of
https://github.com/ACEmulator/ACE
synced 2026-08-17 12:26:06 -04:00
* Adding scrolls to loot profiles Scroll weenies are cached into lists, then created from those weenies, so the database isnt hit everytime there is a new scroll created. * Fixed so that the lists for spell weenies are persistent and only are added when weenies are not present. This should be good to go as I tested it thoroughly. * Loads all weenies on first weenie looup also, renamed variable of result to spellWeenie and returned the dict value and not the value of the lookup. * changed field to static so no need to make Database object * WorldDatabase GetRandomWeeniesOfType -> GetRandomCachedWeeniesOfType WorldDatabasePrecaching set to true is a requirement for proper loot generation * Improve getting scroll weenies by spell id * GetRandomCachedWeeniesOfType -> GetRandomWeeniesOfType
839 lines
30 KiB
C#
839 lines
30 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|
|
|
using log4net;
|
|
|
|
using ACE.Database.Models.World;
|
|
using ACE.Entity.Enum;
|
|
using ACE.Entity.Enum.Properties;
|
|
|
|
namespace ACE.Database
|
|
{
|
|
public class WorldDatabase
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
public bool Exists(bool retryUntilFound)
|
|
{
|
|
var config = Common.ConfigManager.Config.MySql.World;
|
|
|
|
for (; ; )
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
if (((RelationalDatabaseCreator)context.Database.GetService<IDatabaseCreator>()).Exists())
|
|
{
|
|
log.Debug($"Successfully connected to {config.Database} database on {config.Host}:{config.Port}.");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
log.Error($"Attempting to reconnect to {config.Database} database on {config.Host}:{config.Port} in 5 seconds...");
|
|
|
|
if (retryUntilFound)
|
|
Thread.Sleep(5000);
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Will return uint.MaxValue if no records were found within the range provided.
|
|
/// </summary>
|
|
public uint GetMaxGuidFoundInRange(uint min, uint max)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.LandblockInstance
|
|
.AsNoTracking()
|
|
.Where(r => r.Guid >= min && r.Guid <= max)
|
|
.ToList();
|
|
|
|
if (!results.Any())
|
|
return uint.MaxValue;
|
|
|
|
var maxId = min;
|
|
|
|
foreach (var result in results)
|
|
{
|
|
if (result.Guid > maxId)
|
|
maxId = result.Guid;
|
|
}
|
|
|
|
return maxId;
|
|
}
|
|
}
|
|
|
|
|
|
private readonly ConcurrentDictionary<uint, Weenie> weenieCache = new ConcurrentDictionary<uint, Weenie>();
|
|
|
|
/// <summary>
|
|
/// This will populate all sub collections except the following: LandblockInstances, PointsOfInterest<para />
|
|
/// This will also update the weenie cache.
|
|
/// </summary>
|
|
private Weenie GetWeenie(WorldDbContext context, uint weenieClassId)
|
|
{
|
|
// Base properties for every weenie (ACBaseQualities)
|
|
var weenie = context.Weenie
|
|
.Include(r => r.WeeniePropertiesBool)
|
|
.Include(r => r.WeeniePropertiesDID)
|
|
.Include(r => r.WeeniePropertiesFloat)
|
|
.Include(r => r.WeeniePropertiesIID)
|
|
.Include(r => r.WeeniePropertiesInt)
|
|
.Include(r => r.WeeniePropertiesInt64)
|
|
.Include(r => r.WeeniePropertiesPosition)
|
|
.Include(r => r.WeeniePropertiesString)
|
|
.FirstOrDefault(r => r.ClassId == weenieClassId);
|
|
|
|
if (weenie == null)
|
|
{
|
|
weenieCache[weenieClassId] = null;
|
|
return null;
|
|
}
|
|
|
|
var weenieType = (WeenieType)weenie.Type;
|
|
|
|
bool isCreature = weenieType == WeenieType.Creature || weenieType == WeenieType.Cow ||
|
|
weenieType == WeenieType.Sentinel || weenieType == WeenieType.Admin ||
|
|
weenieType == WeenieType.Vendor;
|
|
|
|
//.Include(r => r.LandblockInstances) // When we grab a weenie, we don't need to also know everywhere it exists in the world
|
|
//.Include(r => r.PointsOfInterest) // I think these are just foreign keys for the POI table
|
|
|
|
weenie.WeeniePropertiesAnimPart = context.WeeniePropertiesAnimPart.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
|
|
if (isCreature)
|
|
{
|
|
weenie.WeeniePropertiesAttribute = context.WeeniePropertiesAttribute.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
weenie.WeeniePropertiesAttribute2nd = context.WeeniePropertiesAttribute2nd.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
|
|
weenie.WeeniePropertiesBodyPart = context.WeeniePropertiesBodyPart.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
}
|
|
|
|
if (weenieType == WeenieType.Book)
|
|
{
|
|
weenie.WeeniePropertiesBook = context.WeeniePropertiesBook.FirstOrDefault(r => r.ObjectId == weenie.ClassId);
|
|
weenie.WeeniePropertiesBookPageData = context.WeeniePropertiesBookPageData.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
}
|
|
|
|
weenie.WeeniePropertiesCreateList = context.WeeniePropertiesCreateList.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
weenie.WeeniePropertiesEmote = context.WeeniePropertiesEmote.Include(r => r.WeeniePropertiesEmoteAction).Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
weenie.WeeniePropertiesEventFilter = context.WeeniePropertiesEventFilter.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
|
|
weenie.WeeniePropertiesGenerator = context.WeeniePropertiesGenerator.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
weenie.WeeniePropertiesPalette = context.WeeniePropertiesPalette.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
|
|
if (isCreature)
|
|
{
|
|
weenie.WeeniePropertiesSkill = context.WeeniePropertiesSkill.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
}
|
|
|
|
weenie.WeeniePropertiesSpellBook = context.WeeniePropertiesSpellBook.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
|
|
weenie.WeeniePropertiesTextureMap = context.WeeniePropertiesTextureMap.Where(r => r.ObjectId == weenie.ClassId).ToList();
|
|
|
|
// If the weenie doesn't exist in the cache, we'll add it.
|
|
weenieCache[weenieClassId] = weenie;
|
|
|
|
return weenie;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will populate all sub collections except the following: LandblockInstances, PointsOfInterest<para />
|
|
/// This will also update the weenie cache.
|
|
/// </summary>
|
|
public Weenie GetWeenie(uint weenieClassId)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
return GetWeenie(context, weenieClassId);
|
|
}
|
|
|
|
public uint GetWeenieClassId(string weenieClassName)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = context.Weenie
|
|
.AsNoTracking()
|
|
.FirstOrDefault(r => r.ClassName == weenieClassName);
|
|
|
|
if (result != null)
|
|
return result.ClassId;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will populate all sub collections except the following: LandblockInstances, PointsOfInterest<para />
|
|
/// This will also update the weenie cache.
|
|
/// </summary>
|
|
public Weenie GetWeenie(string weenieClassName)
|
|
{
|
|
var weenieClassId = GetWeenieClassId(weenieClassName);
|
|
|
|
return GetWeenie(weenieClassId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the number of weenies currently cached.
|
|
/// </summary>
|
|
public int GetWeenieCacheCount()
|
|
{
|
|
return weenieCache.Count(r => r.Value != null);
|
|
}
|
|
|
|
public void ClearWeenieCache()
|
|
{
|
|
weenieCache.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Weenies will have all their collections populated except the following: LandblockInstances, PointsOfInterest
|
|
/// </summary>
|
|
public Weenie GetCachedWeenie(uint weenieClassId)
|
|
{
|
|
if (weenieCache.TryGetValue(weenieClassId, out var value))
|
|
return value;
|
|
|
|
return GetWeenie(weenieClassId); // This will add the result into the weenieCache
|
|
}
|
|
|
|
/// <summary>
|
|
/// Weenies will have all their collections populated except the following: LandblockInstances, PointsOfInterest
|
|
/// </summary>
|
|
public Weenie GetCachedWeenie(string weenieClassName)
|
|
{
|
|
foreach (var weenie in weenieCache.Values)
|
|
{
|
|
if (weenie != null && weenie.ClassName == weenieClassName)
|
|
return weenie;
|
|
}
|
|
|
|
var weenieClassId = GetWeenieClassId(weenieClassName);
|
|
|
|
return GetWeenie(weenieClassId); // This will add the result into the weenieCache
|
|
}
|
|
|
|
private readonly ConcurrentDictionary<int, List<Weenie>> weenieCacheByType = new ConcurrentDictionary<int, List<Weenie>>();
|
|
|
|
public List<Weenie> GetRandomWeeniesOfType(int weenieTypeId, int count)
|
|
{
|
|
if (!weenieCacheByType.TryGetValue(weenieTypeId, out var weenies))
|
|
{
|
|
if (!weenieSpecificCachesPopulated)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.Weenie
|
|
.AsNoTracking()
|
|
.Where(r => r.Type == weenieTypeId)
|
|
.ToList();
|
|
|
|
var rand = new Random();
|
|
|
|
weenies = new List<Weenie>();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var index = rand.Next(0, results.Count - 1);
|
|
|
|
var weenie = GetCachedWeenie(results[index].ClassId);
|
|
|
|
weenies.Add(weenie);
|
|
}
|
|
|
|
return weenies;
|
|
}
|
|
}
|
|
|
|
weenies = new List<Weenie>();
|
|
weenieCacheByType[weenieTypeId] = weenies;
|
|
}
|
|
|
|
if (weenies.Count == 0)
|
|
return new List<Weenie>();
|
|
|
|
{
|
|
var rand = new Random();
|
|
|
|
var results = new List<Weenie>();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var index = rand.Next(0, weenies.Count - 1);
|
|
|
|
var weenie = GetCachedWeenie(weenies[index].ClassId);
|
|
|
|
results.Add(weenie);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
}
|
|
|
|
private readonly Dictionary<uint, Weenie> scrollsBySpellID = new Dictionary<uint, Weenie>();
|
|
|
|
public Weenie GetScrollWeenie(uint spellID)
|
|
{
|
|
if (!scrollsBySpellID.TryGetValue(spellID, out var weenie))
|
|
{
|
|
if (!weenieSpecificCachesPopulated)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var query = from weenieRecord in context.Weenie
|
|
join did in context.WeeniePropertiesDID on weenieRecord.ClassId equals did.ObjectId
|
|
where weenieRecord.Type == (int)WeenieType.Scroll && did.Type == (ushort)PropertyDataId.Spell && did.Value == spellID
|
|
select weenieRecord;
|
|
|
|
weenie = query.FirstOrDefault();
|
|
|
|
scrollsBySpellID[spellID] = weenie;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return weenie;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will make sure every weenie in the database has been read and cached.<para />
|
|
/// This function may take 15+ minutes to complete.
|
|
/// </summary>
|
|
public void CacheAllWeenies()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.Weenie
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
{
|
|
if (weenieCache.ContainsKey(result.ClassId))
|
|
continue;
|
|
|
|
GetWeenie(context, result.ClassId);
|
|
}
|
|
}
|
|
|
|
PopulateWeenieSpecificCaches();
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will make sure every weenie in the database has been read and cached.<para />
|
|
/// This function may take 2+ minutes to complete.
|
|
/// </summary>
|
|
public void CacheAllWeeniesInParallel()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.Weenie
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
Parallel.ForEach(results, result =>
|
|
{
|
|
if (!weenieCache.ContainsKey(result.ClassId))
|
|
GetWeenie(result.ClassId);
|
|
});
|
|
}
|
|
|
|
PopulateWeenieSpecificCaches();
|
|
}
|
|
|
|
private bool weenieSpecificCachesPopulated;
|
|
|
|
private void PopulateWeenieSpecificCaches()
|
|
{
|
|
// populate weenieCacheByType
|
|
foreach (var weenie in weenieCache.Values)
|
|
{
|
|
if (weenie == null)
|
|
continue;
|
|
|
|
if (!weenieCacheByType.TryGetValue(weenie.Type, out var weenies))
|
|
{
|
|
weenies = new List<Weenie>();
|
|
weenieCacheByType[weenie.Type] = weenies;
|
|
}
|
|
|
|
if (!weenies.Contains(weenie))
|
|
weenies.Add(weenie);
|
|
}
|
|
|
|
// populate scrollsBySpellID
|
|
foreach (var weenie in weenieCache.Values)
|
|
{
|
|
if (weenie == null)
|
|
continue;
|
|
|
|
if (weenie.Type == (int)WeenieType.Scroll)
|
|
{
|
|
foreach (var record in weenie.WeeniePropertiesDID)
|
|
{
|
|
if (record.Type == (ushort)PropertyDataId.Spell)
|
|
{
|
|
scrollsBySpellID[record.Value] = weenie;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
weenieSpecificCachesPopulated = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Weenies will have all their collections populated except the following: LandblockInstances, PointsOfInterest
|
|
/// </summary>
|
|
public Dictionary<Weenie, List<LandblockInstance>> GetCachedWeenieInstancesByLandblock(ushort landblock)
|
|
{
|
|
var builder = new Dictionary<uint, List<LandblockInstance>>();
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.LandblockInstance
|
|
.Include(r => r.LandblockInstanceLink)
|
|
.AsNoTracking()
|
|
.Where(r => r.Landblock == landblock)
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
{
|
|
if (builder.TryGetValue(result.WeenieClassId, out var value))
|
|
value.Add(result);
|
|
else
|
|
builder[result.WeenieClassId] = new List<LandblockInstance>() { result };
|
|
}
|
|
}
|
|
|
|
var ret = new Dictionary<Weenie, List<LandblockInstance>>();
|
|
|
|
foreach (var kvp in builder)
|
|
ret[GetCachedWeenie(kvp.Key)] = kvp.Value;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
private readonly ConcurrentDictionary<ushort, List<LandblockInstance>> cachedLandblockInstances = new ConcurrentDictionary<ushort, List<LandblockInstance>>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of LandblockInstances currently cached.
|
|
/// </summary>
|
|
public int GetLandblockInstancesCacheCount()
|
|
{
|
|
return cachedLandblockInstances.Count(r => r.Value != null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Weenies will have all their collections populated except the following: LandblockInstances, PointsOfInterest
|
|
/// </summary>
|
|
public List<LandblockInstance> GetCachedInstancesByLandblock(ushort landblock)
|
|
{
|
|
if (cachedLandblockInstances.TryGetValue(landblock, out var value))
|
|
return value;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.LandblockInstance
|
|
.Include(r => r.LandblockInstanceLink)
|
|
.AsNoTracking()
|
|
.Where(r => r.Landblock == landblock)
|
|
.ToList();
|
|
|
|
cachedLandblockInstances.TryAdd(landblock, results.ToList());
|
|
}
|
|
|
|
return cachedLandblockInstances[landblock];
|
|
}
|
|
|
|
public LandblockInstance GetLandblockInstanceByGuid(uint guid)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
return context.LandblockInstance
|
|
.AsNoTracking()
|
|
.FirstOrDefault(r => r.Guid == guid);
|
|
}
|
|
}
|
|
|
|
|
|
private readonly ConcurrentDictionary<string, PointsOfInterest> cachedPointsOfInterest = new ConcurrentDictionary<string, PointsOfInterest>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of PointsOfInterest currently cached.
|
|
/// </summary>
|
|
public int GetPointsOfInterestCacheCount()
|
|
{
|
|
return cachedPointsOfInterest.Count(r => r.Value != null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the PointsOfInterest cache.
|
|
/// </summary>
|
|
public ConcurrentDictionary<string, PointsOfInterest> GetPointsOfInterestCache()
|
|
{
|
|
return new ConcurrentDictionary<string, PointsOfInterest>(cachedPointsOfInterest);
|
|
}
|
|
|
|
public PointsOfInterest GetCachedPointOfInterest(string name)
|
|
{
|
|
var nameToLower = name.ToLower();
|
|
|
|
if (cachedPointsOfInterest.TryGetValue(nameToLower, out var value))
|
|
return value;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = context.PointsOfInterest
|
|
.AsNoTracking()
|
|
.FirstOrDefault(r => r.Name.ToLower() == nameToLower);
|
|
|
|
cachedPointsOfInterest[nameToLower] = result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves all points of interest from the database and adds/updates the points of interest cache entries with every point of interest retrieved.
|
|
/// 57 entries cached in 00:00:00.0057937
|
|
/// </summary>
|
|
public void CacheAllPointsOfInterest()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.PointsOfInterest
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
cachedPointsOfInterest[result.Name.ToLower()] = result;
|
|
}
|
|
}
|
|
|
|
private readonly Dictionary<uint, Dictionary<uint, CookBook>> cookbookCache = new Dictionary<uint, Dictionary<uint, CookBook>>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of Cookbooks currently cached.
|
|
/// </summary>
|
|
public int GetCookbookCacheCount()
|
|
{
|
|
lock (cookbookCache)
|
|
return cookbookCache.Count(r => r.Value != null);
|
|
}
|
|
|
|
public CookBook GetCachedCookbook(uint sourceWeenieClassid, uint targetWeenieClassId)
|
|
{
|
|
lock (cookbookCache)
|
|
{
|
|
if (cookbookCache.TryGetValue(sourceWeenieClassid, out var recipiesForSource))
|
|
{
|
|
if (recipiesForSource.TryGetValue(targetWeenieClassId, out var value))
|
|
return value;
|
|
}
|
|
}
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = context.CookBook
|
|
.AsNoTracking()
|
|
.Include(r => r.Recipe)
|
|
.Include(r => r.Recipe.RecipeMod)
|
|
.ThenInclude(r => r.RecipeModsBool)
|
|
.Include(r => r.Recipe.RecipeMod)
|
|
.ThenInclude(r => r.RecipeModsDID)
|
|
.Include(r => r.Recipe.RecipeMod)
|
|
.ThenInclude(r => r.RecipeModsFloat)
|
|
.Include(r => r.Recipe.RecipeMod)
|
|
.ThenInclude(r => r.RecipeModsIID)
|
|
.Include(r => r.Recipe.RecipeMod)
|
|
.ThenInclude(r => r.RecipeModsInt)
|
|
.Include(r => r.Recipe.RecipeMod)
|
|
.ThenInclude(r => r.RecipeModsString)
|
|
.Include(r => r.Recipe.RecipeRequirementsBool)
|
|
.Include(r => r.Recipe.RecipeRequirementsDID)
|
|
.Include(r => r.Recipe.RecipeRequirementsFloat)
|
|
.Include(r => r.Recipe.RecipeRequirementsIID)
|
|
.Include(r => r.Recipe.RecipeRequirementsInt)
|
|
.Include(r => r.Recipe.RecipeRequirementsString)
|
|
.FirstOrDefault(r => r.SourceWCID == sourceWeenieClassid && r.TargetWCID == targetWeenieClassId);
|
|
|
|
lock (cookbookCache)
|
|
{
|
|
// We double check before commiting the recipe.
|
|
// We could be in this lock, and queued up behind us is an attempt to add a result for the same source:target pair.
|
|
if (cookbookCache.TryGetValue(sourceWeenieClassid, out var sourceRecipies))
|
|
{
|
|
if (!sourceRecipies.ContainsKey(targetWeenieClassId))
|
|
sourceRecipies.Add(targetWeenieClassId, result);
|
|
}
|
|
else
|
|
cookbookCache.Add(sourceWeenieClassid, new Dictionary<uint, CookBook>() { { targetWeenieClassId, result } });
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This can take 1-2 minutes to complete.
|
|
/// </summary>
|
|
public void CacheAllCookbooksInParallel()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.CookBook
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
Parallel.ForEach(results, result =>
|
|
{
|
|
GetCachedCookbook(result.SourceWCID, result.TargetWCID);
|
|
});
|
|
}
|
|
}
|
|
|
|
public Weenie GetScrollBySpellID(uint spellID)
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = from weenie in context.Weenie
|
|
join did in context.WeeniePropertiesDID on weenie.ClassId equals did.ObjectId
|
|
where weenie.Type == 34 && did.Type == 28 && did.Value == spellID
|
|
select weenie;
|
|
return result.FirstOrDefault();
|
|
//return result.FirstOrDefault().ClassName;
|
|
}
|
|
}
|
|
|
|
private readonly ConcurrentDictionary<uint, Spell> spellCache = new ConcurrentDictionary<uint, Spell>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of Spells currently cached.
|
|
/// </summary>
|
|
public int GetSpellCacheCount()
|
|
{
|
|
return spellCache.Count(r => r.Value != null);
|
|
}
|
|
|
|
public Spell GetCachedSpell(uint spellId)
|
|
{
|
|
if (spellCache.TryGetValue(spellId, out var spell))
|
|
return spell;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = context.Spell
|
|
.AsNoTracking()
|
|
.FirstOrDefault(r => r.Id == spellId);
|
|
|
|
spellCache[spellId] = result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This takes under 1 second to complete.
|
|
/// </summary>
|
|
public void CacheAllSpells()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.Spell
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
spellCache[result.Id] = result;
|
|
}
|
|
}
|
|
|
|
|
|
private readonly ConcurrentDictionary<ushort, List<Encounter>> cachedEncounters = new ConcurrentDictionary<ushort, List<Encounter>>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of Encounters currently cached.
|
|
/// </summary>
|
|
public int GetEncounterCacheCount()
|
|
{
|
|
return cachedEncounters.Count(r => r.Value != null);
|
|
}
|
|
|
|
public List<Encounter> GetCachedEncountersByLandblock(ushort landblock)
|
|
{
|
|
if (cachedEncounters.TryGetValue(landblock, out var value))
|
|
return value;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.Encounter
|
|
.AsNoTracking()
|
|
.Where(r => r.Landblock == landblock)
|
|
.ToList();
|
|
|
|
cachedEncounters.TryAdd(landblock, results);
|
|
return results;
|
|
}
|
|
}
|
|
|
|
private readonly ConcurrentDictionary<string, Event> cachedEvents = new ConcurrentDictionary<string, Event>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of Events currently cached.
|
|
/// </summary>
|
|
public int GetEventsCacheCount()
|
|
{
|
|
return cachedEvents.Count(r => r.Value != null);
|
|
}
|
|
|
|
public Event GetCachedEvent(string name)
|
|
{
|
|
var nameToLower = name.ToLower();
|
|
|
|
if (cachedEvents.TryGetValue(nameToLower, out var value))
|
|
return value;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = context.Event
|
|
.AsNoTracking()
|
|
.FirstOrDefault(r => r.Name.ToLower() == nameToLower);
|
|
|
|
cachedEvents[nameToLower] = result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This takes under 1 second to complete.
|
|
/// </summary>
|
|
public List<Event> GetAllEvents()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.Event
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
cachedEvents[result.Name.ToLower()] = result;
|
|
|
|
return results;
|
|
}
|
|
}
|
|
|
|
private readonly ConcurrentDictionary<uint, TreasureDeath> cachedDeathTreasure = new ConcurrentDictionary<uint, TreasureDeath>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of TreasureDeath currently cached.
|
|
/// </summary>
|
|
public int GetDeathTreasureCacheCount()
|
|
{
|
|
return cachedDeathTreasure.Count(r => r.Value != null);
|
|
}
|
|
|
|
public TreasureDeath GetCachedDeathTreasure(uint dataId)
|
|
{
|
|
if (cachedDeathTreasure.TryGetValue(dataId, out var value))
|
|
return value;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var result = context.TreasureDeath
|
|
.AsNoTracking()
|
|
.FirstOrDefault(r => r.TreasureType == dataId);
|
|
|
|
cachedDeathTreasure[dataId] = result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This takes under 1 second to complete.
|
|
/// </summary>
|
|
public void CacheAllDeathTreasures()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.TreasureDeath
|
|
.AsNoTracking()
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
cachedDeathTreasure[result.TreasureType] = result;
|
|
}
|
|
}
|
|
|
|
private readonly ConcurrentDictionary<uint, List<TreasureWielded>> cachedWieldedTreasure = new ConcurrentDictionary<uint, List<TreasureWielded>>();
|
|
|
|
/// <summary>
|
|
/// Returns the number of TreasureWielded currently cached.
|
|
/// </summary>
|
|
public int GetWieldedTreasureCacheCount()
|
|
{
|
|
return cachedWieldedTreasure.Count(r => r.Value != null);
|
|
}
|
|
|
|
public List<TreasureWielded> GetCachedWieldedTreasure(uint dataId)
|
|
{
|
|
if (cachedWieldedTreasure.TryGetValue(dataId, out var value))
|
|
return value;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.TreasureWielded
|
|
.AsNoTracking()
|
|
.Where(r => r.TreasureType == dataId)
|
|
.ToList();
|
|
|
|
cachedWieldedTreasure[dataId] = results;
|
|
return results;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This takes under 1 second to complete.
|
|
/// </summary>
|
|
public void CacheAllWieldedTreasuresInParallel()
|
|
{
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
var results = context.TreasureWielded
|
|
.AsNoTracking()
|
|
.GroupBy(r => r.TreasureType)
|
|
.ToList();
|
|
|
|
foreach (var result in results)
|
|
cachedWieldedTreasure[result.Key] = result.ToList();
|
|
}
|
|
}
|
|
|
|
private readonly ConcurrentDictionary<string, Quest> cachedQuest = new ConcurrentDictionary<string, Quest>();
|
|
|
|
public Quest GetCachedQuest(string questName)
|
|
{
|
|
if (cachedQuest.TryGetValue(questName, out var quest))
|
|
return quest;
|
|
|
|
using (var context = new WorldDbContext())
|
|
{
|
|
quest = context.Quest.FirstOrDefault(q => q.Name.Equals(questName));
|
|
cachedQuest[questName] = quest;
|
|
|
|
return quest;
|
|
}
|
|
}
|
|
}
|
|
}
|