AFNAFN BRIDGECC:TWEAKED FUNCTION WIKI

AFN 高级频段网络
模组知识库

围绕 Create 公开双频无线链路构建的分层频段、鉴权、信道值、票务、桥接器与外部设备系统。CC:Tweaked 和 Synaxis 是可选集成;API 参数、返回值和错误码见函数手册。

CREATE ADDONHIERARCHICAL FREQUENCIESAUTH ACLCHANNEL VALUESCC:T OPTIONALSYNAXIS OPTIONAL

模组概览

从无线频率到可管理的网络

AFN 不替换 Create 的无线链路,而是在其上增加可编辑的层级地址、历史库、别名、规则匹配、鉴权板、信道值和多种交互设备。普通 Create 设备仍按强度收发;AFN 设备之间还可以同步文本、布尔值和实数组。

组成作用是否需要额外模组
频段板保存主频、别名和鉴权信息仅需 AFN
无线设备把频段板接入发送、接收和收发设备仅需 AFN + Create
桥接器管理最多 64 条信道,连接红石、玩家、无线、Synaxis 和 CCCC、Synaxis 可选
票务设备签发、验证和保存鉴权票券仅需 AFN
信箱单信道收发并与 Create Display Link 互读写仅需 AFN + Create

频段系统

主频、别名和鉴权板

普通频段板保存一个主频和最多五个别名。主频是默认发送地址,别名是同一块板追加的匹配地址;别名可以使用 OR 或 AND 逻辑。历史库只记录纯字面地址,按层级整理,不把含有规则字符的表达式写入历史。

鉴权频段板额外保存 Owner、READ / WRITE ACL 和隐藏鉴权主频。READ 控制查看和接收,WRITE 控制修改;Owner 管理授权。锁定后,绑定设备中的鉴权板不能被普通拆卸操作取出。没有权限时,隐藏主频不会出现在 GUI、Tooltip 或护目镜悬浮信息中。

匹配语法

语法范围说明
?当前层匹配一个字符
*当前层匹配任意字符,但不跨越点号
**跨层匹配任意层级和点号
[A-C]当前层匹配一个大小写敏感的字符范围
!上一层只排除紧邻上一层的简写项,可连续使用
1.2.[1-9].!1!2!3![4-8].[2-4].!2!3

上式只匹配 1.2.9.4。规则在服务端编译后匹配,不交给正则表达式执行;历史库仅保存不含规则字符的地址。

设备

无线设备与控制设备

设备能力
无线红石信号终端兼容 Create 双槽无线链路;频段板方向和终端水平、垂直摆放不影响匹配。
信箱单信道发送、接收或收发;可安装普通板或鉴权板,保存接收内容,并与 Display Link 支持的来源和目标互读写。
AFN 桥接器64 条信道、CRT、红石绑定、信道值、Synaxis 端口和 CC:T 外设。
大型桥接器2×1×2 触控大屏版本;实体电源键和锁定键控制屏幕。
AFN 高级电脑受保护的 CC:T 主机;允许白名单 ComputerID 使用 AFN 函数。

设备中的鉴权板是安装凭证,不会被消耗。未锁定时,Owner 或有权限玩家可以查看和按设备规则拆卸;锁定后只能破坏设备移除。护目镜只显示当前玩家有权限读取的频段。

票务与门禁

签发、验证和红石放行

发票机需要有效鉴权板,批量读取 Owner、标题和主频,为普通票券写入票据元数据。相同鉴权板签发的票券可以堆叠到 64;票面展示标题和发行人,Tooltip 不显示隐藏主频。

验票机先检查票券主频是否符合自身规则,再检查票券 Owner 是否满足鉴权板 ACL。验证成功后,只有在 27 格留票库存在空位时才扣除一张票并放行;库存已满时不扣票、不触发脉冲。成功输出 20 tick 红石脉冲,可同步发送配置的普通信号和鉴权信号。鉴权刷卡机与身份验证柱同样输出一秒脉冲,待机暗色、成功绿光、失败红光。

屏幕、信道值与地图

统一信道值

每条信道可以同时拥有主频、可选副频、可选值和激活状态。值类型为文本、布尔或 1~7 项有限实数组;空文本和无值状态不同。写值不会激活,激活也不要求存在值。AFN→AFN 可以携带值,普通 Create 设备只处理 0~15 强度。

显示模式

模式显示与交互
默认液晶风格显示信道名、文本或实数组。
开关把布尔值显示为开关;无法解释时回退为关闭。
柱状图按上下限显示实数组,可配置名称。
仪表盘按上下限显示实数组刻度,可配置名称。
地图读取坐标实数组前三项或文本坐标,绘制设备、信道和收藏点。

屏幕设置可控制展示顺序、可见性、交互确认、整数输入和地图背景。地图只低频读取客户端已加载区域;关闭背景时只绘制线条、点和收藏文本,不生成或强制加载区块。大型桥接器使用实体按键切换电源和锁定,锁定后屏幕不可编辑。

兼容与性能

公开链路兼容

AFN 通过 Create 的公开双频无线链路工作。未修改 Create 接口的附属设备可以继续完成基础频率匹配;航空学物理化设备按物理化域坐标参与匹配,方向以设备自身朝向计算。绕过 Create 公开链路、使用独立通信协议的设备不在自动兼容范围内。

CC:Tweaked 和 Synaxis 都是可选集成。桥接器为 CC 提供 afn_bridge 外设和 require("afn") 模块;Synaxis 提供激活输入、值输入和值输出端口。完整 API 见 FUNCTIONS.md

权限策略在鉴权板、白名单或能力开关变化时推送到会话。普通调用只读取 O(1) 会话缓存,不逐次扫描世界、NBT、容器或 ACL;电脑生命周期检查每 tick 执行,完整物理凭证审计低频执行。撤销准入或激活能力会清理对应 ComputerID 的持续租约和临时发送。

五分钟入门

代码中的 doornoticeyard_gateboiler 均为示例信道名。运行时应替换为桥接器 GUI 左侧的实际信道名;信道名不是无线主频表达式

1准备两条统一信道

信道名主频可选值本节用途
doorfactory.doorOPEN同时演示无线脉冲和值
notice留空候车中只在本机展示和修改文字

每条信道都可以同时拥有主频和值,`frequency` 与 `information` 不是互斥的存储类型。主频留空表示不加入无线网络,值仍可保存和显示。信道创建后始终有效;在 CC:T 页开放本节需要的读取、激活和配置权限。安装鉴权板后,还需把本机 ComputerID 加入白名单。详见权限章节

2连接并确认 CC 看得到桥接器

让电脑紧贴桥接器,或使用有线调制解调器联网,然后在 CC 终端创建程序并运行:

local afn = require("afn")

print("ComputerID:", os.getComputerID())
for _, channel in ipairs(afn.channels()) do
  print(channel.name, channel.primary_frequency, channel.value_present)
end

第一行用 CC 的 require 加载 AFN 模块,并把返回的函数表保存在普通局部变量 afn 中;之后的 afn.pulse 等调用都来自这张表。

预期:终端能列出 door factory.door true 和主频为空的 notice。若提示找不到桥接器,请检查相邻连接或有线网络;若提示权限问题,请检查白名单和读取权限。

3让信道发送 1 秒

local afn = require("afn")
local result = afn.pulse("door")
assert(result.success, result.error)

pulse 省略参数时使用 15 强度、20 tick;20 tick 通常就是 1 秒。成功后,door 信道会短暂激活,对应 AFN 无线接收设备应响应。若得到 unknown_channel,说明填的是不存在的名称(请从 GUI 复制信道名,而不是复制主频);权限异常请检查白名单和激活权限。

4读取并直接修改值

local afn = require("afn")

local before = assert(afn.value("notice"))
print("修改前:", before.value)

local result = afn.set_value("notice", "列车即将进站")
assert(result.success, result.error)

local after = assert(afn.value("notice"))
print("修改后:", after.value)

这里只想覆盖一次内容,所以不需要先处理 revision。写值需要配置权限,而且不会激活信道。若要变成真正的无值状态,请调用 clear_value;写入 "" 得到的是一个存在的空文本。

电脑不会绕过桥接器直接变成无线终端。持久无线输出来自桥接器内填写了有效主频的统一信道;临时发送也由桥接器建立。需要鉴权时,只能附加桥接器槽内的有效鉴权板,Lua 无法提交或伪造身份数据。

常用操作速查

以下写法假定只连接一台桥接器,且示例信道已在 GUI 中创建。每段程序先加载 local afn = require("afn")

操作最短写法需要的权限详细说明
查看全部信道afn.channels()读取afn.channels
查看一条完整信道afn.get("door")读取afn.get
读取值(含无值状态)afn.value("door")读取afn.value
直接修改值afn.set_value("door", "OPEN")配置afn.set_value
清除值afn.clear_value("door")配置afn.clear_value
激活 1 秒afn.pulse("door")激活afn.pulse
持续激活afn.set("door")激活afn.set
关闭自己的持续激活afn.clear("door")仍通过准入afn.clear
修改主频afn.set_primary_frequency("door", "factory.door")配置afn.set_primary_frequency
切换 CRT 当前显示项afn.set_display_channel("door")读取afn.set_display_channel
向任意主频发送 1 秒afn.pulse_temporary("station.bell")激活afn.pulse_temporary

函数签名怎么读

方括号表示“可选”,不是 Lua 代码

手册中的签名:

afn.set_value(channel, value[, revision[, bridge]])
部分含义
channel必填。桥接器 GUI 中的信道名,例如 notice
value必填。准备写入的新值。
[revision]可选。用于防止覆盖别人刚写入的值;简单覆盖时省略。
[bridge]可选。CC 看到的桥接器外设名,例如 left;只有一台时通常省略。

方括号不应输入。若要跳过中间的 revision,却指定最后的桥接器,需要用 nil 占位:

afn.set_value("notice", "新内容", nil, "left")

old 到底是什么?

local old = assert(afn.value("notice"))

old 只是示例作者随意取的普通 Lua 局部变量名,换成 infocurrent 都不影响 AFN。它保存函数返回的表:

{ present=true, kind="text", value="当前内容", revision=12 }

resultrchanged 也都是普通变量名,不是关键字。

最后的 bridge 是什么?

它是 CC 分配给外设的名称,例如直接相邻时可能是 left,有线网络上可能是 afn_bridge_3;不是方块标题、信道名、主频,也不是 afn.find() 返回的代理对象。可用 CC 的 peripherals 命令查看名称。

-- 指定名为 left 的桥接器
afn.pulse("door", 15, 20, "left")

核心概念与术语

统一信道模型

字段说明
信道名供 GUI 与 API 查找;绝大多数 channel 参数都填它。
主频可为空。有效且信道被本地来源激活时发送无线信号。
副频none、普通 manual 或鉴权板 auth
可选值文本、布尔或 1~7 项有限实数组;可与主频同时存在。
激活状态和值独立;写值不激活,激活也不要求有值。

AFN 桥接器之间可沿同一条已放行连接携带强度和值;普通 Create 设备只处理强度。无线入站不会自动中继,只有本地红石、玩家、CC:T 或 Synaxis 激活输入驱动 TX。

收发、激活、展示互不相同

所有信道始终有效。receive_enabled 收发为 false 时仅发送,为 true 时允许发送和接收;active 激活表示当前至少有一个有效来源;displayed 展示决定是否列入 CRT。新信道默认允许收发并展示,激活不会自动改变展示清单。

强度、tick、来源与租约

强度范围为 1~15。20 tick 通常为 1 秒。set 建立本电脑的持续租约,pulse 建立定时租约,clear 只清本电脑的来源;红石、其他电脑与 Synaxis 可以同时存在,实际强度取有效来源最大值。

revision:值版本号

设置、改变或清除值时,revision 单调前进;无值状态也保留版本号。直接覆盖可以不传;只有“先读取、根据旧值计算、再写回”时才传入旧 revision。冲突返回 revision_conflict,应重新读取后再计算。

返回失败与 Lua 异常

动作函数通常返回 {success,error,active,strength},配置函数通常返回 {success,error,channel};业务拒绝表现为 success=false 与错误码。最短程序可用 assert(result.success, result.error)assert 是 Lua 自带的“失败就中止并显示原因”,不是 AFN 函数。连接、参数、白名单或权限问题可能直接抛 Lua 异常,长期运行程序应再用 pcall 包住调用。完整模板见错误章节

五种屏幕方式都是解释视图

默认、开关、柱状图、仪表盘和地图不会限制信道存什么。无法解释时只做视觉回退:开关显示关闭、图表显示 0、地图只显示设备点;只有真实触控才写入规范值。地图读取实数组前三项或可解析文本坐标。整数模式只影响玩家屏幕触控,不影响 CC:T、Synaxis、无线或普通 GUI 写入。

术语

snapshotget/channels 返回的一条完整信道状态;handle 是临时发送函数返回的唯一句柄,传给 clear_temporary 才能停止那一次发送;Synaxis 的 Schema 是接线两端必须一致的数据形状,例如 vec3quaternion;CRT 是桥接器的主屏幕。

常用场景示例

持续开启 5 秒,再安全关闭

前置:door 已填写有效主频;电脑具有激活权限。

local afn = require("afn")
local opened = afn.set("door", 15)
assert(opened.success, opened.error)

sleep(5)

local closed = afn.clear("door")
assert(closed.success, closed.error)

clear 只移除本电脑建立的租约,不会关闭其他电脑、红石或 Synaxis 的来源。

直接写文字、布尔和实数组

前置:三个信道都已存在;它们是否有主频不影响写值。电脑具有配置权限。

local afn = require("afn")

local text_result = afn.set_value("notice", "列车进站")
assert(text_result.success, text_result.error)

local bool_result = afn.set_value("maintenance", true)
assert(bool_result.success, bool_result.error)

local array_result = afn.set_value("target", {120.5, 64, -31.25})
assert(array_result.success, array_result.error)

仅想设置新值时,这就是完整写法,不需要先读取 revision

读取—计算—防覆盖写回

适用:counter 当前保存单分量实数,新值依赖旧值。其他玩家、CC、Synaxis 或无线可能在两步之间改值。

local afn = require("afn")

local current = assert(afn.value("counter"))
assert(current.present and current.kind == "real", "counter 不是实数值")
local next_value = current.value + 1
local result = afn.set_value(
  "counter", next_value, current.revision
)

if not result.success and result.error == "revision_conflict" then
  printError("内容已变化,请重新读取后再试")
else
  assert(result.success, result.error)
end

current 是普通变量;真正起防覆盖作用的是传入的 current.revision

长期程序的双层错误处理

local afn = require("afn")

local called, result = pcall(afn.pulse, "door", 15, 20)
if not called then
  printError(result)       -- 连接、参数或权限异常
elseif not result.success then
  printError(result.error) -- 信道业务规则拒绝
else
  print("已激活,强度:", result.strength)
end

一次性脚本通常用 assert 足够;无人值守程序更适合这个模板。

鉴权板 ComputerID 白名单与权限

先准入,再分配能力

print("ComputerID:", os.getComputerID())
-- 也可以在 CC 终端直接运行:id

ComputerID 是非负整数,0 合法。没有鉴权板时忽略白名单并准入所有非负 ID;安装鉴权板后启用目标桥接器 GUI CC:T 页的鉴权板白名单,此时空名单拒绝全部电脑。读取、激活、配置三个开关始终分别生效:读取负责查询和 CRT,激活负责租约与临时发送,配置负责信道值、主副频、展示清单、Synaxis 与红石绑定。

变化会话行为
外设刚连接服务端推送一次当前策略;初始化完成前 fail closed
鉴权板、白名单或三权限改变立即推送到已连接会话,无需重启或重新连接
安装鉴权板后移出白名单停止事件,并清理该 ComputerID 的持续租约和全部临时发送
关闭激活权限清理持续与临时输出;仍获准时可使用自己的故障安全清理函数

普通函数调用只读取附件会话中的 O(1) 固定时间权限缓存,不会逐函数遍历方块实体、白名单,也不会反复读取 NBT 或玩家 ACL。require("afn")afn.find() 只能证明模块或外设可见,不代表 ComputerID 已获得对应能力。

发现与查询

afn.find([name])查找第一台或指定桥接器

参数:name 可选 string。返回:bridge, peripheral_name。查找本身不调用受保护方法,因此不检查读取权限或准入条件;返回的代理方法仍要求 ComputerID 通过当前准入条件并具有对应权限。

成功

local bridge, name = afn.find("left")
print(name)
-- bridge.listChannels() 还需要通过准入 + 开启读取权限

失败

local ok, err = pcall(afn.find, "missing")
if not ok then printError(err) end
-- no AFN bridge named missing
afn.channels([bridge])列出全部完整信道快照

返回:按配置顺序排列的快照数组。需要读取权限。新字段包含 schema_version,primary_frequency,secondary_mode,secondary_frequency,value_present,value_kind,channel_value,value_revision,synaxis_activation;旧 type/subtype/value/attach_auth 仅为兼容投影。

成功

for _, c in ipairs(afn.channels()) do
  print(c.name, c.primary_frequency, c.value_present, c.strength)
end

失败

local ok, err = pcall(afn.channels)
if not ok then printError(err) end
-- computer read access is disabled...
afn.active([bridge])列出拥有有效租约的信道名

返回:string 数组。红石、CC 或 Synaxis 任一来源有效即算激活;需要读取权限。

成功

for _, n in ipairs(afn.active()) do print("active", n) end

失败

local ok, err = pcall(afn.active, "missing")
if not ok then printError(err) end
afn.display_channels([bridge])读取 CRT 展示清单与轮播顺序

返回:被明确设为展示的信道名数组;需要读取权限。激活状态不会改变此清单。

成功

print(textutils.serialize(afn.display_channels("left")))

失败

local ok, err = pcall(afn.display_channels, 123)
if not ok then printError(err) end
-- bridge name must be a string
afn.get(channel[, bridge])读取一条完整信道快照

参数:信道名称。返回:完整快照;不存在为 nil。需要读取权限。

成功

local c = assert(afn.get("boiler"))
print(c.primary_frequency, c.value_present, c.synaxis_receive.enabled)

失败

assert(afn.get("no_such_channel") == nil)
afn.state(channel[, bridge])读取精简运行状态

返回:{receive_enabled,active,strength,displayed,value_present,value_kind,revision},同时保留旧 type/subtype 投影;不存在为 nil。需要读取权限。

成功

local s = assert(afn.state("boiler"))
print(s.active, s.strength)

失败

local ok, err = pcall(afn.state, "boiler", "missing")
if not ok then printError(err) end
afn.value(channel[, bridge])读取统一值,并区分无值与空文本

读取权限返回 {present,kind,value,revision};信道不存在才返回 nilpresent=falsevalue="" 只是 CC 表占位,不能当成空文本;是否有值必须看 present

local v = assert(afn.value("door"))
if not v.present then
  print("没有值,版本", v.revision)
elseif v.kind == "text" and v.value == "" then
  print("这是存在的空文本")
else
  print(v.kind, textutils.serialize(v.value))
end
afn.channel_value(channel[, bridge])afn.value 的同义别名

参数、权限和返回值与 afn.value 完全相同。

local v = afn.channel_value("door")
print(v and v.present)
afn.frequency(channel[, bridge])读取主频和副频配置

读取权限返回 {primary,secondary_mode,secondary_frequency,attach_auth};信道不存在返回 nilattach_auth 是兼容投影,新程序应看 secondary_mode

local f = assert(afn.frequency("door"))
print("主频", f.primary)
print("副频模式", f.secondary_mode)
afn.information(channel[, bridge])统一值兼容读取接口

兼容接口有值时返回 {value,subtype,revision},无值或信道不存在时返回 nil。它无法区分“不存在的信道”和“存在但无值”,新程序应使用 afn.value

local legacy = afn.information("notice")
if legacy then print(legacy.subtype, legacy.value) end
afn.last_error(channel[, bridge])读取最近无线错误

返回:错误 string;正常、未知信道或无错误为 nil。典型值:invalid_frequency_or_authwireless_unavailable

成功

local err = afn.last_error("secure_gate")
if err then printError(err) end

失败

local ok, err = pcall(afn.last_error, "secure_gate")
if not ok then printError(err) end -- 读取权限关闭

CRT 主屏幕

afn.get_display_channel([bridge])当前 CRT 信道

返回:名称;展示清单为空时 nil。需要读取权限。

成功

print(afn.get_display_channel() or "standby")

失败

local ok, err = pcall(afn.get_display_channel, "missing")
if not ok then printError(err) end
afn.set_display_channel(channel[, bridge])选择展示清单中的信道

返回:boolean。切换 CRT 不激活、不停止、不修改信道;需要读取权限。

成功

assert(afn.set_display_channel("notice"))

失败

local ok = afn.set_display_channel("hidden")
if not ok then printError("not in display list") end
afn.next_display_channel([bridge])按稳定顺序切换下一项

返回:切换后的名称;空清单为 nil。需要读取权限。

成功

print(afn.next_display_channel() or "standby")

失败

local ok, err = pcall(afn.next_display_channel)
if not ok then printError(err) end
afn.previous_display_channel([bridge])按稳定顺序切换上一项

返回:切换后的名称;空清单为 nil。需要读取权限。

成功

print(afn.previous_display_channel("left") or "standby")

失败

local ok, err = pcall(afn.previous_display_channel, false)
if not ok then printError(err) end

运行时租约与统一值

合并规则

一条信道可以同时有红石、多个 CC 电脑、Synaxis 和无线来源,实际强度取有效来源最大值。只要主频有效,本地来源激活就会发送无线信号;是否存在信道值不改变这一点。AFN→AFN 可附带值,普通 Create 设备只处理强度,无线入站不自动中继。

afn.set(channel[, strength[, bridge]])建立本电脑持续租约

参数:strength 1~15,默认 15。返回:{success,error,active,strength}。需要激活权限。

成功

local r = afn.set("yard_gate", 12)
assert(r.success, r.error)

失败

local r = afn.set("missing", 15)
print(r.success, r.error) -- false unknown_channel
afn.pulse(channel[, strength[, ticks[, bridge]]])建立 1~1200 tick 的租约

strength 默认 15;ticks 默认 20。到期自动清理并可产生 timeout 事件。

成功

local r = afn.pulse("bell", 15, 40)
assert(r.success, r.error)

失败

local ok, err = pcall(afn.pulse, "bell", 15, 1201)
if not ok then printError(err) end
afn.toggle(channel[, strength[, bridge]])切换本电脑自己的持续租约

不会清除其他电脑、红石或 Synaxis 来源。返回动作结果;需要激活权限。

成功

local r = afn.toggle("maintenance", 8)
print(r.success, r.active)

失败

local r = afn.toggle("missing", 8)
print(r.error) -- unknown_channel
afn.clear(channel[, bridge])清除本电脑在目标信道的租约

ComputerID 仍获准时,这是不要求激活权限的故障安全清理;其他来源不受影响。安装鉴权板后移出白名单会由桥接器自动清除该电脑的租约。返回动作结果。

成功

assert(afn.clear("yard_gate").success)

失败

local r = afn.clear("missing")
print(r.error) -- unknown_channel
afn.clear_all(channel[, bridge])清目标信道的全部来源

清除 CC、红石和 Synaxis 租约;需要配置权限。返回动作结果。

成功

assert(afn.clear_all("emergency").success)

失败

local ok, err = pcall(afn.clear_all, "emergency")
if not ok then printError(err) end -- configuration disabled
afn.set_value(channel, value[, revision[, bridge]])设置或替换统一信道值

配置权限接受文本、布尔、有限 number 或 1~7 项连续有限数字数组。文本最多 1024 个 Unicode 码点且不超过 4096 UTF-8 字节。写值不激活;简单覆盖不必传 revision。

assert(afn.set_value("notice", "列车即将进站").success)
assert(afn.set_value("door_open", true).success)
assert(afn.set_value("pose", {12.5, 64, -8, 0, 0, 0, 1}).success)
assert(afn.set_value("blank", "").success) -- 存在的空文本

空数组、稀疏表、NaN、无穷大或超过 7 项会整次拒绝。需要防覆盖时先用 value 读取 revision,再作为第三个参数提交。

afn.set_channel_value(...)afn.set_value 的同义别名

参数、权限、校验和返回值与 set_value 相同。

assert(afn.set_channel_value("counter", 42).success)
afn.clear_value(channel[, revision[, bridge]])把信道变成无值状态

配置权限清除值但保留单调 revision;它不同于写入空文本。可选 revision 用于防止并发覆盖。

local old = assert(afn.value("notice"))
local r = afn.clear_value("notice", old.revision)
assert(r.success, r.error)
assert(afn.value("notice").present == false)
afn.clear_channel_value(...)afn.clear_value 的同义别名

参数和行为与 clear_value 相同。

assert(afn.clear_channel_value("notice").success)
afn.set_information(channel, value[, revision[, bridge]])统一值兼容写入接口

兼容接口映射到统一值写入;名称无法表达“主频和值可以共存”。新程序应使用 set_value

兼容写法

local result = afn.set_information("notice", "列车即将进站")
assert(result.success, result.error)

这段兼容代码仍会直接覆盖 notice 的值,但新代码请改为 afn.set_value("notice", "内容", nil, "left")

展示清单与持久配置

afn.set_primary_frequency(channel, frequency[, bridge])设置或清空主频

配置权限频段必须是合法表达式;传空字符串可让信道退出无线网络,但不会删除值、屏幕设置或端口。

assert(afn.set_primary_frequency("door", "factory.door.*").success)
assert(afn.set_primary_frequency("local_note", "").success)
afn.set_secondary(channel, mode[, frequency[, bridge]])配置无副频、手动副频或鉴权副频

配置权限modenonemanualauth。只有 manual 必须提供合法 frequency;auth 只使用桥接器当前有效鉴权板,Lua 不能提交隐藏身份。

assert(afn.set_secondary("door", "manual", "station.public").success)
assert(afn.set_secondary("secure", "auth").success)
assert(afn.set_secondary("local", "none").success)
afn.set_channel_displayed(channel, shown[, bridge])修改单条展示状态

返回:boolean。目标必须存在;需要配置权限。展示状态不影响信道收发或激活。

成功

assert(afn.set_channel_displayed("notice", true))

失败

assert(not afn.set_channel_displayed("missing", true))
afn.set_display_channels(names[, bridge])原子覆写全部展示状态与顺序

names 是连续数组,可为空;名称必须存在且不重复。返回 boolean;需要配置权限。清单外的信道即使激活也不会自动显示。

成功

assert(afn.set_display_channels({"notice", "boiler", "gate"}))

失败

assert(not afn.set_display_channels({"boiler", "boiler"}))
-- 失败时旧清单完整保留
afn.create_channel(definition[, bridge])新建统一持久信道

新字段为 name,primary_frequency,secondary_mode,secondary_frequency,value_present,value_kind,channel_value,receive_enabled,displayed。主频和值都可省略;若 value_present=true 必须同时给 channel_value。新信道默认允许收发并展示;receive_enabled=false 表示仅发送。返回配置结果;需要配置权限。

成功

local r = afn.create_channel({
  name="yard_gate",
  primary_frequency="station.gate.*.!test!staff",
  secondary_mode="none",
  value_present=true, value_kind="text", channel_value="READY",
  displayed=true
})
assert(r.success, r.error)

失败

local r = afn.create_channel({
  name="broken", value_present=true
})
print(r.success, r.error) -- 缺少 channel_value,整次拒绝
afn.update_channel(channel, changes[, bridge])原子修改统一字段

只修改给出的字段,失败不会部分提交。同一表中不得混用相互冲突的新旧别名;value_present=false 表示清除值,不能同时提供 channel_value

成功

local r = afn.update_channel("yard_gate", {
  name="yard_exit",
  primary_frequency="station.exit.[1-4]",
  secondary_mode="auth"
})
assert(r.success, r.error)

清除值

assert(afn.update_channel("yard_exit", {
  value_present=false
}).success)
afn.remove_channel(channel[, bridge])删除配置及关联运行状态

成功结果的 channel=nil;同步清租约、无线 actor 与 Synaxis endpoint。需要配置权限。

成功

local r = afn.remove_channel("temporary_config")
assert(r.success and r.channel == nil)

失败

local r = afn.remove_channel("missing")
print(r.error) -- unknown_channel
afn.set_channel_type(channel, type[, replacement[, bridge]])旧顶层类型兼容投影

兼容期只为旧程序保留,无法表达同一信道同时拥有主频和值。新代码应组合使用 set_primary_frequencyset_valueclear_value

旧代码仍可运行

local r = afn.set_channel_type("old_text", "frequency", "factory.line.*")
assert(r.success, r.error)

失败

local r = afn.set_channel_type("old_text", "frequency")
print(r.error) -- frequency_required_for_type_change
afn.set_information_subtype(channel, subtype[, replacement[, bridge]])旧值子类兼容投影

兼容期只为旧程序保留。新代码直接用类型明确的 Lua 值调用 set_value;旧 coordinate/player 仍可读取但不可新建。

旧代码仍可运行

local r = afn.set_information_subtype("counter", "real", 42.5)
assert(r.success, r.error)

失败

local r = afn.set_information_subtype("counter", "boolean", "yes")
print(r.error) -- invalid_information_value

Synaxis 与红石

三个彼此独立的 Synaxis 端口

激活输入只控制 0~15 强度,支持 real / boolean;值输入只写统一值,不激活;值输出只发布统一值,也不激活。三者拥有稳定且独立的 endpoint key。Synaxis 要求接线两端 Schema 完全一致,因此必须在接线前选择格式,不能根据第一帧内容动态猜测。

值端口支持 real、boolean、vec3、quaternion。短数组输入覆写前部并保留旧尾部,长数组扩展;输出截断多余项、补齐缺项,Quaternion 缺少的 w 补 1。无法转换的输出使用 Schema 安全默认值;非法输入整次忽略并保留旧值。Pose / Twist 只保留旧存档兼容,Bundle 暂不支持。

afn.set_synaxis_activation(channel, enabled[, format[, x, y[, bridge]]])配置独立激活输入端口

配置权限format 为 real 或 boolean。Real 的值小于 1 表示关闭,达到 1 后转换并限制到 1~15;Boolean 的 false/true 对应 0/15。x/y 必须同时提供,省略格式时保留当前格式。

assert(afn.set_synaxis_activation(
  "door", true, "real", 12, 20
).success)
assert(afn.set_synaxis_activation("door", false).success)
afn.set_synaxis_receive(channel, enabled[, format[, x, y[, bridge]]])配置 Synaxis → 桥接器值输入

明确给出 format 时可选 real/vec3/quaternion/boolean;省略或传空字符串保留值输入当前格式。x/y 必须同时提供。该端口只改值,不激活,也不修改另外两个端口。

Quaternion 值输入与安全关闭

assert(afn.set_synaxis_receive(
  "vehicle_rotation", true, "quaternion", 20, 70
).success)
-- 省略 format 关闭并保留接收格式;发布方向不受影响
assert(afn.set_synaxis_receive("vehicle_rotation", false).success)

失败

local r = afn.set_synaxis_receive("notice", true, "boolean")
print(r.error) -- invalid_synaxis_port
afn.set_synaxis_publish(channel, enabled[, format[, x, y[, bridge]]])配置桥接器 → Synaxis 值输出

格式与坐标规则同值输入,但独立配置。比如 4 项实数组发布为 vec3 时只取前三项;Quaternion 缺少的 w 补 1。不存在或无法转换的值输出 Schema 安全默认值。该端口不激活信道。

Quaternion 值输出与安全关闭

assert(afn.set_synaxis_publish(
  "vehicle_rotation", true, "quaternion", 88, 70
).success)
assert(afn.set_synaxis_publish("vehicle_rotation", false).success)

失败

local r = afn.set_synaxis_publish("vehicle_rotation", true, "quaternion", 200, 70)
print(r.error) -- invalid_synaxis_position
afn.bind_redstone(channel, side, strength[, bridge])增加方向 + 强度选择器绑定

side 以桥接器大屏幕正面为基准,为 front/back/left/right/up/down 或字符串 "all"(左右是玩家正对屏幕时看到的左右);strength 为精确整数 1~15 或字符串 "all"(任意非零输入)。支持具体方向/全向与具体强度/全强度的四种组合;匹配时采用实际输入强度。数字不是阈值。一个信道最多保存 112 个不同组合且不会重复保存完全相同项;GUI 新增行默认双 all。返回配置结果;需要配置权限。

四种组合

assert(afn.bind_redstone("yard_gate", "front", 15).success)
assert(afn.bind_redstone("site_alarm", "all", "all").success)
assert(afn.bind_redstone("precision_alarm", "all", 7).success)
assert(afn.bind_redstone("left_input", "left", "all").success)
-- 依次表示:精确组合、双通配、全向精确强度、具体方向全强度

失败

local r = afn.bind_redstone("yard_gate", "north", 15)
print(r.error) -- invalid_redstone_binding
afn.unbind_redstone(channel, side[, bridge])移除一个方向选择器的全部绑定

传具体方向只移除该方向的行;传 "all" 只移除全向行,不会连带删除六个具体方向。返回配置结果;需要配置权限。

成功

assert(afn.unbind_redstone("yard_gate", "front").success)
assert(afn.unbind_redstone("site_alarm", "all").success)

失败

local r = afn.unbind_redstone("missing", "front")
print(r.error) -- invalid_redstone_binding

临时无线发送

独立 handle

临时发送不创建持久信道、展示项、红石绑定或 Synaxis 端口。同一电脑可并发创建多个 handle;桥接器总计上限 32。鉴权只能来自桥接器自己的有效板。

afn.transmit_temporary(frequency[, strength[, auth[, bridge]]])建立持续临时发送

frequency 必须合法非空;strength 1~15,默认 15;auth 默认 false。返回动作字段和唯一 handle。需要激活权限。

成功

local r = afn.transmit_temporary("factory.*.!test!maintenance", 12, false)
assert(r.success, r.error)
print(r.handle)

失败

local r = afn.transmit_temporary("secure.gate", 15, true)
print(r.error) -- auth_board_unavailable
afn.pulse_temporary(frequency[, strength[, ticks[, auth[, bridge]]]])建立定时临时发送

ticks 1~1200,默认 20。返回 handle;到期关闭并产生 timeout 事件。

成功

local r = afn.pulse_temporary("station.bell", 15, 40, false)
assert(r.success, r.error)

失败

local ok, err = pcall(afn.pulse_temporary, "station.bell", 15, 0)
if not ok then printError(err) end
afn.clear_temporary(handle[, bridge])停止本电脑指定 handle

不能清其他电脑的 handle;ComputerID 仍获准时不要求激活权限。安装鉴权板后移出白名单会自动关闭该电脑全部 handle。返回动作结果。

成功

local tx = afn.transmit_temporary("factory.test")
assert(tx.success)
assert(afn.clear_temporary(tx.handle).success)

失败

local r = afn.clear_temporary("unknown")
print(r.error) -- unknown_temporary_handle
afn.clear_temporary_all([bridge])停止本电脑全部临时发送

返回:removed_count integer。其他电脑和持久信道不受影响;ComputerID 仍获准时不要求激活权限,安装鉴权板后撤销白名单时同一清理会自动执行。

成功

afn.transmit_temporary("test.one")
afn.transmit_temporary("test.two")
print(afn.clear_temporary_all()) -- 2

失败

local ok, err = pcall(afn.clear_temporary_all, "missing")
if not ok then printError(err) end

raw afn_bridge 外设索引

当前没有信道启用/禁用 API;raw 动态方法索引为 0~38。下表列出统一信道方法的索引。

索引raw 方法Lua 包装函数
32getChannelValueafn.value / channel_value
33setChannelValueafn.set_value / set_channel_value
34clearChannelValueafn.clear_value / clear_channel_value
35getFrequencyafn.frequency
36setPrimaryFrequencyafn.set_primary_frequency
37setSecondaryafn.set_secondary
38setSynaxisActivationafn.set_synaxis_activation
local bridge = peripheral.wrap("left")
local value = bridge.getChannelValue("door")
print(value.present, value.kind, textutils.serialize(value.value))

新快照字段和新方法进入兼容层的同时,旧方法仍保留至少一个大版本;旧投影无法完整表达主频和值共存,新程序应迁移到上表。

CC 事件

只有已完成策略初始化、ComputerID 仍获准并具有读取权限的附件会话会收到事件;未授权电脑不注册监听。第二个返回值是 payload table,刚连接不会补发历史状态。

事件主要字段
afn_channel_startedchannel, active=true, strength
afn_channel_changed有效强度变化后的信道字段
afn_channel_stoppedchannel, active=false, strength=0
afn_channel_value_changedrevision, value_present, value_kind, channel_value
afn_information_changed上一事件的旧名称兼容副本
afn_channel_rejectedoperation, error,可能含 channel
afn_channel_timeout信道脉冲字段;或 operation, handle, active=false
afn_display_changedchannel;待机时为空串
while true do
  local event, data = os.pullEvent()
  if event:sub(1, 4) == "afn_" then
    print(event, textutils.serialize(data))
  end
end

错误与返回值

外设不存在、ComputerID 未通过准入、会话尚未初始化、参数类型错误或对应权限关闭时会抛 Lua 异常;业务拒绝通常返回 success=false 与错误码。配置返回形如 {success,error,channel},失败时 channel=nil 且原配置不变。同 tick 值写入按玩家 > CC:T > Synaxis > 无线仲裁,较低优先级返回 information_write_conflict

local called, result = pcall(afn.set, "yard_gate", 15)
if not called then
  printError(result)       -- Lua 异常
elseif not result.success then
  printError(result.error) -- 业务拒绝
else
  print(result.strength)
end

常见错误:unknown_channelrevision_conflictinformation_write_conflictinvalid_information_valuevalue_present_conflictinvalid_frequencyinvalid_secondarysecondary_frequency_requires_manual_modeunsupported_synaxis_activation_formatinvalid_synaxis_portinvalid_redstone_bindingauth_board_unavailabletemporary_transmitter_limitwireless_unavailable

故障排查

看到的现象通常原因下一步
require("afn") 失败电脑未安装 CC:Tweaked,或 Lua ROM 未加载确认 CC:Tweaked 已安装并重启电脑。
unknown_channel把主频、标题或拼写错误当成信道名复制桥接器 GUI 左侧的信道名。
value(...).present == false信道存在,但当前没有值set_value 创建值;不要把占位的空串误认为空文本。
computer configuration access is disabled...对应 CC:T 能力开关关闭在 CC:T 页开启调用需要的读取、激活或配置权限。
revision_conflict读取后,其他来源先修改了值重新调用 value,根据新值重新计算。
返回成功但无线设备不响应主频为空或非法、副频鉴权不可用、距离/物理化域不通或接收规则不匹配get 检查 primary_frequencysecondary_modereceive_enabledlast_error;仅发送模式不影响本地发送。
Synaxis 接线变红两端 Schema 不一致在接线前把两端设为相同格式;激活端口仅 real/boolean,值端口另行选择。
操作了错误的桥接器多台外设时省略或写错 bridge运行 peripherals 查看名称,并把它作为最后参数。

information_write_conflictrevision_conflict 不同:前者表示同一服务器 tick 已接受优先级更高的玩家、CC:T、Synaxis 或无线写入。等待下一 tick、重新读取当前值,再决定是否提交。

没有匹配的内容。可尝试操作目标、函数名、参数名或错误码。