一、模组概况
WindowX(mod ID windowx,版本 2.1.10,作者 XuTrain,MIT 协议)是一款运行在 NeoForge (≥21.1.234) + Minecraft 1.21.1 上的客户端控制模组。它包含约 378 个类,核心包在 com.xutrain.windowx 下,并声明对可选模组 mcef(网页内容)和 sable(物理兼容)的支持。
模组的核心定位是:通过游戏内命令远程控制 Minecraft 客户端所在操作系统的窗口,并将桌面画面投影回游戏世界,实现“桌面在 MC 里看,MC 在桌面上玩”的双向镜像。以下是基于 Recaf 解析该模组 JAR 后提取的主要技术细节。
二、整体架构
- client:桌面采集(WGC / PrintWindow / macOS CoreGraphics)、WASAPI 环回音频捕获、全屏透明覆盖窗、多窗口管理器、HUD 镜像叠加(雨雪、火焰、下界传送门等)、30 多个缓动函数。
- desktop:桌面摄像头服务端、会话管理、投影平面几何、分块媒体传输(DesktopMediaTransport/Assembler/Pacer)、音频编码、桌面光标实体与窗口碰撞体。
- camera:相机方块/实体/菜单、相机渲染管线、着色器与 Iris 兼容。
- network:约 40 个自定义 Payload,构成服务端 ↔ 客户端的命令与媒体总线。
- command:
/windowx 与 /windowxm 两套 Brigadier 命令,分别覆盖主窗控制与多窗口/动画/网页子系统。
- api:WindowXApi / 客户端 API / 服务端 API、WindowXExtension(Context 注册制)、窗口创建/移除/变更事件。
- mixin:1 个公共 + 9 个客户端注入,包括
WindowAccessor(直接操作 GLFW 窗口)、MinecraftAccessor、GameRendererAccessor、CameraLevelRendererMixin 等。
三、核心机制一:桌面输入 → 游戏内操作
这是模组最“危险”也最有趣的方向:真实桌面鼠标被采样后,在游戏内表现为虚拟光标,进而触发实体攻击或方块破坏。
1. 桌面鼠标采样与防误触
DesktopCameraCapture 启动一个独立线程(WindowX-DesktopCursor-*),每 4ms 调用 User32.INSTANCE.GetCursorPos,同时读取 VK_LBUTTON、VK_RBUTTON、Tab(旋转修饰键)和滚轮(DesktopScrollCapture),并换算成所选显示器上的归一化坐标。
DesktopCursorInputGate 提供防误触逻辑:当 Minecraft 窗口处于前台(gameFocused == true)时,所有桌面鼠标输入被全部屏蔽;只有 Alt-Tab 离开游戏后,桌面点击才会流入游戏,避免正常游玩时桌鼠误触发挖掘或拖拽。
2. 点击 vs 拖拽区分
DesktopCursorLeftButton 依据按住时长(HOLD_NANOS = 250_000_000,即 250 ms)与移动阈值,将行为分类为:
- 单击:按下后 250 ms 内释放且位移极小,进入
clickCursor();
- 拖拽:超过阈值,进入
grabNearest(),可抓取 Sable 物理子结构或附近生物并随光标移动。
3. 游戏内效果产生
单击时,pickCursorTarget() 从光标锚点向世界发射射线:
- 命中实体 → 源玩家执行
source.attack(target);
- 命中方块且为生存模式 → 进入
beginMiningGesture() → 每游戏刻执行 tickMining():执行 canMineBlock() 权限校验 → 触发 NeoForge CommonHooks.onLeftClickBlock 事件 → miningProgress.advance() 根据 destroyProgress 推进挖掘进度。
进度变更时,服务端广播 CursorMiningFeedback(stage, hitFeedback),源玩家客户端同步播放挖掘裂纹、粒子与音效;挖掘完成则调用 gameMode.destroyBlock() 并发送 CursorBreakFeedback,播放破坏粒子。
整条链条使用的是 源玩家 的身份、手持物品与权限检查(如 mayInteract、方块破坏速度 >= 0、canAttackBlock),桌面鼠标本质上是源玩家的远程输入代理。
四、核心机制二:游戏内画面 → 桌面实时显示
这是本模组最技术性的部分:在游戏内发生的方块破坏、生物移动等变化,会实时出现在你的物理显示器上。实现分为“覆盖窗 + 双渲染 + alpha 擦除”三步。
1. 创建全屏透明覆盖窗
桌面摄像头会话启动时,MultiWindowManager.addWindow 会为每台选中显示器创建一个 fulltransparent 模式的 GLFW 次窗,覆盖整个显示器,设为置顶层(top)、鼠标穿透(passthrough)、不抢焦点(NoFocusOnClick),并以 STRETCH 模式拉伸。次窗与主游戏窗口共享 GL 上下文,因此纹理可零拷贝直接引用。
2. 第二次渲染游戏世界
CameraRenderManager.doRender() 在每帧 RenderLevelStageEvent.AFTER_LEVEL 阶段启动:
- 通过反射临时替换
Minecraft#mainRenderTarget,将渲染目标切换到该虚拟相机的独立 FBO;
- 相机位姿来自
CameraRegistry 中 desktop_camera 方块注册的姿态,使用 正交投影(orthoHeight × 桌面宽高比);
- 临时移除夜视/黑暗效果,禁用雾、天气、云、天空;天空区域通过
CameraSkyMask 把 alpha 清零,变成透明;
- 对整个关卡执行一次完整的
levelRenderer.renderLevel() 第二遍渲染。
3. 用 blendFuncSeparate(0,0,0,0) “擦除”遮罩
渲染完成后,DesktopCameraMaskRenderer 在贴图上使用 ERASE_MASK(blendFuncSeparate(ZERO, ZERO, ZERO, ZERO)),把以下区域的颜色与 alpha 直接置零:
- 每块显示器对应的屏幕矩形;
- 每个真实桌面窗口的 3D 盒状投影(
windowDepth 层级位置 + 厚度);
- 光标柱区域。
这些位置变成全透明,从而在覆盖窗中“透出”底层真正的桌面与桌面窗口,而剩余区域显示的是“桌面墙后方”的 MC 世界。因为覆盖窗每帧都重新渲染整个关卡,游戏内的方块破坏、实体移动、光照变化都会 实时同步到物理显示器上。
4. 防止自递归与资源回收
- 覆盖窗的相机绑定了
hideDesktopProjection = true,主视角的投影几何(桌面墙面板)在该相机中不渲染,避免“镜中镜”无限递归;
setCaptureExcluded(WDA_EXCLUDEFROMCAPTURE) 把 MC 主窗口和覆盖窗口排除出 Windows Graphics Capture 的采集范围;
- 壁纸优先从文件加载(
WindowsWallpaperLoader,支持 Wallpaper Engine 时改用 BitBlt + CAPTUREBLT 抓实时桌面),而非截屏自身。
五、游戏内的“桌面”:桌面画面如何进 MC
方向相反,桌面本身也被采集并投进游戏世界:
- 壁纸底图:从系统壁纸文件加载(支持 Wallpaper Engine 动态壁纸实时抓取),只在版本变更或 15 秒超时时重传;
- 逐窗口采集:最多 16 个可见窗口按 Z 序用 WGC(Win11)/PrintWindow/macOS CoreGraphics 分别抓取,保留 alpha 通道,按层级指数分配帧率预算(越靠前的窗口更新越频繁);
- 世界内表现:壁纸作为墙面平面,每个真实窗口渲染为凸出的 3D 面板(位于
(layer + 1) × windowDepth 处,带 windowThickness 厚度),并生成对应的 DesktopWindowColliderEntity 碰撞网格(不可见、无敌、不可选中,但可碰撞——玩家穿不过);
- 桌面光标:一个名为
DesktopCursorEntity 的实体在世界中漂浮,深度由 DesktopCursorDepth.resolve() 沿光标柱计算,可显示按下/右键/旋转状态;虽然不可被选中挖掘,但可以被攻击,攻击时会产生冲量并对源玩家造成反伤;
- 音频:
WindowsProcessAudioCapture 通过 WASAPI 环回捕获按进程分流的桌面音频,DesktopAudioCodec 编码,带令牌桶限流,按窗口与距离广播,媒体数据分块(DesktopMediaChunkPayload + Ack)传输。
六、API、命令与安全门禁
公开 API
WindowXApi、WindowXClientApi、WindowXServerApi 与 WindowXExtension 提供 Context 注册机制;事件包括窗口创建/移除/变更及命令注册事件,供其他模组集成。
命令系统
/windowx 支持 transmit / move / encircle / physics / size / zoom / shake / stop / minimize / maximize / fullscreen / borderless / hidehud / notice / title / breath / follow / wobble / get / score / test / button 等子命令;/windowxm 则是多窗口子系统(add / remove / modify / gui / follow / anim / physics / zoom / web / camera 绑定),支持每玩家窗口 ID 与图层、网页内容(需 mcef)、分层动画。
安全配置
WindowXConfig 提供约 10 个布尔开关,用于逐项放行 OS 级能力:ALLOW_DESKTOP_CAMERA、ALLOW_SUBWINDOWS、ALLOW_MOUSE_CONTROL、ALLOW_MAIN_WINDOW_CONTROL、INDEPENDENT_WIN32_OVERLAYS、DISABLE_GL_CONTEXT_SHARING、ENABLE_WINDOWS_COLOR_KEY_TRANSPARENCY、ENABLE_WINDOWS_LAYERED_ALPHA、SHARE_DESKTOP_AUDIO、MONITOR_DESKTOP_AUDIO,并通过 shareRadius 限制媒体广播半径。生产环境部署时建议保守开启。
七、值得注意的技巧小结
- 双渲染管线:通过反射交换
Minecraft#mainRenderTarget,对同一个关卡做两遍不同相机的渲染,一遍给主窗,一遍给桌面覆盖窗。
- alpha 擦除遮罩:
blendFuncSeparate(ZERO,ZERO,ZERO,ZERO) 精确切出桌面窗口与光标柱的透明孔,实现“桌面内容穿透覆盖窗”。
- 零拷贝纹理共享:次窗与主窗共享 GL 上下文,相机 FBO 的颜色纹理 id 直接交由子窗显示,无需 GPU 回读。
- 跨平台采集:Windows 走 WGC(需 Win11 22000+)或 PrintWindow,macOS 走 CoreGraphics(10.15–14)或
screencapture 子进程。
- 媒体分块传输:窗口图像与音频均按块分段、带 Ack 确认,单帧上限 8 MiB。
- 防误触门禁:游戏窗口前台时完全屏蔽桌面输入;单击/拖拽按 250 ms 阈值拆分,避免意外抓取。
结语
WindowX 本质上是在 Minecraft 客户端与操作系统桌面之间搭建了一条双向实时通道:桌面鼠标点击被代理为游戏内挖掘与攻击,而游戏内世界的每一帧变化则通过正交双渲染 + 透明覆盖窗实时投射回物理显示器。模组把 Brigadier 命令、NeoForge 事件总线、自定义 Payload 媒体流、原生窗口 API 与 Minecraft 渲染管线深度交织在一起,是一个值得参考的“游戏内外交互”技术实践。
本文基于 Recaf 对 windowx-2.1.10-full-1.21.1-NeoForge.jar(378 个类)的静态解析整理,供技术讨论参考。

Comments NOTHING