add enchantments (#7)

* adding enchantments

added enchantments, changed minor apis to ensure c# stays synced with the c++ server

* add missing enchant apis, oops

* add proper docs, and fix namings for stuff in itemmeta

---------

Co-authored-by: sylvessa <225480449+sylvessa@users.noreply.github.com>
This commit is contained in:
DrPerkyLegit 2026-03-28 14:33:54 -04:00 committed by GitHub
parent 921abd48a7
commit 017f42b7cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 1181 additions and 4 deletions

View file

@ -0,0 +1,4 @@
[*.cs]
# IDE1006: Naming Styles
dotnet_diagnostic.IDE1006.severity = suggestion

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class AquaAffinityEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.CHAINMAIL_HELMET, Material.GOLD_HELMET, Material.IRON_HELMET, Material.DIAMOND_HELMET,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR_HEAD;
public override EnchantmentType getEnchantType() => EnchantmentType.WATER_WORKER;
public override int getMaxLevel() => 1;
public override string getName() => "aquaaffinity";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,31 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
//name could be changed
public class BaneOfArthropodsEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.DAMAGE_ALL,
EnchantmentType.DAMAGE_UNDEAD,
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
public override EnchantmentType getEnchantType() => EnchantmentType.DAMAGE_ARTHOPODS;
public override int getMaxLevel() => 5;
public override string getName() => "arthopods"; //could be changed
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,34 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class BlastProtectionEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.PROTECTION_ENVIRONMENTAL,
EnchantmentType.PROTECTION_FIRE,
EnchantmentType.PROTECTION_PROJECTILE,
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_EXPLOSIVE;
public override int getMaxLevel() => 4;
public override string getName() => "blastprotection";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,32 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class EfficiencyEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
Material.SHEARS
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.TOOL;
public override EnchantmentType getEnchantType() => EnchantmentType.DIG_SPEAD;
public override int getMaxLevel() => 5;
public override string getName() => "efficiency";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,274 @@
namespace Minecraft.Server.FourKit.Enchantments;
using Minecraft.Server.FourKit.Inventory;
/// <summary>
/// Represents the applicable target for a Enchantment
/// </summary>
public enum EnchantmentTarget
{
/// <summary>
/// Allows the Enchantment to be placed on all items
/// </summary>
ALL,
/// <summary>
/// Allows the Enchantment to be placed on armor
/// </summary>
ARMOR,
/// <summary>
/// Allows the Enchantment to be placed on feet slot armor
/// </summary>
ARMOR_FEET,
/// <summary>
/// Allows the Enchantment to be placed on head slot armor
/// </summary>
ARMOR_HEAD,
/// <summary>
/// Allows the Enchantment to be placed on leg slot armor
/// </summary>
ARMOR_LEGS,
/// <summary>
/// Allows the Enchantment to be placed on torso slot armor
/// </summary>
ARMOR_TORSO,
/// <summary>
/// Allows the Enchantment to be placed on bows.
/// </summary>
BOW,
/// <summary>
/// Allows the Enchantment to be placed on tools (spades, pickaxe, hoes, axes)
/// </summary>
TOOL,
/// <summary>
/// Allows the Enchantment to be placed on weapons (swords)
/// </summary>
WEAPON,
}
//these numbers match the same ones that the enchants register as, Enchantment.cpp - 41
/// <summary>
/// The various type of enchantments that may be added to armour or weapons
/// </summary>
public enum EnchantmentType
{
/// <summary>
/// Provides extra damage when shooting arrows from bows
/// </summary>
ARROW_DAMAGE = 48,
/// <summary>
/// Sets entities on fire when hit by arrows shot from a bow
/// </summary>
ARROW_FIRE = 50,
/// <summary>
/// Provides infinite arrows when shooting a bow
/// </summary>
ARROW_INFINITE = 51,
/// <summary>
/// Provides a knockback when an entity is hit by an arrow from a bow
/// </summary>
ARROW_KNOCKBACK = 49,
/// <summary>
/// Increases damage against all targets
/// </summary>
DAMAGE_ALL = 16,
/// <summary>
/// Increases damage against arthropod targets
/// </summary>
DAMAGE_ARTHOPODS = 18,
/// <summary>
/// Increases damage against undead targets
/// </summary>
DAMAGE_UNDEAD = 17,
/// <summary>
/// Increases the rate at which you mine/dig
/// </summary>
DIG_SPEAD = 32,
/// <summary>
/// Decreases the rate at which a tool looses durability
/// </summary>
DURABILITY = 34,
/// <summary>
/// When attacking a target, has a chance to set them on fire
/// </summary>
FIRE_ASPECT = 20,
/// <summary>
/// All damage to other targets will knock them back when hit
/// </summary>
KNOCKBACK = 19,
/// <summary>
/// Provides a chance of gaining extra loot when destroying blocks
/// </summary>
LOOT_BONUS_BLOCKS = 35,
/// <summary>
/// Provides a chance of gaining extra loot when killing monsters
/// </summary>
LOOT_BONUS_MOBS = 21,
/// <summary>
/// Decreases the rate of air loss whilst underwater
/// </summary>
OXYGEN = 5,
/// <summary>
/// Provides protection against environmental damage
/// </summary>
PROTECTION_ENVIRONMENTAL = 0,
/// <summary>
/// Provides protection against explosive damage
/// </summary>
PROTECTION_EXPLOSIVE = 3,
/// <summary>
/// Provides protection against fall damage
/// </summary>
PROTECTION_FALL = 2,
/// <summary>
/// Provides protection against fire damage
/// </summary>
PROTECTION_FIRE = 1,
/// <summary>
/// Provides protection against projectile damage
/// </summary>
PROTECTION_PROJECTILE = 4,
/// <summary>
/// Allows blocks to drop themselves instead of fragments (for example, stone instead of cobblestone)
/// </summary>
SILK_TOUCH = 33,
/// <summary>
/// Damages the attacker
/// </summary>
THORNS = 7,
/// <summary>
/// Increases the speed at which a player may mine underwater
/// </summary>
WATER_WORKER = 6
}
public abstract class Enchantment
{
public static Enchantment PowerEnchantment => _registry[EnchantmentType.ARROW_DAMAGE];
public static Enchantment FlameEnchantment => _registry[EnchantmentType.ARROW_FIRE];
public static Enchantment InfinityEnchantment => _registry[EnchantmentType.ARROW_INFINITE];
public static Enchantment PunchEnchantment => _registry[EnchantmentType.ARROW_KNOCKBACK];
public static Enchantment SharpnessEnchantment => _registry[EnchantmentType.DAMAGE_ALL];
public static Enchantment BaneOfArthropodsEnchantment => _registry[EnchantmentType.DAMAGE_ARTHOPODS];
public static Enchantment SmiteEnchantment => _registry[EnchantmentType.DAMAGE_UNDEAD];
public static Enchantment EfficiencyEnchantment => _registry[EnchantmentType.DIG_SPEAD];
public static Enchantment UnbreakingEnchantment => _registry[EnchantmentType.DURABILITY];
public static Enchantment FireAspectEnchantment => _registry[EnchantmentType.FIRE_ASPECT];
public static Enchantment KnockbackEnchantment => _registry[EnchantmentType.KNOCKBACK];
public static Enchantment FortuneEnchantment => _registry[EnchantmentType.LOOT_BONUS_BLOCKS];
public static Enchantment LootingEnchantment => _registry[EnchantmentType.LOOT_BONUS_MOBS];
public static Enchantment RespirationEnchantment => _registry[EnchantmentType.OXYGEN];
public static Enchantment ProtectionEnchantment => _registry[EnchantmentType.PROTECTION_ENVIRONMENTAL];
public static Enchantment BlastProtectionEnchantment => _registry[EnchantmentType.PROTECTION_EXPLOSIVE];
public static Enchantment FeatherFallingEnchantment => _registry[EnchantmentType.PROTECTION_FALL];
public static Enchantment FireProtectionEnchantment => _registry[EnchantmentType.PROTECTION_FIRE];
public static Enchantment ProjectileProtectionEnchantment => _registry[EnchantmentType.PROTECTION_PROJECTILE];
public static Enchantment SilkTouchEnchantment => _registry[EnchantmentType.SILK_TOUCH];
public static Enchantment ThornsEnchantment => _registry[EnchantmentType.THORNS];
public static Enchantment AquaAffinityEnchantment => _registry[EnchantmentType.WATER_WORKER];
private static Dictionary<EnchantmentType, Enchantment> _registry = new Dictionary<EnchantmentType, Enchantment>()
{
{ EnchantmentType.ARROW_DAMAGE, new PowerEnchantment() },
{ EnchantmentType.ARROW_FIRE, new FlameEnchantment() },
{ EnchantmentType.ARROW_INFINITE, new InfinityEnchantment() },
{ EnchantmentType.ARROW_KNOCKBACK, new PunchEnchantment() },
{ EnchantmentType.DAMAGE_ALL, new SharpnessEnchantment() },
{ EnchantmentType.DAMAGE_ARTHOPODS, new BaneOfArthropodsEnchantment() },
{ EnchantmentType.DAMAGE_UNDEAD, new SmiteEnchantment() },
{ EnchantmentType.DIG_SPEAD, new EfficiencyEnchantment() },
{ EnchantmentType.DURABILITY, new UnbreakingEnchantment() },
{ EnchantmentType.FIRE_ASPECT, new FireAspectEnchantment() },
{ EnchantmentType.KNOCKBACK, new KnockbackEnchantment() },
{ EnchantmentType.LOOT_BONUS_BLOCKS, new FortuneEnchantment() },
{ EnchantmentType.LOOT_BONUS_MOBS, new LootingEnchantment() },
{ EnchantmentType.OXYGEN, new RespirationEnchantment() },
{ EnchantmentType.PROTECTION_ENVIRONMENTAL, new ProtectionEnchantment() },
{ EnchantmentType.PROTECTION_EXPLOSIVE, new BlastProtectionEnchantment() },
{ EnchantmentType.PROTECTION_FALL, new FeatherFallingEnchantment() },
{ EnchantmentType.PROTECTION_FIRE, new FireProtectionEnchantment() },
{ EnchantmentType.PROTECTION_PROJECTILE, new ProjectileProtectionEnchantment() },
{ EnchantmentType.SILK_TOUCH, new SilkTouchEnchantment() },
{ EnchantmentType.THORNS, new ThornsEnchantment() },
{ EnchantmentType.WATER_WORKER, new AquaAffinityEnchantment() },
};
/// <summary>
/// Checks if this Enchantment may be applied to the given <see cref="ItemStack"/>. This does not check if it conflicts with any enchantments already applied to the item.
/// </summary>
/// <param name="item">Item to test</param>
/// <returns>True if the enchantment may be applied, otherwise False</returns>
public abstract bool canEnchantItem(ItemStack item);
/// <summary>
/// Check if this enchantment conflicts with another enchantment.
/// </summary>
/// <param name="other">The enchantment to check against </param>
/// <returns>True if there is a conflict.</returns>
public abstract bool conflictsWith(Enchantment other);
//public abstract Enchantment getById(int id); //deprecated by bukkit
/// <summary>
/// Gets the Enchantment at the specified name
/// </summary>
/// <param name="name">Name to fetch.</param>
/// <returns>Resulting Enchantment, or null if not found</returns>
public static Enchantment? getByName(string name)
{
foreach (KeyValuePair<EnchantmentType, Enchantment> enchantmentPair in _registry)
{
if (enchantmentPair.Value.getName().Equals(name)) return enchantmentPair.Value;
}
return null;
}
/// <summary>
/// Gets the Enchantment at the specified type
/// </summary>
/// <param name="type">Type to fetch.</param>
/// <returns>Resulting Enchantment, or null if not found</returns>
public static Enchantment getByType(EnchantmentType type)
{
return _registry[type]; //we should always have the enchant based on the type
}
//public abstract int getId(); //deprecated by bukkit
/// <summary>
/// Gets the type of <see cref="ItemStack"/> that may fit this Enchantment.
/// </summary>
/// <returns>Gets the type of <see cref="ItemStack"/> that may fit this Enchantment.</returns>
public abstract EnchantmentTarget getItemTarget();
/// <summary>
/// Returns the <see cref="EnchantmentType"/>.
/// </summary>
/// <returns>Gets the enchantment type.</returns>
public abstract EnchantmentType getEnchantType();
/// <summary>
/// Gets the maximum level that this Enchantment may become.
/// </summary>
/// <returns>Maximum level of the Enchantment</returns>
public abstract int getMaxLevel();
/// <summary>
/// Gets the unique name of this enchantment
/// </summary>
/// <returns>Unique name</returns>
public abstract string getName();
/// <summary>
/// Gets the level that this Enchantment should start at
/// </summary>
/// <returns>Starting level of the Enchantment</returns>
public abstract int getStartLevel();
//public static bool isAcceptingRegistrations(); //we dont have enchant registrations
//public static void registerEnchantment(Enchantment enchantment); //we dont have enchant registrations
//public static void stopAcceptingRegistrations(); //we dont have enchant registrations
}

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class FeatherFallingEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_BOOTS, Material.LEATHER_BOOTS, Material.CHAINMAIL_BOOTS, Material.GOLD_BOOTS, Material.IRON_BOOTS, Material.DIAMOND_BOOTS,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR_FEET;
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_FALL;
public override int getMaxLevel() => 4;
public override string getName() => "featherfalling";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,27 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class FireAspectEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
public override EnchantmentType getEnchantType() => EnchantmentType.FIRE_ASPECT;
public override int getMaxLevel() => 2;
public override string getName() => "fireaspect";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,34 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class FireProtectionEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.PROTECTION_ENVIRONMENTAL,
EnchantmentType.PROTECTION_EXPLOSIVE,
EnchantmentType.PROTECTION_PROJECTILE,
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_FIRE;
public override int getMaxLevel() => 4;
public override string getName() => "fireprotection";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class FlameEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.BOW
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_FIRE;
public override int getMaxLevel() => 1;
public override string getName() => "flame";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,31 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class FortuneEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.SILK_TOUCH
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.TOOL;
public override EnchantmentType getEnchantType() => EnchantmentType.LOOT_BONUS_BLOCKS;
public override int getMaxLevel() => 3;
public override string getName() => "fortune";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class InfinityEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.BOW
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_INFINITE;
public override int getMaxLevel() => 1;
public override string getName() => "infinity";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,27 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class KnockbackEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
public override EnchantmentType getEnchantType() => EnchantmentType.KNOCKBACK;
public override int getMaxLevel() => 2;
public override string getName() => "knockback";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,27 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class LootingEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
public override EnchantmentType getEnchantType() => EnchantmentType.LOOT_BONUS_MOBS;
public override int getMaxLevel() => 3;
public override string getName() => "looting";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class PowerEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.BOW
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_DAMAGE;
public override int getMaxLevel() => 5;
public override string getName() => "power";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,34 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class ProjectileProtectionEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.PROTECTION_ENVIRONMENTAL,
EnchantmentType.PROTECTION_EXPLOSIVE,
EnchantmentType.PROTECTION_FIRE,
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_PROJECTILE;
public override int getMaxLevel() => 4;
public override string getName() => "projectileprotection";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,34 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class ProtectionEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.PROTECTION_EXPLOSIVE,
EnchantmentType.PROTECTION_FIRE,
EnchantmentType.PROTECTION_PROJECTILE,
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
public override EnchantmentType getEnchantType() => EnchantmentType.PROTECTION_ENVIRONMENTAL;
public override int getMaxLevel() => 4;
public override string getName() => "protection";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class PunchEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.BOW
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.BOW;
public override EnchantmentType getEnchantType() => EnchantmentType.ARROW_KNOCKBACK;
public override int getMaxLevel() => 2;
public override string getName() => "punch";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,26 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class RespirationEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.CHAINMAIL_HELMET, Material.GOLD_HELMET, Material.IRON_HELMET, Material.DIAMOND_HELMET,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR_HEAD;
public override EnchantmentType getEnchantType() => EnchantmentType.OXYGEN;
public override int getMaxLevel() => 3;
public override string getName() => "respiration";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,30 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class SharpnessEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.DAMAGE_ARTHOPODS,
EnchantmentType.DAMAGE_UNDEAD
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
public override EnchantmentType getEnchantType() => EnchantmentType.DAMAGE_ALL;
public override int getMaxLevel() => 5;
public override string getName() => "sharpness";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,33 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class SilkTouchEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
Material.SHEARS
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.LOOT_BONUS_BLOCKS
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.TOOL;
public override EnchantmentType getEnchantType() => EnchantmentType.SILK_TOUCH;
public override int getMaxLevel() => 1;
public override string getName() => "silktouch";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,30 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class SmiteEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
};
static readonly EnchantmentType[] conflictedEnchants = {
EnchantmentType.DAMAGE_ALL,
EnchantmentType.DAMAGE_ARTHOPODS
};
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.WEAPON;
public override EnchantmentType getEnchantType() => EnchantmentType.DAMAGE_UNDEAD;
public override int getMaxLevel() => 5;
public override string getName() => "smite";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,30 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class ThornsEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ARMOR;
public override EnchantmentType getEnchantType() => EnchantmentType.THORNS;
public override int getMaxLevel() => 3;
public override string getName() => "thorns";
public override int getStartLevel() => 1;
}

View file

@ -0,0 +1,39 @@
using Minecraft.Server.FourKit.Inventory;
namespace Minecraft.Server.FourKit.Enchantments;
public class UnbreakingEnchantment : Enchantment
{
static readonly Material[] supportedItems = {
Material.WOOD_SWORD, Material.STONE_SWORD, Material.IRON_SWORD, Material.GOLD_SWORD, Material.DIAMOND_SWORD,
Material.WOOD_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.GOLD_PICKAXE, Material.DIAMOND_PICKAXE,
Material.WOOD_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.GOLD_AXE, Material.DIAMOND_AXE,
Material.WOOD_SPADE, Material.STONE_SPADE, Material.IRON_SPADE, Material.GOLD_SPADE, Material.DIAMOND_SPADE,
Material.WOOD_HOE, Material.STONE_HOE, Material.IRON_HOE, Material.GOLD_HOE, Material.DIAMOND_HOE,
Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS,
Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS,
Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS,
Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS,
Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS,
Material.FISHING_ROD, Material.BOW,
Material.SHEARS, Material.FLINT_AND_STEEL, Material.CARROT_STICK
};
static readonly EnchantmentType[] conflictedEnchants = { };
public override bool canEnchantItem(ItemStack item) => supportedItems.Contains(item.getType());
public override bool conflictsWith(Enchantment other) => conflictedEnchants.Contains(other.getEnchantType());
public override EnchantmentTarget getItemTarget() => EnchantmentTarget.ALL;
public override EnchantmentType getEnchantType() => EnchantmentType.DURABILITY;
public override int getMaxLevel() => 3;
public override string getName() => "unbreaking";
public override int getStartLevel() => 1;
}

View file

@ -126,6 +126,7 @@ public class ItemStack
public bool setItemMeta(ItemMeta? itemMeta)
{
_meta = itemMeta?.clone();
SyncToOwner();
return true;
}

View file

@ -1,11 +1,14 @@
namespace Minecraft.Server.FourKit.Inventory.Meta;
using Minecraft.Server.FourKit.Enchantments;
/// <summary>
/// Represents the metadata of an <see cref="ItemStack"/>, including display name and lore.
/// </summary>
public class ItemMeta
{
private string? _displayName;
private Dictionary<EnchantmentType, int>? _enchants;
private List<string>? _lore;
/// <summary>
@ -49,16 +52,123 @@ public class ItemMeta
_lore = lore != null ? new List<string>(lore) : null;
}
/// <summary>
/// Adds the specified enchantment to this item meta.
/// </summary>
/// <param name="enchantment">Enchantment to add</param>
/// <param name="level">Level for the enchantment</param>
/// <param name="ignoreLevelRestriction">Indicates the enchantment should be applied, ignoring the level limit</param>
/// <returns>true if the item meta changed as a result of this call, false otherwise</returns>
public bool addEnchant(EnchantmentType enchantment, int level, bool ignoreLevelRestriction)
{
if (_enchants == null)
_enchants = new Dictionary<EnchantmentType, int>();
if (!ignoreLevelRestriction)
{
Enchantment enchant = Enchantment.getByType(enchantment);
if (enchant.getMaxLevel() < level) return false;
}
try
{
_enchants.Add(enchantment, level);
return true;
} catch { }
return false;
}
/// <summary>
/// Removes the specified enchantment from this item meta.
/// </summary>
/// <param name="enchantment">Enchantment to remove</param>
/// <returns>true if the item meta changed as a result of this call, false otherwise</returns>
public bool removeEnchant(EnchantmentType enchantment)
{
if (!hasEnchant(enchantment)) return false;
return _enchants.Remove(enchantment);
}
/// <summary>
/// Returns a copy of the enchantments in this ItemMeta. Returns an empty map if none.
/// </summary>
/// <returns>An immutable copy of the enchantments</returns>
public Dictionary<EnchantmentType, int> getEnchants() => _enchants != null ? new Dictionary<EnchantmentType, int>(_enchants) { } : new Dictionary<EnchantmentType, int>();
/// <summary>
/// Checks for the level of the specified enchantment.
/// </summary>
/// <param name="enchantment">Enchantment to check</param>
/// <returns>The level that the specified enchantment has, or 0 if none</returns>
public int getEnchantLevel(EnchantmentType enchantment)
{
if (!hasEnchant(enchantment)) return 0;
return _enchants[enchantment]; //this cant be invalid, we check above
}
/// <summary>
/// Checks if the specified enchantment conflicts with any enchantments in this ItemMeta.
/// </summary>
/// <param name="enchantment">Enchantment to test</param>
/// <returns>true if the enchantment conflicts, false otherwise</returns>
public bool hasConflictingEnchant(EnchantmentType enchantment)
{
Enchantment enchantmentClass = Enchantment.getByType(enchantment);
if (enchantmentClass == null) return false; //this should never happen
foreach (KeyValuePair<EnchantmentType, int> ench in _enchants)
{
Enchantment enchClass = Enchantment.getByType(ench.Key);
if (enchClass == null) continue; //this should never happen
if (enchClass.conflictsWith(enchantmentClass))
{
return true;
}
}
return false;
}
/// <summary>
/// Checks for existence of the specified enchantment.
/// </summary>
/// <param name="enchantment">Enchantment to check</param>
/// <returns>true if this enchantment exists for this meta</returns>
public bool hasEnchant(EnchantmentType enchantment) => hasEnchants() && _enchants.ContainsKey(enchantment);
/// <summary>
/// Checks for the existence of any enchantments.
/// </summary>
/// <returns>true if an enchantment exists on this meta</returns>
public bool hasEnchants() => _enchants != null && _enchants.Count > 0;
/// <summary>
/// Sets the enchantments for this item meta.
/// </summary>
/// <param name="enchants">The enchantments to set.</param>
public void setEnchants(Dictionary<EnchantmentType, int>? enchants)
{
enchants = enchants != null ? new Dictionary<EnchantmentType, int>(enchants) : null;
}
public ItemMeta clone()
{
var copy = new ItemMeta();
copy._displayName = _displayName;
copy._enchants = _enchants != null ? new Dictionary<EnchantmentType, int>(_enchants) : null;
copy._lore = _lore != null ? new List<string>(_lore) : null;
return copy;
}
internal bool isEmpty()
{
return _displayName == null && (_lore == null || _lore.Count == 0);
return _displayName == null && (_lore == null || _lore.Count == 0) && (_enchants == null || _enchants.Count == 0);
}
}

View file

@ -1,7 +1,9 @@
namespace Minecraft.Server.FourKit.Inventory;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using Minecraft.Server.FourKit.Enchantments;
using Minecraft.Server.FourKit.Entity;
using Minecraft.Server.FourKit.Inventory.Meta;
@ -154,7 +156,10 @@ public class PlayerInventory : Inventory
/// Gets the item the player is currently holding.
/// </summary>
/// <returns>The held ItemStack.</returns>
public ItemStack? getItemInHand() => getItem(_heldItemSlot);
public ItemStack? getItemInHand() {
EnsureSynced();
return getItem(_heldItemSlot);
}
/// <summary>
/// Sets the item in the player's hand.
@ -278,7 +283,33 @@ public class PlayerInventory : Inventory
}
}
if (displayName == null && (lore == null || lore.Count == 0))
int enchantCount = 0;
if (offset + 4 <= bytesWritten)
{
enchantCount = BitConverter.ToInt32(buf, offset);
offset += 4;
}
Dictionary<EnchantmentType, int>? enchants = null;
if (enchantCount > 0)
{
enchants = new Dictionary<EnchantmentType, int>(enchantCount);
for (int i = 0; i < enchantCount; i++)
{
if (offset + (4 + 4) > bytesWritten)
break;
int type = BitConverter.ToInt32(buf, offset);
offset += 4;
int level = BitConverter.ToInt32(buf, offset);
offset += 4;
enchants.Add((EnchantmentType)type, level);
}
}
if (displayName == null && (lore == null || lore.Count == 0) && (enchants == null || enchants.Count == 0))
return null;
var meta = new ItemMeta();
@ -286,6 +317,8 @@ public class PlayerInventory : Inventory
meta.setDisplayName(displayName);
if (lore != null && lore.Count > 0)
meta.setLore(lore);
if (enchants != null && enchants.Count > 0)
meta.setEnchants(enchants);
return meta;
}
@ -330,6 +363,27 @@ public class PlayerInventory : Inventory
bw.Write(0);
}
if (meta.hasEnchants())
{
Debug.WriteLine("Writting Enchants");
var enchants = meta.getEnchants();
bw.Write(enchants.Count);
foreach (var enchant in enchants)
{
Debug.WriteLine("Wrote A Enchant");
bw.Write((int)enchant.Key);
bw.Write(enchant.Value);
}
}
else
{
Debug.WriteLine("Had No Enchants");
bw.Write(0);
}
bw.Flush();
byte[] data = ms.ToArray();
var gh = GCHandle.Alloc(data, GCHandleType.Pinned);

View file

@ -41,6 +41,7 @@
#include "Access\Access.h"
#include "Common\NetworkUtils.h"
#include "ServerLogManager.h"
#include "../Minecraft.World/ItemInstance.cpp"
namespace
{
@ -751,10 +752,12 @@ void __cdecl NativeOpenVirtualContainer(int entityId, int nativeType, const char
player->openContainer(container);
}
//didnt update this for enchants
// [nameLen:int32][nameUTF8:bytes][loreCount:int32][lore0Len:int32][lore0UTF8:bytes]
int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
{
printf("NativeGetItemMeta::entry\n");
auto player = FindPlayer(entityId);
if (!player || !player->inventory)
return 0;
@ -775,6 +778,8 @@ int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
bool hasName = display->contains(L"Name");
bool hasLore = display->contains(L"Lore");
bool hasEnchantments = item->isEnchanted();
if (!hasName && !hasLore)
return 0;
@ -827,6 +832,34 @@ int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
offset += 4;
}
if (hasEnchantments) {
ListTag<CompoundTag>* list = item->getEnchantmentTags();
if (list != nullptr) {
int listSize = list->size();
if ((offset + 4 + (listSize * (4 + 4))) > bufSize) return 0;
memcpy(outBuf + offset, &listSize, 4);
offset += 4;
for (int i = 0; i < listSize; i++) {
int type = list->get(i)->getShort((wchar_t*)ItemInstance::TAG_ENCH_ID);
int level = list->get(i)->getShort((wchar_t*)ItemInstance::TAG_ENCH_LEVEL);
memcpy(outBuf + offset, &type, 4);
offset += 4;
memcpy(outBuf + offset, &level, 4);
offset += 4;
}
}
}
else {
int zero = 0;
if (offset + 4 > bufSize) return 0;
memcpy(outBuf + offset, &zero, 4);
offset += 4;
}
return offset;
}
@ -861,6 +894,11 @@ void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bu
item->setTag(nullptr);
}
}
if (tag && tag->contains(L"ench"))
{
tag->remove(L"ench");
}
}
return;
}
@ -925,6 +963,47 @@ void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bu
tag->getCompound(L"display")->remove(L"Lore");
}
}
if (offset + 4 > bufSize) return;
int enchantCount = 0;
memcpy(&enchantCount, inBuf + offset, 4);
offset += 4;
if (enchantCount > 0)
{
if (!item->hasTag()) item->setTag(new CompoundTag());
CompoundTag* tag = item->getTag();
if (!tag->contains(L"ench")) tag->put(L"ench", new ListTag<CompoundTag>(L"ench"));
ListTag<CompoundTag>* enchantments = static_cast<ListTag<CompoundTag> *>(tag->get(L"ench"));
for (int i = 0; i < enchantCount; i++) {
if (offset + (4 + 4) > bufSize) break;
int type = 0;
memcpy(&type, inBuf + offset, 4);
offset += 4;
int level = 0;
memcpy(&level, inBuf + offset, 4);
offset += 4;
CompoundTag* ench = new CompoundTag();
ench->putShort((wchar_t*)ItemInstance::TAG_ENCH_ID, static_cast<short>(type));
ench->putShort((wchar_t*)ItemInstance::TAG_ENCH_LEVEL, static_cast<byte>(level));
enchantments->add(ench);
}
}
else
{
if (item->hasTag())
{
CompoundTag* tag = item->getTag();
if (tag && tag->contains(L"ench"))
{
tag->remove(L"ench");
}
}
}
}
void __cdecl NativeSetHeldItemSlot(int entityId, int slot)