LTCatt 6 лет назад
Родитель
Сommit
77780e78a7

+ 310 - 0
src/main/java/com/hexdragon/enchrebirth/block/AnvilContainerRe.java

@@ -0,0 +1,310 @@
+package com.hexdragon.enchrebirth.block;
+
+import net.minecraft.block.AnvilBlock;
+import net.minecraft.block.BlockState;
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.enchantment.EnchantmentHelper;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.container.AbstractRepairContainer;
+import net.minecraft.inventory.container.ContainerType;
+import net.minecraft.item.EnchantedBookItem;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.tags.BlockTags;
+import net.minecraft.util.IWorldPosCallable;
+import net.minecraft.util.IntReferenceHolder;
+import net.minecraft.util.text.StringTextComponent;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.api.distmarker.OnlyIn;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.AnvilUpdateEvent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.annotation.Nonnull;
+import java.util.Map;
+
+public class AnvilContainerRe extends AbstractRepairContainer {
+    private static final Logger LOGGER = LogManager.getLogger();
+    public int materialCost;
+    private String repairedItemName;
+    private final IntReferenceHolder maximumCost = IntReferenceHolder.single();
+
+    public AnvilContainerRe(int id, PlayerInventory playerInventory) {
+        this(id, playerInventory, IWorldPosCallable.DUMMY);
+    }
+
+    public AnvilContainerRe(int id, PlayerInventory playerInventory, IWorldPosCallable worldPosCallable) {
+        super(ContainerType.ANVIL, id, playerInventory, worldPosCallable);
+        this.trackInt(this.maximumCost);
+    }
+
+    protected boolean func_230302_a_(BlockState p_230302_1_) {
+        return p_230302_1_.isIn(BlockTags.ANVIL);
+    }
+
+    protected boolean func_230303_b_(PlayerEntity p_230303_1_, boolean p_230303_2_) {
+        return (p_230303_1_.abilities.isCreativeMode || p_230303_1_.experienceLevel >= this.maximumCost.get()) && this.maximumCost.get() > 0;
+    }
+
+    protected ItemStack func_230301_a_(PlayerEntity p_230301_1_, ItemStack p_230301_2_) {
+        if (!p_230301_1_.abilities.isCreativeMode) {
+            p_230301_1_.addExperienceLevel(-this.maximumCost.get());
+        }
+
+        float breakChance = net.minecraftforge.common.ForgeHooks.onAnvilRepair(p_230301_1_, p_230301_2_, AnvilContainerRe.this.field_234643_d_.getStackInSlot(0), AnvilContainerRe.this.field_234643_d_.getStackInSlot(1));
+
+        this.field_234643_d_.setInventorySlotContents(0, ItemStack.EMPTY);
+        if (this.materialCost > 0) {
+            ItemStack itemstack = this.field_234643_d_.getStackInSlot(1);
+            if (!itemstack.isEmpty() && itemstack.getCount() > this.materialCost) {
+                itemstack.shrink(this.materialCost);
+                this.field_234643_d_.setInventorySlotContents(1, itemstack);
+            } else {
+                this.field_234643_d_.setInventorySlotContents(1, ItemStack.EMPTY);
+            }
+        } else {
+            this.field_234643_d_.setInventorySlotContents(1, ItemStack.EMPTY);
+        }
+
+        this.maximumCost.set(0);
+        this.field_234644_e_.consume((p_234633_1_, p_234633_2_) -> {
+            BlockState blockstate = p_234633_1_.getBlockState(p_234633_2_);
+            if (!p_230301_1_.abilities.isCreativeMode && blockstate.isIn(BlockTags.ANVIL) && p_230301_1_.getRNG().nextFloat() < breakChance) {
+                BlockState blockstate1 = AnvilBlock.damage(blockstate);
+                if (blockstate1 == null) {
+                    p_234633_1_.removeBlock(p_234633_2_, false);
+                    p_234633_1_.playEvent(1029, p_234633_2_, 0);
+                } else {
+                    p_234633_1_.setBlockState(p_234633_2_, blockstate1, 2);
+                    p_234633_1_.playEvent(1030, p_234633_2_, 0);
+                }
+            } else {
+                p_234633_1_.playEvent(1030, p_234633_2_, 0);
+            }
+
+        });
+        return p_230301_2_;
+    }
+
+    /**
+     * called when the Anvil Input Slot changes, calculates the new result and puts it in the output slot
+     */
+    public void updateRepairOutput() {
+        ItemStack itemstack = this.field_234643_d_.getStackInSlot(0);
+        this.maximumCost.set(1);
+        int i = 0;
+        int j = 0;
+        int k = 0;
+        if (itemstack.isEmpty()) {
+            this.field_234642_c_.setInventorySlotContents(0, ItemStack.EMPTY);
+            this.maximumCost.set(0);
+        } else {
+            ItemStack itemstack1 = itemstack.copy();
+            ItemStack itemstack2 = this.field_234643_d_.getStackInSlot(1);
+            Map<Enchantment, Integer> map = EnchantmentHelper.getEnchantments(itemstack1);
+            j = j + itemstack.getRepairCost() + (itemstack2.isEmpty() ? 0 : itemstack2.getRepairCost());
+            this.materialCost = 0;
+            boolean flag = false;
+
+            if (!itemstack2.isEmpty()) {
+                if (!onAnvilChange(this, itemstack, itemstack2, field_234642_c_, repairedItemName, j)) return;
+                flag = itemstack2.getItem() == Items.ENCHANTED_BOOK && !EnchantedBookItem.getEnchantments(itemstack2).isEmpty();
+                if (itemstack1.isDamageable() && itemstack1.getItem().getIsRepairable(itemstack, itemstack2)) {
+                    int l2 = Math.min(itemstack1.getDamage(), itemstack1.getMaxDamage() / 4);
+                    if (l2 <= 0) {
+                        this.field_234642_c_.setInventorySlotContents(0, ItemStack.EMPTY);
+                        this.maximumCost.set(0);
+                        return;
+                    }
+
+                    int i3;
+                    for (i3 = 0; l2 > 0 && i3 < itemstack2.getCount(); ++i3) {
+                        int j3 = itemstack1.getDamage() - l2;
+                        itemstack1.setDamage(j3);
+                        ++i;
+                        l2 = Math.min(itemstack1.getDamage(), itemstack1.getMaxDamage() / 4);
+                    }
+
+                    this.materialCost = i3;
+                } else {
+                    if (!flag && (itemstack1.getItem() != itemstack2.getItem() || !itemstack1.isDamageable())) {
+                        this.field_234642_c_.setInventorySlotContents(0, ItemStack.EMPTY);
+                        this.maximumCost.set(0);
+                        return;
+                    }
+
+                    if (itemstack1.isDamageable() && !flag) {
+                        int l = itemstack.getMaxDamage() - itemstack.getDamage();
+                        int i1 = itemstack2.getMaxDamage() - itemstack2.getDamage();
+                        int j1 = i1 + itemstack1.getMaxDamage() * 12 / 100;
+                        int k1 = l + j1;
+                        int l1 = itemstack1.getMaxDamage() - k1;
+                        if (l1 < 0) {
+                            l1 = 0;
+                        }
+
+                        if (l1 < itemstack1.getDamage()) {
+                            itemstack1.setDamage(l1);
+                            i += 2;
+                        }
+                    }
+
+                    Map<Enchantment, Integer> map1 = EnchantmentHelper.getEnchantments(itemstack2);
+                    boolean flag2 = false;
+                    boolean flag3 = false;
+
+                    for (Enchantment enchantment1 : map1.keySet()) {
+                        if (enchantment1 != null) {
+                            int i2 = map.getOrDefault(enchantment1, 0);
+                            int j2 = map1.get(enchantment1);
+                            j2 = i2 == j2 ? j2 + 1 : Math.max(j2, i2);
+                            boolean flag1 = enchantment1.canApply(itemstack);
+                            if (this.field_234645_f_.abilities.isCreativeMode || itemstack.getItem() == Items.ENCHANTED_BOOK) {
+                                flag1 = true;
+                            }
+
+                            for (Enchantment enchantment : map.keySet()) {
+                                if (enchantment != enchantment1 && !enchantment1.isCompatibleWith(enchantment)) {
+                                    flag1 = false;
+                                    ++i;
+                                }
+                            }
+
+                            if (!flag1) {
+                                flag3 = true;
+                            } else {
+                                flag2 = true;
+                                if (j2 > enchantment1.getMaxLevel()) {
+                                    j2 = enchantment1.getMaxLevel();
+                                }
+
+                                map.put(enchantment1, j2);
+                                int k3 = 0;
+                                switch (enchantment1.getRarity()) {
+                                    case COMMON:
+                                        k3 = 1;
+                                        break;
+                                    case UNCOMMON:
+                                        k3 = 2;
+                                        break;
+                                    case RARE:
+                                        k3 = 4;
+                                        break;
+                                    case VERY_RARE:
+                                        k3 = 8;
+                                }
+
+                                if (flag) {
+                                    k3 = Math.max(1, k3 / 2);
+                                }
+
+                                i += k3 * j2;
+                                if (itemstack.getCount() > 1) {
+                                    i = 40;
+                                }
+                            }
+                        }
+                    }
+
+                    if (flag3 && !flag2) {
+                        this.field_234642_c_.setInventorySlotContents(0, ItemStack.EMPTY);
+                        this.maximumCost.set(0);
+                        return;
+                    }
+                }
+            }
+
+            if (StringUtils.isBlank(this.repairedItemName)) {
+                if (itemstack.hasDisplayName()) {
+                    k = 1;
+                    i += k;
+                    itemstack1.clearCustomName();
+                }
+            } else if (!this.repairedItemName.equals(itemstack.getDisplayName().getString())) {
+                k = 1;
+                i += k;
+                itemstack1.setDisplayName(new StringTextComponent(this.repairedItemName));
+            }
+            if (flag && !itemstack1.isBookEnchantable(itemstack2)) itemstack1 = ItemStack.EMPTY;
+
+            this.maximumCost.set(j + i);
+            if (i <= 0) {
+                itemstack1 = ItemStack.EMPTY;
+            }
+
+            if (k == i && k > 0 && this.maximumCost.get() >= 40) {
+                this.maximumCost.set(39);
+            }
+
+            if (this.maximumCost.get() >= 40 && !this.field_234645_f_.abilities.isCreativeMode) {
+                itemstack1 = ItemStack.EMPTY;
+            }
+
+            if (!itemstack1.isEmpty()) {
+                int k2 = itemstack1.getRepairCost();
+                if (!itemstack2.isEmpty() && k2 < itemstack2.getRepairCost()) {
+                    k2 = itemstack2.getRepairCost();
+                }
+
+                if (k != i || k == 0) {
+                    k2 = getNewRepairCost(k2);
+                }
+
+                itemstack1.setRepairCost(k2);
+                EnchantmentHelper.setEnchantments(map, itemstack1);
+            }
+
+            this.field_234642_c_.setInventorySlotContents(0, itemstack1);
+            this.detectAndSendChanges();
+        }
+    }
+
+    // 从 ForgeHooks 中复制
+    public static boolean onAnvilChange(AnvilContainerRe container, @Nonnull ItemStack left, @Nonnull ItemStack right, IInventory outputSlot, String name, int baseCost) {
+        AnvilUpdateEvent e = new AnvilUpdateEvent(left, right, name, baseCost);
+        if (MinecraftForge.EVENT_BUS.post(e)) return false;
+        if (e.getOutput().isEmpty()) return true;
+
+        outputSlot.setInventorySlotContents(0, e.getOutput());
+        container.setMaximumCost(e.getCost());
+        container.materialCost = e.getMaterialCost();
+        return false;
+    }
+
+    public static int getNewRepairCost(int oldRepairCost) {
+        return oldRepairCost * 2 + 1;
+    }
+
+    /**
+     * used by the Anvil GUI to update the Item Name being typed by the player
+     */
+    public void updateItemName(String newName) {
+        this.repairedItemName = newName;
+        if (this.getSlot(2).getHasStack()) {
+            ItemStack itemstack = this.getSlot(2).getStack();
+            if (StringUtils.isBlank(newName)) {
+                itemstack.clearCustomName();
+            } else {
+                itemstack.setDisplayName(new StringTextComponent(this.repairedItemName));
+            }
+        }
+
+        this.updateRepairOutput();
+    }
+
+    /**
+     * Get's the maximum xp cost
+     */
+    @OnlyIn(Dist.CLIENT)
+    public int getMaximumCost() {
+        return this.maximumCost.get();
+    }
+
+    public void setMaximumCost(int value) {
+        this.maximumCost.set(value);
+    }
+}

+ 122 - 0
src/main/java/com/hexdragon/enchrebirth/block/AnvilScreenRe.java

@@ -0,0 +1,122 @@
+package com.hexdragon.enchrebirth.block;
+
+import com.mojang.blaze3d.matrix.MatrixStack;
+import com.mojang.blaze3d.systems.RenderSystem;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.screen.inventory.AbstractRepairScreen;
+import net.minecraft.client.gui.widget.TextFieldWidget;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.inventory.container.Container;
+import net.minecraft.inventory.container.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.play.client.CRenameItemPacket;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TranslationTextComponent;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.api.distmarker.OnlyIn;
+
+@OnlyIn(Dist.CLIENT)
+public class AnvilScreenRe extends AbstractRepairScreen<AnvilContainerRe> {
+    private static final ResourceLocation ANVIL_RESOURCE = new ResourceLocation("textures/gui/container/anvil.png");
+    private static final ITextComponent field_243333_B = new TranslationTextComponent("container.repair.expensive");
+    private TextFieldWidget nameField;
+
+    public AnvilScreenRe(AnvilContainerRe container, PlayerInventory playerInventory, ITextComponent title) {
+        super(container, playerInventory, title, ANVIL_RESOURCE);
+        this.titleX = 60;
+    }
+
+    protected void initFields() {
+        this.minecraft.keyboardListener.enableRepeatEvents(true);
+        int i = (this.width - this.xSize) / 2;
+        int j = (this.height - this.ySize) / 2;
+        this.nameField = new TextFieldWidget(this.font, i + 62, j + 24, 103, 12, new TranslationTextComponent("container.repair"));
+        this.nameField.setCanLoseFocus(false);
+        this.nameField.setTextColor(-1);
+        this.nameField.setDisabledTextColour(-1);
+        this.nameField.setEnableBackgroundDrawing(false);
+        this.nameField.setMaxStringLength(35);
+        this.nameField.setResponder(this::renameItem);
+        this.children.add(this.nameField);
+        this.setFocusedDefault(this.nameField);
+    }
+
+    public void resize(Minecraft minecraft, int width, int height) {
+        String s = this.nameField.getText();
+        this.init(minecraft, width, height);
+        this.nameField.setText(s);
+    }
+
+    public void onClose() {
+        super.onClose();
+        this.minecraft.keyboardListener.enableRepeatEvents(false);
+    }
+
+    public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+        if (keyCode == 256) {
+            this.minecraft.player.closeScreen();
+        }
+
+        return !this.nameField.keyPressed(keyCode, scanCode, modifiers) && !this.nameField.canWrite() ? super.keyPressed(keyCode, scanCode, modifiers) : true;
+    }
+
+    private void renameItem(String name) {
+        if (!name.isEmpty()) {
+            String s = name;
+            Slot slot = this.container.getSlot(0);
+            if (slot != null && slot.getHasStack() && !slot.getStack().hasDisplayName() && name.equals(slot.getStack().getDisplayName().getString())) {
+                s = "";
+            }
+
+            this.container.updateItemName(s);
+            this.minecraft.player.connection.sendPacket(new CRenameItemPacket(s));
+        }
+    }
+
+    protected void drawGuiContainerForegroundLayer(MatrixStack matrixStack, int x, int y) {
+        RenderSystem.disableBlend();
+        super.drawGuiContainerForegroundLayer(matrixStack, x, y);
+        int i = this.container.getMaximumCost();
+        if (i > 0) {
+            int j = 8453920;
+            ITextComponent itextcomponent;
+            if (i >= 40 && !this.minecraft.player.abilities.isCreativeMode) {
+                itextcomponent = field_243333_B;
+                j = 16736352;
+            } else if (!this.container.getSlot(2).getHasStack()) {
+                itextcomponent = null;
+            } else {
+                itextcomponent = new TranslationTextComponent("container.repair.cost", i);
+                if (!this.container.getSlot(2).canTakeStack(this.playerInventory.player)) {
+                    j = 16736352;
+                }
+            }
+
+            if (itextcomponent != null) {
+                int k = this.xSize - 8 - this.font.getStringPropertyWidth(itextcomponent) - 2;
+                int l = 69;
+                fill(matrixStack, k - 2, 67, this.xSize - 8, 79, 1325400064);
+                this.font.func_243246_a(matrixStack, itextcomponent, (float) k, 69.0F, j);
+            }
+        }
+
+    }
+
+    public void renderNameField(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
+        this.nameField.render(matrixStack, mouseX, mouseY, partialTicks);
+    }
+
+    /**
+     * Sends the contents of an inventory slot to the client-side Container. This doesn't have to match the actual
+     * contents of that slot.
+     */
+    public void sendSlotContents(Container containerToSend, int slotInd, ItemStack stack) {
+        if (slotInd == 0) {
+            this.nameField.setText(stack.isEmpty() ? "" : stack.getDisplayName().getString());
+            this.nameField.setEnabled(!stack.isEmpty());
+            this.setListener(this.nameField);
+        }
+
+    }
+}

+ 32 - 0
src/main/java/com/hexdragon/enchrebirth/mixin/block/AnvilBlockMixin.java

@@ -0,0 +1,32 @@
+package com.hexdragon.enchrebirth.mixin.block;
+
+import com.hexdragon.enchrebirth.block.AnvilContainerRe;
+import net.minecraft.block.AnvilBlock;
+import net.minecraft.block.BlockState;
+import net.minecraft.block.FallingBlock;
+import net.minecraft.inventory.container.INamedContainerProvider;
+import net.minecraft.inventory.container.SimpleNamedContainerProvider;
+import net.minecraft.util.IWorldPosCallable;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.text.TranslationTextComponent;
+import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+@Mixin(AnvilBlock.class)
+public abstract class AnvilBlockMixin extends FallingBlock {
+    public AnvilBlockMixin(Properties properties) {super(properties);}
+
+    // 将铁砧的处理事件替换为 Mod 所提供的事件
+    @Inject(method = "getContainer", at = @At(value = "HEAD"), cancellable = true, locals = LocalCapture.CAPTURE_FAILEXCEPTION)
+    private void getContainer(BlockState state, World worldIn, BlockPos pos, CallbackInfoReturnable<INamedContainerProvider> cir) {
+        cir.setReturnValue(new SimpleNamedContainerProvider(
+                (id, inventory, player) -> new AnvilContainerRe(id, inventory, IWorldPosCallable.of(worldIn, pos)),
+                new TranslationTextComponent("block.minecraft.anvil")));
+        cir.cancel();
+    }
+
+}

+ 1 - 1
src/main/java/com/hexdragon/enchrebirth/mixin/GrindstoneBlockMixin.java → src/main/java/com/hexdragon/enchrebirth/mixin/block/GrindstoneBlockMixin.java

@@ -1,4 +1,4 @@
-package com.hexdragon.enchrebirth.mixin;
+package com.hexdragon.enchrebirth.mixin.block;
 
 import com.hexdragon.enchrebirth.block.GrindstoneContainerRe;
 import net.minecraft.block.BlockState;

+ 2 - 0
src/main/java/com/hexdragon/enchrebirth/registry/RegClientSetup.java

@@ -1,6 +1,7 @@
 package com.hexdragon.enchrebirth.registry;
 
 import com.hexdragon.enchrebirth.EnchRebirth;
+import com.hexdragon.enchrebirth.block.AnvilScreenRe;
 import com.hexdragon.enchrebirth.block.GrindstoneScreenRe;
 import net.minecraft.client.gui.ScreenManager;
 import net.minecraftforge.api.distmarker.Dist;
@@ -15,6 +16,7 @@ public class RegClientSetup {
     @SubscribeEvent
     public static void clientSetup(final FMLClientSetupEvent e) {
         ScreenManager.registerFactory(RegMain.containerGrindstone.get(), GrindstoneScreenRe::new);
+        ScreenManager.registerFactory(RegMain.containerAnvil.get(), AnvilScreenRe::new);
     }
 
 }

+ 2 - 0
src/main/java/com/hexdragon/enchrebirth/registry/RegMain.java

@@ -1,6 +1,7 @@
 package com.hexdragon.enchrebirth.registry;
 
 import com.hexdragon.enchrebirth.EnchRebirth;
+import com.hexdragon.enchrebirth.block.AnvilContainerRe;
 import com.hexdragon.enchrebirth.block.GrindstoneContainerRe;
 import net.minecraft.entity.player.PlayerInventory;
 import net.minecraft.inventory.container.ContainerType;
@@ -15,5 +16,6 @@ public class RegMain {
     // 容器
     public static final DeferredRegister<ContainerType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.CONTAINERS, EnchRebirth.MODID);
     public static final RegistryObject<ContainerType<GrindstoneContainerRe>> containerGrindstone = CONTAINERS.register("grindstone", () -> IForgeContainerType.create((int windowId, PlayerInventory inv, PacketBuffer data) -> new GrindstoneContainerRe(windowId, inv)));
+    public static final RegistryObject<ContainerType<AnvilContainerRe>> containerAnvil = CONTAINERS.register("anvil", () -> IForgeContainerType.create((int windowId, PlayerInventory inv, PacketBuffer data) -> new AnvilContainerRe(windowId, inv)));
 
 }

+ 2 - 1
src/main/resources/mixins.enchrebirth.json

@@ -4,6 +4,7 @@
   "compatibilityLevel": "JAVA_8",
   "mixins": [
     "RepairItemRecipeMixin",
-    "GrindstoneBlockMixin"
+    "block/GrindstoneBlockMixin",
+    "block/AnvilBlockMixin"
   ]
 }