Skip to content

局域网联机 ​

api.lan 让插件在局域网里广播一个 Minecraft「对局域网开放」的世界,这样用户的 Minecraft 客户端会在多人游戏列表里自动发现它。

这是给联机类插件用的——世界其实是通过别的途径(比如一个隧道)连进来的,但让原版客户端能发现它,需要发这个广播。

ts
const { handle } = await api.lan.announce('某某的世界', 25565)

需要 lan 权限(高风险)。

为什么要原生实现 ​

Minecraft 发现局域网游戏的方式是监听 UDP 多播 224.0.2.60:4445,包体格式是:

[MOTD]<名字>[/MOTD][AD]<端口>[/AD]

webview 开不了多播 socket,所以这件事必须在原生层做。这就是它需要一个单独权限的原因。

announce(motd, port) ​

开始广播,每 1.5 秒重复一次,直到 stop 或插件卸载。

ts
const { handle } = await api.lan.announce('我的世界', 25565)
参数说明
motd显示在客户端多人游戏列表里的名字
port客户端要连的端口。不能是 0

返回 { handle },用来停止。

motd 里的方括号会被去掉

包体用 [MOTD]...[/MOTD] 分隔。名字里有方括号会破坏格式,所以启动器自动把它们删掉。

"我的[测试]世界" → "我的测试世界"

stop(handle) ​

停止广播。

ts
await api.lan.stop(handle)

一般不用手动停

插件卸载、应用退出时,启动器会停掉所有广播。手动 stop 只在你想主动关闭时用。

谁会发现它 ​

局域网里任何开着 Minecraft 的客户端——不只是本机的。这正是这个能力要小心的地方:持有 lan 权限的插件,能往局域网里每台机器的多人游戏列表里塞一个条目。

所以它是高风险权限,用户要手动批准。

完整例子 ​

联机类插件的典型流程:

ts
import type { PluginHostApi } from '@celestial/plugin'

export async function activate(api: PluginHostApi): Promise<void> {
	let lanHandle: number | null = null

	async function startHosting(motd: string, port: number) {
		try {
			const { handle } = await api.lan.announce(motd, port)
			lanHandle = handle
			api.log(`已开始广播「${motd}」,端口 ${port}`)
		} catch (error) {
			// lan 权限没批准 —— 降级
			api.log('无法广播(可能是未授权)', error)
		}
	}

	async function stopHosting() {
		if (lanHandle !== null) {
			await api.lan.stop(lanHandle)
			lanHandle = null
		}
	}

	// 通常由界面上的按钮触发
	api.slots.add('sidebar.top', {
		id: 'host-button',
		component: {
			name: 'HostButton',
			setup() {
				const { h } = api.vue
				return () =>
					h('button', { class: 'm-2', onClick: () => void startHosting('我的世界', 25565) }, '开放到局域网')
			},
		},
	})
}

和 sidecar 一起用 ​

联机插件通常两个一起用:sidecar 跑隧道程序,LAN 广播让客户端能发现。

官方的陶瓦联机插件就是这样——它跑一个 sidecar,然后广播一个局域网世界指向它。见拆解:陶瓦联机插件。

常见错误 ​

现象原因
cannot use lan: the "lan" permission has not been grantedmanifest 没声明 lan,或用户没批准
LAN announce port must not be zero端口传了 0
客户端看不到世界防火墙挡了 UDP 4445,或者不在同一网段
motd 里的方括号没了故意的,见上

参考手册见PluginHostApi 全量。接下来去实例拆解看真实插件。

Celestial Launcher 基于 Modrinth App 构建,遵循其开源许可。