From b613958435146321fcb069db200e1baac874cd31 Mon Sep 17 00:00:00 2001 From: BlusterySasha Date: Mon, 28 Aug 2023 01:24:12 +0400 Subject: [PATCH] Initial code for the server-side enchanting --- src/main/java/cn/nukkit/Player.java | 37 +++- src/main/java/cn/nukkit/block/Block.java | 2 +- .../PlayerEnchantOptionsRequestEvent.java | 26 +++ .../cn/nukkit/inventory/EnchantInventory.java | 31 +++- .../transaction/EnchantTransaction.java | 52 +++--- .../nukkit/item/enchantment/Enchantment.java | 63 ++++--- .../enchantment/EnchantmentDurability.java | 9 +- .../enchantment/EnchantmentEfficiency.java | 7 +- .../item/enchantment/EnchantmentHelper.java | 164 ++++++++++++++++++ .../enchantment/EnchantmentKnockback.java | 7 +- .../item/enchantment/EnchantmentMending.java | 7 +- .../enchantment/EnchantmentSilkTouch.java | 7 +- .../enchantment/EnchantmentSwiftSneak.java | 7 +- .../item/enchantment/EnchantmentThorns.java | 7 +- .../item/enchantment/EnchantmentType.java | 57 +++--- .../EnchantmentVanishingCurse.java | 7 +- .../enchantment/EnchantmentWaterBreath.java | 7 +- .../item/enchantment/bow/EnchantmentBow.java | 6 +- .../enchantment/bow/EnchantmentBowFlame.java | 7 +- .../bow/EnchantmentBowInfinity.java | 7 +- .../bow/EnchantmentBowKnockback.java | 7 +- .../enchantment/bow/EnchantmentBowPower.java | 7 +- .../enchantment/damage/EnchantmentDamage.java | 6 +- .../damage/EnchantmentDamageAll.java | 7 +- .../enchantment/loot/EnchantmentLoot.java | 6 +- .../loot/EnchantmentLootDigging.java | 7 +- .../protection/EnchantmentProtection.java | 6 +- .../protection/EnchantmentProtectionAll.java | 7 +- .../EnchantmentProtectionExplosion.java | 7 +- .../protection/EnchantmentProtectionFall.java | 7 +- .../protection/EnchantmentProtectionFire.java | 9 +- .../EnchantmentProtectionProjectile.java | 7 +- .../protocol/PlayerEnchantOptionsPacket.java | 96 ++-------- 33 files changed, 503 insertions(+), 193 deletions(-) create mode 100644 src/main/java/cn/nukkit/event/player/PlayerEnchantOptionsRequestEvent.java create mode 100644 src/main/java/cn/nukkit/item/enchantment/EnchantmentHelper.java diff --git a/src/main/java/cn/nukkit/Player.java b/src/main/java/cn/nukkit/Player.java index 24f34e74f..d48bf79bd 100644 --- a/src/main/java/cn/nukkit/Player.java +++ b/src/main/java/cn/nukkit/Player.java @@ -109,6 +109,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -265,6 +266,7 @@ public class Player extends EntityHuman implements CommandSender, InventoryHolde private int exp = 0; private int expLevel = 0; + private int expSeed; protected PlayerFood foodData = null; @@ -2390,6 +2392,18 @@ private static EntityInteractable getEntityAtPosition(Entity[] nearbyEntities, i return null; } + public int getEnchantmentSeed() { + return this.expSeed; + } + + public void setEnchantmentSeed(int seed) { + this.expSeed = seed; + } + + public int generateEnchantmentSeed() { + return ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE); + } + public void checkNetwork() { if (this.protocol < ProtocolInfo.v1_16_100 && !this.isOnline()) { return; @@ -2442,11 +2456,15 @@ protected void processLogin() { if (!this.server.isWhitelisted(lowerName)) { this.kick(PlayerKickEvent.Reason.NOT_WHITELISTED, server.whitelistReason); return; - } else if (this.isBanned()) { + } + + if (this.isBanned()) { String reason = this.server.getNameBans().getEntires().get(lowerName).getReason(); this.kick(PlayerKickEvent.Reason.NAME_BANNED, "You are banned!" + (reason.isEmpty() ? "" : (" Reason: " + reason))); return; - } else if (!server.strongIPBans && this.server.getIPBans().isBanned(this.getAddress())) { + } + + if (!server.strongIPBans && this.server.getIPBans().isBanned(this.getAddress())) { this.kick(PlayerKickEvent.Reason.IP_BANNED, "Your IP is banned!"); return; } @@ -2554,7 +2572,6 @@ protected void processLogin() { this.fogStack.add(i, new PlayerFogPacket.Fog(Identifier.tryParse(fogIdentifiers.get(i).data), userProvidedFogIds.get(i).data)); } - for (Tag achievement : nbt.getCompound("Achievements").getAllTags()) { if (!(achievement instanceof ByteTag)) { continue; @@ -2593,6 +2610,13 @@ protected void processLogin() { this.namedTag.putFloat("foodSaturationLevel", 20); } + if (this.namedTag.contains("xpSeed")) { + this.expSeed = this.namedTag.getInt("xpSeed"); + } else { + this.expSeed = this.generateEnchantmentSeed(); + this.namedTag.putInt("xpSeed", this.expSeed); + } + this.foodData = new PlayerFood(this, this.namedTag.getInt("foodLevel"), this.namedTag.getFloat("foodSaturationLevel")); if (this.isSpectator()) { @@ -5316,9 +5340,9 @@ public void save(boolean async) { namedTag.remove("SpawnBlockPositionX").remove("SpawnBlockPositionY").remove("SpawnBlockPositionZ").remove("SpawnBlockLevel"); } else if (spawnBlockPosition.isValid()) { namedTag.putInt("SpawnBlockPositionX", spawnBlockPosition.getFloorX()) - .putInt("SpawnBlockPositionY", spawnBlockPosition.getFloorY()) - .putInt("SpawnBlockPositionZ", spawnBlockPosition.getFloorZ()) - .putString("SpawnBlockLevel", this.spawnBlockPosition.getLevel().getFolderName()); + .putInt("SpawnBlockPositionY", spawnBlockPosition.getFloorY()) + .putInt("SpawnBlockPositionZ", spawnBlockPosition.getFloorZ()) + .putString("SpawnBlockLevel", this.spawnBlockPosition.getLevel().getFolderName()); } CompoundTag achievements = new CompoundTag(); @@ -5339,6 +5363,7 @@ public void save(boolean async) { this.namedTag.putInt("foodLevel", this.foodData.getLevel()); this.namedTag.putFloat("foodSaturationLevel", this.foodData.getFoodSaturationLevel()); + this.namedTag.putInt("xpSeed", this.expSeed); this.namedTag.putInt("TimeSinceRest", this.timeSinceRest); ListTag fogIdentifiers = new ListTag<>("fogIdentifiers"); diff --git a/src/main/java/cn/nukkit/block/Block.java b/src/main/java/cn/nukkit/block/Block.java index 21d1b2854..d14521add 100644 --- a/src/main/java/cn/nukkit/block/Block.java +++ b/src/main/java/cn/nukkit/block/Block.java @@ -784,7 +784,7 @@ public int getItemId() { } return id; - } + } /** * The full id is a combination of the id and data. diff --git a/src/main/java/cn/nukkit/event/player/PlayerEnchantOptionsRequestEvent.java b/src/main/java/cn/nukkit/event/player/PlayerEnchantOptionsRequestEvent.java new file mode 100644 index 000000000..f2a602db6 --- /dev/null +++ b/src/main/java/cn/nukkit/event/player/PlayerEnchantOptionsRequestEvent.java @@ -0,0 +1,26 @@ +package cn.nukkit.event.player; + +import cn.nukkit.Player; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.inventory.EnchantInventory; +import cn.nukkit.network.protocol.PlayerEnchantOptionsPacket; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PlayerEnchantOptionsRequestEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private EnchantInventory table; + private List options; + + public PlayerEnchantOptionsRequestEvent(Player player, EnchantInventory table, List options) { + this.player = player; + this.table = table; + this.options = options; + } +} diff --git a/src/main/java/cn/nukkit/inventory/EnchantInventory.java b/src/main/java/cn/nukkit/inventory/EnchantInventory.java index 2fcb0c75d..4206cd5ef 100644 --- a/src/main/java/cn/nukkit/inventory/EnchantInventory.java +++ b/src/main/java/cn/nukkit/inventory/EnchantInventory.java @@ -1,18 +1,27 @@ package cn.nukkit.inventory; import cn.nukkit.Player; +import cn.nukkit.event.player.PlayerEnchantOptionsRequestEvent; import cn.nukkit.item.Item; +import cn.nukkit.item.enchantment.EnchantmentHelper; import cn.nukkit.level.Position; +import cn.nukkit.network.protocol.PlayerEnchantOptionsPacket; +import lombok.Getter; + +import java.util.Collections; +import java.util.List; /** * @author MagicDroidX * Nukkit Project */ public class EnchantInventory extends FakeBlockUIComponent { - public static final int ENCHANT_INPUT_ITEM_UI_SLOT = 14; public static final int ENCHANT_REAGENT_UI_SLOT = 15; + @Getter + private List options = Collections.emptyList(); + public EnchantInventory(PlayerUIInventory playerUI, Position position) { super(playerUI, InventoryType.ENCHANT_TABLE, 14, position); } @@ -36,6 +45,26 @@ public void onClose(Player who) { who.resetCraftingGridType(); } + @Override + public void onSlotChange(int index, Item before, boolean send) { + if (index == 0) { + for (final Player viewer : this.getViewers()) { + List options = EnchantmentHelper.getEnchantOptions(this.getHolder(), this.getInputSlot(), viewer.getEnchantmentSeed()); + PlayerEnchantOptionsRequestEvent event = new PlayerEnchantOptionsRequestEvent(viewer, this, options); + + if (!event.isCancelled() && !event.getOptions().isEmpty()) { + this.options = event.getOptions(); + + PlayerEnchantOptionsPacket pk = new PlayerEnchantOptionsPacket(); + pk.options = event.getOptions(); + viewer.dataPacket(pk); + } + } + } + + super.onSlotChange(index, before, false); + } + public Item getInputSlot() { return this.getItem(0); } diff --git a/src/main/java/cn/nukkit/inventory/transaction/EnchantTransaction.java b/src/main/java/cn/nukkit/inventory/transaction/EnchantTransaction.java index 6cccb6970..701e0127a 100644 --- a/src/main/java/cn/nukkit/inventory/transaction/EnchantTransaction.java +++ b/src/main/java/cn/nukkit/inventory/transaction/EnchantTransaction.java @@ -3,11 +3,12 @@ import cn.nukkit.Player; import cn.nukkit.event.inventory.EnchantItemEvent; import cn.nukkit.inventory.EnchantInventory; -import cn.nukkit.inventory.Inventory; import cn.nukkit.inventory.transaction.action.EnchantingAction; import cn.nukkit.inventory.transaction.action.InventoryAction; import cn.nukkit.inventory.transaction.action.SlotChangeAction; import cn.nukkit.item.Item; +import cn.nukkit.item.enchantment.Enchantment; +import cn.nukkit.network.protocol.PlayerEnchantOptionsPacket; import cn.nukkit.network.protocol.types.NetworkInventoryAction; import lombok.Getter; import lombok.Setter; @@ -17,7 +18,7 @@ @Getter @Setter public class EnchantTransaction extends InventoryTransaction { - + private EnchantInventory inv; private Item inputItem; private Item outputItem; private int cost = -1; @@ -35,16 +36,19 @@ public EnchantTransaction(Player source, List actions) { @Override public boolean canExecute() { - Inventory inv = getSource().getWindowById(Player.ENCHANT_WINDOW_ID); - if (inv == null) return false; - EnchantInventory eInv = (EnchantInventory) inv; - if (!getSource().isCreative()) { - if (cost == -1 || !eInv.getReagentSlot().equals(Item.get(Item.DYE, 4), true, false) || eInv.getReagentSlot().count < cost) + if (!(this.getSource().getWindowById(Player.ENCHANT_WINDOW_ID) instanceof final EnchantInventory inv)) { + return false; + } + + if (!this.getSource().isCreative()) { + if (cost == -1 || !inv.getReagentSlot().equals(Item.get(Item.DYE, 4), true, false) || inv.getReagentSlot().count < cost) { return false; + } } + return inputItem != null && outputItem != null - && inputItem.equals(eInv.getInputSlot(), true, true) - && this.checkEnchantValid(); + && inputItem.equals(inv.getInputSlot(), true, true) + && this.checkEnchantValid(inv); } @Override @@ -55,7 +59,7 @@ public boolean execute() { this.sendInventories(); return false; } - EnchantInventory inv = (EnchantInventory) getSource().getWindowById(Player.ENCHANT_WINDOW_ID); + EnchantInventory inv = (EnchantInventory) this.getSource().getWindowById(Player.ENCHANT_WINDOW_ID); EnchantItemEvent ev = new EnchantItemEvent(inv, inputItem, outputItem, cost, source); source.getServer().getPluginManager().callEvent(ev); if (ev.isCancelled()) { @@ -80,8 +84,10 @@ public boolean execute() { } if (!source.isCreative()) { + source.setEnchantmentSeed(source.generateEnchantmentSeed()); source.setExperience(source.getExperience(), source.getExperienceLevel() - ev.getXpCost()); } + return true; } @@ -90,21 +96,18 @@ public void addAction(InventoryAction action) { super.addAction(action); if (action instanceof EnchantingAction) { switch (((EnchantingAction) action).getType()) { - case NetworkInventoryAction.SOURCE_TYPE_ENCHANT_INPUT: + case NetworkInventoryAction.SOURCE_TYPE_ENCHANT_INPUT -> this.inputItem = action.getTargetItem(); // Input sent as newItem - break; - case NetworkInventoryAction.SOURCE_TYPE_ENCHANT_OUTPUT: + case NetworkInventoryAction.SOURCE_TYPE_ENCHANT_OUTPUT -> this.outputItem = action.getSourceItem(); // Output sent as oldItem - break; - case NetworkInventoryAction.SOURCE_TYPE_ENCHANT_MATERIAL: + case NetworkInventoryAction.SOURCE_TYPE_ENCHANT_MATERIAL -> { if (action.getTargetItem().equals(Item.get(Item.AIR), false, false)) { this.cost = action.getSourceItem().count; } else { this.cost = action.getSourceItem().count - action.getTargetItem().count; } - break; + } } - } } @@ -115,14 +118,17 @@ public boolean checkForEnchantPart(List actions) { return false; } - public boolean checkEnchantValid() { - if (this.inputItem.getId() != this.outputItem.getId() - || this.inputItem.getCount() != this.outputItem.getCount()) { - return false; + public boolean checkEnchantValid(EnchantInventory inv) { + for (final PlayerEnchantOptionsPacket.EnchantOptionData option : inv.getOptions()) { + for (final Enchantment ench : option.enchantments()) { + if (outputItem.hasEnchantment(ench.getId())) { + return outputItem.getId() == inputItem.getId() && outputItem.getDamage() == inputItem.getDamage(); + } + } } - //TODO 检查附魔 + System.out.println(inv.getOptions()); - return true; + return false; } } diff --git a/src/main/java/cn/nukkit/item/enchantment/Enchantment.java b/src/main/java/cn/nukkit/item/enchantment/Enchantment.java index 4596d5995..2762c6374 100644 --- a/src/main/java/cn/nukkit/item/enchantment/Enchantment.java +++ b/src/main/java/cn/nukkit/item/enchantment/Enchantment.java @@ -76,6 +76,10 @@ public abstract class Enchantment implements Cloneable { public static void init() { enchantments = new Enchantment[256]; + // TODO: some enchantments are not implemented to + // enchanted table because they need enchantingPowerRange + // and getMinEnchantingPower methods + enchantments[ID_PROTECTION_ALL] = new EnchantmentProtectionAll(); enchantments[ID_PROTECTION_FIRE] = new EnchantmentProtectionFire(); enchantments[ID_PROTECTION_FALL] = new EnchantmentProtectionFall(); @@ -83,13 +87,13 @@ public static void init() { enchantments[ID_PROTECTION_PROJECTILE] = new EnchantmentProtectionProjectile(); enchantments[ID_THORNS] = new EnchantmentThorns(); enchantments[ID_WATER_BREATHING] = new EnchantmentWaterBreath(); - enchantments[ID_WATER_WORKER] = new EnchantmentWaterWorker(); - enchantments[ID_WATER_WALKER] = new EnchantmentWaterWalker(); + enchantments[ID_WATER_WORKER] = new EnchantmentWaterWorker(); // TODO + enchantments[ID_WATER_WALKER] = new EnchantmentWaterWalker(); // TODO enchantments[ID_DAMAGE_ALL] = new EnchantmentDamageAll(); - enchantments[ID_DAMAGE_SMITE] = new EnchantmentDamageSmite(); - enchantments[ID_DAMAGE_ARTHROPODS] = new EnchantmentDamageArthropods(); + enchantments[ID_DAMAGE_SMITE] = new EnchantmentDamageSmite(); // TODO + enchantments[ID_DAMAGE_ARTHROPODS] = new EnchantmentDamageArthropods(); // TODO enchantments[ID_KNOCKBACK] = new EnchantmentKnockback(); - enchantments[ID_FIRE_ASPECT] = new EnchantmentFireAspect(); + enchantments[ID_FIRE_ASPECT] = new EnchantmentFireAspect(); // TODO enchantments[ID_LOOTING] = new EnchantmentLootWeapon(); enchantments[ID_EFFICIENCY] = new EnchantmentEfficiency(); enchantments[ID_SILK_TOUCH] = new EnchantmentSilkTouch(); @@ -99,20 +103,20 @@ public static void init() { enchantments[ID_BOW_KNOCKBACK] = new EnchantmentBowKnockback(); enchantments[ID_BOW_FLAME] = new EnchantmentBowFlame(); enchantments[ID_BOW_INFINITY] = new EnchantmentBowInfinity(); - enchantments[ID_FORTUNE_FISHING] = new EnchantmentLootFishing(); - enchantments[ID_LURE] = new EnchantmentLure(); - enchantments[ID_FROST_WALKER] = new EnchantmentFrostWalker(); + enchantments[ID_FORTUNE_FISHING] = new EnchantmentLootFishing(); // TODO + enchantments[ID_LURE] = new EnchantmentLure(); // TODO + enchantments[ID_FROST_WALKER] = new EnchantmentFrostWalker(); // TODO enchantments[ID_MENDING] = new EnchantmentMending(); - enchantments[ID_BINDING_CURSE] = new EnchantmentBindingCurse(); + enchantments[ID_BINDING_CURSE] = new EnchantmentBindingCurse(); // TODO enchantments[ID_VANISHING_CURSE] = new EnchantmentVanishingCurse(); - enchantments[ID_TRIDENT_IMPALING] = new EnchantmentTridentImpaling(); - enchantments[ID_TRIDENT_LOYALTY] = new EnchantmentTridentLoyalty(); - enchantments[ID_TRIDENT_RIPTIDE] = new EnchantmentTridentRiptide(); - enchantments[ID_TRIDENT_CHANNELING] = new EnchantmentTridentChanneling(); - enchantments[ID_CROSSBOW_MULTISHOT] = new EnchantmentCrossbowMultishot(); - enchantments[ID_CROSSBOW_PIERCING] = new EnchantmentCrossbowPiercing(); - enchantments[ID_CROSSBOW_QUICK_CHARGE] = new EnchantmentCrossbowQuickCharge(); - enchantments[ID_SOUL_SPEED] = new EnchantmentSoulSpeed(); + enchantments[ID_TRIDENT_IMPALING] = new EnchantmentTridentImpaling(); // TODO + enchantments[ID_TRIDENT_LOYALTY] = new EnchantmentTridentLoyalty(); // TODO + enchantments[ID_TRIDENT_RIPTIDE] = new EnchantmentTridentRiptide(); // TODO + enchantments[ID_TRIDENT_CHANNELING] = new EnchantmentTridentChanneling(); // TODO + enchantments[ID_CROSSBOW_MULTISHOT] = new EnchantmentCrossbowMultishot(); // TODO + enchantments[ID_CROSSBOW_PIERCING] = new EnchantmentCrossbowPiercing(); // TODO + enchantments[ID_CROSSBOW_QUICK_CHARGE] = new EnchantmentCrossbowQuickCharge(); // TODO + enchantments[ID_SOUL_SPEED] = new EnchantmentSoulSpeed(); // TODO enchantments[ID_SWIFT_SNEAK] = new EnchantmentSwiftSneak(); } @@ -144,20 +148,25 @@ public static Enchantment[] getEnchantments() { return list.toArray(new Enchantment[0]); } + protected final String name; + protected int level = 1; + public final int id; - private final Rarity rarity; public EnchantmentType type; - protected int level = 1; - - protected final String name; + private final Rarity rarity; + private final int enchantingPowerRange; protected Enchantment(int id, String name, Rarity rarity, EnchantmentType type) { + this(id, name, rarity, type, 50); + } + + protected Enchantment(int id, String name, Rarity rarity, EnchantmentType type, int enchantingPowerRange) { this.id = id; + this.name = name; this.rarity = rarity; this.type = type; - - this.name = name; + this.enchantingPowerRange = enchantingPowerRange; } public int getLevel() { @@ -189,6 +198,14 @@ public Rarity getRarity() { return this.rarity; } + public int getMinEnchantingPower(int level) { + return 1; + } + + public int getMaxEnchantingPower(int level) { + return this.getMinEnchantingPower(level) + enchantingPowerRange; + } + public int getWeight() { return this.rarity.getWeight(); } diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentDurability.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentDurability.java index 1f3e533e3..0fa1cf267 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentDurability.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentDurability.java @@ -11,12 +11,17 @@ public class EnchantmentDurability extends Enchantment { protected EnchantmentDurability() { - super(ID_DURABILITY, "durability", Rarity.UNCOMMON, EnchantmentType.BREAKABLE); + super(ID_DURABILITY, "durability", Rarity.UNCOMMON, EnchantmentType.BREAKABLE, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 8 * (level - 1) + 5; } @Override public int getMinEnchantAbility(int level) { - return 5 + ((level - 1) << 3); + return 5 + (level - 1 << 3); } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentEfficiency.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentEfficiency.java index 289c601d9..d585c8b40 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentEfficiency.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentEfficiency.java @@ -9,7 +9,12 @@ public class EnchantmentEfficiency extends Enchantment { protected EnchantmentEfficiency() { - super(ID_EFFICIENCY, "digging", Rarity.COMMON, EnchantmentType.DIGGER); + super(ID_EFFICIENCY, "digging", Rarity.COMMON, EnchantmentType.DIGGER, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 10 * (level - 1) + 1; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentHelper.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentHelper.java new file mode 100644 index 000000000..3d41356e1 --- /dev/null +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentHelper.java @@ -0,0 +1,164 @@ +package cn.nukkit.item.enchantment; + +import cn.nukkit.block.BlockID; +import cn.nukkit.item.Item; +import cn.nukkit.level.Level; +import cn.nukkit.level.Position; +import cn.nukkit.math.NukkitRandom; +import cn.nukkit.network.protocol.PlayerEnchantOptionsPacket; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public final class EnchantmentHelper { + private static final int MAX_BOOKSHELF_COUNT = 15; + + public static List getEnchantOptions(Position tablePos, Item input, int seed) { + if (input == null || input.hasEnchantments()) { + return Collections.emptyList(); + } + + NukkitRandom random = new NukkitRandom(seed); + + int bookshelfCount = countBookshelves(tablePos); + int baseRequiredLevel = random.nextRange(1, 8) + (bookshelfCount >> 1) + random.nextRange(0, bookshelfCount); + + return List.of( + createEnchantOption(random, input, (int) Math.floor(Math.max(baseRequiredLevel / 3D, 1))), + createEnchantOption(random, input, (int) Math.floor(baseRequiredLevel * 2D / 3 + 1)), + createEnchantOption(random, input, Math.max(baseRequiredLevel, bookshelfCount * 2)) + ); + } + + private static int countBookshelves(Position tablePos) { + int bookshelfCount = 0; + Level world = tablePos.getLevel(); + + for (int x = -2; x <= 2; x++) { + outer: + for (int z = -2; z <= 2; z++) { + // We only check blocks at a distance of 2 blocks from the enchanting table + if (Math.abs(x) != 2 && Math.abs(z) != 2) { + continue; + } + + // Ensure the space between the bookshelf stack at this X/Z and the enchanting table is empty + for (int y = 0; y <= 1; y++) { + // Calculate the coordinates of the space between the bookshelf and the enchanting table + if (world.getBlock( + tablePos.add(Math.max(Math.min(x, 1), -1),y, Math.max(Math.min(z, 1), -1)) + ).getId() != BlockID.AIR) { + continue outer; + } + } + + // Finally, check the number of bookshelves at the current position + for (int y = 0; y <= 1; y++) { + if (world.getBlock(tablePos.add(x, y, z)).getId() == BlockID.BOOKSHELF) { + bookshelfCount++; + if (bookshelfCount == MAX_BOOKSHELF_COUNT) { + return bookshelfCount; + } + } + } + } + } + + return bookshelfCount; + } + + private static PlayerEnchantOptionsPacket.EnchantOptionData createEnchantOption(NukkitRandom random, Item inputItem, int requiredXpLevel) { + int enchantingPower = requiredXpLevel; + + int enchantability = inputItem.getEnchantAbility(); + enchantingPower = enchantingPower + random.nextRange(0, enchantability >> 2) + random.nextRange(0, enchantability >> 2) + 1; + + // Random bonus for enchanting power between 0.85 and 1.15 + double bonus = 1 + (random.nextFloat() + random.nextFloat() - 1) * 0.15; + enchantingPower = (int) Math.round(enchantingPower * bonus); + + List resultEnchantments = new ArrayList<>(); + List availableEnchantments = getAvailableEnchantments(enchantingPower, inputItem); + Enchantment lastEnchantment = getRandomWeightedEnchantment(random, availableEnchantments); + + if (lastEnchantment != null) { + resultEnchantments.add(lastEnchantment); + + // With probability (power + 1) / 50, continue adding enchantments + while (random.nextFloat() <= (enchantingPower + 1) / 50D) { + availableEnchantments = availableEnchantments.stream() + .filter(e -> e.getId() != lastEnchantment.getId() && e.isCompatibleWith(lastEnchantment)) + .collect(Collectors.toList()); + Enchantment nextEnchantment = getRandomWeightedEnchantment(random, availableEnchantments); + + if (nextEnchantment == null) break; + + resultEnchantments.add(nextEnchantment); + enchantingPower >>= 1; + } + } + + return new PlayerEnchantOptionsPacket.EnchantOptionData(requiredXpLevel, getRandomOptionName(random), resultEnchantments); + } + + private static List getAvailableEnchantments(int enchantingPower, Item item) { + List list = new ArrayList<>(); + for (Enchantment enchantment : getPrimaryEnchantmentsForItem(item)) { + for (int lvl = enchantment.getMaxLevel(); lvl > 0; lvl--) { + if (enchantingPower >= enchantment.getMinEnchantingPower(lvl) && + enchantingPower <= enchantment.getMaxEnchantingPower(lvl) + ) { + list.add(enchantment.setLevel(lvl)); + break; + } + } + } + return list; + } + + private static Enchantment getRandomWeightedEnchantment(NukkitRandom random, List enchantments) { + if (enchantments.size() == 0) { + return null; + } + + int totalWeight = 0; + for (Enchantment enchantment : enchantments) { + totalWeight += enchantment.getRarity().getWeight(); + } + + Enchantment result = null; + int randomWeight = random.nextRange(1, totalWeight); + + for (Enchantment enchantment : enchantments) { + randomWeight -= enchantment.getRarity().getWeight(); + if (randomWeight <= 0) { + result = enchantment; + break; + } + } + + return result; + } + + private static String getRandomOptionName(NukkitRandom random) { + StringBuilder name = new StringBuilder(); + for (int i = random.nextBoundedInt(15 - 5 + 1) + 5; i > 0; i--) { + name.append((char) (random.nextBoundedInt('z' - 'a' + 1) + 'a')); + } + return name.toString(); + } + + private static List getPrimaryEnchantmentsForItem(Item item) { + final List list = new ArrayList<>(); + + for (final Enchantment ench : Enchantment.getEnchantments()) { + if (ench.canEnchant(item)) { + list.add(ench); + } + } + + return list; + } +} diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentKnockback.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentKnockback.java index bd4d47e01..f2598f228 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentKnockback.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentKnockback.java @@ -7,7 +7,12 @@ public class EnchantmentKnockback extends Enchantment { protected EnchantmentKnockback() { - super(ID_KNOCKBACK, "knockback", Rarity.UNCOMMON, EnchantmentType.SWORD); + super(ID_KNOCKBACK, "knockback", Rarity.UNCOMMON, EnchantmentType.SWORD, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 20 * (level - 1) + 5; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentMending.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentMending.java index c07de6083..f48a311bc 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentMending.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentMending.java @@ -6,7 +6,12 @@ public class EnchantmentMending extends Enchantment { protected EnchantmentMending() { - super(ID_MENDING, "mending", Rarity.RARE, EnchantmentType.BREAKABLE); + super(ID_MENDING, "mending", Rarity.RARE, EnchantmentType.BREAKABLE, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 25; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentSilkTouch.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentSilkTouch.java index 740ee115f..a7986fd4d 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentSilkTouch.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentSilkTouch.java @@ -9,7 +9,12 @@ public class EnchantmentSilkTouch extends Enchantment { protected EnchantmentSilkTouch() { - super(ID_SILK_TOUCH, "untouching", Rarity.VERY_RARE, EnchantmentType.DIGGER); + super(ID_SILK_TOUCH, "untouching", Rarity.VERY_RARE, EnchantmentType.DIGGER, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 15; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentSwiftSneak.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentSwiftSneak.java index e81627d5f..eaa432e7d 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentSwiftSneak.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentSwiftSneak.java @@ -3,7 +3,12 @@ public class EnchantmentSwiftSneak extends Enchantment { protected EnchantmentSwiftSneak() { - super(ID_SWIFT_SNEAK, "swift_sneak", Rarity.VERY_RARE, EnchantmentType.ARMOR_LEGS); + super(ID_SWIFT_SNEAK, "swift_sneak", Rarity.VERY_RARE, EnchantmentType.ARMOR_LEGS, 5); + } + + @Override + public int getMinEnchantingPower(int level) { + return 10 * level; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentThorns.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentThorns.java index 2f2dc3605..29457b921 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentThorns.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentThorns.java @@ -15,7 +15,12 @@ public class EnchantmentThorns extends Enchantment { protected EnchantmentThorns() { - super(ID_THORNS, "thorns", Rarity.RARE, EnchantmentType.ARMOR); + super(ID_THORNS, "thorns", Rarity.RARE, EnchantmentType.ARMOR, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 20 * (level - 1) + 10; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentType.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentType.java index 2c7f8bac0..b642a8446 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentType.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentType.java @@ -25,46 +25,35 @@ public enum EnchantmentType { public boolean canEnchantItem(Item item) { if (this == ALL) { return true; + } - } else if (this == BREAKABLE && item.getMaxDurability() >= 0) { + if (this == BREAKABLE && item.getMaxDurability() >= 0) { return true; + } - } else if (item instanceof ItemArmor) { - if (this == WEARABLE || (this == ARMOR && item.isArmor())) { + if (item instanceof ItemArmor) { + if (this == WEARABLE || this == ARMOR && item.isArmor()) { return true; } - switch (this) { - case ARMOR_HEAD: - return item.isHelmet(); - case ARMOR_TORSO: - return item.isChestplate(); - case ARMOR_LEGS: - return item.isLeggings(); - case ARMOR_FEET: - return item.isBoots(); - default: - return false; - } - } else { - switch (this) { - case SWORD: - return item.isSword(); - case DIGGER: - return item.isPickaxe() || item.isShovel() || item.isAxe() || item.isHoe(); - case BOW: - return item instanceof ItemBow; - case FISHING_ROD: - return item instanceof ItemFishingRod; - case WEARABLE: - return item instanceof ItemSkull; - case TRIDENT: - return item instanceof ItemTrident; - case CROSSBOW: - return item instanceof ItemCrossbow; - default: - return false; - } + return switch (this) { + case ARMOR_HEAD -> item.isHelmet(); + case ARMOR_TORSO -> item.isChestplate(); + case ARMOR_LEGS -> item.isLeggings(); + case ARMOR_FEET -> item.isBoots(); + default -> false; + }; } + + return switch (this) { + case SWORD -> item.isSword(); + case DIGGER -> item.isPickaxe() || item.isShovel() || item.isAxe() || item.isHoe(); + case BOW -> item instanceof ItemBow; + case FISHING_ROD -> item instanceof ItemFishingRod; + case WEARABLE -> item instanceof ItemSkull; + case TRIDENT -> item instanceof ItemTrident; + case CROSSBOW -> item instanceof ItemCrossbow; + default -> false; + }; } } diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentVanishingCurse.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentVanishingCurse.java index 40ad778af..f11f6c0f5 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentVanishingCurse.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentVanishingCurse.java @@ -5,7 +5,12 @@ public class EnchantmentVanishingCurse extends Enchantment { protected EnchantmentVanishingCurse() { - super(ID_VANISHING_CURSE, "curse.vanishing", Rarity.VERY_RARE, EnchantmentType.BREAKABLE); + super(ID_VANISHING_CURSE, "curse.vanishing", Rarity.VERY_RARE, EnchantmentType.BREAKABLE, 25); + } + + @Override + public int getMinEnchantingPower(int level) { + return 25; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/EnchantmentWaterBreath.java b/src/main/java/cn/nukkit/item/enchantment/EnchantmentWaterBreath.java index 7e1fd5e3f..158e2e62b 100644 --- a/src/main/java/cn/nukkit/item/enchantment/EnchantmentWaterBreath.java +++ b/src/main/java/cn/nukkit/item/enchantment/EnchantmentWaterBreath.java @@ -7,7 +7,12 @@ public class EnchantmentWaterBreath extends Enchantment { protected EnchantmentWaterBreath() { - super(ID_WATER_BREATHING, "oxygen", Rarity.RARE, EnchantmentType.ARMOR_HEAD); + super(ID_WATER_BREATHING, "oxygen", Rarity.RARE, EnchantmentType.ARMOR_HEAD, 30); + } + + @Override + public int getMinEnchantingPower(int level) { + return 10 * level; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBow.java b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBow.java index 30581eab1..4e5e92ea5 100644 --- a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBow.java +++ b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBow.java @@ -10,6 +10,10 @@ public abstract class EnchantmentBow extends Enchantment { protected EnchantmentBow(int id, String name, Rarity rarity) { - super(id, name, rarity, EnchantmentType.BOW); + super(id, name, rarity, EnchantmentType.BOW, -1); + } + + protected EnchantmentBow(int id, String name, Rarity rarity, int enchantingPowerRange) { + super(id, name, rarity, EnchantmentType.BOW, enchantingPowerRange); } } diff --git a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowFlame.java b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowFlame.java index 6bb109edc..e8fc3f8a3 100644 --- a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowFlame.java +++ b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowFlame.java @@ -8,7 +8,12 @@ */ public class EnchantmentBowFlame extends EnchantmentBow { public EnchantmentBowFlame() { - super(Enchantment.ID_BOW_FLAME, "arrowFire", Rarity.RARE); + super(Enchantment.ID_BOW_FLAME, "arrowFire", Rarity.RARE, 30); + } + + @Override + public int getMinEnchantingPower(int level) { + return 20; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowInfinity.java b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowInfinity.java index 7848e7b75..188eb1b4c 100644 --- a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowInfinity.java +++ b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowInfinity.java @@ -9,7 +9,12 @@ public class EnchantmentBowInfinity extends EnchantmentBow { public EnchantmentBowInfinity() { - super(Enchantment.ID_BOW_INFINITY, "arrowInfinite", Rarity.VERY_RARE); + super(Enchantment.ID_BOW_INFINITY, "arrowInfinite", Rarity.VERY_RARE, 30); + } + + @Override + public int getMinEnchantingPower(int level) { + return 20; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowKnockback.java b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowKnockback.java index 51cf980f9..ea49d8309 100644 --- a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowKnockback.java +++ b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowKnockback.java @@ -8,7 +8,12 @@ */ public class EnchantmentBowKnockback extends EnchantmentBow { public EnchantmentBowKnockback() { - super(Enchantment.ID_BOW_KNOCKBACK, "arrowKnockback", Rarity.RARE); + super(Enchantment.ID_BOW_KNOCKBACK, "arrowKnockback", Rarity.RARE, 25); + } + + @Override + public int getMinEnchantingPower(int level) { + return 20 * (level - 1) + 12; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowPower.java b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowPower.java index 3c832fffc..1ab2881f3 100644 --- a/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowPower.java +++ b/src/main/java/cn/nukkit/item/enchantment/bow/EnchantmentBowPower.java @@ -9,7 +9,12 @@ public class EnchantmentBowPower extends EnchantmentBow { public EnchantmentBowPower() { - super(Enchantment.ID_BOW_POWER, "arrowDamage", Rarity.COMMON); + super(Enchantment.ID_BOW_POWER, "arrowDamage", Rarity.COMMON, 15); + } + + @Override + public int getMinEnchantingPower(int level) { + return 10 * (level - 1) + 1; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamage.java b/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamage.java index 9f864befd..9c975c6e6 100644 --- a/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamage.java +++ b/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamage.java @@ -17,7 +17,11 @@ public enum TYPE { } protected EnchantmentDamage(int id, String name, Rarity rarity, TYPE type) { - super(id, name, rarity, EnchantmentType.SWORD); + super(id, name, rarity, EnchantmentType.SWORD, -1); + } + + protected EnchantmentDamage(int id, String name, Rarity rarity, TYPE type, int enchantingPowerRange) { + super(id, name, rarity, EnchantmentType.SWORD, enchantingPowerRange); } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamageAll.java b/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamageAll.java index 7121b211e..3bcd22093 100644 --- a/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamageAll.java +++ b/src/main/java/cn/nukkit/item/enchantment/damage/EnchantmentDamageAll.java @@ -9,7 +9,12 @@ public class EnchantmentDamageAll extends EnchantmentDamage { public EnchantmentDamageAll() { - super(ID_DAMAGE_ALL, "all", Rarity.COMMON, TYPE.ALL); + super(ID_DAMAGE_ALL, "all", Rarity.COMMON, TYPE.ALL, 20); + } + + @Override + public int getMinEnchantingPower(int level) { + return 11 * (level - 1) + 1; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLoot.java b/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLoot.java index 3c002d520..d5a50a315 100644 --- a/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLoot.java +++ b/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLoot.java @@ -10,7 +10,11 @@ public abstract class EnchantmentLoot extends Enchantment { protected EnchantmentLoot(int id, String name, Rarity rarity, EnchantmentType type) { - super(id, name, rarity, type); + super(id, name, rarity, type, -1); + } + + protected EnchantmentLoot(int id, String name, Rarity rarity, EnchantmentType type, int enchantingPowerRange) { + super(id, name, rarity, type, enchantingPowerRange); } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLootDigging.java b/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLootDigging.java index 6e5fa3da8..de4eb1819 100644 --- a/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLootDigging.java +++ b/src/main/java/cn/nukkit/item/enchantment/loot/EnchantmentLootDigging.java @@ -10,6 +10,11 @@ public class EnchantmentLootDigging extends EnchantmentLoot { public EnchantmentLootDigging() { - super(Enchantment.ID_FORTUNE_DIGGING, "lootBonusDigger", Rarity.RARE, EnchantmentType.DIGGER); + super(Enchantment.ID_FORTUNE_DIGGING, "lootBonusDigger", Rarity.RARE, EnchantmentType.DIGGER, 50); + } + + @Override + public int getMinEnchantingPower(int level) { + return 9 * (level - 1) + 15; } } diff --git a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtection.java b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtection.java index 7096d2689..cbfb7cdc3 100644 --- a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtection.java +++ b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtection.java @@ -20,7 +20,11 @@ public enum TYPE { protected final TYPE protectionType; protected EnchantmentProtection(int id, String name, Rarity rarity, EnchantmentProtection.TYPE type) { - super(id, name, rarity, EnchantmentType.ARMOR); + this(id, name, rarity, type, 50); + } + + protected EnchantmentProtection(int id, String name, Rarity rarity, EnchantmentProtection.TYPE type, int enchantingPowerRange) { + super(id, name, rarity, EnchantmentType.ARMOR, enchantingPowerRange); this.protectionType = type; if (protectionType == TYPE.FALL) { this.type = EnchantmentType.ARMOR_FEET; diff --git a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionAll.java b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionAll.java index 44c479745..13e993fe1 100644 --- a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionAll.java +++ b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionAll.java @@ -11,7 +11,12 @@ public class EnchantmentProtectionAll extends EnchantmentProtection { public EnchantmentProtectionAll() { - super(Enchantment.ID_PROTECTION_ALL, "all", Rarity.COMMON, TYPE.ALL); + super(Enchantment.ID_PROTECTION_ALL, "all", Rarity.COMMON, TYPE.ALL, 20); + } + + @Override + public int getMinEnchantingPower(int level) { + return 11 * (level - 1) + 1; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionExplosion.java b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionExplosion.java index d9e54c2dd..80f247079 100644 --- a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionExplosion.java +++ b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionExplosion.java @@ -10,7 +10,12 @@ public class EnchantmentProtectionExplosion extends EnchantmentProtection { public EnchantmentProtectionExplosion() { - super(ID_PROTECTION_EXPLOSION, "explosion", Rarity.RARE, TYPE.EXPLOSION); + super(ID_PROTECTION_EXPLOSION, "explosion", Rarity.RARE, TYPE.EXPLOSION, 12); + } + + @Override + public int getMinEnchantingPower(int level) { + return 8 * (level - 1) + 5; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFall.java b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFall.java index d8cac97d0..cf8d3e24b 100644 --- a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFall.java +++ b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFall.java @@ -10,7 +10,12 @@ public class EnchantmentProtectionFall extends EnchantmentProtection { public EnchantmentProtectionFall() { - super(ID_PROTECTION_FALL, "fall", Rarity.UNCOMMON, TYPE.FALL); + super(ID_PROTECTION_FALL, "fall", Rarity.UNCOMMON, TYPE.FALL, 10); + } + + @Override + public int getMinEnchantingPower(int level) { + return 6 * (level - 1) + 5; } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFire.java b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFire.java index 378a4db25..6c015262f 100644 --- a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFire.java +++ b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionFire.java @@ -10,12 +10,17 @@ public class EnchantmentProtectionFire extends EnchantmentProtection { public EnchantmentProtectionFire() { - super(ID_PROTECTION_FIRE, "fire", Rarity.UNCOMMON, TYPE.FIRE); + super(ID_PROTECTION_FIRE, "fire", Rarity.UNCOMMON, TYPE.FIRE, 12); + } + + @Override + public int getMinEnchantingPower(int level) { + return 8 * (level - 1) + 10; } @Override public int getMinEnchantAbility(int level) { - return 10 + ((level - 1) << 3); + return 10 + (level - 1 << 3); } @Override diff --git a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionProjectile.java b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionProjectile.java index 9674dd98c..6874d09e1 100644 --- a/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionProjectile.java +++ b/src/main/java/cn/nukkit/item/enchantment/protection/EnchantmentProtectionProjectile.java @@ -10,7 +10,12 @@ public class EnchantmentProtectionProjectile extends EnchantmentProtection { public EnchantmentProtectionProjectile() { - super(ID_PROTECTION_PROJECTILE, "projectile", Rarity.UNCOMMON, TYPE.PROJECTILE); + super(ID_PROTECTION_PROJECTILE, "projectile", Rarity.UNCOMMON, TYPE.PROJECTILE, 15); + } + + @Override + public int getMinEnchantingPower(int level) { + return 6 * (level - 1) + 3; } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/PlayerEnchantOptionsPacket.java b/src/main/java/cn/nukkit/network/protocol/PlayerEnchantOptionsPacket.java index 249ac05b1..2ea875170 100644 --- a/src/main/java/cn/nukkit/network/protocol/PlayerEnchantOptionsPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/PlayerEnchantOptionsPacket.java @@ -1,16 +1,16 @@ package cn.nukkit.network.protocol; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import lombok.Value; +import cn.nukkit.item.enchantment.Enchantment; import java.util.ArrayList; import java.util.List; public class PlayerEnchantOptionsPacket extends DataPacket { - public static final byte NETWORK_ID = ProtocolInfo.PLAYER_ENCHANT_OPTIONS_PACKET; - public final List options = new ArrayList<>(); + public List options = new ArrayList<>(); + + private static int nextId = 100000; @Override public byte pid() { @@ -19,48 +19,7 @@ public byte pid() { @Override public void decode() { - int size = (int) this.getUnsignedVarInt(); - if (size > 1000) { - throw new RuntimeException("EnchantOptions too big: " + size); - } - for (int i = 0; i < size; i++) { - int minLevel = this.getVarInt(); - int slot = this.getInt(); - - int eSize = (int) this.getUnsignedVarInt(); - if (eSize > 1000) { - throw new RuntimeException("Enchantment list too big: " + eSize); - } - List list1 = new ObjectArrayList<>(); - for (int j = 0; j < eSize; j++) { - EnchantData data = new EnchantData(this.getByte(), this.getByte()); - list1.add(data); - } - - eSize = (int) this.getUnsignedVarInt(); - if (eSize > 1000) { - throw new RuntimeException("Enchantment list too big: " + eSize); - } - List list2 = new ObjectArrayList<>(); - for (int j = 0; j < eSize; j++) { - EnchantData data = new EnchantData(this.getByte(), this.getByte()); - list2.add(data); - } - - eSize = (int) this.getUnsignedVarInt(); - if (eSize > 1000) { - throw new RuntimeException("Enchantment list too big: " + eSize); - } - List list3 = new ObjectArrayList<>(); - for (int j = 0; j < eSize; j++) { - EnchantData data = new EnchantData(this.getByte(), this.getByte()); - list3.add(data); - } - String enchantName = this.getString(); - int eNetId = (int) this.getUnsignedVarInt(); - this.options.add(new EnchantOptionData(minLevel, slot, list1, list2, list3, enchantName, eNetId)); - } - + // TODO } @Override @@ -68,43 +27,22 @@ public void encode() { this.reset(); this.putUnsignedVarInt(this.options.size()); for (EnchantOptionData option : this.options) { - this.putVarInt(option.getMinLevel()); - this.putInt(option.getPrimarySlot()); - this.putUnsignedVarInt(option.getEnchants0().size()); - for (EnchantData data : option.getEnchants0()) { - this.putByte((byte) data.getType()); - this.putByte((byte) data.getLevel()); - } - this.putUnsignedVarInt(option.getEnchants1().size()); - for (EnchantData data : option.getEnchants1()) { - this.putByte((byte) data.getType()); + this.putVarInt(option.minLevel()); + this.putInt(0); + this.putUnsignedVarInt(option.enchantments.size()); + for (Enchantment data : option.enchantments) { + this.putByte((byte) data.getId()); this.putByte((byte) data.getLevel()); } - this.putUnsignedVarInt(option.getEnchants2().size()); - for (EnchantData data : option.getEnchants2()) { - this.putByte((byte) data.getType()); - this.putByte((byte) data.getLevel()); - } - this.putString(option.getEnchantName()); - this.putUnsignedVarInt(option.getEnchantNetId()); + this.putUnsignedVarInt(0); + this.putUnsignedVarInt(0); + this.putString(option.enchantName); + this.putUnsignedVarInt(nextId++); } - - } - - @Value - public class EnchantOptionData { - private final int minLevel; - private final int primarySlot; - private final List enchants0; - private final List enchants1; - private final List enchants2; - private final String enchantName; - private final int enchantNetId; } - @Value - public class EnchantData { - private final int type; - private final int level; + public record EnchantOptionData( + int minLevel, String enchantName, List enchantments + ) { } }