import * as mc from "@minecraft/server";
import * as GMath from "./utils/GMath";
import * as EntityRun from "./utils/EntityRuntime";
import { EntityUtils } from "./utils/EntityUtils";
import backpackAbilities from "./configs/backpackAbilities";
import projectileAbilities from "./configs/projectileAbilities";

//Classes
class Button {
    /**
     * 
     * @param {number} slot 
     * @param {string} itemType 
     * @param {mc.Container} inventory 
     * @param {mc.Entity} entity
     */
    constructor(slot, itemType, inventory, entity) {
        this.type = itemType
        this.lastType = itemType
        this.slot = slot
        this.inventory = inventory
        this.entity = entity
        this.updateButton(true)
    }
    changed = false
    lore = []
    state = "released"
    onPressed = (slot) => { }
    onReleased = (slot) => { }
    onUpdate = (current_state) => { }
    setLore(lore = []) {
        this.lore = lore
        const slot = this.inventory.getSlot(this.slot)
        //  //console.warn("Lore")
        const item = new mc.ItemStack(this.type)
        item.setLore(this.lore)
        slot.setItem(item)
    }
    changeItem(itemType) {
        this.changed = true
        this.type = itemType
    }
    updateButton(start = false) {
        const slot = this.inventory.getSlot(this.slot)
        const pressed = ((slot.hasItem() && (slot.typeId != this.type)) || !slot.hasItem())
        if (start == false) {
            if (slot.hasItem() && slot.typeId != this.type && this.changed == false) {
                this.entity.dimension.spawnItem(slot.getItem(), this.entity.location)
            }
        }
        if (pressed) {
            const item = new mc.ItemStack(this.type)

            item.setLore(this.lore)
            slot.setItem(item)
            if (this.lastType == this.type) {
                this.changed = false
                if (start == false && this.state == "released") {
                    this.onPressed(this.slot)
                    state = "pressed"
                }
            } else {
                // //console.warn(this.type)
                this.lastType = this.type
            }
        } else {
            if (this.state == "pressed") {
                this.state = "released"
                this.onReleased(this.slot)
            }
        }
        this.onUpdate(this.state)
    }
}
//Variables
const validTiers = [
    "snst_bckp:wooden_tier",
    "snst_bckp:leather_tier",
    "snst_bckp:iron_tier",
    "snst_bckp:diamond_tier",
    "snst_bckp:netherite_tier",
]
//Functions
/**
 * 
 * @param {mc.ContainerSlot} slot 
 * @param {'+', '-'} mode 
 * @param {number} value
 */
function operateSlot(slot, mode, value, container) {

    if (typeof (slot) == "number") {
        slot = container.getSlot(slot)
    }
    const item = slot.getItem().clone()
    if (mode == "+") {
        var nextValue = item.amount + value
        item.amount = nextValue < item.maxAmount ? nextValue : item.amount
        slot.setItem(item)

    } else if (mode == "-") {
        var nextValue = item.amount - value
        item.amount = nextValue > 0 ? nextValue : 1
        slot.setItem(nextValue <= 0 ? undefined : item)
    }
    return slot
}
function createList(array, itemsPerPage) {
    const result = []
    for (let i = 0; i < array.length; i += itemsPerPage) {
        result.push(array.slice(i, i + itemsPerPage));
    }
    return result
}
//Entities
class Backpack extends EntityRun.EntityObject {
    /**@type {mc.Entity} */
    owner = undefined
    /**@type {Button[]} */
    buttons = []
    /**@type {Button[]} */
    utilityArea = []
    /**@type {Button[]} */
    waterSlots = []
    /**@type {Button[]} */
    lavaSlots = []
    onUpdateInventory() {
        if (!this.owner) { return; }
        const ownerHand = EntityUtils.getHandSlot(this.owner)
        const entity = this.getEntity()
        const data = this.data
        const container = this.getInventory()
        const inventory = this.getInventorySlots()
        const containerSlots = [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25]
        const lockedSlots = [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 17, 8, 26]
        const backpackTier = ownerHand.getTags().find(e => validTiers.includes(e))
        /**
         * @type {[mc.ContainerSlot[]]}
         */
        let pagedInventory = []
        /**
        * @type {mc.ContainerSlot[]}
        */
        let currentSelectedPageList = []
        /**
         * @type {mc.ContainerSlot[]}
         */
        let interfaceInventory = []
        //Pages Load
        inventory.map((slot, index) => {
            if (lockedSlots.includes(index) == false) {
                pagedInventory.push(slot)
            } else if (containerSlots.includes(index)) {
                interfaceInventory.push(slot)
            }
        })
        pagedInventory = createList(pagedInventory, 24)
        inventory.forEach((slot, index) => {
            if (lockedSlots.includes(index) == false) {
                if (slot.hasItem() == false) {
                    slot.setItem(new mc.ItemStack("snst_bckp:slot_block"))
                }
            }
        })
        currentSelectedPageList = pagedInventory[data["current_page"] - 1]
        if (data["page_loaded"] == false) {
            this.utilityArea[0] = []
            currentSelectedPageList.forEach((slot, index) => {
                const interfaceSlot = interfaceInventory[index]
                if (slot.hasItem()) {
                    if (slot.typeId == "snst_bckp:slot_block") {
                        interfaceSlot.setItem()
                    } else {
                        if (data["current_page"] < 9) {
                            const item = slot.getItem().clone()
                            item.setLore(item.getLore().filter(e => e != "[Backup]"))
                            interfaceSlot.setItem(item)
                        } else {
                            if (index == 16) {
                                const item = slot.getItem().clone()
                                item.setLore(item.getLore().filter(e => e != "[Backup]"))
                                interfaceSlot.setItem(item)
                            }
                        }
                    }
                }
            })
            if (data["current_page"] == 9) {
                //entity.nameTag = "ui.snst_bckp.utility_area"
                this.utilityArea[0] = new Button(containerSlots[0], "snst_bckp:bucket_lava_in", container, entity)
                this.utilityArea[1] = new Button(containerSlots[8], "snst_bckp:bucket_water_in", container, entity)
                this.utilityArea[2] = new Button(containerSlots[7], "snst_bckp:bucket_out", container, entity)
                this.utilityArea[3] = new Button(containerSlots[15], "snst_bckp:bucket_out", container, entity)
                this.utilityArea = this.utilityArea.concat([
                    new Button(containerSlots[17], "snst_bckp:slot_empty", container, entity),
                    new Button(containerSlots[18], "snst_bckp:slot_empty", container, entity),
                    new Button(containerSlots[19], "snst_bckp:slot_empty", container, entity),
                    new Button(containerSlots[20], "snst_bckp:slot_empty", container, entity),
                    new Button(containerSlots[21], "snst_bckp:slot_empty", container, entity),
                    new Button(containerSlots[22], "snst_bckp:slot_empty", container, entity),
                    new Button(containerSlots[23], "snst_bckp:slot_empty", container, entity)
                ])
                const waterSlots = [
                    new Button(containerSlots[9], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[10], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[11], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[12], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[13], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[14], "snst_bckp:liquid_slot_empty", container, entity)
                ]
                const lavaSlots = [
                    new Button(containerSlots[1], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[2], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[3], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[4], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[5], "snst_bckp:liquid_slot_empty", container, entity),
                    new Button(containerSlots[6], "snst_bckp:liquid_slot_empty", container, entity)
                ]
                this.waterSlots = waterSlots
                this.lavaSlots = lavaSlots
                this.utilityArea[0].onPressed = () => {
                  
                    const inventoryLavaBuckets = EntityUtils.getInventoryItems(this.owner).filter(e => e.typeId == "minecraft:lava_bucket")
                    if (inventoryLavaBuckets.length > 0 && data["lava_buckets"] < 20 && data["lava_buckets"] >= 0) {
                        this.owner.dimension.playSound("bucket.fill_lava", entity.location)
                        inventoryLavaBuckets.forEach(slot => {
                            if (data["lava_buckets"] < 20) {
                                data["lava_buckets"] += 1
                                slot.setItem(undefined)
                                this.owner.dimension.spawnItem(new mc.ItemStack("minecraft:bucket"), this.owner.location)
                            }
                        })
                    }
                }
                this.utilityArea[1].onPressed = () => {
                    const inventoryLavaBuckets = EntityUtils.getInventoryItems(this.owner).filter(e => e.typeId == "minecraft:water_bucket")
                    if (inventoryLavaBuckets.length > 0 && data["water_buckets"] < 20 && data["water_buckets"] >= 0) {
                        this.owner.dimension.playSound("bucket.fill_water", entity.location)
                        inventoryLavaBuckets.forEach(slot => {
                            if (data["water_buckets"] < 20) {

                                data["water_buckets"] += 1
                                slot.setItem(undefined)
                                this.owner.dimension.spawnItem(new mc.ItemStack("minecraft:bucket"), this.owner.location)
                            }
                        })
                    }
                }
                this.utilityArea[2].onPressed = () => {
                    const inventoryBuckets = EntityUtils.getInventoryItems(this.owner).filter(e => e.typeId == "minecraft:bucket")
                    if (inventoryBuckets.length > 0 && data["lava_buckets"] >= 1) {
                        const bucket = inventoryBuckets[0]
                        if (bucket) {
                            this.owner.dimension.playSound("bucket.empty_lava", entity.location)
                            data["lava_buckets"] -= 1
                            operateSlot(bucket, "-", 1, EntityUtils.getContainer(this.owner))
                            this.owner.dimension.spawnItem(new mc.ItemStack("minecraft:lava_bucket"), this.owner.location)
                        }
                    }
                }
                this.utilityArea[3].onPressed = () => {
                    const inventoryBuckets = EntityUtils.getInventoryItems(this.owner).filter(e => e.typeId == "minecraft:bucket")
                    if (inventoryBuckets.length > 0 && data["water_buckets"] >= 1) {
                        const bucket = inventoryBuckets[0]
                        if (bucket) {
                            this.owner.dimension.playSound("bucket.empty_water", entity.location)
                            data["water_buckets"] -= 1
                            operateSlot(bucket, "-", 1, EntityUtils.getContainer(this.owner))
                            this.owner.dimension.spawnItem(new mc.ItemStack("minecraft:water_bucket"), this.owner.location)
                        }
                    }
                }
                this.waterSlots.forEach((button, index, arr) => {
                    button.onUpdate = (state) => {
                        if (state == "released") {
                            const liquidPercent = Math.round((data["water_buckets"] / 20) * 100)
                            const quantityBars = (index + 1)
                            const currentPercent = Math.round((quantityBars / arr.length) * 100)
                            button.setLore([`§7Filled: ${liquidPercent}%`, `§7Buckets: ${data["water_buckets"]} / 20`])
                            if ((index == 0 && liquidPercent >= 1) || (index >= 1 && liquidPercent >= currentPercent)) {
                                button.changeItem("snst_bckp:water_slot")
                            } else {
                                button.changeItem("snst_bckp:liquid_slot_empty")
                            }
                        }
                    }
                })
                this.lavaSlots.forEach((button, index, arr) => {
                    button.onUpdate = (state) => {
                        if (state == "released") {
                            const liquidPercent = Math.round((data["lava_buckets"] / 20) * 100)
                            const quantityBars = (index + 1)
                            const currentPercent = Math.round((quantityBars / arr.length) * 100)
                            button.setLore([`§7Filled: ${liquidPercent}%`, `§7Buckets: ${data["lava_buckets"]} / 20`])
                            if ((index == 0 && liquidPercent >= 1) || (index >= 1 && liquidPercent >= currentPercent)) {
                                button.changeItem("snst_bckp:lava_slot")
                            } else {
                                button.changeItem("snst_bckp:liquid_slot_empty")
                            }
                        }
                    }
                })
            }
            data["page_loaded"] = true
        } else {
            interfaceInventory.forEach((slot, index) => {
                const pageSlot = currentSelectedPageList[index]
                if (slot.hasItem()) {
                    if (data["current_page"] < 9) {
                        const item = slot.getItem().clone()
                        const currentLore = item.getLore()
                        currentLore.push("[Backup]")
                        item.setLore(item)
                        pageSlot.setItem(item)
                    } else {
                        if (index == 16 && data["current_page"] == 9) {
                            const item = slot.getItem().clone()
                            const currentLore = item.getLore()
                            currentLore.push("[Backup]")
                            item.setLore(item)
                            pageSlot.setItem(item)

                            if (slot.getTags().find(e => e == "snst_bckp:is_pattern") && slot.getTags().find(e => validTiers.indexOf(e) >= validTiers.indexOf(backpackTier))) {
                                if(ownerHand && ownerHand.getDynamicProperty("backpack_id") == data["id"] && ownerHand.typeId != item.typeId.replace("_pattern", "_backpack")){
                                    EntityUtils.transformType(ownerHand, item.typeId.replace("_pattern", "_backpack"))
                                    console.warn("Teste")
                                }
                              
                                
                            } else {
                                if(ownerHand.getItem() && ownerHand.getDynamicProperty("backpack_id") == data["id"] && ownerHand.typeId != data["original_item_type"]){
                                    EntityUtils.transformType(ownerHand, data["original_item_type"])
                                    console.warn("Teste2")
                                }
                               
                            }
                        }
                    }
                } else {
                    if (index == 16 && data["current_page"] == 9) {
                        if(ownerHand.getItem() && ownerHand.getDynamicProperty("backpack_id") == data["id"] && ownerHand.typeId != data["original_item_type"]){
                            EntityUtils.transformType(ownerHand, data["original_item_type"])
                            console.warn("Teste3")
                        }
                    }
                    pageSlot.setItem(new mc.ItemStack("snst_bckp:slot_block"))
                }
            })
            if (data["current_page"] == 9) {
                this.utilityArea.forEach(button => {
                    button.updateButton(false)
                })
                this.waterSlots.forEach(button => {
                    button.updateButton(true)
                })
                this.lavaSlots.forEach(button => {
                    button.updateButton(true)
                })
            }
        }

        // Drop backpacks that are in backpacks.
        // for (let slot=0; slot < container.size; slot++) {
        //     const itemStack = container.getItem(slot);
        //     if (!itemStack || itemStack.hasTag('snst_bckp:destroy_item')) continue;
        //     if (itemStack.hasTag('snst_bckp:backpack')) {
        //         container.setItem(slot, undefined);
        //         entity.dimension.spawnItem(itemStack, entity.location);
        //         itemStack.remove();
        //     }
        // }
    }
    onCreate() {
        const entity = this.getEntity()
        const data = this.data
        data["page_loaded"] = false
        data["current_page"] = data["current_page"] || 1
        data["last_page"] = data["current_page"] < 9 ? data["current_page"] : data["max_pages"]
        data["max_pages"] = data["max_pages"] || 1
        data["first_time"] = data["first_time"] || false
        data["disabled"] = false
        data["id"] = data["id"] || entity.id
        data["lava_buckets"] = data["lava_buckets"] != undefined ? data["lava_buckets"] : 0
        data["water_buckets"] = data["water_buckets"] != undefined ? data["water_buckets"] : 0
        //  //console.warn(data["water_buckets"])
        this.buttons[0] = new Button(8, "snst_bckp:previous_button", entity.getComponent("inventory").container, entity)
        this.buttons[1] = new Button(17, `snst_bckp:page_button_${data["current_page"]}`, entity.getComponent("inventory").container, entity)
        this.buttons[2] = new Button(26, `snst_bckp:next_button`, entity.getComponent("inventory").container, entity)
        //Interface Events
        this.buttons[0].onPressed = () => {
            if (data["current_page"] > 1) {
                data["current_page"] = GMath.clamp(data["current_page"] - 1, 1, data["max_pages"])
                entity.dimension.playSound("bundle.drop_contents", entity.location)
                this.buttons[1].changeItem(`snst_bckp:page_button_${data["current_page"]}`)
                data["last_page"] = data["current_page"]
                data["page_loaded"] = false
            } else {
                entity.dimension.playSound("bundle.insert_fail", entity.location)
            }
        }
        this.buttons[1].onPressed = () => {
            if (data["current_page"] != 9) {
                data["last_page"] = GMath.clamp(data["current_page"], 1, data["max_pages"])
                data["current_page"] = 9
                entity.dimension.playSound("bundle.drop_contents", entity.location)
                this.buttons[1].changeItem(`snst_bckp:close_button`)
                data["page_loaded"] = false
            } else {
                data["current_page"] = data["last_page"]
                entity.dimension.playSound("bundle.drop_contents", entity.location)
                this.buttons[1].changeItem(`snst_bckp:page_button_${data["current_page"]}`)
                data["page_loaded"] = false
            }
        }
        this.buttons[2].onPressed = () => {
            if (data["current_page"] < data["max_pages"]) {
                data["current_page"] = GMath.clamp(data["current_page"] + 1, 1, data["max_pages"])
                entity.dimension.playSound("bundle.drop_contents", entity.location)
                this.buttons[1].changeItem(`snst_bckp:page_button_${data["current_page"]}`)
                data["last_page"] = data["current_page"]
                data["page_loaded"] = false
            } else {
                entity.dimension.playSound("bundle.insert_fail", entity.location)
            }
        }
    }
    onTick() {
        const entity = this.getEntity()
        const data = this.data
        const owner = mc.world.getEntity(data["owner"])
        entity.nameTag = `entity.snst_bckp:backpack_ent.name`
        if (owner) {
            this.owner = owner
            const ownerBackpackUse = owner.getDynamicProperty("current_backpack")
            if (ownerBackpackUse != data["id"]) {
                if (data["current_page"] == 9) {
                    data["current_page"] = data["last_page"]
                }
                try {
                    let structure = mc.world.structureManager.get(`snst_bckp:backpack_${data["id"]}`)
                    if (structure) {
                        mc.world.structureManager.delete(`snst_bckp:backpack_${data["id"]}`)
                        structure = mc.world.structureManager.createFromWorld(`snst_bckp:backpack_${data["id"]}`, entity.dimension, entity.location, entity.location, { includeBlocks: false, includeEntities: true, saveMode: mc.StructureSaveMode.World })
                        structure.saveToWorld()
                    } else {
                        structure = mc.world.structureManager.createFromWorld(`snst_bckp:backpack_${data["id"]}`, entity.dimension, entity.location, entity.location, { includeBlocks: false, includeEntities: true, saveMode: mc.StructureSaveMode.World })
                        structure.saveToWorld()
                    }
                } catch (e) { }
                entity.remove()
            } else {
                this.buttons.forEach((button) => {
                    button.updateButton(false)
                })
                this.onUpdateInventory()
                if (!owner.isSneaking) {
                    entity.teleport(new GMath.Vector3(0, -0.5, 0).add(owner.getHeadLocation()))
                    entity.triggerEvent("snst_bckp:active_collision")
                } else {
                    entity.teleport(new GMath.Vector3(0, 0, 0).add(owner.getHeadLocation()))
                    entity.triggerEvent("snst_bckp:desactive_collision")
                }
            }
        }
    }
}
class Player extends EntityRun.EntityObject {
    onUpdateHand() {
        /**
         * @type {mc.Player}
         */
        const entity = this.getEntity()
        const dimension = entity.dimension
        const data = this.data
        const handItem = this.getEquipament("Mainhand")
        const items = this.getInventoryItems()
        const viewDirection = new GMath.Vector3(entity.getViewDirection()).normalize().round()
        const locationStart = entity.getHeadLocation()
        /**@type {mc.PlayerCursorInventoryComponent} */
        const cursor = entity.getComponent("cursor_inventory")
        if (cursor && cursor.item && cursor.item.getTags().includes("snst_bckp:destroy_item")) {
            cursor.clear()
        }
        items.forEach(slot => {
            // //console.warn("Teste", slot.getTags())
            if (slot.hasItem()) {
                if (slot.getTags().includes("snst_bckp:backpack") && slot.getDynamicProperty("backpack_id")) {
                    const id = slot.getDynamicProperty("backpack_id")
                    if (id != data["current_backpack"]) {
                        slot.lockMode = mc.ItemLockMode.none
                        slot.setItem(slot.getItem())
                    }
                } else if (slot.getTags().includes("snst_bckp:destroy_item")) {
                    //console.warn("Teste")
                    slot.setItem(undefined)
                }
            }

        })

        if (handItem && handItem.hasItem() && handItem.getTags().includes("snst_bckp:backpack")) {
            //console.warn("Teste")
            //  const entityIn = dimension.getEntities({location: locationStart, maxDistance: 0.5}).find(e=>e.id != entity.id)
            const id = handItem.getDynamicProperty("backpack_id")
            if (id == undefined) {
                const backpack = dimension.spawnEntity("snst_bckp:backpack_ent", locationStart)
                data["current_backpack"] = backpack.id
                backpack.setDynamicProperty("owner", entity.id)
                backpack.setDynamicProperty("original_item_type", handItem.typeId)
                backpack.setDynamicProperty("current_item_type", handItem.typeId)
                backpack.setDynamicProperty("max_pages", Number(handItem.getTags().find(e => e.startsWith("snst_bckp:backpack_max_pages:")).replace("snst_bckp:backpack_max_pages:", "")))
                handItem.setDynamicProperty("owner", entity.id)
                handItem.setDynamicProperty("backpack_id", backpack.id)
                handItem.lockMode = mc.ItemLockMode.slot
                handItem.setLore([
                    `Backpack ID: ${backpack.id}`,
                    `Owner: ${entity.name}`
                ])
                //   //console.warn("Teste")
                handItem.setItem(handItem.getItem())
            } else if (id != undefined && data["current_backpack"] == "") {
                //console.warn("Load")
                handItem.lockMode = mc.ItemLockMode.slot
                handItem.setItem(handItem.getItem())
                const backpackData = mc.world.structureManager.get(`snst_bckp:backpack_${id}`)
                mc.world.structureManager.place(backpackData, dimension, locationStart, { includeBlocks: false, includeEntities: true })
                data["current_backpack"] = id

            } else if (id != undefined && data["current_backpack"] != id) {
                data["last_backpack"] = data["current_backpack"]
                data["current_backpack"] = ""

            }
        } else {
            if (data["current_backpack"] != "") {
                data["last_backpack"] = data["current_backpack"]
                data["current_backpack"] = ""

            }
        }
    }
    onUpdateOffhand() {
        /**
        * @type {mc.Player}
        */
        const entity = this.getEntity()
        const dimension = entity.dimension
        const data = this.data
        const handItem = this.getEquipament("Offhand")
        if (handItem.hasItem() && handItem?.typeId in backpackAbilities) {
            data["backpack_type"] = handItem.typeId
            const backpackAbility = backpackAbilities[handItem?.typeId]
            const queriesFunctions = {
                "onUpdate": true,
                "onSneaking": entity.isSneaking,
                "onJump": entity.isJumping,
                "onSwim": entity.isSwimming && entity.isInWater
            }
            Object.keys(queriesFunctions).forEach((event) => {
                const valid = queriesFunctions[event]
                if (valid && event in backpackAbility) {
                    backpackAbility[event](entity, handItem)
                }
            })
        } else {

            if (data["backpack_type"] && data["backpack_type"] in backpackAbilities) {
                const backpack = backpackAbilities[data["backpack_type"]]
                data["backpack_type"] = ""
                if ("onUnequip" in backpack) {
                    backpack.onUnequip(entity)
                }
            }
        }

    }
    onCreate() {
        const entity = this.getEntity()
        const data = this.data
        data["current_backpack"] = data["current_backpack"] || ""
        data["last_backpack"] = data["last_backpack"] || ""
        data["last_slot"] = 0
        data["loaded"] = false
        data["backpack_type"] = ""
    }
    onTick() {
        this.onUpdateHand()
        this.onUpdateOffhand()
    }

}
//Register
EntityRun.EntityRuntime.register("snst_bckp:backpack_ent", Backpack)
EntityRun.EntityRuntime.register("minecraft:player", Player)
//Events
mc.world.beforeEvents.playerInteractWithEntity.subscribe(data => {
    const target = data.target
    const player = data.player
    if (target.typeId == "snst_bckp:backpack_ent" && target.getDynamicProperty("owner") != player.id) {
        data.cancel = true
    }
})
mc.world.beforeEvents.itemUse.subscribe(data => {
    const item = data.itemStack
    const player = data.source
    if (player.typeId == "minecraft:player") {
        const offhandSlot = player.getComponent("equippable").getEquipmentSlot(mc.EquipmentSlot.Offhand)
        const mainhandSlot = player.getComponent("equippable").getEquipmentSlot("Mainhand")
        if ( offhandSlot.hasItem() && backpackAbilities[offhandSlot?.typeId] != undefined) {
            const backpackAbility = backpackAbilities[offhandSlot.typeId]
            if (backpackAbility["onItemUse"] != undefined) {
                mc.system.run(()=>{
                    backpackAbility["onItemUse"](player, offhandSlot, mainhandSlot)
                })
            }

        }
    }
})
mc.system.afterEvents.scriptEventReceive.subscribe(data=>{
    const {message, id, sourceEntity} = data
    if(id == "snst_bckp:hit_projectile" && sourceEntity){
        const projectileAbility = projectileAbilities[sourceEntity.typeId]
        if(!projectileAbility){ return;}
        if("onHit" in projectileAbility){
            const projectileComp = sourceEntity.getComponent("minecraft:projectile")
            projectileAbility["onHit"](sourceEntity, projectileComp)
        }
    }
})