Implemented enchanting pricing

This commit is contained in:
Andrew 2022-08-10 21:55:00 +07:00
parent 40c2ea09e4
commit e565bbf78c
6 changed files with 171 additions and 60 deletions

View file

@ -11,9 +11,7 @@ import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerLevelAccess;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
@ -26,11 +24,12 @@ import org.jetbrains.annotations.Nullable;
import xyz.nuark.enchantrium.Enchantrium;
import xyz.nuark.enchantrium.block.entity.ModBlockEntities;
import xyz.nuark.enchantrium.screen.EnchanterMenu;
import xyz.nuark.enchantrium.util.EnchantmentUtil;
import java.util.List;
public class EnchanterBlockEntity extends BlockEntity implements MenuProvider {
private final ItemStackHandler itemHandler = new ItemStackHandler(2) {
private final ItemStackHandler itemHandler = new ItemStackHandler(3) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
@ -71,7 +70,7 @@ public class EnchanterBlockEntity extends BlockEntity implements MenuProvider {
}
@Override
public void invalidateCaps() {
public void invalidateCaps() {
super.invalidateCaps();
lazyItemHandler.invalidate();
}
@ -105,18 +104,26 @@ public class EnchanterBlockEntity extends BlockEntity implements MenuProvider {
return itemHandler.getStackInSlot(0);
}
public void enchant(List<EnchantmentInstance> enchantments) {
if (itemHandler.extractItem(1, 1, true).is(Items.AIR)) {
return;
}
public ItemStack getEmeralds() {
return itemHandler.getStackInSlot(1);
}
public ItemStack getNetherite() {
return itemHandler.getStackInSlot(2);
}
public boolean enchant(List<EnchantmentInstance> enchantments, EnchantmentUtil.EnchantmentCost enchantmentCost, boolean setUnbreakable) {
ItemStack input = itemHandler.extractItem(0, 1, false);
itemHandler.extractItem(1, 1, false);
itemHandler.extractItem(1, enchantmentCost.lapis(), false);
itemHandler.extractItem(2, enchantmentCost.netherite(), false);
for (EnchantmentInstance enchantment : enchantments) {
input.enchant(enchantment.enchantment, enchantment.level);
}
input.getOrCreateTag().putBoolean("Unbreakable", setUnbreakable);
itemHandler.setStackInSlot(0, input);
itemHandler.insertItem(0, input, false);
return true;
}
}

View file

@ -1,36 +1,36 @@
package xyz.nuark.enchantrium.network.message;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.Level;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.registries.ForgeRegistries;
import xyz.nuark.enchantrium.Enchantrium;
import xyz.nuark.enchantrium.block.entity.custom.EnchanterBlockEntity;
import xyz.nuark.enchantrium.network.Networking;
import xyz.nuark.enchantrium.util.EnchantmentUtil;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
public class PacketEnchantItem {
private final BlockPos blockEntityPos;
private final List<EnchantmentInstance> enchantments;
private final EnchantmentUtil.EnchantmentCost enchantmentCost;
private final boolean unbreakingSet;
public PacketEnchantItem(BlockPos blockEntityPos, List<EnchantmentInstance> enchantments) {
public PacketEnchantItem(BlockPos blockEntityPos, List<EnchantmentInstance> enchantments, EnchantmentUtil.EnchantmentCost enchantmentCost, boolean unbreakingSet) {
this.blockEntityPos = blockEntityPos;
this.enchantments = enchantments;
this.enchantmentCost = enchantmentCost;
this.unbreakingSet = unbreakingSet;
}
public boolean handle(Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context ctx = supplier.get();
ctx.enqueueWork(() -> {
EnchanterBlockEntity ebe = (EnchanterBlockEntity)ctx.getSender().level.getBlockEntity(blockEntityPos);
ebe.enchant(enchantments);
if (ebe.enchant(enchantments, enchantmentCost, unbreakingSet)) {
ctx.getSender().giveExperienceLevels(-enchantmentCost.levels());
}
});
return true;
}
@ -41,6 +41,10 @@ public class PacketEnchantItem {
buf.writeResourceLocation(ForgeRegistries.ENCHANTMENTS.getKey(enchantment.enchantment));
buf.writeVarInt(enchantment.level);
});
friendlyByteBuf.writeVarInt(enchantmentCost.levels());
friendlyByteBuf.writeVarInt(enchantmentCost.lapis());
friendlyByteBuf.writeVarInt(enchantmentCost.netherite());
friendlyByteBuf.writeBoolean(unbreakingSet);
}
public static PacketEnchantItem decode(FriendlyByteBuf friendlyByteBuf) {
@ -49,7 +53,13 @@ public class PacketEnchantItem {
friendlyByteBuf.readList((buf) -> new EnchantmentInstance(
ForgeRegistries.ENCHANTMENTS.getValue(buf.readResourceLocation()),
buf.readVarInt()
))
)),
new EnchantmentUtil.EnchantmentCost(
friendlyByteBuf.readVarInt(),
friendlyByteBuf.readVarInt(),
friendlyByteBuf.readVarInt()
),
friendlyByteBuf.readBoolean()
);
}
}

View file

@ -17,7 +17,6 @@ import net.minecraftforge.common.Tags;
import net.minecraftforge.items.CapabilityItemHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.nuark.enchantrium.Enchantrium;
import xyz.nuark.enchantrium.block.ModBlocks;
import xyz.nuark.enchantrium.block.entity.custom.EnchanterBlockEntity;
import xyz.nuark.enchantrium.network.Networking;
@ -33,6 +32,7 @@ public class EnchanterMenu extends AbstractContainerMenu {
private ItemStack inputStack = new ItemStack(Items.AIR);
private List<EnchantmentInstance> enchantments = Lists.newArrayList();
private boolean unbreakingSet = false;
private int currentEnchantmentIndex = -1;
private final Object lock = new Object();
@ -42,7 +42,7 @@ public class EnchanterMenu extends AbstractContainerMenu {
public EnchanterMenu(int containerId, Inventory inv, BlockEntity entity) {
super(ModMenuTypes.ENCHANTER_MENU.get(), containerId);
checkContainerSize(inv, 2);
checkContainerSize(inv, 3);
blockEntity = ((EnchanterBlockEntity) entity);
this.level = inv.player.level;
@ -55,8 +55,12 @@ public class EnchanterMenu extends AbstractContainerMenu {
stack -> EnchantmentUtil.canBeEnchanted(stack) && !stack.isEnchanted() && !stack.is(Items.BOOK)
));
this.addSlot(new FilteredSlot(
handler, 1, 8, 43,
stack -> stack.is(Tags.Items.GEMS_EMERALD) || stack.is(Tags.Items.INGOTS_NETHERITE)
handler, 1, 31, 19,
stack -> stack.is(Tags.Items.STORAGE_BLOCKS_LAPIS)
));
this.addSlot(new FilteredSlot(
handler, 2, 54, 19,
stack -> stack.is(Tags.Items.INGOTS_NETHERITE)
));
});
}
@ -79,33 +83,55 @@ public class EnchanterMenu extends AbstractContainerMenu {
}
}
public boolean unbreakable() {
return unbreakingSet;
}
public EnchantmentUtil.EnchantmentCost getEnchantmentRequirements() {
return EnchantmentUtil.calculateEnchantmentPrice(this.enchantments.stream().filter(e -> e.level > 0).toList(), unbreakingSet);
}
public boolean requirementsMet(Player player, EnchantmentUtil.EnchantmentCost enchantmentRequirements) {
return player.experienceLevel >= enchantmentRequirements.levels()
&& blockEntity.getEmeralds().getCount() >= enchantmentRequirements.lapis()
&& blockEntity.getNetherite().getCount() >= enchantmentRequirements.netherite();
}
@Override
public boolean clickMenuButton(Player player, int buttonId) {
if (buttonId < 0 || buttonId >= 5) {
if (buttonId < 0 || buttonId >= 6) {
Util.logAndPauseIfInIde(player.getName() + " pressed invalid button id: " + buttonId);
return false;
}
Enchantrium.LOGGER.debug("{} clicked button {}", player.getName(), buttonId);
synchronized (lock) {
if (buttonId == 0) {
Networking.sendToServer(new PacketEnchantItem(blockEntity.getBlockPos(), this.enchantments.stream().filter(e -> e.level > 0).toList()));
var enchantments = this.enchantments.stream().filter(e -> e.level > 0).toList();
if (enchantments.isEmpty()) return true;
Networking.sendToServer(new PacketEnchantItem(
blockEntity.getBlockPos(),
enchantments,
getEnchantmentRequirements(),
unbreakingSet
));
} else if (buttonId == 1) {
currentEnchantmentIndex = (currentEnchantmentIndex + 1) % enchantments.size();
} else if (buttonId == 2) {
currentEnchantmentIndex = (currentEnchantmentIndex - 1 + enchantments.size()) % enchantments.size();
} else if (buttonId == 2) {
currentEnchantmentIndex = (currentEnchantmentIndex + 1) % enchantments.size();
} else if (buttonId == 3) {
var enchantment = this.enchantments.get(currentEnchantmentIndex);
this.enchantments.set(currentEnchantmentIndex, new EnchantmentInstance(
enchantment.enchantment,
enchantment.level > 0 ? (enchantment.level - 1) : 0
));
} else if (buttonId == 4) {
var enchantment = this.enchantments.get(currentEnchantmentIndex);
this.enchantments.set(currentEnchantmentIndex, new EnchantmentInstance(
enchantment.enchantment,
enchantment.level < enchantment.enchantment.getMaxLevel() ? (enchantment.level + 1) : enchantment.level
));
} else {
var enchantment = this.enchantments.get(currentEnchantmentIndex);
this.enchantments.set(currentEnchantmentIndex, new EnchantmentInstance(
enchantment.enchantment,
enchantment.level > 0 ? (enchantment.level - 1) : 0
));
unbreakingSet = !unbreakingSet;
}
}
return true;
@ -119,14 +145,14 @@ public class EnchanterMenu extends AbstractContainerMenu {
private void addPlayerInventory(Inventory playerInventory) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 9; j++) {
addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 86 + i * 18));
addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 150 + i * 18));
}
}
}
private void addPlayerHotbar(Inventory playerInventory) {
for (int i = 0; i < 9; i++) {
addSlot(new Slot(playerInventory, i, 8 + i * 18, 144));
addSlot(new Slot(playerInventory, i, 8 + i * 18, 208));
}
}
@ -146,7 +172,7 @@ public class EnchanterMenu extends AbstractContainerMenu {
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
// THIS YOU HAVE TO DEFINE!
private static final int TE_INVENTORY_SLOT_COUNT = 2; // must be the number of slots you have!
private static final int TE_INVENTORY_SLOT_COUNT = 3; // must be the number of slots you have!
@Override
public @NotNull ItemStack quickMoveStack(@NotNull Player playerIn, int index) {

View file

@ -2,21 +2,19 @@ package xyz.nuark.enchantrium.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.game.ServerboundContainerButtonClickPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.NotNull;
import xyz.nuark.enchantrium.Enchantrium;
import xyz.nuark.enchantrium.network.Networking;
import xyz.nuark.enchantrium.network.message.PacketEnchantItem;
import xyz.nuark.enchantrium.screen.widget.Label;
public class EnchanterScreen extends AbstractContainerScreen<EnchanterMenu> {
@ -29,58 +27,77 @@ public class EnchanterScreen extends AbstractContainerScreen<EnchanterMenu> {
private Button prevBtn;
private Button increaseLevelBtn;
private Button decreaseLevelBtn;
private Button switchUnbreakableBtn;
public EnchanterScreen(EnchanterMenu enchanterMenu, Inventory inventory, Component title) {
super(enchanterMenu, inventory, title);
imageWidth = 176;
imageHeight = 232;
}
@Override
protected void init() {
super.init();
int sx = width / 2 - imageWidth / 2;
int sy = height / 2 - imageHeight / 2;
currentEnchantmentLabel = new Label(
new TextComponent(""),
width / 2, height / 2 + 80, 0xFFFFFF, true
sx + 7, sy + 51, 0xFFFFFF, false
);
enchantBtn = new Button(
width / 2 - 50, height / 2 + 100, 100, 20,
sx + 76, sy + 18, 93, 20,
new TextComponent("Enchant"),
button -> clickButton(0)
);
nextBtn = new Button(
width / 2 + 60, height / 2 + 100, 20, 20,
new TextComponent("\u2192"),
prevBtn = new Button(
sx + 7, sy + 71, 78, 20,
new TextComponent("Previous"),
button -> clickButton(1)
);
prevBtn = new Button(
width / 2 - 80, height / 2 + 100, 20, 20,
new TextComponent("\u2190"),
nextBtn = new Button(
sx + 91, sy + 71, 78, 20,
new TextComponent("Next"),
button -> clickButton(2)
);
increaseLevelBtn = new Button(
width / 2 + 90, height / 2 + 100, 20, 10,
new TextComponent("\u2191"),
decreaseLevelBtn = new Button(
sx + 7, sy + 97, 78, 20,
new TextComponent("Decrease"),
button -> clickButton(3)
);
decreaseLevelBtn = new Button(
width / 2 + 90, height / 2 + 110, 20, 10,
new TextComponent("\u2193"),
increaseLevelBtn = new Button(
sx + 91, sy + 97, 78, 20,
new TextComponent("Increase"),
button -> clickButton(4)
);
switchUnbreakableBtn = new Button(
sx + 7, sy + 123, 162, 20,
new TextComponent(""),
button -> clickButton(5)
);
addRenderableWidget(enchantBtn);
addRenderableWidget(nextBtn);
addRenderableWidget(prevBtn);
addRenderableWidget(increaseLevelBtn);
addRenderableWidget(nextBtn);
addRenderableWidget(decreaseLevelBtn);
addRenderableWidget(increaseLevelBtn);
addRenderableWidget(switchUnbreakableBtn);
addRenderableOnly(new Label(
new TextComponent("Selected Enchantment:"),
sx + 7, sy + 41, 0xFFFFFF, false
));
addRenderableOnly(currentEnchantmentLabel);
}
private void clickButton(int buttonId) {
assert Minecraft.getInstance().player != null;
menu.clickMenuButton(Minecraft.getInstance().player, buttonId);
menu.clickMenuButton(Minecraft.getInstance().player, buttonId);
}
@Override
@ -94,6 +111,11 @@ public class EnchanterScreen extends AbstractContainerScreen<EnchanterMenu> {
this.blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight);
}
@Override
protected void renderLabels(@NotNull PoseStack pPoseStack, int pMouseX, int pMouseY) {
this.font.draw(pPoseStack, this.title, (float) this.titleLabelX, (float) this.titleLabelY, 4210752);
}
@Override
public void render(@NotNull PoseStack pPoseStack, int mouseX, int mouseY, float delta) {
renderBackground(pPoseStack);
@ -104,21 +126,50 @@ public class EnchanterScreen extends AbstractContainerScreen<EnchanterMenu> {
if (enchantmentInstance != null) {
var enchantment = enchantmentInstance.enchantment;
var level = enchantmentInstance.level;
Component description;
MutableComponent description;
if (level == 0) {
description = new TranslatableComponent(enchantment.getDescriptionId());
} else {
description = enchantment.getFullname(level);
description = new TranslatableComponent(enchantment.getDescriptionId());
description.withStyle(ChatFormatting.GREEN);
if (level != 1 || enchantment.getMaxLevel() != 1) {
description.append(" ").append(new TranslatableComponent("enchantment.level." + level));
}
}
currentEnchantmentLabel.setText(description);
} else {
currentEnchantmentLabel.setText(new TextComponent("No enchantment selected"));
}
enchantBtn.active = enchantmentInstance != null;
var enchantmentRequirements = menu.getEnchantmentRequirements();
if (Minecraft.getInstance().player != null) {
enchantBtn.active = enchantmentInstance != null && menu.requirementsMet(Minecraft.getInstance().player, enchantmentRequirements);
} else {
enchantBtn.active = false;
}
nextBtn.active = enchantmentInstance != null;
prevBtn.active = enchantmentInstance != null;
increaseLevelBtn.active = enchantmentInstance != null;
decreaseLevelBtn.active = enchantmentInstance != null;
switchUnbreakableBtn.active = enchantmentInstance != null;
switchUnbreakableBtn.setMessage(new TextComponent(menu.unbreakable() ? "Make unbreakable" : "Make breakable"));
if (enchantmentInstance != null && enchantBtn.isHoveredOrFocused()) {
renderTooltip(
pPoseStack,
new TextComponent("Requirements: ")
.append(String.valueOf(enchantmentRequirements.lapis()))
.append(new TextComponent(" lapis").withStyle(ChatFormatting.BLUE))
.append(", ")
.append(String.valueOf(enchantmentRequirements.netherite()))
.append(new TextComponent(" netherite").withStyle(ChatFormatting.DARK_PURPLE))
.append(", ")
.append(String.valueOf(enchantmentRequirements.levels()))
.append(new TextComponent(" levels").withStyle(ChatFormatting.YELLOW)),
mouseX, mouseY
);
}
}
}

View file

@ -24,4 +24,21 @@ public class EnchantmentUtil {
return list;
}
public static EnchantmentCost calculateEnchantmentPrice(List<EnchantmentInstance> enchantments, boolean hasUnbreaking) {
if (enchantments.isEmpty()) {
return new EnchantmentCost(0, 0, 0);
}
int lapis = Math.min(20 + enchantments.size() * (hasUnbreaking ? 6 : 3), 64);
int netherite = Math.min(Math.max((hasUnbreaking ? 5 : -3) + enchantments.size() / 2, 0), 64);
int levels = enchantments.stream().reduce(
0,
(acc, enchantment) -> acc + enchantment.level,
Integer::sum
);
return new EnchantmentCost(levels, lapis, netherite);
}
public record EnchantmentCost(int levels, int lapis, int netherite) {
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 991 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After