Anvil crafting

This commit is contained in:
Aleksey 2020-10-06 17:59:23 +03:00
parent 1ceb433a61
commit 115ce76b5a
12 changed files with 270 additions and 61 deletions

View file

@ -99,7 +99,7 @@ public class REIAlloyingDisplay implements TransferRecipeDisplay {
@Override
public List<List<EntryStack>> getOrganisedInputEntries(ContainerInfo<ScreenHandler> containerInfo, ScreenHandler container) {
return input;
return this.input;
}
static {

View file

@ -0,0 +1,85 @@
package ru.betterend.compat;
import java.util.Collections;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.ints.IntList;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.api.TransferRecipeCategory;
import me.shedaniel.rei.api.widgets.Widgets;
import me.shedaniel.rei.gui.entries.RecipeEntry;
import me.shedaniel.rei.gui.entries.SimpleRecipeEntry;
import me.shedaniel.rei.gui.widget.Widget;
import net.minecraft.block.Blocks;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import ru.betterend.recipe.AnvilSmithingRecipe;
import ru.betterend.util.LangUtil;
public class REIAnvilCategory implements TransferRecipeCategory<REIAnvilDisplay> {
@Override
public @NotNull Identifier getIdentifier() {
return AnvilSmithingRecipe.ID;
}
@Override
public @NotNull String getCategoryName() {
return LangUtil.translate(Blocks.ANVIL.getTranslationKey());
}
@Override
public @NotNull EntryStack getLogo() {
return REIPlugin.ANVIL;
}
@Override
public @NotNull List<Widget> setupDisplay(REIAnvilDisplay display, Rectangle bounds) {
Point startPoint = new Point(bounds.getCenterX() - 41, bounds.y + 10);
List<Widget> widgets = Lists.newArrayList();
widgets.add(Widgets.createRecipeBase(bounds));
int x = startPoint.x + 10;
int y = startPoint.y;
widgets.add(Widgets.createResultSlotBackground(new Point(x + 61, y + 9)));
List<List<EntryStack>> inputEntries = display.getInputEntries();
widgets.add(Widgets.createArrow(new Point(x + 24, y + 8)));
widgets.add(Widgets.createSlot(new Point(x - 20, y + 8)).entries(inputEntries.get(0)).markInput());
widgets.add(Widgets.createSlot(new Point(x + 1, y + 8)).entries(inputEntries.get(1)).markInput());
widgets.add(Widgets.createSlot(new Point(x + 61, y + 9)).entries(display.getResultingEntries().get(0)).disableBackground().markOutput());
return widgets;
}
@Override
public void renderRedSlots(MatrixStack matrices, List<Widget> widgets, Rectangle bounds, REIAnvilDisplay display,
IntList redSlots) {
Point startPoint = new Point(bounds.getCenterX() - 41, bounds.getCenterY() - 27);
matrices.push();
matrices.translate(0, 0, 400);
if (redSlots.contains(0)) {
DrawableHelper.fill(matrices, startPoint.x - 20, startPoint.y + 8, startPoint.x - 20 + 16, startPoint.y + 8 + 16, 1090453504);
DrawableHelper.fill(matrices, startPoint.x + 1, startPoint.y + 8, startPoint.x + 1 + 16, startPoint.y + 8 + 16, 1090453504);
}
matrices.pop();
}
@Override
public @NotNull RecipeEntry getSimpleRenderer(REIAnvilDisplay recipe) {
return SimpleRecipeEntry.from(Collections.singletonList(recipe.getInputEntries().get(0)), recipe.getResultingEntries());
}
@Override
public int getDisplayHeight() {
return 49;
}
}

View file

@ -0,0 +1,71 @@
package ru.betterend.compat;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.api.TransferRecipeDisplay;
import me.shedaniel.rei.server.ContainerInfo;
import net.minecraft.recipe.Recipe;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.util.Identifier;
import ru.betterend.recipe.AnvilSmithingRecipe;
public class REIAnvilDisplay implements TransferRecipeDisplay {
private AnvilSmithingRecipe recipe;
private List<List<EntryStack>> input;
private List<EntryStack> output;
public REIAnvilDisplay(AnvilSmithingRecipe recipe) {
this.recipe = recipe;
this.input = EntryStack.ofIngredients(recipe.getPreviewInputs());
this.output = Collections.singletonList(EntryStack.create(recipe.getOutput()));
}
@Override
public @NotNull Optional<Identifier> getRecipeLocation() {
return Optional.ofNullable(recipe).map(Recipe::getId);
}
@Override
public @NotNull List<List<EntryStack>> getInputEntries() {
return this.input;
}
@Override
public @NotNull List<List<EntryStack>> getResultingEntries() {
return Collections.singletonList(output);
}
@Override
public @NotNull Identifier getRecipeCategory() {
return AnvilSmithingRecipe.ID;
}
@Override
public @NotNull List<List<EntryStack>> getRequiredEntries() {
return this.input;
}
@Override
public int getWidth() {
return 2;
}
@Override
public int getHeight() {
return 1;
}
@Override
public List<List<EntryStack>> getOrganisedInputEntries(ContainerInfo<ScreenHandler> containerInfo,
ScreenHandler container) {
return this.input;
}
}

View file

@ -11,5 +11,4 @@ public class REIContainer implements Runnable {
public void run() {
ContainerInfoHandler.registerContainerInfo(AlloyingRecipe.ID, CraftingContainerInfoWrapper.create(EndStoneSmelterScreenHandler.class));
}
}

View file

@ -3,19 +3,28 @@ package ru.betterend.compat;
import me.shedaniel.rei.api.EntryStack;
import me.shedaniel.rei.api.RecipeHelper;
import me.shedaniel.rei.api.plugins.REIPluginV0;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Blocks;
import net.minecraft.recipe.BlastingRecipe;
import net.minecraft.util.Identifier;
import ru.betterend.BetterEnd;
import ru.betterend.recipe.AlloyingRecipe;
import ru.betterend.recipe.AnvilSmithingRecipe;
import ru.betterend.registry.BlockRegistry;
@Environment(EnvType.CLIENT)
public class REIPlugin implements REIPluginV0 {
public final static Identifier PLUGIN_ID = BetterEnd.makeID("rei_plugin");
public final static Identifier ALLOING = AlloyingRecipe.ID;
public final static Identifier SMITHING = AlloyingRecipe.ID;
public final static EntryStack END_STONE_SMELTER = EntryStack.create(BlockRegistry.END_STONE_SMELTER);
public final static EntryStack ANVIL = EntryStack.create(Blocks.ANVIL);
@Override
public Identifier getPluginIdentifier() {
@ -24,17 +33,21 @@ public class REIPlugin implements REIPluginV0 {
@Override
public void registerRecipeDisplays(RecipeHelper recipeHelper) {
recipeHelper.registerRecipes(AlloyingRecipe.ID, AlloyingRecipe.class, REIAlloyingDisplay::new);
recipeHelper.registerRecipes(AlloyingRecipe.ID, BlastingRecipe.class, REIAlloyingDisplay::new);
recipeHelper.registerRecipes(ALLOING, AlloyingRecipe.class, REIAlloyingDisplay::new);
recipeHelper.registerRecipes(ALLOING, BlastingRecipe.class, REIAlloyingDisplay::new);
recipeHelper.registerRecipes(SMITHING, AnvilSmithingRecipe.class, REIAnvilDisplay::new);
}
@Override
public void registerOthers(RecipeHelper recipeHelper) {
recipeHelper.registerWorkingStations(AlloyingRecipe.ID, END_STONE_SMELTER);
recipeHelper.registerWorkingStations(ALLOING, END_STONE_SMELTER);
recipeHelper.registerWorkingStations(SMITHING, ANVIL);
recipeHelper.removeAutoCraftButton(SMITHING);
}
@Override
public void registerPluginCategories(RecipeHelper recipeHelper) {
recipeHelper.registerCategory(new REIAlloyingCategory());
recipeHelper.registerCategories(new REIAlloyingCategory(),
new REIAnvilCategory());
}
}

View file

@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.recipebook.ClientRecipeBook;
import net.minecraft.client.recipebook.RecipeBookGroup;
import net.minecraft.recipe.Recipe;
import ru.betterend.recipe.AlloyingRecipe;
@Mixin(ClientRecipeBook.class)

View file

@ -1,8 +1,5 @@
package ru.betterend.mixin.common;
import java.util.List;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -10,16 +7,19 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.block.AnvilBlock;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeManager;
import net.minecraft.screen.AnvilScreenHandler;
import net.minecraft.screen.ForgingScreenHandler;
import net.minecraft.screen.Property;
import net.minecraft.screen.ScreenHandlerContext;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.tag.BlockTags;
import net.minecraft.world.World;
import ru.betterend.recipe.AnvilSmithingRecipe;
@Mixin(AnvilScreenHandler.class)
@ -29,48 +29,65 @@ public abstract class AnvilScreenHandlerMixin extends ForgingScreenHandler {
private final RecipeManager recipeManager = this.world.getRecipeManager();
private AnvilSmithingRecipe currentRecipe;
@Final
@Shadow
private Property levelCost;
public AnvilScreenHandlerMixin(ScreenHandlerType<?> type, int syncId, PlayerInventory playerInventory,
ScreenHandlerContext context) {
super(type, syncId, playerInventory, context);
}
@Inject(method = "canTakeOutput", at = @At("RETURN"))
@Shadow
public abstract void updateResult();
@Inject(method = "canTakeOutput", at = @At("HEAD"), cancellable = true)
protected void canTakeOutput(PlayerEntity player, boolean present, CallbackInfoReturnable<Boolean> info) {
if (!info.getReturnValue()) {
info.setReturnValue(currentRecipe != null && !currentRecipe.craft(input, player).isEmpty());
if (currentRecipe != null) {
ItemStack output = this.currentRecipe.craft(input, player);
if (!output.isEmpty()) {
info.setReturnValue(true);
info.cancel();
}
}
}
@Inject(method = "onTakeOutput", at = @At("HEAD"), cancellable = true)
protected void onTakeOutput(PlayerEntity player, ItemStack stack, CallbackInfoReturnable<ItemStack> info) {
if (currentRecipe != null) {
this.input.getStack(0).decrement(1);
if (!currentRecipe.matches(input)) {
this.currentRecipe = null;
this.input.getStack(1).decrement(1);
this.updateResult();
this.context.run((world, blockPos) -> {
BlockState anvilState = world.getBlockState(blockPos);
if (!player.abilities.creativeMode && anvilState.isIn(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) {
BlockState landingState = AnvilBlock.getLandingState(anvilState);
if (landingState == null) {
world.removeBlock(blockPos, false);
world.syncWorldEvent(1029, blockPos, 0);
} else {
world.setBlockState(blockPos, landingState, 2);
world.syncWorldEvent(1030, blockPos, 0);
}
} else {
world.syncWorldEvent(1030, blockPos, 0);
}
});
info.setReturnValue(stack);
info.cancel();
}
}
@Inject(method = "updateResult", at = @At("HEAD"), cancellable = true)
public void updateResult(CallbackInfo info) {
this.currentRecipe = null;
List<AnvilSmithingRecipe> recipes = this.recipeManager.listAllOfType(AnvilSmithingRecipe.TYPE);
for (AnvilSmithingRecipe entry : recipes) {
if (entry.matches(input)) {
this.currentRecipe = entry;
break;
}
}
public void updateOutput(CallbackInfo info) {
this.currentRecipe = this.recipeManager.getFirstMatch(AnvilSmithingRecipe.TYPE, input, world).orElse(null);
if (currentRecipe != null) {
this.levelCost.set(0);
this.output.setStack(0, currentRecipe.getOutput());
this.output.setStack(0, currentRecipe.craft(input));
this.sendContentUpdates();
info.cancel();
}
}
@Inject(method = "setNewItemName", at = @At("HEAD"), cancellable = true)
public void setNewItemName(String string, CallbackInfo info) {
if (currentRecipe != null) {
info.cancel();
}
}
}

View file

@ -28,7 +28,7 @@ public class AlloyingRecipe implements Recipe<Inventory> {
public final static String GROUP = "alloying";
public final static RecipeType<AlloyingRecipe> TYPE = EndRecipeManager.registerType(GROUP);
public final static Serializer SERIALIZER = EndRecipeManager.registerSerializer(GROUP, new Serializer());
public final static Identifier ID = BetterEnd.makeID("alloying");
public final static Identifier ID = BetterEnd.makeID(GROUP);
protected final RecipeType<?> type;
protected final Identifier id;
@ -39,7 +39,6 @@ public class AlloyingRecipe implements Recipe<Inventory> {
protected final float experience;
protected final int smeltTime;
public AlloyingRecipe(Identifier id, String group, Ingredient primaryInput, Ingredient secondaryInput, ItemStack output, float experience, int smeltTime) {
this.group = group;
this.id = id;
@ -59,6 +58,7 @@ public class AlloyingRecipe implements Recipe<Inventory> {
return this.smeltTime;
}
@Override
public DefaultedList<Ingredient> getPreviewInputs() {
DefaultedList<Ingredient> defaultedList = DefaultedList.of();
defaultedList.add(primaryInput);

View file

@ -4,6 +4,7 @@ import com.google.gson.JsonObject;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
@ -15,14 +16,19 @@ import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.RecipeType;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import ru.betterend.BetterEnd;
import ru.betterend.registry.ItemTagRegistry;
public class AnvilSmithingRecipe implements Recipe<Inventory> {
public final static RecipeType<AnvilSmithingRecipe> TYPE = EndRecipeManager.registerType("smithing");
public final static Serializer SERIALIZER = EndRecipeManager.registerSerializer("smithing", new Serializer());
public final static String GROUP = "smithing";
public final static RecipeType<AnvilSmithingRecipe> TYPE = EndRecipeManager.registerType(GROUP);
public final static Serializer SERIALIZER = EndRecipeManager.registerSerializer(GROUP, new Serializer());
public final static Identifier ID = BetterEnd.makeID(GROUP);
private final Identifier id;
private final Ingredient input;
@ -43,14 +49,9 @@ public class AnvilSmithingRecipe implements Recipe<Inventory> {
return SERIALIZER;
}
@Override
public boolean isIgnoredInRecipeBook() {
return false;
}
@Override
public ItemStack getOutput() {
return ItemStack.EMPTY;
return this.output;
}
@Override
@ -60,35 +61,39 @@ public class AnvilSmithingRecipe implements Recipe<Inventory> {
@Override
public ItemStack craft(Inventory craftingInventory) {
if (!matches(craftingInventory)) return ItemStack.EMPTY;
ItemStack hammer = craftingInventory.getStack(1);
int damage = hammer.getDamage() + this.damage;
if (damage >= hammer.getMaxDamage()) return ItemStack.EMPTY;
hammer.setDamage(damage);
return this.output.copy();
}
public ItemStack craft(Inventory craftingInventory, PlayerEntity player) {
if (!matches(craftingInventory)) return ItemStack.EMPTY;
ItemStack hammer = craftingInventory.getStack(1);
if (!player.isCreative()) {
ItemStack hammer = craftingInventory.getStack(0);
int damage = hammer.getDamage() + this.damage;
if (damage >= hammer.getMaxDamage()) return ItemStack.EMPTY;
hammer.damage(this.damage, player, ((entity) -> {
hammer.damage(this.damage, player, entity -> {
entity.sendEquipmentBreakStatus(null);
}));
return this.output.copy();
});
}
return this.craft(craftingInventory);
}
public boolean matches(Inventory craftingInventory) {
ItemStack hammer = craftingInventory.getStack(1);
System.out.println(ItemTagRegistry.HAMMERS.values());
ItemStack hammer = craftingInventory.getStack(0);
if (hammer.isEmpty() || !ItemTagRegistry.HAMMERS.contains(hammer.getItem())) {
return false;
}
int level = ((ToolItem) hammer.getItem()).getMaterial().getMiningLevel();
return level >= this.level && this.input.test(craftingInventory.getStack(0));
return level >= this.level && this.input.test(craftingInventory.getStack(1));
}
@Override
public DefaultedList<Ingredient> getPreviewInputs() {
DefaultedList<Ingredient> defaultedList = DefaultedList.of();
defaultedList.add(Ingredient.ofStacks(ItemTagRegistry.HAMMERS.values().stream().filter(hammer -> {
return ((ToolItem) hammer).getMaterial().getMiningLevel() >= level;
}).map(ItemStack::new)));
defaultedList.add(input);
return defaultedList;
}
@Override
@ -107,6 +112,11 @@ public class AnvilSmithingRecipe implements Recipe<Inventory> {
return TYPE;
}
@Override
public boolean isIgnoredInRecipeBook() {
return true;
}
public static class Serializer implements RecipeSerializer<AnvilSmithingRecipe> {
@Override
public AnvilSmithingRecipe read(Identifier id, JsonObject json) {

View file

@ -70,7 +70,7 @@ public class ItemRegistry {
public static ToolItem IRON_HAMMER = registerTool("iron_hammer", new EndHammer(ToolMaterials.IRON, 5.0F, -3.2F, 0.2D, makeSettings()));
public static ToolItem GOLDEN_HAMMER = registerTool("golden_hammer", new EndHammer(ToolMaterials.GOLD, 4.5F, -3.4F, 0.3D, makeSettings()));
public static ToolItem DIAMOND_HAMMER = registerTool("diamond_hammer", new EndHammer(ToolMaterials.DIAMOND, 5.5F, -3.1F, 0.2D, makeSettings()));
public static ToolItem NETHERITE_HAMMER = registerTool("netherite_hammer", new EndHammer(ToolMaterials.DIAMOND, 6.0F, -3.0F, 0.2D, makeSettings()));
public static ToolItem NETHERITE_HAMMER = registerTool("netherite_hammer", new EndHammer(ToolMaterials.NETHERITE, 5.0F, -3.0F, 0.2D, makeSettings()));
protected static Item registerItem(String name, Item item) {
if (item != Items.AIR) {

View file

@ -5,9 +5,11 @@ import java.util.Arrays;
import net.fabricmc.fabric.api.tag.TagRegistry;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
import net.fabricmc.fabric.impl.tool.attribute.handlers.ModdedToolsVanillaBlocksToolHandler;
import net.minecraft.item.Item;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
import ru.betterend.BetterEnd;
public class ItemTagRegistry {

View file

@ -0,0 +1,11 @@
{
"replace": false,
"values": [
"betterend:iron_hammer",
"betterend:golden_hammer",
"betterend:diamond_hammer",
"betterend:netherite_hammer",
"betterend:terminite_hammer",
"betterend:aeternium_hammer"
]
}