Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions SmithingPlus/Common/Metal/MetalMaterialExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ public static class MetalMaterialExtensions

public static MetalMaterial? GetOrCacheMetalMaterial(this CollectibleObject collObj, ICoreAPI api)
{
var metalMaterial =
CacheHelper.GetOrAdd(Core.MetalMaterialCache, collObj.Code, () => collObj.GetMetalMaterial(api));
var cache = Core.MetalMaterialCache;
if (cache.TryGetValue(collObj.Code, out var cached)) return cached;
var metalMaterial = collObj.GetMetalMaterial(api);
// Negative results are only meaningful once the loader has resolved its materials;
// before that point every lookup returns null and must not poison the cache.
if (metalMaterial != null || api.GetModSystem<MetalMaterialLoader>()?.MaterialsResolved == true)
cache[collObj.Code] = metalMaterial;
return metalMaterial;
}

Expand Down Expand Up @@ -144,10 +149,10 @@ public static bool HasMetalMaterialSimple(this CollectibleObject collObj)
public static MetalMaterial? GetOrCacheMetalMaterial(this ItemStack itemStack, ICoreAPI api)
{
var collObj = itemStack.Collectible;
if (collObj is not IAnvilWorkable anvilWorkable) return collObj?.GetMetalMaterial(api);
if (collObj is not IAnvilWorkable anvilWorkable) return collObj?.GetOrCacheMetalMaterial(api);
var ingotStack = anvilWorkable.GetBaseMaterial(itemStack);
var metalMaterial = ingotStack.Collectible.GetOrCacheMetalMaterial(api);
return metalMaterial ?? collObj.GetMetalMaterial(api);
return metalMaterial ?? collObj.GetOrCacheMetalMaterial(api);
}

// Use when what matters is the processed result (e.g., iron bloom > iron, blister steel > steel)
Expand Down
2 changes: 2 additions & 0 deletions SmithingPlus/Common/Metal/MetalMaterialLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class MetalMaterialLoader : ModSystem
{
private readonly Dictionary<AssetLocation, MetalMaterial> _metalMaterials = new();
public Dictionary<AssetLocation, MetalMaterial> ResolvedMaterials { get; private set; } = new();
public bool MaterialsResolved { get; private set; }

public override double ExecuteOrder()
{
Expand Down Expand Up @@ -81,6 +82,7 @@ public override void AssetsFinalize(ICoreAPI api)
ResolvedMaterials = _metalMaterials
.Where(kvp => kvp.Value.Resolved)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
MaterialsResolved = true;
Core.Logger.Notification("[MetalMaterial] Done resolving metal materials.");
Core.Logger.Notification(
$"[MetalMaterial] Resolved {resolvedCount} out of {_metalMaterials.Count} metal materials.");
Expand Down
63 changes: 44 additions & 19 deletions SmithingPlus/Util/CollectibleExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,33 +73,58 @@ public static bool MatchesToolHeadSelector(this CollectibleObject collObj, bool

public static SmithingRecipe? GetSmithingRecipe(this CollectibleObject collObj, ICoreAPI api)
{
var smithingRecipe = api.ModLoader
.GetModSystem<RecipeRegistrySystem>()
.SmithingRecipes
.FirstOrDefault(r => r.Output.ResolvedItemstack.Collectible.Code.Equals(collObj.Code));
return smithingRecipe;
var byOutput = ObjectCacheUtil.GetOrCreate(api, $"{Core.ModId}:smithingRecipesByOutput", () =>
{
var dict = new Dictionary<AssetLocation, SmithingRecipe>();
foreach (var recipe in api.ModLoader.GetModSystem<RecipeRegistrySystem>().SmithingRecipes)
{
var code = recipe?.Output?.ResolvedItemstack?.Collectible?.Code;
if (code != null) dict.TryAdd(code, recipe!);
}

return dict;
});
return byOutput.TryGetValue(collObj.Code, out var smithingRecipe) ? smithingRecipe : null;
}

public static IEnumerable<SmithingRecipe> GetSmithingRecipesAsIngredient(this CollectibleObject collObj,
ICoreAPI api)
{
var smithingRecipes =
from recipe in api.ModLoader.GetModSystem<RecipeRegistrySystem>().SmithingRecipes
from ing in recipe.Ingredients
where ing.ResolvedItemStack?.Collectible?.Code?.Equals(collObj.Code) is true
select recipe;
return smithingRecipes;
var byIngredient = ObjectCacheUtil.GetOrCreate(api, $"{Core.ModId}:smithingRecipesByIngredient", () =>
{
var dict = new Dictionary<AssetLocation, List<SmithingRecipe>>();
foreach (var recipe in api.ModLoader.GetModSystem<RecipeRegistrySystem>().SmithingRecipes)
foreach (var ing in recipe.Ingredients)
{
var code = ing?.ResolvedItemStack?.Collectible?.Code;
if (code == null) continue;
if (!dict.TryGetValue(code, out var list)) dict[code] = list = [];
// Prevent duplicate entries when a recipe has the same ingredient multiple times
if (list.Count == 0 || list[^1] != recipe) list.Add(recipe);
}

return dict;
});
return byIngredient.TryGetValue(collObj.Code, out var recipes) ? recipes : [];
}

public static IEnumerable<GridRecipe> GetGridRecipesAsIngredient(this CollectibleObject collObj, ICoreAPI api)
{
var gridRecipes =
from recipe in api.World.GridRecipes
from ing in recipe.RecipeIngredients
where ing is { ResolvedItemStack.Collectible: not null } &&
ing.ResolvedItemStack?.Collectible?.Code?.Equals(collObj.Code) is true
select recipe;
return gridRecipes;
var byIngredient = ObjectCacheUtil.GetOrCreate(api, $"{Core.ModId}:gridRecipesByIngredient", () =>
{
var dict = new Dictionary<AssetLocation, List<GridRecipe>>();
foreach (var recipe in api.World.GridRecipes)
foreach (var ing in recipe.RecipeIngredients)
{
var code = ing?.ResolvedItemStack?.Collectible?.Code;
if (code == null) continue;
if (!dict.TryGetValue(code, out var list)) dict[code] = list = [];
if (list.Count == 0 || list[^1] != recipe) list.Add(recipe);
}

return dict;
});
return byIngredient.TryGetValue(collObj.Code, out var recipes) ? recipes : [];
}

public static CollectibleObject? CollectibleWithVariant(this CollectibleObject collObj, string type, string value)
Expand Down Expand Up @@ -138,4 +163,4 @@ public static T GetBehavior<T>(this CollectibleObject collObj, bool withInherita
{
return behavior?.GetField<CollectibleBehaviorQuenchable.MetalPropertyVariant>("metalProps");
}
}
}