Skip to content

Commit

Permalink
Recipe builder enhancements (#310)
Browse files Browse the repository at this point in the history
* Update/Create builder interfaces

* Oop fix names

* Cleanup/Finalize all builder changes

* Cleanup main recipe classes

* Keep function names consistent

* Keep function names consistent pt 2

* Rename Name to Identifier to match up inline with mojang

* Make sure Identifier uses an internal setter

* Oop fix that

* Smithing recipes don't have groups

* Refactor ShapelessRecipeBuilder and IIngredientRecipe
  • Loading branch information
Tides authored Jan 5, 2023
1 parent daa21f6 commit b76834e
Show file tree
Hide file tree
Showing 25 changed files with 267 additions and 347 deletions.
41 changes: 41 additions & 0 deletions Obsidian.API/Crafting/Builders/BaseRecipeBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Obsidian.API.Crafting.Builders.Interfaces;

namespace Obsidian.API.Crafting.Builders;
public abstract class BaseRecipeBuilder<TRecipe> : IGroupedRecipe<TRecipe>, INamedRecipe<TRecipe>, IRecipeResult<TRecipe>,
IRecipeBuilder<TRecipe> where TRecipe : IRecipe
{
protected string Identifier { get; set; }

protected string? Group { get; set; }

protected ItemStack Result { get; set; }

public virtual IRecipeResult<TRecipe> WithIdentifier(string identifier)
{
ArgumentNullException.ThrowIfNull(identifier);

this.Identifier = identifier;

return this;
}

public virtual IRecipeBuilder<TRecipe> WithResult(ItemStack result)
{
ArgumentNullException.ThrowIfNull(result);

this.Result = result;

return this;
}

public virtual INamedRecipe<TRecipe> InGroup(string group)
{
this.Group = group;

return this;
}

public virtual INamedRecipe<TRecipe> HasNoGroup() => this;

public abstract TRecipe Build();
}
80 changes: 80 additions & 0 deletions Obsidian.API/Crafting/Builders/CookingRecipeBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using Obsidian.API.Crafting.Builders.Interfaces;

namespace Obsidian.API.Crafting.Builders;

public sealed class CookingRecipeBuilder : BaseRecipeBuilder<SmeltingRecipe>, IIngredientRecipe<ICookingRecipe>, ICookingRecipe
{
private readonly CookingBookCategory category;

private readonly SmeltingType type;

private Ingredient ingredient = new();

private float experience;

private int cookingTime;

private CookingRecipeBuilder(CookingBookCategory category, SmeltingType type)
{
this.category = category;
this.type = type;
}

public static IIngredientRecipe<ICookingRecipe> Create(CookingBookCategory category, SmeltingType type) => new CookingRecipeBuilder(category, type);

public ICookingRecipe WithIngredient(params ItemStack[] items)
{
foreach (var item in items)
this.ingredient.Add(item);

return this;
}

public ICookingRecipe GivesExperience(float exp)
{
this.experience += exp;//Just add if this function gets called again

return this;
}

public IGroupedRecipe<SmeltingRecipe> WithCookingTime(int cookingTime)
{
this.cookingTime = cookingTime;

return this;
}
public override SmeltingRecipe Build()
{
CraftingType type = this.type switch
{
SmeltingType.Default => CraftingType.Smelting,
SmeltingType.Blasting => CraftingType.Blasting,
SmeltingType.Smoking => CraftingType.Smoking,
SmeltingType.CampfireCooking => CraftingType.CampfireCooking,
_ => throw new NotImplementedException()
};

if (this.ingredient.Count <= 0)
throw new InvalidOperationException("Recipe must atleast have 1 item as an ingredient");

return new SmeltingRecipe
{
Identifier = this.Identifier ?? throw new NullReferenceException("Recipe must have a name"),
Type = type,
Group = this.Group,
Result = this.Result != null ? new Ingredient { this.Result } : throw new NullReferenceException("Result is not set."),
Ingredient = this.ingredient,
Experience = this.experience,
CookingTime = this.cookingTime,
Category = this.category
};
}
}

public enum SmeltingType
{
Default,
Blasting,
Smoking,
CampfireCooking
}
54 changes: 16 additions & 38 deletions Obsidian.API/Crafting/Builders/CuttingRecipeBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,66 +1,44 @@
namespace Obsidian.API.Crafting.Builders;
using Obsidian.API.Crafting.Builders.Interfaces;

public class CuttingRecipeBuilder : IRecipeBuilder<CuttingRecipeBuilder>
{
public string? Name { get; set; }
public string? Group { get; set; }
public ItemStack? Result { get; set; }
namespace Obsidian.API.Crafting.Builders;

public Ingredient Ingredient { get; private set; } = new Ingredient();
public sealed class CuttingRecipeBuilder : BaseRecipeBuilder<CuttingRecipe>, IIngredientRecipe<IOutputCountRecipe<CuttingRecipe>>, IOutputCountRecipe<CuttingRecipe>
{
private Ingredient ingredient = new();

public int Count { get; set; }

public CuttingRecipeBuilder AddIngredients(params ItemStack[] items)
{
foreach (var item in items)
this.Ingredient.Add(item);

return this;
}

public CuttingRecipeBuilder SetOutputCount(int count)
{
this.Count = count;

return this;
}

public CuttingRecipeBuilder WithName(string name)
{
this.Name = name;
private CuttingRecipeBuilder() { }

return this;
}
public static IIngredientRecipe<IOutputCountRecipe<CuttingRecipe>> Create() => new CuttingRecipeBuilder();

public CuttingRecipeBuilder SetResult(ItemStack result)
public IOutputCountRecipe<CuttingRecipe> WithIngredient(params ItemStack[] items)
{
if (this.Result != null)
throw new InvalidOperationException("Result is already set.");

this.Result = result;
foreach (var item in items)
this.ingredient.Add(item);

return this;
}

public CuttingRecipeBuilder InGroup(string group)
public IGroupedRecipe<CuttingRecipe> WithOutputCount(int count)
{
this.Group = group;
this.Count = count;

return this;
}

public IRecipe Build()
public override CuttingRecipe Build()
{
if (this.Ingredient.Count <= 0)
if (this.ingredient.Count <= 0)
throw new InvalidOperationException("Recipe must atleast have 1 item as an ingredient");

return new CuttingRecipe
{
Name = this.Name ?? throw new NullReferenceException("Name must not be null"),
Identifier = this.Identifier ?? throw new NullReferenceException("Name must not be null"),
Type = CraftingType.Stonecutting,
Group = this.Group,
Result = this.Result != null ? new Ingredient { this.Result } : throw new NullReferenceException("Result is not set."),
Ingredient = this.Ingredient ?? throw new NullReferenceException("Ingredient must not be null"),
Ingredient = this.ingredient ?? throw new NullReferenceException("Ingredient must not be null"),
Count = this.Count
};
}
Expand Down
18 changes: 0 additions & 18 deletions Obsidian.API/Crafting/Builders/IRecipeBuilder.cs

This file was deleted.

10 changes: 10 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/IBaseIngredientRecipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface IBaseIngredientRecipe<TRecipe>
{
public IUpgradeIngredientRecipe<TRecipe> WithBaseIngredient(params ItemStack[] items);
}

public interface IUpgradeIngredientRecipe<TRecipe>
{
public INamedRecipe<TRecipe> WithUpgradeIngredient(params ItemStack[] items);
}
7 changes: 7 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/ICookingRecipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface ICookingRecipe
{
public ICookingRecipe GivesExperience(float exp);

public IGroupedRecipe<SmeltingRecipe> WithCookingTime(int time);
}
7 changes: 7 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/IGroupedRecipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface IGroupedRecipe<TRecipe>
{
public INamedRecipe<TRecipe> InGroup(string group);

public INamedRecipe<TRecipe> HasNoGroup();
}
10 changes: 10 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/IIngredientRecipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface IIngredientRecipe<TBuilder>
{
public TBuilder WithIngredient(params ItemStack[] items);
}

public interface IShapelessIngredientRecipe<TRecipe>
{
public IGroupedRecipe<TRecipe> AddIngredients(params Ingredient[] ingredients);
}
5 changes: 5 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/INamedRecipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface INamedRecipe<TRecipe>
{
public IRecipeResult<TRecipe> WithIdentifier(string name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface IOutputCountRecipe<TRecipe>
{
public IGroupedRecipe<TRecipe> WithOutputCount(int count);
}
7 changes: 7 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/IPatternedRecipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface IPatternedRecipe
{
public IPatternedRecipe WithKey(char key, params ItemStack[] items);

public IGroupedRecipe<ShapedRecipe> WithPattern(params string[] pattern);
}
5 changes: 5 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/IRecipeBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;
public interface IRecipeBuilder<TRecipe>
{
public TRecipe Build();
}
6 changes: 6 additions & 0 deletions Obsidian.API/Crafting/Builders/Interfaces/IRecipeResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Obsidian.API.Crafting.Builders.Interfaces;

public interface IRecipeResult<TRecipe>
{
public IRecipeBuilder<TRecipe> WithResult(ItemStack result);
}
Loading

0 comments on commit b76834e

Please sign in to comment.