//Version: 1160R20250211TS
import { world, system } from '@minecraft/server';
let players = new Map();
let playerJumpState = new Map();
let playerSneakState = new Map();
let playerFromSlot = new Map();
for (let player of world.getAllPlayers()) {
    players.set(player.id, player);
    playerJumpState.set(player.id, player.isJumping);
    playerSneakState.set(player.id, player.isSneaking);
    playerFromSlot.set(player.id, player.selectedSlotIndex);
}
class PlayerLookAtBlockAfterEventSignal {
    /**
     * @remarks
     * 为玩家看向方块添加一个回调。
     *
     * 该方法无法在只读模式中使用。
     *
     */
    subscribe(callback, opt) {
        system.runInterval(() => {
            players.forEach((player, playerId) => {
                if (!player || !player.isValid())
                    return;
                const raycastHit = player.getBlockFromViewDirection(opt);
                if (raycastHit) {
                    callback(new PlayerLookAtBlockAfterEvent({ player, raycastHit }));
                }
            });
        });
    }
    ;
    /**
     * @remarks
     * 该方法目前没有作用。
     *
     * This function can't be called in read-only mode.
     *
     * @throws This function can throw errors.
     */
    unsubscribe(callback) { }
    ;
}
/**
 * @remarks
 * 玩家看向方块时触发该事件。
 */
export class PlayerLookAtBlockAfterEvent {
    constructor(args) {
        this.player = args.player;
        this.raycastHit = args.raycastHit;
    }
}
class PlayerStartJumpAfterEventSignal {
    /**
     * @remarks
     * 为玩家开始跳跃添加一个回调。
     *
     * 该方法无法在只读模式中使用。
     *
     */
    subscribe(callback) {
        system.runInterval(() => {
            players.forEach((player, playerId) => {
                if (!player || !player.isValid())
                    return;
                //若不存在该玩家对应信息则初始化
                if (!playerJumpState.has(player.id)) {
                    playerJumpState.set(player.id, player.isJumping);
                }
                else {
                    if (!playerJumpState.get(player.id) && playerJumpState.get(player.id) != player.isJumping) {
                        const { x, y, z } = player.location;
                        const block = player.dimension.getBlock({ x, y: y - 1, z });
                        callback(new PlayerStartJumpAfterEvent({ player: player, block: block }));
                    }
                    playerJumpState.set(player.id, player.isJumping);
                }
            });
        });
    }
    ;
    /**
     * @remarks
     * 该方法目前没有作用。
     *
     * This function can't be called in read-only mode.
     *
     * @throws This function can throw errors.
     */
    unsubscribe(callback) { }
    ;
}
/**
 * @remarks
 * 玩家开始跳跃时触发该事件。
 */
export class PlayerStartJumpAfterEvent {
    constructor(args) {
        this.player = args.player;
        this.block = args.block;
    }
}
class PlayerStartSneakAfterEventSignal {
    /**
     * @remarks
     * 为玩家开始跳跃添加一个回调。
     *
     * 该方法无法在只读模式中使用。
     *
     */
    subscribe(callback) {
        system.runInterval(() => {
            players.forEach((player, playerId) => {
                if (!player || !player.isValid())
                    return;
                //若不存在该玩家对应信息则初始化
                if (!playerSneakState.has(player.id)) {
                    playerSneakState.set(player.id, player.isSneaking);
                }
                else {
                    if (!playerSneakState.get(player.id) && playerSneakState.get(player.id) != player.isSneaking) {
                        const { x, y, z } = player.location;
                        const block = player.dimension.getBlock({ x, y: y - 1, z });
                        callback(new PlayerStartSneakAfterEvent({ player: player, block: block }));
                    }
                    playerSneakState.set(player.id, player.isSneaking);
                }
            });
        });
    }
    ;
    /**
     * @remarks
     * 该方法目前没有作用。
     *
     * This function can't be called in read-only mode.
     *
     * @throws This function can throw errors.
     */
    unsubscribe(callback) { }
    ;
}
/**
 * @remarks
 * 玩家开始潜行时触发该事件。
 */
export class PlayerStartSneakAfterEvent {
    constructor(args) {
        this.player = args.player;
        this.block = args.block;
    }
}
class SelectedItemChangeAfterEventSignal {
    /**
     * @remarks
     * 为玩家更换手持物品添加一个回调。
     *
     * 该方法无法在只读模式中使用。
     *
     */
    subscribe(callback) {
        system.runInterval(() => {
            players.forEach((player, playerId) => {
                if (!player || !player.isValid())
                    return;
                //若不存在该玩家对应信息则初始化
                if (!playerFromSlot.has(player.id)) {
                    playerFromSlot.set(player.id, player.selectedSlotIndex);
                }
                else {
                    const fromSlot = playerFromSlot.get(player.id);
                    if (fromSlot !== undefined && fromSlot != player.selectedSlotIndex) {
                        callback(new SelectedItemChangeAfterEvent({ player: player, fromSlot, toSlot: player.selectedSlotIndex }));
                        playerFromSlot.set(player.id, player.selectedSlotIndex);
                    }
                }
            });
        });
    }
    ;
    /**
     * @remarks
     * 该方法目前没有作用。
     *
     * This function can't be called in read-only mode.
     *
     * @throws This function can throw errors.
     */
    unsubscribe(callback) { }
    ;
}
/**
 * @remarks
 * 玩家更换手持物品时触发该事件。
 */
export class SelectedItemChangeAfterEvent {
    constructor(args) {
        this.player = args.player;
        this.fromSlot = args.fromSlot;
        this.toSlot = args.toSlot;
    }
}
export class ExpansionEvents {
    constructor() {
        /**
         * @remarks
         * 玩家更换手持物品时触发该事件。
         */
        this.selectedItemChange = new SelectedItemChangeAfterEventSignal();
        /**
         * @remarks
         * 玩家开始跳跃时触发该事件。
         */
        this.playerStartJump = new PlayerStartJumpAfterEventSignal();
        /**
         * @remarks
         * 玩家开始潜行时触发该事件。
         */
        this.playerStartSneak = new PlayerStartSneakAfterEventSignal();
        /**
         * @remarks
         * 玩家看向方块时触发该事件。
         */
        this.playerLookAtBlock = new PlayerLookAtBlockAfterEventSignal();
    }
}
export const expansionEvents = new ExpansionEvents();
/**
 * @remarks
 * 计时器管理类。
 */
export class TimerManager {
    constructor() {
        this.timers = new Map();
    }
    /**
     * @remarks
     * 创建一个计时器。
     */
    createTimer(callback, timerOptions) {
        if (!timerOptions) {
            timerOptions = { time: 20, repeat: false };
        }
        if (!timerOptions.time) {
            timerOptions.time = 20;
        }
        let timerId = system.runTimeout(() => {
            callback();
            if (timerOptions?.repeat) {
                this.update(callback, timerId, timerOptions.time);
            }
        }, timerOptions.time);
        this.timers.set(timerId, timerId);
        return timerId;
    }
    /**
     * @remarks
     * 销毁一个计时器。
     */
    removeTimer(timerId) {
        system.clearRun(this.timers.get(timerId));
    }
    update(callback, timerId, time) {
        let timer = system.runTimeout(() => {
            callback();
            this.update(callback, timerId, time);
        }, time);
        this.timers.set(timerId, timer);
    }
}
export class TimerOptions {
    constructor() { }
}
export const timerManager = new TimerManager();
export class Logger {
    constructor(namespace) {
        this.namespace = namespace;
    }
    log(data) {
        world.sendMessage(`[${this.namespace}-LOG]${JSON.stringify(data)}`);
    }
    warn(data) {
        world.sendMessage(`§e[${this.namespace}-WARN]${JSON.stringify(data)}`);
    }
    error(data) {
        world.sendMessage(`§c[${this.namespace}-ERROR]${JSON.stringify(data)}`);
    }
}
world.afterEvents.playerJoin.subscribe(args => {
    players.set(args.playerId, world.getEntity(args.playerId));
});
//玩家退出时销毁
world.beforeEvents.playerLeave.subscribe(args => {
    players.set(args.player.id, undefined);
    playerJumpState.set(args.player.id, undefined);
    playerSneakState.set(args.player.id, undefined);
    playerFromSlot.set(args.player.id, undefined);
});
