Skip to content

Commit

Permalink
Add ability to break down a tool in the part builder
Browse files Browse the repository at this point in the history
  • Loading branch information
KnightMiner committed Sep 20, 2022
1 parent 1485a9f commit 4b13e1f
Show file tree
Hide file tree
Showing 20 changed files with 484 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "tconstruct:part_builder_tool_recycling",
"pattern": {
"tag": "tconstruct:patterns"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package slimeknights.tconstruct.library.recipe.material;

import net.minecraft.world.item.ItemStack;
import slimeknights.mantle.recipe.container.ISingleStackContainer;
import slimeknights.tconstruct.library.materials.definition.MaterialVariant;

/**
* Represents a material with an amount and a cost
*/
public interface IMaterialValue {
/** Gets the material represented in this cost */
MaterialVariant getMaterial();

/** Gets the number of items needed for a single craft */
default int getNeeded() {
return 1;
}

/** Gets the value of a single item of this material */
int getValue();

/**
* Gets a copy of the leftover stack for this recipe
* @return Leftover stack
*/
default ItemStack getLeftover() {
return ItemStack.EMPTY;
}


/* Helpers */

/**
* Gets the amount of material present in the inventory as a float for display
* @param inv Inventory reference
* @return Number of material present as a float
*/
default float getMaterialValue(ISingleStackContainer inv) {
return inv.getStack().getCount() * this.getValue() / (float)this.getNeeded();
}

/**
* Gets the number of items in order to craft a material with the given cost
* @param itemCost Cost of the item being crafted
* @return Number of the input to consume
*/
default int getItemsUsed(int itemCost) {
int needed = itemCost * getNeeded();
int value = getValue();
int cost = needed / value;
if (needed % value != 0) {
cost++;
}
return cost;
}

/**
* Gets the number of leftover material from crafting a part with this material
* @param itemCost Cost of the item being crafted
* @return Number of input to consume
*/
default int getRemainder(int itemCost) {
return itemCost * this.getNeeded() % this.getValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
/**
* Recipe to get the material from an ingredient
*/
public class MaterialRecipe implements ICustomOutputRecipe<ISingleStackContainer> {
public class MaterialRecipe implements ICustomOutputRecipe<ISingleStackContainer>, IMaterialValue {
/** Vanilla requires 4 ingots for full repair, we drop it down to 3 to mesh better with nuggets and blocks and to fit small head costs better */
public static final float INGOTS_PER_REPAIR = 3f;

Expand Down Expand Up @@ -90,6 +90,11 @@ public RecipeSerializer<?> getSerializer() {
return TinkerTables.materialRecipeSerializer.get();
}

@Override
public ItemStack getLeftover() {
return this.leftover.get().copy();
}

/* Material methods */

@Override
Expand Down Expand Up @@ -119,38 +124,6 @@ public List<ItemStack> getDisplayItems() {
return displayItems;
}

/**
* Gets the amount of material present in the inventory as a float for display
* @param inv Inventory reference
* @return Number of material present as a float
*/
public float getMaterialValue(ISingleStackContainer inv) {
return inv.getStack().getCount() * this.value / (float)this.needed;
}

/**
* Gets the number of items in order to craft a material with the given cost
* @param itemCost Cost of the item being crafted
* @return Number of the input to consume
*/
public int getItemsUsed(int itemCost) {
int needed = itemCost * this.needed;
int cost = needed / this.value;
if (needed % this.value != 0) {
cost++;
}
return cost;
}

/**
* Gets the number of leftover material from crafting a part with this material
* @param itemCost Cost of the item being crafted
* @return Number of input to consume
*/
public int getRemainder(int itemCost) {
return itemCost * this.needed % this.value;
}

/**
* Gets the amount to repair per item for tool repair
* @param data Tool defintion data for fallback
Expand Down Expand Up @@ -183,12 +156,4 @@ public static int getRepairDurability(ToolDefinitionData toolData, MaterialId ma
}
return optional.map(stats -> ((IRepairableMaterialStats)stats).getDurability()).orElseGet(() -> toolData.getBaseStat(ToolStats.DURABILITY).intValue());
}

/**
* Gets a copy of the leftover stack for this recipe
* @return Leftover stack
*/
public ItemStack getLeftover() {
return this.leftover.get().copy();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package slimeknights.tconstruct.library.recipe.material;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import slimeknights.tconstruct.library.materials.definition.MaterialVariant;
import slimeknights.tconstruct.library.materials.definition.MaterialVariantId;

/**
* Constant material value used for tool parts
*/
@RequiredArgsConstructor
public class MaterialValue implements IMaterialValue {
@Getter
private final MaterialVariant material;
@Getter
private final int value;

public MaterialValue(MaterialVariantId material, int value) {
this(MaterialVariant.of(material), value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import net.minecraft.world.item.ItemStack;
import slimeknights.mantle.recipe.container.ISingleStackContainer;
import slimeknights.tconstruct.library.recipe.material.MaterialRecipe;
import slimeknights.tconstruct.library.recipe.material.IMaterialValue;

import javax.annotation.Nullable;

Expand All @@ -15,7 +15,7 @@ public interface IPartBuilderContainer extends ISingleStackContainer {
* @return Material recipe, or null if the slot contents are not a valid material
*/
@Nullable
MaterialRecipe getMaterial();
IMaterialValue getMaterial();

/**
* Gets the stack in the pattern slot
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
package slimeknights.tconstruct.library.recipe.partbuilder;

import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeType;
import slimeknights.mantle.recipe.ICommonRecipe;
import slimeknights.tconstruct.library.recipe.TinkerRecipeTypes;
import slimeknights.tconstruct.library.recipe.material.MaterialRecipe;
import slimeknights.tconstruct.library.recipe.material.IMaterialValue;
import slimeknights.tconstruct.tables.TinkerTables;
import slimeknights.tconstruct.tables.block.entity.inventory.PartBuilderContainerWrapper;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public interface IPartBuilderRecipe extends ICommonRecipe<IPartBuilderContainer> {
/** Gets the pattern needed for this recipe,
* if there are multiple recipes with the same pattern, they are effectively merged */
Pattern getPattern();

/** Gets a stream of all patterns matching this recipe, allows one recipe to match on multiple patterns */
default Stream<Pattern> getPatterns(IPartBuilderContainer inv) {
return Stream.of(getPattern());
}

/**
* Gets the number of material needed for this recipe
* @return Material amount
Expand All @@ -39,6 +49,11 @@ default int getItemsUsed(IPartBuilderContainer inv) {
.orElse(1);
}

/** Assembles the result with the given pattern */
default ItemStack assemble(IPartBuilderContainer inv, Pattern pattern) {
return assemble(inv);
}

/* Recipe data */

@Override
Expand All @@ -51,9 +66,10 @@ default ItemStack getToastSymbol() {
return new ItemStack(TinkerTables.partBuilder);
}

/** Gets the leftover from performing this recipe */
/** @deprecated use {@link #getLeftover(PartBuilderContainerWrapper, Pattern)} */
@Deprecated
default ItemStack getLeftover(PartBuilderContainerWrapper inventoryWrapper) {
MaterialRecipe recipe = inventoryWrapper.getMaterial();
IMaterialValue recipe = inventoryWrapper.getMaterial();
if (recipe != null) {
int value = recipe.getValue();
if (value > 1) {
Expand All @@ -70,4 +86,23 @@ default ItemStack getLeftover(PartBuilderContainerWrapper inventoryWrapper) {
}
return ItemStack.EMPTY;
}

/**
* Gets the leftover from performing this recipe
* TODO: switch to the interface for the parameter
*/
default ItemStack getLeftover(PartBuilderContainerWrapper inventoryWrapper, Pattern pattern) {
return getLeftover(inventoryWrapper);
}

/** Gets the title to display on the part builder panel. If null, displays default info */
@Nullable
default Component getTitle() {
return null;
}

/** Gets the text to display on the part builder screen */
default List<Component> getText(IPartBuilderContainer inv) {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import slimeknights.tconstruct.common.TinkerTags;
import slimeknights.tconstruct.library.materials.definition.MaterialVariant;
import slimeknights.tconstruct.library.materials.definition.MaterialVariantId;
import slimeknights.tconstruct.library.recipe.material.MaterialRecipe;
import slimeknights.tconstruct.library.recipe.material.IMaterialValue;
import slimeknights.tconstruct.tables.TinkerTables;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -54,7 +54,7 @@ public boolean partialMatch(IPartBuilderContainer inv) {
}
// if there is a material item, it must have a valid material and be craftable
if (!inv.getStack().isEmpty()) {
MaterialRecipe materialRecipe = inv.getMaterial();
IMaterialValue materialRecipe = inv.getMaterial();
return materialRecipe != null && material.matchesVariant(materialRecipe.getMaterial());
}
// no material item? return match in case we get one later
Expand All @@ -63,7 +63,7 @@ public boolean partialMatch(IPartBuilderContainer inv) {

@Override
public boolean matches(IPartBuilderContainer inv, Level worldIn) {
MaterialRecipe materialRecipe = inv.getMaterial();
IMaterialValue materialRecipe = inv.getMaterial();
return materialRecipe != null && material.matchesVariant(materialRecipe.getMaterial())
&& inv.getStack().getCount() >= materialRecipe.getItemsUsed(cost);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import slimeknights.tconstruct.library.materials.definition.MaterialId;
import slimeknights.tconstruct.library.materials.definition.MaterialVariant;
import slimeknights.tconstruct.library.materials.definition.MaterialVariantId;
import slimeknights.tconstruct.library.recipe.material.MaterialRecipe;
import slimeknights.tconstruct.library.recipe.material.IMaterialValue;
import slimeknights.tconstruct.library.tools.part.IMaterialItem;
import slimeknights.tconstruct.tables.TinkerTables;

Expand Down Expand Up @@ -59,8 +59,13 @@ public boolean partialMatch(IPartBuilderContainer inv) {
return false;
}
// if there is a material item, it must have a valid material and be craftable
if (!inv.getStack().isEmpty()) {
MaterialRecipe materialRecipe = inv.getMaterial();
ItemStack stack = inv.getStack();
if (!stack.isEmpty()) {
// no sense allowing if there is no change
if (stack.getItem() == output) {
return false;
}
IMaterialValue materialRecipe = inv.getMaterial();
if (materialRecipe == null) {
return false;
}
Expand All @@ -80,7 +85,7 @@ public boolean partialMatch(IPartBuilderContainer inv) {
@Override
public boolean matches(IPartBuilderContainer inv, Level world) {
// must have a material
MaterialRecipe materialRecipe = inv.getMaterial();
IMaterialValue materialRecipe = inv.getMaterial();
if (materialRecipe != null) {
// material must be craftable, usable in the item, and have a cost we can afford
MaterialVariant material = materialRecipe.getMaterial();
Expand Down Expand Up @@ -112,7 +117,7 @@ public ItemStack getRecipeOutput(MaterialVariantId material) {
@Override
public ItemStack assemble(IPartBuilderContainer inv) {
MaterialVariant material = MaterialVariant.UNKNOWN;
MaterialRecipe materialRecipe = inv.getMaterial();
IMaterialValue materialRecipe = inv.getMaterial();
if (materialRecipe != null) {
material = materialRecipe.getMaterial();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ public static int getModifierLevel(ItemStack stack, ModifierId modifier) {
return 0;
}

/** Checks if the given stack has upgrades */
public static boolean hasUpgrades(ItemStack stack) {
if (!stack.isEmpty() && stack.is(TinkerTags.Items.MODIFIABLE)) {
CompoundTag nbt = stack.getTag();
return nbt != null && !nbt.getList(ToolStack.TAG_UPGRADES, Tag.TAG_COMPOUND).isEmpty();
}
return false;
}

/**
* Adds levels to the given key in entity modifier data for an armor modifier
* @param tool Tool instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import slimeknights.tconstruct.tables.menu.TinkerChestContainerMenu;
import slimeknights.tconstruct.tables.menu.TinkerStationContainerMenu;
import slimeknights.tconstruct.tables.recipe.CraftingTableRepairKitRecipe;
import slimeknights.tconstruct.tables.recipe.PartBuilderToolRecycle;
import slimeknights.tconstruct.tables.recipe.TinkerStationDamagingRecipe;
import slimeknights.tconstruct.tables.recipe.TinkerStationPartSwapping;
import slimeknights.tconstruct.tables.recipe.TinkerStationRepairRecipe;
Expand Down Expand Up @@ -119,6 +120,7 @@ public final class TinkerTables extends TinkerModule {
public static final RegistryObject<SpecializedRepairRecipeSerializer<?>> specializedRepairKitSerializer = RECIPE_SERIALIZERS.register("specialized_repair_kit", () -> new SpecializedRepairRecipeSerializer<>(SpecializedRepairKitRecipe::new));
public static final RegistryObject<SimpleRecipeSerializer<TinkerStationPartSwapping>> tinkerStationPartSwappingSerializer = RECIPE_SERIALIZERS.register("tinker_station_part_swapping", () -> new SimpleRecipeSerializer<>(TinkerStationPartSwapping::new));
public static final RegistryObject<TinkerStationDamagingRecipe.Serializer> tinkerStationDamagingSerializer = RECIPE_SERIALIZERS.register("tinker_station_damaging", TinkerStationDamagingRecipe.Serializer::new);
public static final RegistryObject<PartBuilderToolRecycle.Serializer> partBuilderToolRecycling = RECIPE_SERIALIZERS.register("part_builder_tool_recycling", PartBuilderToolRecycle.Serializer::new);

@SubscribeEvent
void commonSetup(final FMLCommonSetupEvent event) {
Expand Down
Loading

0 comments on commit 4b13e1f

Please sign in to comment.