npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mc-tunnel

v0.2.3

Published

面向 Electron / Node.js 的 Minecraft 局域网联机模块:房间码一键组网,基于 EasyTier 的 P2P 隧道(Minecraft LAN tunnel)

Readme

mc-tunnel

面向 Electron / Node.js 的 Minecraft 局域网联机模块。

房主在游戏里「对局域网开放」,把 房间码 发给朋友;朋友输入房间码后, 游戏「多人游戏 → 局域网世界」里就会出现这条房间,双击即可进入。

EasyTier 以外部子进程方式调用完成 P2P 组网 (详见 合规说明)。

📖 完整使用文档(全部参数、事件、错误码、Electron 集成、排错表)见 docs/USAGE.md。 🔧 口令模式与中文房间码的源码级实现说明(位布局、算法、行号索引)见 docs/PASSPHRASE-ZH-CODE.md。


特性

| | | |---|---| | 零依赖 | 运行时只使用 Node 内置模块(http / dgram / net / child_process),不引入任何 npm 依赖 | | 免管理员权限 | EasyTier 以 --no-tun 运行,不创建虚拟网卡 | | 无需自建服务器 | 房间码自包含凭据,节点发现交给 EasyTier 公共节点;也支持完全离线直连 | | 无需 mod | 通过伪造 Minecraft 局域网多播让原版客户端直接可见 | | 安全 | 房间码含 CRC-12 校验;协调服务使用握手指纹 + 令牌鉴权(恒定时间比较) | | 口令联机 | 用一段短语代替房间码:passphrase: '彩蛋口令',两端相同即可入同一房间(强度取决于口令) | | 中文房间码 | 可选子入口 mc-tunnel/zh,把房间码显示成 7 个汉字(彩蛋玩法) | | 双格式 | 同时产出 ESM 与 CJS,附带 .d.ts 类型声明 | | 可观测 | 全流程 state / players / error 事件,失败时携带 EasyTier 日志尾部 |


安装

npm install mc-tunnel

同时需要准备 EasyTier 的两个可执行文件(本包不打包它们,避免体积与许可问题):

easytier-core(.exe)
easytier-cli(.exe)

放置位置三选一:

  1. Electron:resources/easytier/(配合 electron-builder 的 extraResources)
  2. 任意目录 + 环境变量 MC_TUNNEL_EASYTIER=/path/to/dir
  3. 代码里传 easyTier: { binDir: '/path/to/dir' }

快速开始

import { createHost, createGuest } from 'mc-tunnel';

// ---------- 房主 ----------
const host = await createHost({
  mcPort: 25565,          // 不传则自动监听局域网广播发现
  playerName: 'Alice',
});

console.log('房间码:', host.roomCode);   // 例如 2GJY-DYSK-8825-DZJY

host.on('player-join', (player) => console.log(`${player.name} 加入了`));
host.on('mc-closed', () => console.log('存档已关闭,房间失效'));

// ---------- 客人 ----------
const guest = await createGuest({
  roomCode: '2GJY-DYSK-8825-DZJY',
  playerName: 'Bob',
});

console.log('在游戏里连接:', guest.address);   // 127.0.0.1:25565
// 此时「局域网世界」里已经出现房间,双击即可进入

// 退出时务必关闭,否则会残留 easytier-core 进程
await guest.close();
await host.close();

口令模式(用一段短语代替房间码)

// 房主
const host = await createHost({ mcPort: 25565, passphrase: '彩蛋口令 演示' });

// 客人:口令相同即可(大小写、空白、全角不敏感)
const guest = await createGuest({ passphrase: '  彩蛋口令    演示  ' });

// 口令也会派生出一个等价的标准房间码,UI 可二选一展示
import { roomCodeFromPassphrase } from 'mc-tunnel';
console.log(roomCodeFromPassphrase('彩蛋口令 演示'));

口令强度取决于口令本身:弱口令等于把房间公开。需要严格安全时请用默认的随机房间码。

中文房间码(彩蛋,可选子入口)

import { toChineseRoomCode, parseChineseRoomCode } from 'mc-tunnel/zh';

const zh = toChineseRoomCode(host.roomCode);   // 7 个汉字,例如 '朱上岸雪存违户'
const guest = await createGuest({ roomCode: parseChineseRoomCode(zh) });

16 个 Base32 字符 ⇄ 7 个汉字 无损双向互转(2048⁷ = 2⁷⁷,正好等于版本 1 的有效位宽), 字符集取自 BIP39 简体中文词表(2048 个去重单字,标准且永不改动),支持繁简/全角/标点容错。

Electron 集成

import { app, BrowserWindow } from 'electron';
import { createHostInElectron, manageSessions } from 'mc-tunnel/electron';

const host = await createHostInElectron(app, { mcPort: 25565 });

// 应用退出时自动关闭会话,避免孤儿进程
manageSessions(app, host);

electronDefaults() 会自动把:

  • 设备标识放到 app.getPath('userData')
  • EasyTier 目录指向 process.resourcesPath/easytier

electron-builder 配置示例:

{
  "extraResources": [
    { "from": "vendor/easytier", "to": "easytier" }
  ]
}

⚠️ 如果使用 ASAR 打包,EasyTier 必须放在 extraResources(ASAR 内的可执行文件无法 spawn)。


API

createHost(options?): Promise<TunnelHost>

| 参数 | 类型 | 说明 | |---|---|---| | roomCode | string | 指定房间码,不传则随机生成 | | passphrase | string | 口令模式,与 roomCode 二选一 | | mcPort | number | 指定端口;不传则监听局域网广播自动发现 | | playerName | string | 昵称,默认 Host | | motd | string | 局域网列表显示名 | | coordPort | number | 协调服务端口,默认 25991(双方必须一致) | | listeners | string[] | 额外监听地址,如 ["tcp://0.0.0.0:11010"] | | peers | string[] | 直连对端,如 ["tcp://1.2.3.4:11010"] | | scanTimeoutMs | number | 自动发现超时,默认 30000 | | dataDir | string | 设备标识存储目录 | | easyTier | EasyTierOptions | { binDir, publicNodes, p2pOnly } |

会话属性:roomCode mcPort coordPort virtualIp phase,方法:players() close()。

事件:state players player-join player-leave mc-closed error。

createGuest(options): Promise<TunnelGuest>

| 参数 | 类型 | 说明 | |---|---|---| | roomCode | string | 与 passphrase 二选一必填 | | passphrase | string | 与 roomCode 二选一必填 | | playerName | string | 昵称,默认 Guest | | preferredLocalPort | number | 期望本地端口,默认与房主端口同号 | | peers | string[] | 直连对端,可完全绕开公共节点 | | timeoutMs | number | 建链总超时,默认 90000 | | dataDir / easyTier | | 同上 |

会话属性:roomCode mcPort localPort address natDifficulty phase, 方法:hostPlayers() close()。

事件:state players server-status error。

工具函数

import {
  generateRoomCode,    // () => string
  verifyRoomCode,      // (code) => boolean
  normalizeRoomCode,   // (input) => string | null
  parseRoomCode,       // (code) => { code, networkName, networkSecret }
  pingMc,              // (port, host?, timeoutMs?) => Promise<McStatus | null>
  isPortOpen,          // (port, host?, timeoutMs?) => Promise<boolean>
  resolveBinaries,     // (binDir?) => { core, cli }
} from 'mc-tunnel';

工作原理

房主                                     客人
────                                     ────
扫描局域网广播                            ← 房间码解析出网络名/密钥
    ↓                                        ↓
EasyTier 固定虚拟 IP 10.144.144.1        EasyTier DHCP 拿 IP
    ↓                                        ↓
协调服务 0.0.0.0:25991                   ← 端口映射 127.0.0.1:x → 10.144.144.1:25991
    ↓                                        ↓
提供 /v1/session 返回 MC 端口             HTTP 握手校验 + 取端口
    ↓                                        ↓
Minecraft 0.0.0.0:25565                  ← 端口映射 TCP/UDP → 10.144.144.1:25565
                                             ↓
                                        多播广播「局域网世界」

房间码格式(自研)

16 个字符 × 5 bit = 80 bit:

[4 bit 版本][64 bit 随机种子][12 bit CRC]
  • 字符集:Crockford Base32(0-9A-Z 去掉 I/L/O/U)
  • 展示:XXXX-XXXX-XXXX-XXXX
  • 输入容错:小写、空格、MT- 前缀、I→1 L→1 O→0 U→V 自动纠正
  • 网络名/密钥由种子经 HMAC-SHA256 域分离派生(mc-tunnel/v1/*),房间码本身不含明文凭据

协调协议(自研)

HTTP/1.1 + JSON,跑在隧道内:

| 方法 | 路径 | 鉴权 | 说明 | |---|---|---|---| | GET | /v1/hello | 否 | 返回握手指纹,客人据此确认对端身份 | | GET | /v1/session | 是 | 返回房主 MC 端口与玩家列表 | | POST | /v1/players | 是 | 玩家心跳 / 昵称上报 |

鉴权用房间码派生的令牌(x-mct-token),比较用 timingSafeEqual。


常见问题

为什么不能把 127.0.0.1 写进 peers? EasyTier 连接对端时会绑定本地地址,回环地址会报 10049 AddrNotAvailable。 直连请使用真实网卡 IP(可参考 test/helpers.mjs 的 primaryIpv4())。

客人提前退出了房主仍在? 房主侧玩家列表 12 秒无心跳自动剔除,不阻塞后续加入。

端口冲突怎么办? 协调服务默认 25991,被占用会直接报错(不会静默换端口,否则客人找不到)。 Minecraft 映射端口优先与房主同号,被占用时自动改用随机端口,功能不受影响, 但依赖固定 UDP 端口的 mod(如 SimpleVoiceChat)可能需要手动指定 preferredLocalPort。

对称 NAT 连不上? 默认 p2pOnly: true,不走中继。若需要中继,请自建 EasyTier 公共节点并设置 easyTier: { p2pOnly: false, publicNodes: ['tcp://your-node:11010'] }。

支持哪些平台? Node.js >= 18.17(使用内置 fetch 与 AbortSignal.timeout)。Windows / macOS / Linux 均可用。


开发

npm install          # 国内镜像已写入 .npmrc
npm run build        # 产出 dist/{esm,cjs,types}
npm test             # node:test,无需额外框架

端到端测试需要 EasyTier 二进制,放到 test/fixtures/bin/ 或设置 MC_TUNNEL_EASYTIER,缺失时自动跳过。


合规说明

本包为独立实现:

  • 房间码编码、校验算法、协调协议、状态机均为本项目原创;
  • 不含任何第三方项目的源代码、常量或协议格式;
  • EasyTier 仅在运行时以独立子进程调用(spawn),不做静态/动态链接, 也不修改其可执行文件。

因此:

  • 你可以把本包用于闭源商业软件;
  • 本包自身采用 MIT 许可,你可以自由修改、私有化(也可以把 license 改成 UNLICENSED);
  • 分发时请遵守 EasyTier 自身的许可要求,详见 THIRD_PARTY_NOTICES.md。

许可

MIT