sculk
P2P tunnel core library for Minecraft multiplayer, built on
iroh/QUIC. TunnelService owns the tunnel
lifecycle, state machine, connection snapshots, and event distribution.
Applications only send commands and consume a unified update subscription.
use sculk::tunnel::{
HostOptions, TunnelEvent, TunnelPhase, TunnelService, TunnelUpdate,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let service = TunnelService::new();
let mut updates = service.subscribe();
let mut ticket_printed = false;
service.start_host(HostOptions::new(25565)).await?;
let ctrl_c = tokio::signal::ctrl_c();
tokio::pin!(ctrl_c);
loop {
tokio::select! {
result = &mut ctrl_c => {
result?;
service.shutdown().await?;
break;
}
update = updates.recv() => {
match update {
Some(TunnelUpdate::Status(status)) => {
if status.state.phase == TunnelPhase::Active
&& !ticket_printed
&& let Some(ticket) = status.state.ticket
{
println!("Connection ticket: {ticket}");
ticket_printed = true;
}
if status.state.phase == TunnelPhase::Idle {
break;
}
}
Some(TunnelUpdate::Event(TunnelEvent::Error { message })) => {
eprintln!("Tunnel error: {message}");
}
Some(TunnelUpdate::Event(event)) => {
println!("Tunnel event: {event:?}");
}
Some(_) => {}
None => break,
}
}
}
}
Ok(())
}
To join an existing tunnel, parse the shared Ticket and call
service.start_join(JoinOptions::new(ticket, local_port)). See
sculk for the complete project
and its CLI/TUI integrations.
Features
| Feature |
Enabled by default |
Description |
persist |
No |
Persist keys and user configuration |
clipboard |
No |
Write to the system clipboard |
中文说明
面向 Minecraft 联机的 P2P 隧道核心库,基于
iroh/QUIC。TunnelService 负责隧道的启动、
停止、状态机、连接快照和事件分发;上层只需发送命令并订阅统一更新频道。
use sculk::tunnel::{
HostOptions, TunnelEvent, TunnelPhase, TunnelService, TunnelUpdate,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let service = TunnelService::new();
let mut updates = service.subscribe();
let mut ticket_printed = false;
service.start_host(HostOptions::new(25565)).await?;
let ctrl_c = tokio::signal::ctrl_c();
tokio::pin!(ctrl_c);
loop {
tokio::select! {
result = &mut ctrl_c => {
result?;
service.shutdown().await?;
break;
}
update = updates.recv() => {
match update {
Some(TunnelUpdate::Status(status)) => {
if status.state.phase == TunnelPhase::Active
&& !ticket_printed
&& let Some(ticket) = status.state.ticket
{
println!("连接票据: {ticket}");
ticket_printed = true;
}
if status.state.phase == TunnelPhase::Idle {
break;
}
}
Some(TunnelUpdate::Event(TunnelEvent::Error { message })) => {
eprintln!("隧道错误: {message}");
}
Some(TunnelUpdate::Event(event)) => {
println!("隧道事件: {event:?}");
}
Some(_) => {}
None => break,
}
}
}
}
Ok(())
}
加入已有隧道时,解析对方分享的 Ticket,然后调用
service.start_join(JoinOptions::new(ticket, local_port))。完整项目与 CLI/TUI
示例见 sculk。
Features
| Feature |
默认启用 |
说明 |
persist |
否 |
密钥与用户配置持久化 |
clipboard |
否 |
写入系统剪贴板 |
License / 许可证
Licensed under your choice of MIT or
Apache-2.0.
本核心库采用 MIT 或 Apache-2.0 双重许可,
使用者可任选其一。