🚀 FluffOS 驱动修复 & VSCode LPC 插件更新

前言: > 借力 AI 的深度辅助,近期我对 FluffOS 驱动进行了手术级的重构与功能扩展,不仅引入了高性能的 Go Gateway 支持,更对驱动编译器底层的“陈年顽疾”进行了彻底根治。配套的 VSCode 插件也迎来了生产力爆发式的更新,全方位提升 MUD 开发体验。

驱动、文档等下载内容在文末

💎 第一部分:FluffOS 驱动更新(内核级修复与增强)

具体框架可查看我之前gateway框架的介绍帖子:[架构分享] 彻底告别 IO 阻塞!“零侵入”的 基于FluffOS 高并发网关开发!

报错位置不准问题修复

现在可以准确报告错误行、列。 不会再有偏差了,包括万恶的未使用变量warning等也可以精准定位报错位置。driver链接已经更新。 体验有问题的可以随时联系我。

警告及报错样式展示:(错误讯息拦截开始是master.c里优化的。现在驱动将报错位置推送到了error_handler的mapping参数里,所以也可以正确的获取错误准确信息了) file

/adm/single/master.c的standard_trace()函数需要改造才有上面的准确错误提示效果。需要的代码贴在下面了。 可以往下翻。

1. 🌟 核心特性:高性能 FluffOS Gateway

为支持现代前端接入(Web/App/WeChat)并实现业务解耦,新增了 gateway 核心模块。

  • 虚拟对象会话:通过 fd=-1interactive_t 虚拟对象存储会话,支持大规模连接转发。
  • 全协议链路支持:完整实现 hello, login (触发 master->connect), data (指令/命令注入), discon, sys, output, kick 等消息类型。
  • LPC 层深度控制 (New Efuns)
    • 网关控制gateway_send(), gateway_kick(), gateway_status()
    • 数据处理:内置 json_encode(), json_decode(), write_json(), read_json() 提高数据交换效率。
    • 工具函数:新增 uuid() 支持。
  • 系统守护进程:创建 /adm/daemons/gateway_d.c 处理系统回调(gateway_create_user, gateway_receive 等)。
  • 高性能透传:重构 comm.cc 路由,去掉每包临时 evbuffer 分配,最大包支持从 1KB 提升至 16MB 的运行时保护。

2. 🛠️ 编译器与内核 Bug 修复 (Bug Fixes)

  • 内存安全与空洞修复
    • WebSocket:修正 ASCII 发送时 UTF-8 截断长度计算错误,杜绝分片发送导致的内存破坏
    • 编译器重构:重构 scratchpad 布局,移除旧的 block[2] 头部 hack,改用显式的 header + prefix + payload 安全路径,规避 GCC 未定义行为。
    • Lambda 修复:解决 lambdaassign_svalue_no_free + free_svalue 导致的内存泄漏。
  • 突破架构限制
    • 局部变量突破:修复 reallocate_locals() 逻辑,支持单函数超过 255 个局部变量,且在嵌套匿名函数场景下指针偏移完全正确。
    • 深层继承支持:移除 inherit_list 的 256 项硬编码限制,改用动态容器,彻底解决复杂继承树导致的栈数组越界。
  • 网络与协议修复
    • Socket 状态机:修复 SSL_ERROR_SYSCALL 在可恢复场景下误报日志,及 STATE_HANDSHAKE 完成后逻辑落空的 Bug。
    • 数据校验:统一通过 decode_mud_packet_size() 解析 4 字节长度头,显式拒绝非法长度包。

3. 🪟 Windows 平台深度适配

  • 控制台显示:修复 Windows UTF-8 输出链,MUD_NAME 及启动日志中文乱码问题彻底解决
  • 超时控制:引入基于 steady_clockeval limit 回退机制,解释器循环现在能主动精准检查超时。
  • 构建优化:生成真实 __CXXFLAGS__ 预定义,抑制 Windows Release 构建时的 stringop-overflow 冗余告警,移除无意义的信号处理器安装警告。

⚡ 第二部分:VSCode LPC-update-server 插件更新

安装方式:vscode插件搜索 LPC-Server-UPDATE MUD工具,或点击此链接 LPC插件下载

大版本更新。新增本地LPCC编译。并且可准确提供错误行号、列号。需要配合优化后的驱动和LPCC,下载地址在下面。 效果截图(因为之前fluffos报错不准,所以务必配合我优化后的驱动和插件才能达到此效果) 0mo98-02eoc.gif

1. ✨ 自动函数声明 (Auto Declarations)

  • 保存自动刷新:保存 .c 文件时,自动扫描当前文件函数定义,并在顶部生成/刷新 AUTO DECLARATIONS 声明块,再也不用担心写完代码还要手动自己去顶部声明函数了。

2. 📁 路径管理与常用功能

  • 智能项目根目录识别:按目录特征(log/adm/cmds/feature 等)自动识别 Mudlib 根目录,减少手动配置 rootPath 的频率。
  • 一键复制路径:新增“复制当前文件相对路径”按钮,直接生成 /adm/daemons/logind 格式路径(自动去后缀、去项目根)。
  • 收藏夹面板:支持将当前文件一键加入“常用文件”列表,快速切换核心代码。

3. 🎨 交互调试与 UI 优化

  • 原始流监控:消息面板新增 “原始:开/关” 开关,支持查看服务器发出的原始数据流,便于协议级排查。
  • UI 对比度修复:优化配置环境下拉框颜色,修复部分暗色主题下的不可读问题。
  • 日志精简策略:默认隐藏逐条消息分析噪声,仅保留关键编译摘要,原始模式开启时同步输出 [RAW] 数据。

附录: 详细的 Gateway 接入协议文档及 efun API 列表请下载对应文档 。 驱动下载为driver.exe


更新内容确实有些过多,让AI整理了一下大概的内容。 同时新编译的fluffos驱动在内存方面控制也有提升。 如果需要linux版的请自己查阅项目自行编译。项目地址:https://github.com/serenez/fluffos_Z

文档内容下载地址:

gateway协议文档

网关对接教程文档

windows driver下载

windows LPCC下载

efun注释文档

LPC插件下载

报错信息优化文档代码:(将/adm/single/master.c文件中的string standard_trace函数改为下面内容。)


// ------------------------------------------------------------
// 运行时错误信息
// ------------------------------------------------------------

string query_runtime_error_program(mapping error)
{
    if (stringp(error["program"]))
        return error["program"];
    if (stringp(error["file"]))
        return error["file"];
    return "<unknown>";
}

string query_runtime_error_location(mapping error)
{
    string file, program;
    int line;

    file = stringp(error["file"]) ? error["file"] : 0;
    program = stringp(error["program"]) ? error["program"] : 0;
    line = intp(error["line"]) ? error["line"] : 0;

    if (stringp(file) && line > 0)
        return sprintf("%s 第 %d 行", file, line);
    if (stringp(program) && line > 0)
        return sprintf("%s 第 %d 行", program, line);
    if (stringp(file))
        return file;
    if (stringp(program))
        return program;
    return "<unknown>";
}

string query_error_message(mapping error)
{
    string message;

    message = stringp(error["error"]) ? error["error"] : "<unknown>";
    message = replace_string(message, "\r", "");
    message = replace_string(message, "\n", "");
    return message;
}

// ------------------------------------------------------------
// 编译/载入失败信息
// ------------------------------------------------------------

int is_load_object_failure(mapping error)
{
    string err;

    if (!stringp(error["error"]))
        return 0;

    err = error["error"];
    return sscanf(err, "*Error in loading object '%*s'") == 1;
}

string query_load_failure_target(mapping error)
{
    string err, target;

    if (!stringp(error["error"]))
        return 0;

    err = error["error"];
    if (sscanf(err, "*Error in loading object '%s'", target) == 1)
        return target;

    return 0;
}

int has_compile_error_snapshot(mapping error)
{
    return stringp(error["compile_error_message"]) ||
           stringp(error["compile_error_file"]) ||
           intp(error["compile_error_line"]);
}

string query_compile_error_target(mapping error)
{
    if (stringp(error["compile_error_object"]) &&
        sizeof(error["compile_error_object"]))
        return error["compile_error_object"];

    return query_load_failure_target(error);
}

string query_compile_error_position(mapping error)
{
    string file;
    int line, column;

    file = stringp(error["compile_error_file"]) ? error["compile_error_file"] : 0;
    line = intp(error["compile_error_line"]) ? error["compile_error_line"] : 0;
    column = intp(error["compile_error_column"]) ? error["compile_error_column"] : 0;

    if (stringp(file) && line > 0 && column > 0)
        return sprintf("%s 第 %d 行,第 %d 列", file, line, column);
    if (stringp(file) && line > 0)
        return sprintf("%s 第 %d 行", file, line);
    if (stringp(file))
        return file;
    return "<unknown>";
}

// ------------------------------------------------------------
// 调用链渲染
// ------------------------------------------------------------

int query_trace_start_index(mapping error)
{
    int i, s;

    i = 0;
    s = sizeof(error["trace"]);
    if (! this_player(1) && this_player())
    {
        for (; i < s; i++)
        {
            string prog;
            prog = "/" + error["trace"][i]["program"];
            // MESSAGE_D 已删除,跳过相关检查
            if (! sscanf(prog, "/cmds/chat/%*s") &&
                prog != "/clone/user/chatter.c" &&
                prog != F_COMMAND)
                break;
        }
    }

    return i;
}

string render_trace_entries(mapping error, int start, string prefix, int numbered)
{
    int i, s, index;
    string res;

    res = "";

    s = sizeof(error["trace"]);
    if (start >= s)
        return "";

    index = 1;
    for (i = start; i < s; i++, index++)
    {
        if (numbered)
        {
            res += sprintf("%2d. %s 的 %s() 第 %i 行,物件: %O\n",
                       index,
                       error["trace"][i]["program"],
                       error["trace"][i]["function"],
                       error["trace"][i]["line"],
                       error["trace"][i]["object"]);
        }
        else
        {
            res += sprintf("%s:%s 的 %s() 第 %i 行,物件: %O\n",
                       prefix,
                       error["trace"][i]["program"],
                       error["trace"][i]["function"],
                       error["trace"][i]["line"],
                       error["trace"][i]["object"]);
        }
    }

    return res;
}

// ------------------------------------------------------------
// 最终输出
// ------------------------------------------------------------

string format_runtime_error_trace(mapping error, int caught)
{
    int start;
    string res, program, location, object_name;
    object me;
    mixed *cmds;

    res = caught ? "错误讯息被拦截:" : "";
    program = query_runtime_error_program(error);
    location = query_runtime_error_location(error);
    object_name = objectp(error["object"]) ? file_name(error["object"]) : "<unknown>";

    res = sprintf("%s\n执行时段错误:%s\n", res, query_error_message(error));
    res += sprintf("程式:%s\n位置:%s\n物件:%s\n", program, location, object_name);

    if (! error["object"] && (me = this_player()))
    {
        res += sprintf("当前玩家:%s(%s) - %O  所在环境:%O\n",
                   me->name(1), me->query("id"), me, environment(me));
        cmds = me->query_commands();
        res += me->name(1) + "身上及四周的物品与所在的环境提供以下指令:\n";
        for (int i = 0; i < sizeof(cmds); i++)
            res += sprintf("%-15s  %2d %O\n",
                       cmds[i][0], cmds[i][1], cmds[i][2]);

        res += sprintf("当前的命令:%O\n", me->query_last_input());
    }

    start = query_trace_start_index(error);
    res += render_trace_entries(error, start, "呼叫来自", 0);
    return res;
}

string format_compile_failure_trace(mapping error, int caught)
{
    int start;
    string res, target, position, message, source, caret;

    res = caught ? "错误讯息被拦截:\n" : "";
    target = query_compile_error_target(error);
    if (!stringp(target) || !sizeof(target))
        target = "<unknown>";

    res += sprintf("编译/载入失败:%s\n", target);

    if (has_compile_error_snapshot(error))
    {
        position = query_compile_error_position(error);
        message = stringp(error["compile_error_message"]) ? error["compile_error_message"] : "<unknown>";
        res += sprintf("编译位置:%s\n编译原因:%s\n", position, message);

        source = stringp(error["compile_error_source"]) ? error["compile_error_source"] : 0;
        caret = stringp(error["compile_error_caret"]) ? error["compile_error_caret"] : 0;
        if (stringp(source) || stringp(caret))
        {
            res += "源码片段:\n";
            if (stringp(source))
                res += source + "\n";
            if (stringp(caret))
                res += caret + "\n";
        }
    }
    else
    {
        res += "说明:对象在编译阶段失败,但驱动未提供结构化编译诊断;请以上面的编译输出为准。\n";
    }

    start = query_trace_start_index(error);
    if (start < sizeof(error["trace"]))
    {
        res += "说明:下面是触发这次编译/载入失败的调用链,不是真实编译错误位置。\n";
        res += "触发链:\n";
        res += render_trace_entries(error, start, 0, 1);
    }

    return res;
}

string standard_trace(mapping error, int caught)
{
    if (is_load_object_failure(error))
        return format_compile_failure_trace(error, caught);

    return format_runtime_error_trace(error, caught);
}
京ICP备13031296号-4