猫史档案馆


NomenCommand:同语法我的世界指令解析器

用户:NomenNomen查看:0 回复:3 评论:0 创建时间:2023-05-21T05:59:38


这里是没有开场白的Nomen,NomenCommand正式发布了

他的主要功能在于讲一个字符串解析为指定的参数,然后传给你定义的回调函数,干净利落

本体:

class NomenCommand {
    c喵tructor(cmd) {
        if (!cmd.length) throw new Error('Command String Required');
        this.fun = cmd.trim().split(' ')[0];
        this.arg = cmd.trim().split(' ').slice(1);
        if (NomenCommand.commands[this.fun] === undefined) throw new Error('Command not found');
        for (let i = 0; i < NomenCommand.commands[this.fun].arg.length; i++) {
            if ((function (a, b) {
                let t = a.filter(v => v.required);
                for (let i = 0; i < t.length; i++) {
                    if (!NomenCommand.typeDetector[t[i].type](b[i])) return false;
                }
                return true;
            })(NomenCommand.commands[this.fun].arg[i], this.arg)) {
                this.cmd = this.nparser(i, this.fun, this.arg);
                this.serial = i;
                return this;
            }
        }
        throw new Error('[NomenCommand] Unexpected parameters');
    }
    nparser(serial, command, arg) {
        log({ serial, command, arg });
        let args = {};
        for (let i = 0; i < NomenCommand.commands[command].arg[serial].length; i++) {
            if (arg[i] === undefined) throw new Error('[NomenCommand] Argument Missing: ' + NomenCommand.commands[command].arg[serial][i].name)
            if (NomenCommand.typeConverter[NomenCommand.commands[command].arg[serial][i].type])
                args[NomenCommand.commands[command].arg[serial][i].name] =
                    NomenCommand.typeConverter[NomenCommand.commands[command].arg[serial][i].type](arg[i])
        }
        return args;
    }
    exec(executor) {
        return NomenCommand.commands[this.fun].exec(this.serial, executor, this.cmd);
    }
    static commands = {
        'say': {
            arg: [
                [{ name: 'content', type: 'string', required: false }],
                [{ name: 'content', type: 'ncselector', required: false }]
            ],
            exec: function (serial, executor, { content, content2 }) {
                world.say([content, content.exec()][serial]);
            }
        },
        'add': {
            arg: [
                [{ name: 'num1', type: 'number', required: true }, { name: 'num2', type: 'number', required: true }]
            ],
            exec: function (serial, executor, { num1, num2 }) {
                return (num1 + num2)
            }
        },
        'name': {
            arg: [
                [{ name: 'player', type: 'ncselector', required: true }]
            ],
            exec: function (serial, executor, { player }) {
                world.say(player.exec(executor)[0].player.name)
            }
        },
        '__#NCESCheck__': (() => {
            let r = new Error('"NCSelector"是NomenCommand必须依赖项,请先在当前作用域内检查NCSelector是否存在,或创建"NCSelector.js"并作为模块导出');
            try {
                let Nl = require('./NCSelector.js').NCSelector;
                if (Nl) NomenCommand.NCSelector = Nl;
            } catch {
                try {
                    if (NCSelector !== undefined) NomenCommand.NCSelector = NCSelector;
                    else throw new Error('NCSelector Not Found');
                } catch { throw r }
            }
        })()
    }
    static typeDetector = {
        'string': (c) => { return typeof c == "string" },
        'ncselector': (c) => { return !!c.length && (!c.startsWith('"') && !c.endsWith('"')) },
        'json': (c) => {
            try {
                return !!JSON.parse(c);
            } catch { return false }
        },
        'number': (c) => { return !isNaN(c) }
    }
    static typeConverter = {
        'string': (c) => { return c.replace(/^"(.*)"$/, '$1') },
        'ncselector': (c) => { return new this.NCSelector(c) },
        'json': (c) => { return JSON.parse(c) },
        'number': (c) => { return Number(c) }
    }
    static subscribeCommand(name, arg, exec) {
        if (typeof name == 'string' && Array.isArray(arg) && typeof exec == "function") {
            this.commands[name] = { arg, exec };
        }
    }
}

示例:

/**
 * 大声叫出一个y坐标大于8的玩家的名字
 * executor改为执行者,如果缺失,可能会导致某些指令出错
 */
(new NomenCommand('name @e[y=8..,type=player]')).exec(executor);

/**
 * 大声喊话
 */
(new NomenCommand('say HELLONOMEN!')).exec(executor);

/**
 * 数学运算!
 * 返回值 15
 */
(new NomenCommand('add 12 3')).exec(executor);

/**
 * 自行订阅自定义指令有一些东西要说
 * @param {string} 这里应该是该指令的名字
 * @param {NomenCommandArgument[]} 这是一个数组,因为有时候函数可能是多态形式,意味着一个函数会根据情况改变参数的处理方法
 * 那么这意味着你有多少个数组,你就有多少个形态,数组内每一个元素都是一种形态
 * 每一个形态都需要由name,参数名字,type,参数类型和required,是否为必须三个属性组成
 * @param {exec}
 * @callback exec 
 * @argument {number} serial 形态的序号,NomenCommand在自动为指令分配形态后会告诉指令正在使用的形态是第几个
 * @argument {object} args 执行者传入的参数,对象,仅传入已受到命名和分配的参数
 * 参数会根据你的参数类型来决定,例如填的是json,则返回一个对象,number则返回数字,ncselector则返回一个解析好的NCSelector实例,可以直接调用exec(executor)来搜寻指定的实体
 */
NomenCommand.subscribeCommand(
    'myFirstNomenCommand',
    [
        [{ name: 'arg1', type: 'string', required: true }, { name: 'arg2', type: 'string', required: true }], // 第一种形态的两个参数
        // 参数1,名字叫arg1,类型为字符串,必须
    ],
    (serial, executor, { arg1, arg2 }) => {
        console.log(serial);
        console.log(executor)
        console.log(arg1, arg2);
    }
)

类型声明(js):

const NomenCommandArgument = {
    name: string,
    type: NomenCommandArgumentType,
    required: boolean
}

const NomenCommandArgumentType = {
    'string': string,
    'ncselector': NCSelector,
    'json': json,
    'number': number
}


回复

上一页1 页 / 共 1下一页
NomenNomen

照例沙发

点赞0


评论


NomenNomen

注:NCSelector需要在当前作用域内或者在NCSelector.js内,请确保您按照要求安装了NCSelector

NCSelector:基于我的世界实体搜寻器字符串的语法的实体搜索器
https://shequ.codemao.cn/community/541331

点赞0


评论


145a145a

顶一下

点赞0


评论