private static void HandleEnchantScroll(GameSession session, Item item)
    {
        EnchantScrollMetadata metadata = EnchantScrollMetadataStorage.GetMetadata(item.Function.Id);

        if (metadata is null)
        {
            return;
        }

        Script script      = ScriptLoader.GetScript("Functions/ItemEnchantScroll/getSuccessRate");
        float  successRate = (float)script.RunFunction("getSuccessRate", metadata.Id).Number;

        session.Send(EnchantScrollPacket.OpenWindow(item.Uid, metadata, successRate));
    }
    private static void HandleUseScroll(GameSession session, Item equip, Item scroll, Dictionary <StatAttribute, ItemStat> enchantStats, int enchantLevel, int scrollId)
    {
        Script script      = ScriptLoader.GetScript("Functions/ItemEnchantScroll/getSuccessRate");
        float  successRate = (float)script.RunFunction("getSuccessRate", scrollId).Number;

        int  randomValue   = Random.Shared.Next(0, 10000 + 1);
        bool scrollSuccess = successRate * 10000 >= randomValue;

        session.Player.Inventory.ConsumeItem(session, scroll.Uid, 1);

        if (scrollSuccess)
        {
            equip.EnchantLevel   = enchantLevel;
            equip.EnchantExp     = 0;
            equip.Stats.Enchants = enchantStats;
            session.Send(EnchantScrollPacket.UseScroll((short)EnchantScrollError.None, equip));
        }
    }
    public override void Handle(GameSession session, PacketReader packet)
    {
        EnchantScrollMode mode = (EnchantScrollMode)packet.ReadByte();

        long scrollUid = packet.ReadLong();
        long equipUid  = packet.ReadLong();

        Player player = session.Player;

        if (!player.Inventory.HasItem(equipUid) && !player.Inventory.HasItem(scrollUid))
        {
            session.Send(EnchantScrollPacket.UseScroll((short)EnchantScrollError.ItemsNoLongerValid));
            return;
        }

        Item scroll = player.Inventory.GetByUid(scrollUid);
        Item equip  = player.Inventory.GetByUid(equipUid);

        EnchantScrollMetadata metadata = EnchantScrollMetadataStorage.GetMetadata(scroll.Function.Id);

        if (metadata is null)
        {
            return;
        }

        if (!metadata.Rarities.Contains(equip.Rarity))
        {
            session.Send(EnchantScrollPacket.UseScroll((short)EnchantScrollError.CannotBeEnchantedDueToRarity));
            return;
        }

        if (metadata.MinLevel > equip.Level || metadata.MaxLevel < equip.Level)
        {
            session.Send(EnchantScrollPacket.UseScroll((short)EnchantScrollError.InsufficientItemLevel));
            return;
        }

        if (!metadata.ItemTypes.Contains(equip.Type))
        {
            session.Send(EnchantScrollPacket.UseScroll((short)EnchantScrollError.IneligibleItem));
            return;
        }

        if (equip.EnchantLevel >= metadata.EnchantLevels.Last())
        {
            session.Send(EnchantScrollPacket.UseScroll((short)EnchantScrollError.GearCannotBeEnchanted));
            return;
        }

        int enchantLevelIndex = Random.Shared.Next(metadata.EnchantLevels.Count);
        Dictionary <StatAttribute, ItemStat> enchantStats = EnchantHelper.GetEnchantStats(metadata.EnchantLevels[enchantLevelIndex], equip.Type, equip.Level);

        switch (mode)
        {
        case EnchantScrollMode.AddItem:
            session.Send(EnchantScrollPacket.AddItem(equipUid, enchantStats));
            break;

        case EnchantScrollMode.UseScroll:
            HandleUseScroll(session, equip, scroll, enchantStats, metadata.EnchantLevels[enchantLevelIndex], metadata.Id);
            break;

        default:
            LogUnknownMode(mode);
            break;
        }
    }