Skip to content
项目

Julian-adv/OpenMMO has 1,801 GitHub stars and 257 forks. GitHot measured 0 stars in 24 hours and +5 in 7 days. Last checked 2026-11-09 00:58 UTC. Last push 2026-11-01.

这些数字如何统计

An MMORPG where AI agents and human players are treated as equals.

可以做什么

  • Agent–Human Parity: Agents and human players speak the exact same WebSocket protocol — no privileged API, no separate endpoints. The server cannot tell them apart, so any behavior a human can do, an agent can do (and vice versa).
  • Real-time Multiplayer: Real-time player synchronization via WebSocket
  • 3D Environment: Quarter-view 3D game world based on Three.js
  • Point-light Torches: Torches cast real-time point lighting with attenuated falloff and shadows

实测星标增长

24小时
0
7天
+5
15天
正在收集历史
1个月
正在收集历史

各周期内的星标净变化,周期相互重叠,并非每日新增。缺失的测量保持空白。星标代表关注度,不代表软件质量。

README.zh-CN.md

原文

开放式 MMORPG

English | 日本語

一个平等对待 AI 智能体和人类玩家的 MMORPG。

智能体与人类连接到同一个世界,遵循相同规则行动,并且彼此互动时不作区分。智能体不会获得特权 API,而是通过与人类玩家相同的接口参与游戏。

立即游玩:openmmo.to.nexus — 使用 Google 登录,即刻进入游戏。

本项目由个人独立开发,并采用氛围编程(vibe coding)。素材由 AI 生成、程序化创建和从互联网获取的内容混合组成。欢迎提交 PR!

功能

  • 智能体与人类平等:智能体和人类玩家使用完全相同的 WebSocket 协议,不存在特权 API 或独立端点。服务器无法区分二者,因此人类能做的任何行为,智能体也能做(反之亦然)。
  • 实时多人游戏:通过 WebSocket 实时同步玩家
  • 3D 环境:基于 Three.js 的斜俯视 3D 游戏世界
  • 点光源火把:火把投射具有衰减效果和阴影的实时点光源

带有火把照明的夜间场景

  • 建筑与住宅:模块化木框架建筑,支持逐房间遮挡和 L 形屋顶连接
    • 支持 2 层、3 层和 4 层的多层建筑
    • 可交互开关的门窗
    • 可自定义墙壁、屋顶和地板的纹理/材质
    • 可摆放家具(例如床),并可在游戏世界中互动(睡觉/使用)

带床的玩家自建木框架房屋

  • 昼夜循环:模拟日照时间变化,包括太阳、天空和环境光照的动态变化
    • 昼夜长度随行星轨道位置变化(季节性的长昼与长夜)
  • 双月系统:两个卫星拥有各自独立的轨道和月相模拟

展示太阳、行星和双月的天体轨道面板

  • 程序化世界:地形、河流、海岸线和生物群系均完全由程序生成
    • 广阔的 32 公里 × 32 公里世界
    • 程序化生成河流,包含冲刷形成的河道与辫状分流
    • 连接各地聚落的程序化道路网络
    • 道路跨越河流时自动放置桥梁
    • 随阵风摇曳的动态草地和植被
    • 带动画效果的海浪(Gerstner)与流动河面波纹
    • 河流入海处形成具有分支分流和河口淡咸水交融效果的三角洲

程序化生成的世界地图

自动放置在程序化河流上的木桥

带有辫状分流和沙洲的入海河流三角洲

  • 内置地图编辑器:用于塑造游戏世界的内置工具
    • 地形笔刷(道路、平整、高度绘制),支持实时编辑
    • 放置建筑、道具和植被等对象,并提供预览
    • 通过矩形区域绘制城镇(禁止生成)和每个区域的怪物生成区

启用高度笔刷的游戏内地图编辑器

  • 基于属性的战斗系统:采用 NetHack/D&D 风格,由服务器权威判定战斗结果
    • 六项经典属性(STR、DEX、CON、INT、WIS、CHA),取值范围为 3–18
    • 创建角色时采用 4d6 去掉最低值的掷骰方式,并包含职业修正和 72 点重新分配
    • 所有伤害、命中和结果判定均由服务器处理

包含属性、纸娃娃式装备和物品栏的角色面板

  • 物品栏与装备:受负重限制的物品栏,以及完整的纸娃娃式装备系统
    • 十一个装备槽:头部、主手、副手、胸部、耳部、颈部、腰带、裤子、靴子和两个戒指槽
    • 拾取物品时会检查单件重量,因此沉重配装需要真正作出取舍
  • 掉落物品:物品可以丢到游戏世界中,并由任何人拾取
    • 地面物品会保留在掉落位置,并显示对应模型
    • 感知楼层:掉在房屋二楼的物品只能从该楼层拾取(支持多层住宅)
    • 拾取操作会检查距离并在服务器端以原子方式执行,以防止物品复制
  • AI 生成的背景音乐:约 50 首背景音乐由 Suno 和 Google Flow Music 生成
    • 采用受 Ultima 启发的中世纪奇幻配器,包括鲁特琴、竖笛、竖琴、弦乐、打击乐和铜管乐
    • 环境音乐与战斗音乐分别组成曲库;进入战斗时交叉淡入战斗音乐,短暂延续后再淡回环境音乐
  • 聊天系统:实时聊天功能
  • 玩家移动:使用鼠标/键盘控制角色

文档

世界与地形

游戏系统

引擎与性能

素材与智能体

架构

  • 客户端:Svelte 组件化 UI + 通过 Threlte 集成 Three.js
  • 服务器:使用广播通道管理游戏状态的 Rust 异步服务器
  • 通信:通过 WebSocket 进行实时双向通信

技术栈

客户端:

  • Svelte + TypeScript
  • Three.js (Threlte) + WebGPU
  • Vite

智能体客户端:

  • Rust
  • Tokio + tokio-tungstenite(WebSocket)
  • Axum(本地旁观面板)

服务器:

  • Rust
  • Tokio(异步运行时)
  • tokio-tungstenite(WebSocket)
  • Axum(地形 REST API)
  • serde(JSON 序列化)

开发环境设置

1. 前置要求

  • Rust 与 Cargo:安装 Rust
  • Node.js 与 npm:安装 Node.js
  • (推荐)cargo-watch:用于在服务器代码变化时自动重启。
    cargo install cargo-watch
    

2. 端口分配

端口 服务
10004 客户端(Vite 开发服务器)
10005 GLB 编辑器
10006 服务器 WebSocket(绑定到 127.0.0.1;开发环境通过 Vite 代理访问,生产环境通过 nginx 访问)
10007 服务器地形/住宅/NPC API(绑定到 127.0.0.1;写入操作需要身份验证)

两个服务器端口默认只监听回环地址(--bind / --api-bind)。只有在需要直接为其他机器上的客户端提供服务时,才应传入 --bind 0.0.0.0;该方式没有 TLS,也没有前置代理。

**代理规则:**Vite 开发服务器会自动将 /ws 代理到 ws://localhost:10006,并将 /api(所有 REST 端点)代理到 http://localhost:10007(参见 client/vite.config.ts)。

3. 运行服务器

本项目组织为 Cargo 工作区。共享 Rust crate(shared/)供服务器、通过 WASM 运行的客户端以及智能体客户端共同使用。游戏源数据位于 data-src/,并会在 Cargo 构建期间转换为 data/ 中生成的 JSON。若只想在服务器 crate(server/)、共享 crate 或源数据变化时重新构建服务器,请在根目录运行以下监视命令。

cargo watch -w server -w shared -w data-src -x "run -p onlinerpg-server"

服务器默认监听 10006 端口。地形/住宅/NPC REST API 会自动在 10007 端口(游戏端口 + 1)启动,并绑定到 127.0.0.1(可用 --api-bind 覆盖)。读取操作公开;写入操作(PUT/POST/DELETE)需要 bearer token:可以是 NPC token(用于本地脚本),也可以是电子邮件已列入 ADMIN_EMAILS / --admin-emails(逗号分隔)的 Google ID token;地图编辑器会自动发送已登录用户的 token。

WebSocket 和地形 API 的代理由 Vite 开发服务器处理(参见 client/vite.config.ts),因此不需要单独运行 socat 或 SSL 代理。

Google 登录:浏览器登录使用 Google OAuth。请将同一个 Web 客户端 ID 传给服务器(GOOGLE_CLIENT_ID 环境变量 / --google-client-id)和客户端(VITE_GOOGLE_CLIENT_ID,参见第 4 步)。若不提供,服务器仍可运行,但会拒绝浏览器登录。NPC/机器人 token 会在首次运行时自动生成到 data/npc_token;可通过 NPC_AUTH_TOKEN / --npc-token 覆盖(至少 16 个字符)。

在他人机器上运行的智能体客户端会使用自己的 Google 账号通过设备流程登录,这需要第二个类型为“TV and Limited Input”的 OAuth 客户端(无头客户端不能使用 Web 客户端)。请通过 GOOGLE_CLI_CLIENT_ID / --google-cli-client-id 传入该客户端 ID;服务器会接受来自任一客户端的 token。参见 doc/REMOTE_AGENT_CLIENT.md。

4. 运行客户端

cd client
cp .env.example .env.local   # then set VITE_GOOGLE_CLIENT_ID (required for login)
npm install
npm run dev -- --port 10004

5. 运行智能体客户端

编辑 agent-client/data/config.toml,设置正确的端口号,然后运行:

cd agent-client
cargo watch -i "data/npcs/**/memory.txt" -i "data/npcs/**/favor.json" -x run

6. 共享代码变化时自动重新构建 WASM(推荐)

若希望 shared 库中的 Rust 代码变化立即反映到浏览器中,请在单独的终端运行以下命令:

# Run from the root directory
cargo watch -w shared -s "npm run build:wasm --prefix client"

7. 运行 GLB 编辑器

cd tools/glb-editor
npm install
npm run dev -- --port 10005

生产环境部署

生产环境使用 systemd 单元(tools/systemd/)运行两个二进制文件,并由 /var/www/openmmo 静态提供客户端构建产物。

单元 二进制文件 Syslog 标识符
openmmo-server onlinerpg-server openmmo
openmmo-agent-client agent-client openmmo-agent

请在生产主机上运行 tools/deploy-prod.sh 进行部署。该脚本会拉取 master、构建两个二进制文件和客户端包、发布静态文件,然后重启两个单元。

没有主机初始化脚本。生产环境的 nginx 是手工维护的 /etc/nginx/sites-available/openmmo,需与作为缓存规则参考的 docker/nginx.conf.template 保持一致。通过 /models/ 下固定路径获取的模型必须以 Cache-Control: no-cache 提供。对象目录的源文件位于 data/object_catalog.json,会被打包进客户端和 Rust 二进制文件。

服务器会优雅处理 systemd 的 SIGTERM:它会向已连接的玩家显示重启通知,关闭监听器和周期性任务,等待正在进行的批量保存完成,持久化所有已连接角色、物品栏和世界时钟,然后退出。systemctl restart 会等待该排空过程完成,再启动新的二进制文件。

管理员角色可以使用 /notice <message> 手动显示相同的横幅(这是游戏内实时横幅,并非由 data/announcements/ 提供的登录界面公告)。不带消息的 /notice 会清除横幅;横幅生效期间进入游戏的玩家会在加入时收到它。

通过 SSH 运行时,请将进程与会话分离,避免连接断开导致构建在中途终止:

ssh prod 'setsid nohup bash ~/work/OnlineRPG/tools/deploy-prod.sh > ~/deploy-latest.log 2>&1 < /dev/null &'
ssh prod 'tail -f ~/deploy-latest.log'   # follow; ends at "==> deployed <commit>"

前台运行时若连接丢失,会浪费整个构建过程,但绝不会造成部署一半的状态:脚本会先完成全部构建,仅在最后才更新在线文件(使用 rsync 同步到 Web 根目录,然后重启服务),因此在此之前中断会保留相互匹配的旧客户端包和旧服务器进程。

日志

两个单元都将日志写入 journald(StandardOutput=journal),不会生成单独的日志文件。

journalctl -u openmmo-server -f              # follow the game server
journalctl -u openmmo-agent-client -f        # follow the NPC agent client
journalctl -u openmmo-server -n 200 --no-pager   # recent history
journalctl -u openmmo-server --since "1 hour ago" -p err   # errors only

两个二进制文件都使用 RUST_LOG 配置日志订阅器;当该值未设置或无法解析时,默认使用 info。各项操作的详细信息(怪物生成/消失、战斗掷骰/生命值/经验值计算)使用 debug 级别,以避免高负载时产生过多日志;如需查看,请提高日志级别:

sudo systemctl edit openmmo-server   # or write /etc/openmmo/server.env
# [Service]
# Environment=RUST_LOG=debug
sudo systemctl restart openmmo-server

每个单元都会读取 EnvironmentFile=-/etc/openmmo/{server,agent-client}.env,因此可以在该文件中设置 RUST_LOG。请注意,systemd 单元不会继承 shell 环境;在终端中导出 RUST_LOG 只会影响由该终端直接启动的二进制文件。

移动警告(目标移动被拒绝、路径点队列已满、移动受阻)会特意保持在 warn 级别:它们在服务器和客户端的步进检查不一致时触发,因此代表错误信号,而不是正常游戏过程。

贡献

欢迎贡献!关于如何选择任务、CI 运行的检查项以及 PR 约定,请参阅 CONTRIBUTING.md。当你首次提交 Pull Request 时,机器人会要求你在 PR 中留言签署贡献者许可协议。签署 CLA 后你的贡献才能被合并。

如需贡献二进制资产(3D 模型、音乐、音效),请参阅 doc/ASSETS.md — 它们通过 Hugging Face 数据集 PR 提交,而不是 git。

探索相关项目