LegacyScriptEngine icon indicating copy to clipboard operation
LegacyScriptEngine copied to clipboard

[Bug]: pl.sendForm(fm,callback[,forUpdating]) 其中 forUpdating 参数不起作用

Open zmsgsb opened this issue 5 months ago • 6 comments

Describe the bug

pl.sendForm(fm,callback[,forUpdating]) 其中 forUpdating 参数不起作用,并且加了这个参数后无法正常打开表单

To Reproduce

mc.listen("onServerStarted", () => {
    const command = mc.newCommand("formtest", "表单测试", PermType.Any);
    command.overload([]);
    command.setCallback((cmd, origin, output, result) => {
        CustomFormTest(origin.player);
    });
    command.setup();
})

/**
 * 
 * @param {Player} player
 */
function CustomFormTest(player) {
    // 创建自定义表单对象
    const fm = mc.newCustomForm();

    // 设置表单标题
    fm.setTitle("用户信息更新");

    fm.addLabel(system.getTimeStr());

    // 添加带 tooltip 的输入框
    fm.addInput(
        "新的用户名",          // title
        "输入3-12个字符",      // placeholder
        "Steve",             // default
        "只能使用字母和数字"   // tooltip (0.12.0+)
    );

    // 添加其他表单元素作为示例
    fm.addSwitch("启用VIP功能", true, "开启后享受特权");
    fm.addDropdown("选择职业", ["战士", "法师", "射手"], 1);
    fm.addSlider("音量设置", 0, 100, 10, 70, "0-100范围调整");

    // 设置提交按钮文本 (0.11.0+)
    fm.setSubmitButton("确认更新");

    player.sendForm(fm, (pl, id, res) => { }, true);
}

Expected behavior

表单能正常打开 并且内容可以实时更新

Screenshots

No response

Platform

Win10

BDS Version

1.21.80

LeviLamina Version

1.3.1

LegacyScriptEngine Version

0.12.0

Additional context

No response

zmsgsb avatar Jun 29 '25 05:06 zmsgsb

可能是我用法不对?

zmsgsb avatar Jun 29 '25 05:06 zmsgsb

可能是我用法不对?

需要玩家处于表单打开状态才能发送表单更新。 按道理由加载器判断玩家是否处于表单状态来决定是发送表单还是更新表单会让api使用更方便,但是因为表单更新并不是官方支持的特性(发的数据包不一样),这要求判断要准确,判断错误会导致漏表单而插件收不到反馈。但是问题就是因为网络的延迟不可能实时且准确的判断客户端状态,所以由插件自行决定该发送还是更新,加载器只保证了最开始的发送表单以及后续一系列的更新表单中有且只有一个回调函数会被调用 另一点,表单更新是支持格式甚至类型不一样的表单更新的(虽然不完全支持,ModalForm和其他类型之间更新会有点问题),所以每次更新都要传递回调函数是为了不限制要更新的表单的格式和类型,也因为这样,被调用的回调函数并不一定是最后一次更新表单的回调函数,不过一定是玩家实际提交的表单对应的回调函数

xiaoqch avatar Jun 29 '25 06:06 xiaoqch

const count = 5;
const BUTTONS = Array(count).keys().map((index) => `Button ${index}`).toArray();
const result = Math.floor(Math.random() * count);
function buildForm(index: number) {
  const buttons = BUTTONS.with(index, `§6${BUTTONS[index]}`);
  const form = mc.newSimpleForm().setTitle("Test");
  buttons.forEach((value) => form.addButton(value));
  return form;
}
async function openWindow(player: Player) {
  let coeff = 0;
  let viewing = false;
  let index = (result + 2) % count;
  while (coeff * coeff < 300 || index != result) {
    player.sendForm(buildForm(index), () => (viewing = false), viewing);
    viewing = true;
    coeff = coeff + 0.5;
    await sleep(Math.max(coeff * coeff, 50));
    index = (index + 1) % count;
  }
  await sleep(1000);
  const form = mc
    .newCustomForm()
    .setTitle("Result")
    .addHeader(`Result: ${result}`);
  const { promise, resolve, reject } = Promise.withResolvers<any>();
  player.sendForm(form, resolve, viewing);
  return promise;
}
openWindow(player);

这是测试表单更新用到的一段示例,可以参考一下

xiaoqch avatar Jun 29 '25 07:06 xiaoqch

好的

zmsgsb avatar Jun 29 '25 07:06 zmsgsb

mc.listen("onServerStarted", () => {
    const command = mc.newCommand("formtest", "表单测试", PermType.Any);
    command.overload([]);
    command.setCallback((cmd, origin, output, result) => {
        if (origin.player) {
            // 启动表单动画
            startFormAnimation(origin.player);
        } else {
            output.error("该命令只能由玩家执行");
        }
    });
    command.setup();
})

// 辅助函数:异步等待
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * 启动表单动画效果
 * @param {Player} player 
 */
async function startFormAnimation(player) {
    const BUTTON_COUNT = 5;
    const BUTTONS = Array.from({length: BUTTON_COUNT}, (_, i) => `选项 ${i + 1}`);
    const result = Math.floor(Math.random() * BUTTON_COUNT);
    
    // 构建表单函数
    function buildForm(highlightIndex) {
        const form = mc.newSimpleForm().setTitle("动态表单测试");
        BUTTONS.forEach((text, index) => {
            // 高亮当前选项
            const buttonText = (index === highlightIndex) ? `§6${text} §r(当前)` : text;
            form.addButton(buttonText);
        });
        return form;
    }
    
    // 启动动画循环
    let viewing = false;
    let currentIndex = (result + 2) % BUTTON_COUNT;
    let delay = 50; // 初始延迟
    
    while (delay < 1000) { // 设置最大延迟时间
        // 发送/更新表单
        player.sendForm(
            buildForm(currentIndex), 
            (pl, id) => {
                // 如果玩家在动画过程中点击了按钮
                if (id !== null) {
                    pl.tell(`您选择了: ${BUTTONS[id]}`);
                }
                viewing = false; // 重置状态
            },
            viewing
        );
        
        viewing = true; // 后续发送将作为更新
        await sleep(delay);
        
        // 更新索引和延迟
        currentIndex = (currentIndex + 1) % BUTTON_COUNT;
        delay = Math.min(delay * 1.2, 1000); // 增加延迟但不超过1秒
    }
    
    // 动画结束后显示结果
    const resultForm = mc.newCustomForm()
        .setTitle("测试结果")
        .addLabel(`随机结果: 选项 ${result + 1}`)
        .addLabel("动画已结束");
    
    player.sendForm(resultForm, (pl, data) => {
        if (data === null) {
            pl.tell("您取消了结果表单");
        }
    });
}

让AI写的 还是不行

zmsgsb avatar Jun 29 '25 07:06 zmsgsb

最后发送的表单漏了更新参数, 另外,如果是nodejs引擎的话注意另一个bug,https://github.com/LiteLDev/LegacyScriptEngine/issues/10#issuecomment-2728611983

xiaoqch avatar Jul 05 '25 08:07 xiaoqch