diff --git a/src/main/java/net/minecraft/server/Enchantment.java b/src/main/java/net/minecraft/server/Enchantment.java new file mode 100644 index 0000000000..6397455a23 --- /dev/null +++ b/src/main/java/net/minecraft/server/Enchantment.java @@ -0,0 +1,81 @@ +package net.minecraft.server; + +import org.bukkit.craftbukkit.enchantments.CraftEnchantment; + +public abstract class Enchantment { +// CraftBukkit comment - update CraftEnchant.getName(i) if this changes. + public static final Enchantment[] byId = new Enchantment[256]; + public static final Enchantment PROTECTION_ENVIRONMENTAL = new EnchantmentProtection(0, 10, 0); + public static final Enchantment PROTECTION_FIRE = new EnchantmentProtection(1, 5, 1); + public static final Enchantment PROTECTION_FALL = new EnchantmentProtection(2, 5, 2); + public static final Enchantment PROTECTION_EXPLOSIONS = new EnchantmentProtection(3, 2, 3); + public static final Enchantment PROTECTION_PROJECTILE = new EnchantmentProtection(4, 5, 4); + public static final Enchantment OXYGEN = new EnchantmentOxygen(5, 2); + public static final Enchantment WATER_WORKER = new EnchantmentWaterWorker(6, 2); + public static final Enchantment DAMAGE_ALL = new EnchantmentWeaponDamage(16, 10, 0); + public static final Enchantment DAMAGE_UNDEAD = new EnchantmentWeaponDamage(17, 5, 1); + public static final Enchantment DAMAGE_ARTHROPODS = new EnchantmentWeaponDamage(18, 5, 2); + public static final Enchantment KNOCKBACK = new EnchantmentKnockback(19, 5); + public static final Enchantment FIRE_ASPECT = new EnchantmentFire(20, 2); + public static final Enchantment LOOT_BONUS_MOBS = new EnchantmentLootBonus(21, 2, EnchantmentSlotType.WEAPON); + public static final Enchantment DIG_SPEED = new EnchantmentDigging(32, 10); + public static final Enchantment SILK_TOUCH = new EnchantmentSilkTouch(33, 1); + public static final Enchantment DURABILITY = new EnchantmentDurability(34, 5); + public static final Enchantment LOOT_BONUS_BLOCKS = new EnchantmentLootBonus(35, 2, EnchantmentSlotType.DIGGER); + public final int id; + private final int weight; + public EnchantmentSlotType slot; + protected String name; + + protected Enchantment(int i, int j, EnchantmentSlotType enchantmentslottype) { + this.id = i; + this.weight = j; + this.slot = enchantmentslottype; + if (byId[i] != null) { + throw new IllegalArgumentException("Duplicate enchantment id!"); + } else { + byId[i] = this; + } + + // CraftBukkit start + org.bukkit.enchantments.Enchantment.registerEnchantment(new CraftEnchantment(this)); + // CraftBukkit end + } + + public int getRandomWeight() { + return this.weight; + } + + public int getStartLevel() { + return 1; + } + + public int getMaxLevel() { + return 1; + } + + public int a(int i) { + return 1 + i * 10; + } + + public int b(int i) { + return this.a(i) + 5; + } + + public int a(int i, DamageSource damagesource) { + return 0; + } + + public int a(int i, EntityLiving entityliving) { + return 0; + } + + public boolean a(Enchantment enchantment) { + return this != enchantment; + } + + public Enchantment a(String s) { + this.name = s; + return this; + } +} diff --git a/src/main/java/net/minecraft/server/EnchantmentManager.java b/src/main/java/net/minecraft/server/EnchantmentManager.java new file mode 100644 index 0000000000..1a17062197 --- /dev/null +++ b/src/main/java/net/minecraft/server/EnchantmentManager.java @@ -0,0 +1,242 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public class EnchantmentManager { + + private static final Random random = new Random(); + private static final EnchantmentModifier1 b = new EnchantmentModifier1((EmptyClass3) null); + private static final EnchantmentModifier2 c = new EnchantmentModifier2((EmptyClass3) null); + + public EnchantmentManager() {} + + public static int b(int i, ItemStack itemstack) { // CraftBukkit - priv to pub + if (itemstack == null) { + return 0; + } else { + NBTTagList nbttaglist = itemstack.p(); + + if (nbttaglist == null) { + return 0; + } else { + for (int j = 0; j < nbttaglist.d(); ++j) { + short short1 = ((NBTTagCompound) nbttaglist.a(j)).e("id"); + short short2 = ((NBTTagCompound) nbttaglist.a(j)).e("lvl"); + + if (short1 == i) { + return short2; + } + } + + return 0; + } + } + } + + private static int a(int i, ItemStack[] aitemstack) { + int j = 0; + ItemStack[] aitemstack1 = aitemstack; + int k = aitemstack.length; + + for (int l = 0; l < k; ++l) { + ItemStack itemstack = aitemstack1[l]; + int i1 = b(i, itemstack); + + if (i1 > j) { + j = i1; + } + } + + return j; + } + + private static void a(EnchantmentModifier enchantmentmodifier, ItemStack itemstack) { + if (itemstack != null) { + NBTTagList nbttaglist = itemstack.p(); + + if (nbttaglist != null) { + for (int i = 0; i < nbttaglist.d(); ++i) { + short short1 = ((NBTTagCompound) nbttaglist.a(i)).e("id"); + short short2 = ((NBTTagCompound) nbttaglist.a(i)).e("lvl"); + + if (Enchantment.byId[short1] != null) { + enchantmentmodifier.a(Enchantment.byId[short1], short2); + } + } + } + } + } + + private static void a(EnchantmentModifier enchantmentmodifier, ItemStack[] aitemstack) { + ItemStack[] aitemstack1 = aitemstack; + int i = aitemstack.length; + + for (int j = 0; j < i; ++j) { + ItemStack itemstack = aitemstack1[j]; + + a(enchantmentmodifier, itemstack); + } + } + + public static int a(InventoryPlayer inventoryplayer, DamageSource damagesource) { + b.a = 0; + b.b = damagesource; + a((EnchantmentModifier) b, inventoryplayer.armor); + if (b.a > 25) { + b.a = 25; + } + + return (b.a + 1 >> 1) + random.nextInt((b.a >> 1) + 1); + } + + public static int a(InventoryPlayer inventoryplayer, EntityLiving entityliving) { + c.a = 0; + c.b = entityliving; + a((EnchantmentModifier) c, inventoryplayer.getItemInHand()); + return c.a > 0 ? 1 + random.nextInt(c.a) : 0; + } + + public static int b(InventoryPlayer inventoryplayer, EntityLiving entityliving) { + return b(Enchantment.KNOCKBACK.id, inventoryplayer.getItemInHand()); + } + + public static int c(InventoryPlayer inventoryplayer, EntityLiving entityliving) { + return b(Enchantment.FIRE_ASPECT.id, inventoryplayer.getItemInHand()); + } + + public static int a(InventoryPlayer inventoryplayer) { + return a(Enchantment.OXYGEN.id, inventoryplayer.armor); + } + + public static int b(InventoryPlayer inventoryplayer) { + return b(Enchantment.DIG_SPEED.id, inventoryplayer.getItemInHand()); + } + + public static int c(InventoryPlayer inventoryplayer) { + return b(Enchantment.DURABILITY.id, inventoryplayer.getItemInHand()); + } + + public static boolean d(InventoryPlayer inventoryplayer) { + return b(Enchantment.SILK_TOUCH.id, inventoryplayer.getItemInHand()) > 0; + } + + public static int e(InventoryPlayer inventoryplayer) { + return b(Enchantment.LOOT_BONUS_BLOCKS.id, inventoryplayer.getItemInHand()); + } + + public static int f(InventoryPlayer inventoryplayer) { + return b(Enchantment.LOOT_BONUS_MOBS.id, inventoryplayer.getItemInHand()); + } + + public static boolean g(InventoryPlayer inventoryplayer) { + return a(Enchantment.WATER_WORKER.id, inventoryplayer.armor) > 0; + } + + public static int a(Random random, int i, int j, ItemStack itemstack) { + Item item = itemstack.getItem(); + int k = item.c(); + + if (k <= 0) { + return 0; + } else { + if (j > 30) { + j = 30; + } + + j = 1 + random.nextInt((j >> 1) + 1) + random.nextInt(j + 1); + int l = random.nextInt(5) + j; + + return i == 0 ? (l >> 1) + 1 : (i == 1 ? l * 2 / 3 + 1 : l); + } + } + + public static List a(Random random, ItemStack itemstack, int i) { + Item item = itemstack.getItem(); + int j = item.c(); + + if (j <= 0) { + return null; + } else { + j = 1 + random.nextInt((j >> 1) + 1) + random.nextInt((j >> 1) + 1); + int k = j + i; + float f = (random.nextFloat() + random.nextFloat() - 1.0F) * 0.25F; + int l = (int) ((float) k * (1.0F + f) + 0.5F); + ArrayList arraylist = null; + Map map = a(l, itemstack); + + if (map != null && !map.isEmpty()) { + WeightedRandomChoiceEnchantment weightedrandomchoiceenchantment = (WeightedRandomChoiceEnchantment) WeightedRandom.a(random, map.values()); + + if (weightedrandomchoiceenchantment != null) { + arraylist = new ArrayList(); + arraylist.add(weightedrandomchoiceenchantment); + + for (int i1 = l >> 1; random.nextInt(50) <= i1; i1 >>= 1) { + Iterator iterator = map.keySet().iterator(); + + while (iterator.hasNext()) { + Integer integer = (Integer) iterator.next(); + boolean flag = true; + Iterator iterator1 = arraylist.iterator(); + + while (true) { + if (iterator1.hasNext()) { + WeightedRandomChoiceEnchantment weightedrandomchoiceenchantment1 = (WeightedRandomChoiceEnchantment) iterator1.next(); + + if (weightedrandomchoiceenchantment1.a.a(Enchantment.byId[integer.intValue()])) { + continue; + } + + flag = false; + } + + if (!flag) { + iterator.remove(); + } + break; + } + } + + if (!map.isEmpty()) { + WeightedRandomChoiceEnchantment weightedrandomchoiceenchantment2 = (WeightedRandomChoiceEnchantment) WeightedRandom.a(random, map.values()); + + arraylist.add(weightedrandomchoiceenchantment2); + } + } + } + } + + return arraylist; + } + } + + public static Map a(int i, ItemStack itemstack) { + Item item = itemstack.getItem(); + HashMap hashmap = null; + Enchantment[] aenchantment = Enchantment.byId; + int j = aenchantment.length; + + for (int k = 0; k < j; ++k) { + Enchantment enchantment = aenchantment[k]; + + if (enchantment != null && enchantment.slot.a(item)) { + for (int l = enchantment.getStartLevel(); l <= enchantment.getMaxLevel(); ++l) { + if (i >= enchantment.a(l) && i <= enchantment.b(l)) { + if (hashmap == null) { + hashmap = new HashMap(); + } + + hashmap.put(Integer.valueOf(enchantment.id), new WeightedRandomChoiceEnchantment(enchantment, l)); + } + } + } + } + + return hashmap; + } +} diff --git a/src/main/java/net/minecraft/server/EnchantmentModifier1.java b/src/main/java/net/minecraft/server/EnchantmentModifier1.java new file mode 100644 index 0000000000..2edeacfe9e --- /dev/null +++ b/src/main/java/net/minecraft/server/EnchantmentModifier1.java @@ -0,0 +1,17 @@ +package net.minecraft.server; + +final class EnchantmentModifier1 implements EnchantmentModifier { + + public int a; + public DamageSource b; + + private EnchantmentModifier1() {} + + public void a(Enchantment enchantment, int i) { + this.a += enchantment.a(i, this.b); + } + + EnchantmentModifier1(EmptyClass3 emptyclass3) { + this(); + } +} diff --git a/src/main/java/net/minecraft/server/EnchantmentModifier2.java b/src/main/java/net/minecraft/server/EnchantmentModifier2.java new file mode 100644 index 0000000000..b10eff5ebe --- /dev/null +++ b/src/main/java/net/minecraft/server/EnchantmentModifier2.java @@ -0,0 +1,17 @@ +package net.minecraft.server; + +final class EnchantmentModifier2 implements EnchantmentModifier { + + public int a; + public EntityLiving b; + + private EnchantmentModifier2() {} + + public void a(Enchantment enchantment, int i) { + this.a += enchantment.a(i, this.b); + } + + EnchantmentModifier2(EmptyClass3 emptyclass3) { + this(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 5a730fd948..4dd155a189 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -35,6 +35,7 @@ import jline.ConsoleReader; import net.minecraft.server.ChunkCoordinates; import net.minecraft.server.ConvertProgressUpdater; import net.minecraft.server.Convertable; +import net.minecraft.server.Enchantment; import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityTracker; import net.minecraft.server.IProgressUpdate; @@ -105,6 +106,11 @@ public final class CraftServer implements Server { Bukkit.setServer(this); + // Register all the Enchantments now so we can stop new registration immediately after + Enchantment.DAMAGE_ALL.getClass(); + org.bukkit.enchantments.Enchantment.stopAcceptingRegistrations(); + // Ugly hack :( + if (!Main.useConsole) { getLogger().info("Console input is disabled due to --noconsole command argument"); } diff --git a/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java new file mode 100644 index 0000000000..4fc391b467 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java @@ -0,0 +1,109 @@ +package org.bukkit.craftbukkit.enchantments; + +import net.minecraft.server.Item; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.enchantments.EnchantmentTarget; +import org.bukkit.enchantments.EnchantmentWrapper; +import org.bukkit.inventory.ItemStack; + +public class CraftEnchantment extends Enchantment { + private final net.minecraft.server.Enchantment target; + + public CraftEnchantment(net.minecraft.server.Enchantment target) { + super(target.id); + this.target = target; + } + + @Override + public int getMaxLevel() { + return target.getMaxLevel(); + } + + @Override + public int getStartLevel() { + return target.getStartLevel(); + } + + @Override + public EnchantmentTarget getItemTarget() { + switch (target.slot) { + case ALL: + return EnchantmentTarget.ALL; + case ARMOR: + return EnchantmentTarget.ARMOR; + case ARMOR_FEET: + return EnchantmentTarget.ARMOR_FEET; + case ARMOR_HEAD: + return EnchantmentTarget.ARMOR_HEAD; + case ARMOR_LEGS: + return EnchantmentTarget.ARMOR_LEGS; + case ARMOR_TORSO: + return EnchantmentTarget.ARMOR_TORSO; + case DIGGER: + return EnchantmentTarget.TOOL; + case WEAPON: + return EnchantmentTarget.WEAPON; + default: + return null; + } + } + + @Override + public boolean canEnchantItem(ItemStack item) { + return target.slot.a(Item.byId[item.getTypeId()]); + } + + @Override + public String getName() { + switch (target.id) { + case 0: + return "PROTECTION_ENVIRONMENTAL"; + case 1: + return "PROTECTION_FIRE"; + case 2: + return "PROTECTION_FALL"; + case 3: + return "PROTECTION_EXPLOSIONS"; + case 4: + return "PROTECTION_PROJECTILE"; + case 5: + return "OXYGEN"; + case 6: + return "WATER_WORKER"; + case 16: + return "DAMAGE_ALL"; + case 17: + return "DAMAGE_UNDEAD"; + case 18: + return "DAMAGE_ARTHROPODS"; + case 19: + return "KNOCKBACK"; + case 20: + return "FIRE_ASPECT"; + case 21: + return "LOOT_BONUS_MOBS"; + case 32: + return "DIG_SPEED"; + case 33: + return "SILK_TOUCH"; + case 34: + return "DURABILITY"; + case 35: + return "LOOT_BONUS_BLOCKS"; + default: + return "UNKNOWN_ENCHANT_" + target.id; + } + } + + public static net.minecraft.server.Enchantment getRaw(Enchantment enchantment) { + if (enchantment instanceof EnchantmentWrapper) { + enchantment = ((EnchantmentWrapper)enchantment).getEnchantment(); + } + + if (enchantment instanceof CraftEnchantment) { + return ((CraftEnchantment)enchantment).target; + } + + return null; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 0c3e853882..1f22ea4871 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -1,5 +1,12 @@ package org.bukkit.craftbukkit.inventory; +import java.util.HashMap; +import java.util.Map; +import net.minecraft.server.EnchantmentManager; +import net.minecraft.server.NBTBase; +import net.minecraft.server.NBTTagCompound; +import net.minecraft.server.NBTTagList; +import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.Material; import org.bukkit.configuration.serialization.DelegateDeserialization; @@ -129,4 +136,70 @@ public class CraftItemStack extends ItemStack { public int getMaxStackSize() { return item.getItem().getMaxStackSize(); } + + @Override + public void addUnsafeEnchantment(Enchantment ench, int level) { + Map enchantments = getEnchantments(); + enchantments.put(ench, level); + rebuildEnchantments(enchantments); + } + + @Override + public boolean containsEnchantment(Enchantment ench) { + return getEnchantmentLevel(ench) > 0; + } + + @Override + public int getEnchantmentLevel(Enchantment ench) { + return EnchantmentManager.b(ench.getId(), item); + } + + @Override + public int removeEnchantment(Enchantment ench) { + Map enchantments = getEnchantments(); + Integer previous = enchantments.remove(ench); + + rebuildEnchantments(enchantments); + + return (previous == null) ? 0 : previous; + } + + @Override + public Map getEnchantments() { + Map result = new HashMap(); + NBTTagList list = item.p(); + + if (list == null) { + return result; + } + + for (int i = 0; i < list.d(); i++) { + short id = ((NBTTagCompound)list.a(i)).e("id"); + short level = ((NBTTagCompound)list.a(i)).e("lvl"); + + result.put(Enchantment.getById(id), (int)level); + } + + return result; + } + + private void rebuildEnchantments(Map enchantments) { + NBTTagCompound tag = item.tag; + NBTTagList list = new NBTTagList("ench"); + + if (tag == null) { + tag = item.tag = new NBTTagCompound(); + } + + for (Map.Entry entry : enchantments.entrySet()) { + NBTTagCompound subtag = new NBTTagCompound(); + + subtag.a("id", (short)entry.getKey().getId()); + subtag.a("lvl", (short)(int)entry.getValue()); + + list.a(subtag); + } + + tag.a("ench", (NBTBase)list); + } }