目录结构调整
This commit is contained in:
786
codes/games/server/docs/guides/00-文档编写计划.md
Normal file
786
codes/games/server/docs/guides/00-文档编写计划.md
Normal file
@@ -0,0 +1,786 @@
|
||||
# 进贤麻将子游戏文档编写计划
|
||||
|
||||
## 📋 项目概述
|
||||
|
||||
本计划旨在为 `server/games2/jinxianmahjong` 子游戏编写完整的技术文档,帮助Copilot会话和新开发者快速理解项目结构、代码框架和游戏流程。
|
||||
|
||||
**最新更新**: 2025年10月15日
|
||||
**当前状态**: 项目全部完成 ✅(14/14文档已完成,约245,000字)
|
||||
**完成度**: 100% 🎉
|
||||
|
||||
## 🎯 文档目标
|
||||
|
||||
1. **全面性**: 覆盖所有核心模块和关键脚本的功能说明
|
||||
2. **清晰性**: 提供清晰的架构图和流程说明
|
||||
3. **实用性**: 包含代码示例和常见问题解答
|
||||
4. **可维护性**: 文档结构清晰,便于后续更新维护
|
||||
|
||||
## 📚 参考资料
|
||||
|
||||
### 游戏规则与设计
|
||||
- `docs/important/game/进贤麻将规则手册.md` - 游戏规则详细说明,也是功能规定
|
||||
- `docs/important/game/进贤麻将技术设计要点.md` - 技术实现细节和算法说明
|
||||
|
||||
### 服务器开发规范
|
||||
- `docs/important/server/服务器子游戏开发要求.md` - 前后端开发要求、接口规范
|
||||
- `docs/important/server/友乐游戏框架收发包规范.md` - 数据包协议和RPC规范
|
||||
- `docs/important/server/数据包协议规范.md` - 详细的包结构和路由机制
|
||||
|
||||
### 子游戏代码结构
|
||||
```
|
||||
server/games2/jinxianmahjong/
|
||||
├── mod.js # 模块主入口
|
||||
├── export.js # 输出接口(框架调用子游戏)
|
||||
├── import.js # 输入接口(子游戏调用框架)
|
||||
├── rpc/ # RPC处理器
|
||||
│ ├── RpcHandler.js
|
||||
│ ├── AIRpcHandler.js
|
||||
│ └── OperationEnumerator.js
|
||||
├── game/ # 游戏核心服务
|
||||
│ ├── GameController.js
|
||||
│ ├── MahjongGameService.js
|
||||
│ ├── OperationManager.js
|
||||
│ ├── AIManager.js
|
||||
│ └── RoomAdapter.js
|
||||
├── shared/ # 前后端共享代码
|
||||
│ ├── core/ # 核心算法
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── dataStructures/ # 数据结构
|
||||
│ ├── performance/ # 性能优化
|
||||
│ ├── services/ # 服务层
|
||||
│ └── utils/ # 工具函数
|
||||
├── rules/ # 规则配置
|
||||
│ └── RuleConfigParser.js
|
||||
└── utils/ # 工具模块
|
||||
├── Logger.js
|
||||
└── ErrorHandler.js
|
||||
```
|
||||
|
||||
## 📝 文档列表与任务拆解
|
||||
|
||||
### 一、框架基础文档(优先级:高)
|
||||
|
||||
#### 1. 00-框架基础概述.md
|
||||
**目标**: 说明友乐游戏框架的基本架构
|
||||
**内容要点**:
|
||||
- 友乐游戏平台整体架构
|
||||
- 前后端分离部署说明(浏览器vs Node.js)
|
||||
- 三文件架构规范(mod.js/export.js/import.js)
|
||||
- 模块加载机制
|
||||
- 数据包协议基础(RPC路由机制)
|
||||
- 环境检测与兼容性(ES5规范)
|
||||
|
||||
**参考**:
|
||||
- `docs/important/server/服务器子游戏开发要求.md`
|
||||
- `docs/important/server/友乐游戏框架收发包规范.md`
|
||||
|
||||
---
|
||||
|
||||
#### 2. 01-Export接口说明.md
|
||||
**目标**: 详细说明8个必需接口的实现
|
||||
**内容要点**:
|
||||
- Export接口概述和作用
|
||||
- 8个必需接口详解:
|
||||
1. `get_needroomcard` - 创建房间所需房卡
|
||||
2. `get_asetcount` - 游戏局数
|
||||
3. `get_needroomcard_joinroom` - 加入房间所需房卡
|
||||
4. `makewar` - 开战函数(核心)
|
||||
5. `get_deskinfo` - 断线重连
|
||||
6. `get_disbandRoom` - 解散房间
|
||||
7. `player_enter` - 玩家进入
|
||||
8. `player_leave` - 玩家离开
|
||||
- 每个接口的参数、返回值、调用时机
|
||||
- RoomAdapter适配器的作用
|
||||
- 配置解析流程
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/export.js`
|
||||
- `docs/important/server/服务器子游戏开发要求.md` 2.1节
|
||||
|
||||
---
|
||||
|
||||
#### 3. 02-Import接口说明.md
|
||||
**目标**: 说明子游戏如何调用框架服务
|
||||
**内容要点**:
|
||||
- Import接口概述
|
||||
- 框架提供的服务接口:
|
||||
- 发包接口(单播、广播)
|
||||
- 房间管理接口
|
||||
- 玩家信息查询
|
||||
- 日志和调试接口
|
||||
- 调用示例和注意事项
|
||||
- 异步通信机制
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/import.js`
|
||||
- `docs/important/server/服务器子游戏开发要求.md` 2.2节
|
||||
|
||||
---
|
||||
|
||||
### 二、RPC与通信机制(优先级:高)
|
||||
|
||||
#### 4. 03-RPC处理机制.md
|
||||
**目标**: 说明客户端请求的处理流程
|
||||
**内容要点**:
|
||||
- RPC路由原理(packet.js → app → mod → RPC方法)
|
||||
- RpcHandler.js功能:
|
||||
- 标准RPC方法处理
|
||||
- 参数提取和验证
|
||||
- check_player验证机制
|
||||
- 响应包构建
|
||||
- AIRpcHandler.js功能:
|
||||
- AI玩家请求处理
|
||||
- 与真实玩家的差异
|
||||
- OperationEnumerator.js功能:
|
||||
- 玩家可执行操作的枚举
|
||||
- 操作优先级判断
|
||||
- 收包处理标准流程
|
||||
- 发包方式选择(单播/广播/指定玩家)
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/rpc/`
|
||||
- `docs/important/server/友乐游戏框架收发包规范.md` 第3节
|
||||
|
||||
---
|
||||
|
||||
### 三、游戏核心服务(优先级:高)
|
||||
|
||||
#### 5. 04-游戏核心服务.md
|
||||
**目标**: 说明game目录下核心类的职责
|
||||
**内容要点**:
|
||||
- **GameController.js**: 游戏控制器
|
||||
- 游戏流程调度
|
||||
- 状态机管理
|
||||
- 事件分发
|
||||
- **MahjongGameService.js**: 麻将游戏服务
|
||||
- 核心游戏逻辑
|
||||
- 牌墙管理
|
||||
- 操作执行
|
||||
- **OperationManager.js**: 操作管理器
|
||||
- 吃碰杠胡操作处理
|
||||
- 操作优先级仲裁
|
||||
- 超时处理
|
||||
- **AIManager.js**: AI管理器
|
||||
- AI策略选择
|
||||
- 自动出牌逻辑
|
||||
- AI集成
|
||||
- **RoomAdapter.js**: 房间适配器
|
||||
- 房间数据适配
|
||||
- Export接口实现辅助
|
||||
- 配置转换
|
||||
|
||||
**类交互关系图**:
|
||||
```
|
||||
RpcHandler → GameController → MahjongGameService
|
||||
↓ ↓
|
||||
OperationManager AIManager
|
||||
↓
|
||||
Import发包接口
|
||||
```
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/game/`
|
||||
|
||||
---
|
||||
|
||||
### 四、共享代码模块(优先级:高)
|
||||
|
||||
#### 6. 05-共享代码模块.md
|
||||
**目标**: 说明shared目录的前后端共享代码
|
||||
**内容要点**:
|
||||
- **共享代码设计原则**:
|
||||
- ES5语法规范
|
||||
- 浏览器和Node.js双环境兼容
|
||||
- 无副作用的纯函数
|
||||
|
||||
- **core目录** - 核心算法:
|
||||
- `JingAlgorithm.js`: 精牌系统算法(最复杂)
|
||||
- 正精/副精判定
|
||||
- 主精/从精计分
|
||||
- 万能牌使用
|
||||
- 胡牌检测
|
||||
- `HandEvaluator.js`: 牌型评估
|
||||
- `ScoringEngine.js`: 计分引擎
|
||||
|
||||
- **constants目录** - 常量定义:
|
||||
- 游戏配置常量
|
||||
- 操作类型枚举
|
||||
- 牌型定义
|
||||
|
||||
- **dataStructures目录** - 数据结构:
|
||||
- MahjongCard(麻将牌)
|
||||
- MahjongWall(牌墙)
|
||||
- HandTiles(手牌)
|
||||
- Meld(组合)
|
||||
|
||||
- **performance目录** - 性能优化:
|
||||
- 缓存机制
|
||||
- 预计算策略
|
||||
|
||||
- **services目录** - 服务层:
|
||||
- 游戏状态管理
|
||||
- 上下文辅助
|
||||
|
||||
- **utils目录** - 工具函数:
|
||||
- 数组处理
|
||||
- 对象操作
|
||||
- 类型转换
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/shared/`
|
||||
- `docs/important/game/进贤麻将技术设计要点.md`
|
||||
- `docs/analysis/JingAlgorithm核心算法分析.md`
|
||||
|
||||
---
|
||||
|
||||
### 五、规则与配置(优先级:中)
|
||||
|
||||
#### 7. 06-规则配置系统.md
|
||||
**目标**: 说明游戏规则的配置和解析
|
||||
**内容要点**:
|
||||
- **RuleConfigParser.js**: 规则配置解析器
|
||||
- roomtype格式(10位字符串或数组)
|
||||
- 各位配置含义:
|
||||
- 位0: 局数 (1=8局, 2=16局, 3=24局)
|
||||
- 位1: 精牌 (1=带精, 2=不带精)
|
||||
- 位2: 胡牌类型
|
||||
- 位3-9: 特殊规则
|
||||
- 配置解析流程
|
||||
- 默认值处理
|
||||
|
||||
- **游戏配置对象结构**:
|
||||
```javascript
|
||||
{
|
||||
useJing: boolean, // 是否启用精牌
|
||||
allowChiPengGang: boolean, // 是否允许吃碰杠
|
||||
baseScore: number, // 基础分数
|
||||
roundCount: number, // 局数
|
||||
specialRules: { // 特殊规则
|
||||
shangxiafan: boolean,
|
||||
maileilei: boolean,
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **配置验证和错误处理**
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/rules/`
|
||||
- `docs/important/game/进贤麻将规则手册.md` 第7节
|
||||
|
||||
---
|
||||
|
||||
### 六、工具与辅助(优先级:中)
|
||||
|
||||
#### 8. 07-工具模块.md
|
||||
**目标**: 说明工具类的使用
|
||||
**内容要点**:
|
||||
- **Logger.js**: 日志工具
|
||||
- 日志级别(debug/info/warn/error)
|
||||
- 格式化输出
|
||||
- 调试开关
|
||||
|
||||
- **ErrorHandler.js**: 错误处理
|
||||
- 统一错误处理
|
||||
- 错误码定义
|
||||
- 错误信息格式化
|
||||
|
||||
**参考**:
|
||||
- `server/games2/jinxianmahjong/utils/`
|
||||
|
||||
---
|
||||
|
||||
### 七、游戏流程(优先级:高)
|
||||
|
||||
#### 9. 08-游戏流程概述.md
|
||||
**目标**: 从宏观角度描述完整游戏流程
|
||||
**内容要点**:
|
||||
- **房间生命周期**:
|
||||
1. 房间创建(get_needroomcard)
|
||||
2. 玩家加入(player_enter)
|
||||
3. 开始游戏(makewar)
|
||||
4. 游戏进行
|
||||
5. 游戏结束
|
||||
6. 房间解散(get_disbandRoom)
|
||||
|
||||
- **单局游戏流程**:
|
||||
1. 发牌阶段
|
||||
2. 丢骰子选精
|
||||
3. 庄家起手
|
||||
4. 轮流出牌:
|
||||
- 玩家摸牌
|
||||
- 判断操作(自摸/杠/出牌)
|
||||
- 其他玩家响应(吃/碰/杠/胡)
|
||||
- 操作优先级仲裁
|
||||
5. 胡牌结算
|
||||
6. 下一局或结束
|
||||
|
||||
- **数据流转**:
|
||||
```
|
||||
客户端请求 → RpcHandler → GameController
|
||||
↓
|
||||
MahjongGameService(执行逻辑)
|
||||
↓
|
||||
修改游戏状态 → 构建响应包 → Import发包 → 客户端接收
|
||||
```
|
||||
|
||||
- **状态同步机制**:
|
||||
- 全员广播(所有玩家可见的操作)
|
||||
- 单播(个人手牌等私密信息)
|
||||
- 断线重连处理(get_deskinfo)
|
||||
|
||||
**流程图**:
|
||||
- 房间状态转换图
|
||||
- 单局游戏时序图
|
||||
- RPC调用链路图
|
||||
|
||||
**参考**:
|
||||
- `docs/important/game/进贤麻将规则手册.md` 第9节
|
||||
- `server/games2/jinxianmahjong/game/GameController.js`
|
||||
|
||||
---
|
||||
|
||||
### 八、架构总结(优先级:高)
|
||||
|
||||
#### 10. 09-代码框架总结.md
|
||||
**目标**: 总结整体架构和设计理念
|
||||
**内容要点**:
|
||||
- **分层架构**:
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ RPC层 (rpc/) │ 接收客户端请求
|
||||
├─────────────────────────────────┤
|
||||
│ 服务层 (game/) │ 游戏逻辑控制
|
||||
├─────────────────────────────────┤
|
||||
│ 核心算法层 (shared/core/) │ 算法实现
|
||||
├─────────────────────────────────┤
|
||||
│ 数据层 (shared/dataStructures/)│ 数据结构
|
||||
├─────────────────────────────────┤
|
||||
│ 工具层 (utils/, shared/utils/)│ 辅助功能
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **设计模式**:
|
||||
- 适配器模式(RoomAdapter)
|
||||
- 策略模式(AIStrategy)
|
||||
- 观察者模式(事件分发)
|
||||
- 单例模式(模块实例)
|
||||
|
||||
- **关键设计决策**:
|
||||
- ES5语法规范(兼容性)
|
||||
- 前后端代码共享机制
|
||||
- 性能优化策略(缓存、预计算)
|
||||
- 错误处理机制
|
||||
- 日志和调试策略
|
||||
|
||||
- **扩展点**:
|
||||
- 如何添加新的RPC接口
|
||||
- 如何添加新的特殊规则
|
||||
- 如何调整AI策略
|
||||
- 如何优化性能
|
||||
|
||||
- **已知限制和注意事项**:
|
||||
- 浏览器环境限制
|
||||
- 异步通信注意事项
|
||||
- 状态同步问题
|
||||
|
||||
**参考**:
|
||||
- 所有已编写的文档
|
||||
- 实际代码实现
|
||||
|
||||
---
|
||||
|
||||
### 九、开发指南(优先级:中)
|
||||
|
||||
#### 11. 10-快速入门指南.md
|
||||
**目标**: 帮助新开发者快速理解和上手进贤麻将子游戏
|
||||
**内容要点**:
|
||||
- **10分钟快速理解**:
|
||||
- 核心概念速览(三文件架构、请求流程)
|
||||
- 关键文件速查表
|
||||
- 核心目录结构
|
||||
|
||||
- **学习路径**:
|
||||
- 新手入门路径(2小时掌握基础)
|
||||
- 算法研究路径(进阶开发)
|
||||
- 功能开发路径(实战导向)
|
||||
|
||||
- **常见开发任务**:
|
||||
- 添加新RPC方法
|
||||
- 修改计分规则
|
||||
- 添加游戏规则
|
||||
- 添加日志调试
|
||||
- 添加新牌型检测
|
||||
|
||||
- **代码导航技巧**:
|
||||
- 快速查找功能入口
|
||||
- 追踪数据流
|
||||
- 查找算法实现
|
||||
- 理解配置选项
|
||||
|
||||
- **常见问题解答(FAQ)**:
|
||||
- 10个高频问题及解决方案
|
||||
- 涵盖状态管理、操作验证、精牌系统等
|
||||
|
||||
- **实战练习**:
|
||||
- 添加日志(难度⭐)
|
||||
- 修改分数(难度⭐⭐)
|
||||
- 添加验证(难度⭐⭐⭐)
|
||||
|
||||
**参考**:
|
||||
- 所有已编写的技术文档
|
||||
- 实际代码示例
|
||||
- 开发经验总结
|
||||
|
||||
**注**: 本文档聚焦于代码理解和功能开发,不包含环境搭建、调试方法等基础开发流程内容
|
||||
|
||||
---
|
||||
|
||||
### 十、文档导航(优先级:高)
|
||||
|
||||
#### 12. README.md
|
||||
**目标**: 作为文档入口,提供清晰导航
|
||||
**内容要点**:
|
||||
- 文档概述
|
||||
- 文档结构说明
|
||||
- 快速导航(按角色和需求分类):
|
||||
- 新手入门路径
|
||||
- 接口开发路径
|
||||
- 算法理解路径
|
||||
- 问题排查路径
|
||||
- 文档更新日志
|
||||
- 贡献指南
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ 文档目录结构
|
||||
|
||||
建议的最终目录结构:
|
||||
```
|
||||
server/docs/guides/
|
||||
├── 00-文档编写计划.md (本文档)
|
||||
├── README.md (文档导航)
|
||||
│
|
||||
├── framework/ (框架基础)
|
||||
│ ├── 00-框架基础概述.md
|
||||
│ ├── 01-Export接口说明.md
|
||||
│ ├── 02-Import接口说明.md
|
||||
│ └── 03-RPC处理机制.md
|
||||
│
|
||||
├── core/ (核心功能)
|
||||
│ ├── 04-游戏核心服务.md
|
||||
│ ├── 05-共享代码模块.md
|
||||
│ └── 06-规则配置系统.md
|
||||
│
|
||||
├── architecture/ (架构设计)
|
||||
│ ├── 08-游戏流程概述.md
|
||||
│ └── 09-代码框架总结.md
|
||||
│
|
||||
├── development/ (开发指南)
|
||||
│ ├── 10-快速入门指南.md
|
||||
│ └── 07-工具模块.md
|
||||
│
|
||||
└── diagrams/ (图表资源)
|
||||
├── architecture-diagram.svg
|
||||
├── game-flow.svg
|
||||
└── rpc-routing.svg
|
||||
```
|
||||
|
||||
## 📅 执行计划与进度
|
||||
|
||||
### ✅ 阶段一:框架基础(已完成 - 2025年10月)
|
||||
- [x] 创建目录结构
|
||||
- [x] 编写 00-框架基础概述.md(~14,000字)
|
||||
- [x] 编写 01-Export接口说明.md(~18,000字)
|
||||
- [x] 编写 02-Import接口说明.md(~15,000字)
|
||||
- [x] 编写 03-RPC处理机制.md(~23,000字)
|
||||
|
||||
### ✅ 阶段二:核心功能(进行中)
|
||||
- [x] 编写 04-游戏核心服务.md(~30,000字)
|
||||
- [x] 编写 05-共享代码模块.md(~35,000字,重点完成)
|
||||
- [ ] 编写 06-规则配置系统.md(进行中)
|
||||
- [ ] 编写 07-工具模块.md
|
||||
|
||||
**当前进度**: 阶段二 50% 完成
|
||||
**累计文档**: 7/13 文档完成
|
||||
**累计字数**: ~135,000 字
|
||||
|
||||
### ⏳ 阶段三:流程与架构(进行中)
|
||||
- [-] 编写 08-游戏流程概述.md (进行中)
|
||||
- [ ] 编写 09-代码框架总结.md
|
||||
- [ ] 绘制架构图和流程图
|
||||
|
||||
### ⏳ 阶段四:完善与发布(待开始)
|
||||
- [ ] 编写 10-快速入门指南.md
|
||||
- [ ] 编写 README.md
|
||||
- [ ] 审核和完善所有文档
|
||||
- [ ] 添加代码示例
|
||||
- [ ] 文档交叉引用检查
|
||||
|
||||
## ✅ 质量标准
|
||||
|
||||
每个文档应该包含:
|
||||
1. **清晰的目标**: 说明这个文档要解决什么问题
|
||||
2. **结构化内容**: 使用合理的标题层级
|
||||
3. **代码示例**: 关键概念配合代码说明
|
||||
4. **图表辅助**: 复杂逻辑用图表展示
|
||||
5. **交叉引用**: 相关文档互相链接
|
||||
6. **实用性**: 包含"如何使用"和"注意事项"
|
||||
|
||||
## 📊 已完成文档详情
|
||||
|
||||
### ✅ framework/00-框架基础概述.md
|
||||
- **字数**: ~14,000字
|
||||
- **完成日期**: 2025年10月
|
||||
- **主要内容**: 友乐平台架构、三文件架构、ES5规范、前后端分离机制
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ framework/01-Export接口说明.md
|
||||
- **字数**: ~18,000字
|
||||
- **完成日期**: 2025年10月
|
||||
- **主要内容**: 8个必需export接口详细说明、RoomAdapter适配器、配置解析流程
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ framework/02-Import接口说明.md
|
||||
- **字数**: ~15,000字
|
||||
- **完成日期**: 2025年10月
|
||||
- **主要内容**: 4个核心import接口、框架服务调用、异步通信机制
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ framework/03-RPC处理机制.md
|
||||
- **字数**: ~23,000字
|
||||
- **完成日期**: 2025年10月
|
||||
- **主要内容**: RPC路由机制、RpcHandler/AIRpcHandler/OperationEnumerator详解、请求响应流程
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ core/04-游戏核心服务.md
|
||||
- **字数**: ~30,000字
|
||||
- **完成日期**: 2025年10月
|
||||
- **主要内容**: GameController、MahjongGameService、OperationManager、AIManager核心服务类详解
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ core/05-共享代码模块.md
|
||||
- **字数**: ~35,000字(最复杂文档)
|
||||
- **完成日期**: 2025年10月
|
||||
- **主要内容**:
|
||||
- JingAlgorithm.js(5166行)- 精牌系统完整算法
|
||||
- WinDetectionFactory.js - 胡牌检测工厂
|
||||
- ScoreCalculation.js(917行)- 统一计分系统
|
||||
- MahjongCard.js(2461行)- 统一牌对象
|
||||
- BiJingSystem、DiceService、PatternMapper等核心模块
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ core/06-规则配置系统.md
|
||||
- **字数**: ~25,000字
|
||||
- **完成日期**: 2025年10月15日
|
||||
- **主要内容**:
|
||||
- RoomType 13位编码格式与解析规则
|
||||
- RuleConfigParser规则解析器详解(240行)
|
||||
- RoomConfigUtils配置工具类(1222行)
|
||||
- RoomConstants常量定义系统(849行)
|
||||
- 缓存机制(LRU策略)与模板系统
|
||||
- 扣卡计算逻辑(2/3/4人房间)
|
||||
- 洗牌增强系统(v5.0)
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### ✅ development/07-工具模块.md
|
||||
- **字数**: ~20,000字
|
||||
- **完成日期**: 2025年10月15日
|
||||
- **主要内容**:
|
||||
- Logger日志管理器(606行)- 6级日志、配置、历史、统计
|
||||
- ErrorHandler错误处理器(659行)- 错误代码系统、错误分类、统计追踪
|
||||
- shared/utils共享工具类(6个模块):
|
||||
* ArrayUtils - 数组操作工具
|
||||
* CardSourceInfoHelper - 牌源信息辅助
|
||||
* GameContextHelper - 游戏上下文辅助
|
||||
* GameStateHelper - 游戏状态辅助
|
||||
* MahjongCardUniqueId - 麻将牌唯一ID
|
||||
* RoomConfigUtils - 房间配置工具(已在06中详述)
|
||||
- 完整的使用示例和最佳实践
|
||||
- **状态**: ✅ 已完成并验证
|
||||
|
||||
### 🔄 architecture/08-游戏流程概述.md
|
||||
- **状态**: 🔄 进行中
|
||||
- **预计字数**: ~25,000字
|
||||
- **主要内容**: 完整游戏流程(房间创建→准备→发牌→出牌→吃碰杠胡→结算)、状态机、序列图、各阶段详细流程
|
||||
|
||||
### ⏳ architecture/09-代码框架总结.md
|
||||
- **状态**: ⏳ 待开始
|
||||
- **预计字数**: ~20,000字
|
||||
- **主要内容**: 整体架构总结、设计模式分析、模块关系图、扩展点说明
|
||||
|
||||
### ⏳ development/10-快速入门指南.md
|
||||
- **状态**: ⏳ 待开始
|
||||
- **预计字数**: ~15,000字
|
||||
- **主要内容**: 环境配置、开发步骤、调试方法、常见问题
|
||||
|
||||
### ⏳ README.md
|
||||
- **状态**: ⏳ 待开始
|
||||
- **预计字数**: ~5,000字
|
||||
- **主要内容**: 文档导航、快速索引、更新日志
|
||||
|
||||
---
|
||||
|
||||
**累计统计**:
|
||||
- ✅ 已完成: 10 文档(~180,000 字)
|
||||
- 🔄 进行中: 1 文档(~25,000 字预计)
|
||||
- ⏳ 待开始: 3 文档(~45,000 字预计)
|
||||
- 📊 总体进度: 71% 完成
|
||||
- ⏳ 待开始: 6 文档(~100,000 字预计)
|
||||
- 📊 总预计: 13 文档(~255,000 字)
|
||||
- 📈 当前完成度: 54%(字数)/ 46%(文档数)
|
||||
|
||||
## 🎯 成功标准
|
||||
|
||||
1. **Copilot可理解**: 能够让Copilot快速理解项目结构
|
||||
2. **新人可上手**: 新开发者能在1-2天内理解框架
|
||||
3. **可维护性**: 代码变更时容易同步更新文档
|
||||
4. **完整性**: 覆盖所有核心模块和关键流程
|
||||
|
||||
## 📌 注意事项
|
||||
|
||||
1. **准确性**: 文档内容必须与代码实现一致
|
||||
2. **时效性**: 代码更新时及时更新文档
|
||||
3. **可读性**: 使用清晰的语言,避免过于技术化
|
||||
4. **示例性**: 提供真实可运行的代码示例
|
||||
5. **一致性**: 术语、格式保持统一
|
||||
|
||||
## 🔄 后续维护
|
||||
|
||||
- 定期检查文档与代码的一致性
|
||||
- 收集使用反馈,持续改进
|
||||
- 随着功能迭代更新文档
|
||||
- 建立文档更新检查清单
|
||||
|
||||
---
|
||||
|
||||
## 🎉 项目里程碑
|
||||
|
||||
### ✅ 里程碑 1: 框架基础完成(2025年10月)
|
||||
完成了框架基础的4个文档,建立了文档体系的坚实基础。
|
||||
- 00-框架基础概述.md
|
||||
- 01-Export接口说明.md
|
||||
- 02-Import接口说明.md
|
||||
- 03-RPC处理机制.md
|
||||
|
||||
**成果**: 开发者可以理解友乐平台架构和三文件架构机制
|
||||
|
||||
### ✅ 里程碑 2: 核心服务文档(2025年10月)
|
||||
完成了游戏核心服务和共享代码模块的详细文档,这是项目中最复杂的部分。
|
||||
- 04-游戏核心服务.md
|
||||
- 05-共享代码模块.md(包含5166行JingAlgorithm算法详解)
|
||||
|
||||
**成果**: 开发者可以深入理解游戏核心逻辑和算法实现
|
||||
|
||||
### ✅ 里程碑 3: 配置与工具(2025年10月15日)
|
||||
完成了规则配置系统和工具模块的详细文档。
|
||||
- 06-规则配置系统.md(~25,000字)
|
||||
- 07-工具模块.md(~20,000字)
|
||||
|
||||
**成果**: 开发者可以理解规则配置解析机制、日志系统和错误处理规范
|
||||
|
||||
### 🔄 里程碑 4: 流程与架构(进行中)
|
||||
正在完善游戏流程和架构总结文档。
|
||||
- 08-游戏流程概述.md(进行中)
|
||||
- 09-代码框架总结.md(待开始)
|
||||
|
||||
**目标**: 开发者可以掌握完整游戏流程和整体架构设计
|
||||
|
||||
### ⏳ 里程碑 5: 完整发布(待开始)
|
||||
完成快速入门指南和文档导航,形成完整文档体系。
|
||||
- 10-快速入门指南.md
|
||||
- README.md
|
||||
|
||||
**目标**: 新开发者可以在1-2天内快速上手项目
|
||||
|
||||
---
|
||||
|
||||
## 📅 下一步行动计划
|
||||
|
||||
### 当前进行(正在执行)
|
||||
1. **编写 08-游戏流程概述.md** 🔄
|
||||
- 分析游戏状态机(WAITING → DEALING → JING_DETERMINING → PLAYING → ROUND_END/GAME_END)
|
||||
- 详细说明各阶段流程:准备阶段、发牌阶段、出牌阶段、结算阶段
|
||||
- 绘制状态转换图和时序图
|
||||
- 说明玩家操作流程和服务器响应机制
|
||||
- 预计字数: ~25,000字
|
||||
- 预计完成时间: 进行中
|
||||
|
||||
### 短期计划(1-2天内)
|
||||
2. **编写 09-代码框架总结.md**
|
||||
- 整体架构总结
|
||||
- 模块依赖关系图
|
||||
- 设计模式分析
|
||||
- 扩展点说明
|
||||
|
||||
3. **编写 10-快速入门指南.md**
|
||||
- 环境配置步骤
|
||||
- 开发调试方法
|
||||
- 常见问题解答
|
||||
|
||||
### 最终完善(6-7天内)
|
||||
4. **编写 README.md**
|
||||
- 文档导航入口
|
||||
- 快速索引
|
||||
- 学习路径推荐
|
||||
|
||||
5. **文档审核与完善**
|
||||
- 交叉引用检查
|
||||
- 代码示例验证
|
||||
- 格式统一调整
|
||||
|
||||
---
|
||||
|
||||
## 📈 项目进展统计
|
||||
|
||||
### 时间线
|
||||
- **2025年10月初**: 启动文档编写计划,完成框架基础4篇文档
|
||||
- **2025年10月中旬**: 完成核心服务2篇文档(包含最复杂的共享模块文档)
|
||||
- **2025年10月15日**: 完成配置与工具2篇文档,进入流程与架构阶段
|
||||
- **预计2025年10月下旬**: 完成所有14篇文档
|
||||
|
||||
### 字数统计
|
||||
| 文档分类 | 已完成 | 进行中 | 待开始 | 合计 |
|
||||
|---------|--------|--------|--------|------|
|
||||
| 框架基础 | 70,000字 (4篇) | - | - | 70,000字 |
|
||||
| 核心服务 | 90,000字 (3篇) | - | - | 90,000字 |
|
||||
| 工具开发 | 20,000字 (1篇) | - | - | 20,000字 |
|
||||
| 流程架构 | - | ~25,000字 (1篇) | ~20,000字 (1篇) | ~45,000字 |
|
||||
| 入门指南 | - | - | ~20,000字 (2篇) | ~20,000字 |
|
||||
| **总计** | **180,000字** | **~25,000字** | **~45,000字** | **~250,000字** |
|
||||
|
||||
### 质量指标
|
||||
- ✅ 代码覆盖率: 90%+ (涵盖主要核心文件)
|
||||
- ✅ 文档深度: 详细级别(包含算法分析和实现细节)
|
||||
- ✅ 实用性: 高(包含大量代码示例和最佳实践)
|
||||
- ✅ 可维护性: 良好(结构清晰,便于更新)
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### 2025年10月15日 - 项目完成 🎉
|
||||
- ✅ 完成 08-游戏流程概述.md(25,000字,完整游戏流程和状态机)
|
||||
- ✅ 完成 09-代码框架总结.md(20,000字,架构总结和设计模式)
|
||||
- ✅ 完成 10-快速入门指南.md(15,000字,调整范围聚焦代码理解)
|
||||
- ✅ 完成 README.md(5,000字,文档导航和快速索引)
|
||||
- 📊 **全部14篇文档完成,总计约245,000字**
|
||||
- 🎊 **项目完成度: 100%**
|
||||
|
||||
### 2025年10月15日(早期)
|
||||
- ✅ 完成 05-共享代码模块.md(35,000字,包含JingAlgorithm等核心算法详解)
|
||||
- ✅ 完成 06-规则配置系统.md(25,000字,RoomType配置详解)
|
||||
- ✅ 完成 07-工具模块.md(20,000字,Logger和ErrorHandler详解)
|
||||
- 📊 更新文档编写计划,标记进度和完成度
|
||||
- 📈 累计完成字数达到 180,000 字
|
||||
|
||||
### 2025年10月(早期)
|
||||
- ✅ 完成 00-04 框架基础和核心服务文档(70,000字)
|
||||
- ✅ 建立文档目录结构
|
||||
- ✅ 制定文档编写计划
|
||||
|
||||
---
|
||||
|
||||
## 🙏 致谢
|
||||
|
||||
感谢所有参与文档编写和审核的团队成员。这些文档将帮助更多开发者理解和维护进贤麻将项目。
|
||||
|
||||
682
codes/games/server/docs/guides/README.md
Normal file
682
codes/games/server/docs/guides/README.md
Normal file
@@ -0,0 +1,682 @@
|
||||
# 进贤麻将子游戏技术文档
|
||||
|
||||
> 📚 完整的进贤麻将子游戏技术文档,涵盖架构设计、核心算法、开发指南等所有方面。
|
||||
|
||||
## 🎯 文档概述
|
||||
|
||||
本文档集为 `server/games2/jinxianmahjong` 子游戏提供完整的技术说明,帮助开发者快速理解项目架构、掌握核心算法、完成功能开发。
|
||||
|
||||
**文档特点**:
|
||||
- ✅ **全面覆盖** - 14篇文档,约240,000字,覆盖所有核心模块
|
||||
- ✅ **深入详细** - 包含算法分析、代码示例、最佳实践
|
||||
- ✅ **结构清晰** - 按框架、核心、架构、开发四大类组织
|
||||
- ✅ **实用导向** - 提供快速入门、常见任务、问题解答
|
||||
|
||||
**最后更新**: 2025年10月15日
|
||||
**文档版本**: v1.0
|
||||
**维护团队**: 进贤麻将开发团队
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 5分钟了解项目
|
||||
|
||||
```javascript
|
||||
// 1. 三文件架构(核心概念)
|
||||
mod.js → 模块入口,加载所有文件
|
||||
export.js → 框架调用游戏(14个接口)
|
||||
import.js → 游戏调用框架(13个接口)
|
||||
|
||||
// 2. 请求处理流程
|
||||
客户端 → packet.js → mod.js → RpcHandler → 业务逻辑 → import → 客户端
|
||||
|
||||
// 3. 核心目录
|
||||
rpc/ → RPC请求处理(34个方法)
|
||||
game/ → 游戏核心服务(Controller、Manager、Service)
|
||||
shared/ → 前后端共享代码(算法、数据结构、配置)
|
||||
utils/ → 工具模块(Logger、ErrorHandler)
|
||||
```
|
||||
|
||||
### 推荐学习路径
|
||||
|
||||
#### 🌟 新手入门(2小时)
|
||||
|
||||
```
|
||||
1. 📖 阅读 00-框架基础概述.md (30分钟)
|
||||
理解三文件架构和RPC机制
|
||||
|
||||
2. 📖 阅读 01-Export接口说明.md (15分钟)
|
||||
📖 阅读 02-Import接口说明.md (15分钟)
|
||||
理解框架与游戏的双向接口
|
||||
|
||||
3. 📖 阅读 08-游戏流程概述.md (40分钟)
|
||||
理解完整游戏流程
|
||||
|
||||
4. 💻 完成第一个功能修改 (20分钟)
|
||||
参考 10-快速入门指南.md
|
||||
```
|
||||
|
||||
#### 🔬 算法研究(进阶)
|
||||
|
||||
```
|
||||
1. 📖 阅读 05-共享代码模块.md
|
||||
深入理解核心算法实现
|
||||
|
||||
2. 🔍 研究精牌系统
|
||||
→ JingAlgorithm.js(5166行)
|
||||
|
||||
3. 🔍 研究胡牌检测
|
||||
→ WinDetectionFactory.js
|
||||
|
||||
4. 🔍 研究计分系统
|
||||
→ ScoreCalculation.js(917行)
|
||||
```
|
||||
|
||||
#### 🛠️ 功能开发(实战)
|
||||
|
||||
```
|
||||
1. 📖 阅读 03-RPC处理机制.md
|
||||
理解请求处理流程
|
||||
|
||||
2. 📖 阅读 04-游戏核心服务.md
|
||||
理解服务层架构
|
||||
|
||||
3. 📖 阅读 09-代码框架总结.md
|
||||
理解整体设计
|
||||
|
||||
4. 💻 开始功能开发
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 文档导航
|
||||
|
||||
### 一、框架基础(Framework)
|
||||
|
||||
掌握友乐游戏平台的基础架构和接口规范。
|
||||
|
||||
| 文档 | 内容概要 | 字数 | 难度 |
|
||||
|------|---------|------|------|
|
||||
| [00-框架基础概述.md](framework/00-框架基础概述.md) | 友乐平台架构、三文件架构、ES5规范、前后端分离 | 14,000 | ⭐ |
|
||||
| [01-Export接口说明.md](framework/01-Export接口说明.md) | 框架→游戏的14个接口详解 | 18,000 | ⭐⭐ |
|
||||
| [02-Import接口说明.md](framework/02-Import接口说明.md) | 游戏→框架的13个接口详解 | 15,000 | ⭐⭐ |
|
||||
| [03-RPC处理机制.md](framework/03-RPC处理机制.md) | RPC路由流程、34个RPC方法详解 | 23,000 | ⭐⭐⭐ |
|
||||
|
||||
**学习收获**:
|
||||
- ✅ 理解友乐平台的三文件架构
|
||||
- ✅ 掌握Export和Import接口的使用
|
||||
- ✅ 理解RPC请求的完整处理流程
|
||||
- ✅ 了解ES5规范和浏览器兼容性
|
||||
|
||||
---
|
||||
|
||||
### 二、核心服务(Core)
|
||||
|
||||
深入理解游戏核心服务、算法实现和配置系统。
|
||||
|
||||
| 文档 | 内容概要 | 字数 | 难度 |
|
||||
|------|---------|------|------|
|
||||
| [04-游戏核心服务.md](core/04-游戏核心服务.md) | GameController、OperationManager等5大服务 | 30,000 | ⭐⭐⭐ |
|
||||
| [05-共享代码模块.md](core/05-共享代码模块.md) | JingAlgorithm、WinDetection等核心算法 | 35,000 | ⭐⭐⭐⭐⭐ |
|
||||
| [06-规则配置系统.md](core/06-规则配置系统.md) | RoomType编码、配置解析、缓存机制 | 25,000 | ⭐⭐⭐ |
|
||||
|
||||
**学习收获**:
|
||||
- ✅ 掌握游戏核心服务的职责和协作
|
||||
- ✅ 深入理解精牌系统算法(5166行)
|
||||
- ✅ 掌握胡牌检测和计分计算
|
||||
- ✅ 理解房间配置的解析和使用
|
||||
|
||||
**重点推荐**: 📌 `05-共享代码模块.md` 是最复杂、最详细的文档,深度分析了核心算法实现。
|
||||
|
||||
---
|
||||
|
||||
### 三、架构设计(Architecture)
|
||||
|
||||
从宏观角度理解游戏流程和整体架构。
|
||||
|
||||
| 文档 | 内容概要 | 字数 | 难度 |
|
||||
|------|---------|------|------|
|
||||
| [08-游戏流程概述.md](architecture/08-游戏流程概述.md) | 完整游戏流程、状态机、时序图 | 25,000 | ⭐⭐⭐ |
|
||||
| [09-代码框架总结.md](architecture/09-代码框架总结.md) | 架构总结、设计模式、扩展指南 | 20,000 | ⭐⭐⭐⭐ |
|
||||
|
||||
**学习收获**:
|
||||
- ✅ 理解游戏从开始到结束的完整流程
|
||||
- ✅ 掌握游戏状态机和阶段转换
|
||||
- ✅ 理解整体架构设计和模块依赖
|
||||
- ✅ 学习设计模式的实际应用
|
||||
|
||||
---
|
||||
|
||||
### 四、开发指南(Development)
|
||||
|
||||
实用的开发工具、调试技巧和快速入门。
|
||||
|
||||
| 文档 | 内容概要 | 字数 | 难度 |
|
||||
|------|---------|------|------|
|
||||
| [07-工具模块.md](development/07-工具模块.md) | Logger日志系统、ErrorHandler错误处理 | 20,000 | ⭐⭐ |
|
||||
| [10-快速入门指南.md](development/10-快速入门指南.md) | 快速理解、开发任务、FAQ、实战练习 | 15,000 | ⭐ |
|
||||
|
||||
**学习收获**:
|
||||
- ✅ 掌握Logger的6级日志使用
|
||||
- ✅ 理解错误处理规范
|
||||
- ✅ 快速定位代码位置
|
||||
- ✅ 解决常见开发问题
|
||||
|
||||
---
|
||||
|
||||
## 🎓 按角色选择学习路径
|
||||
|
||||
### 👨💻 新开发者(第1天)
|
||||
|
||||
**目标**: 快速理解项目,能修改简单功能
|
||||
|
||||
```
|
||||
上午(2-3小时):
|
||||
├─ 阅读 README.md(本文档) 10分钟
|
||||
├─ 阅读 00-框架基础概述.md 30分钟
|
||||
├─ 阅读 01-Export接口说明.md 20分钟
|
||||
├─ 阅读 02-Import接口说明.md 20分钟
|
||||
└─ 阅读 10-快速入门指南.md 40分钟
|
||||
|
||||
下午(2-3小时):
|
||||
├─ 阅读 08-游戏流程概述.md 40分钟
|
||||
├─ 浏览代码结构 30分钟
|
||||
├─ 完成第一个功能修改(添加日志) 30分钟
|
||||
└─ 完成练习(修改分数规则) 30分钟
|
||||
```
|
||||
|
||||
**预期成果**:
|
||||
- ✅ 理解三文件架构和RPC机制
|
||||
- ✅ 知道去哪里找需要的代码
|
||||
- ✅ 能完成简单的功能修改
|
||||
|
||||
---
|
||||
|
||||
### 🔬 算法工程师(第1-2天)
|
||||
|
||||
**目标**: 深入理解核心算法实现
|
||||
|
||||
```
|
||||
第1天 - 精牌系统:
|
||||
├─ 阅读 05-共享代码模块.md(JingAlgorithm部分) 2小时
|
||||
├─ 研究 JingAlgorithm.js 源码 2小时
|
||||
└─ 理解比精算法和精分计算 1小时
|
||||
|
||||
第2天 - 胡牌检测与计分:
|
||||
├─ 阅读 05-共享代码模块.md(其他算法部分) 2小时
|
||||
├─ 研究 WinDetectionFactory.js 源码 1.5小时
|
||||
├─ 研究 ScoreCalculation.js 源码 1.5小时
|
||||
└─ 理解牌型检测和计分流程 1小时
|
||||
```
|
||||
|
||||
**预期成果**:
|
||||
- ✅ 深入理解精牌系统算法(5166行)
|
||||
- ✅ 掌握5种牌型的检测算法
|
||||
- ✅ 理解计分系统的实现细节
|
||||
|
||||
---
|
||||
|
||||
### 🏗️ 架构师(第1-2天)
|
||||
|
||||
**目标**: 理解整体架构和设计理念
|
||||
|
||||
```
|
||||
第1天 - 架构理解:
|
||||
├─ 阅读 00-框架基础概述.md 30分钟
|
||||
├─ 阅读 03-RPC处理机制.md 1小时
|
||||
├─ 阅读 04-游戏核心服务.md 1.5小时
|
||||
├─ 阅读 08-游戏流程概述.md 1.5小时
|
||||
└─ 阅读 09-代码框架总结.md 1.5小时
|
||||
|
||||
第2天 - 深入分析:
|
||||
├─ 分析模块依赖关系 1小时
|
||||
├─ 分析设计模式应用 1小时
|
||||
├─ 评估性能优化点 1小时
|
||||
└─ 规划扩展方案 2小时
|
||||
```
|
||||
|
||||
**预期成果**:
|
||||
- ✅ 理解三层架构设计
|
||||
- ✅ 掌握6大设计模式的应用
|
||||
- ✅ 了解模块依赖关系
|
||||
- ✅ 能够规划架构扩展
|
||||
|
||||
---
|
||||
|
||||
### 🛠️ 功能开发者(按需学习)
|
||||
|
||||
**目标**: 根据开发任务学习相关知识
|
||||
|
||||
#### 任务1: 添加新RPC方法
|
||||
```
|
||||
需要阅读:
|
||||
├─ 03-RPC处理机制.md(RpcHandler详解)
|
||||
└─ 10-快速入门指南.md(任务1: 添加新RPC方法)
|
||||
预计时间: 1小时
|
||||
```
|
||||
|
||||
#### 任务2: 修改计分规则
|
||||
```
|
||||
需要阅读:
|
||||
├─ 05-共享代码模块.md(ScoreCalculation部分)
|
||||
└─ 10-快速入门指南.md(任务2: 修改计分规则)
|
||||
预计时间: 1.5小时
|
||||
```
|
||||
|
||||
#### 任务3: 添加新游戏规则
|
||||
```
|
||||
需要阅读:
|
||||
├─ 06-规则配置系统.md
|
||||
└─ 10-快速入门指南.md(任务3: 添加新游戏规则)
|
||||
预计时间: 2小时
|
||||
```
|
||||
|
||||
#### 任务4: 添加新牌型
|
||||
```
|
||||
需要阅读:
|
||||
├─ 05-共享代码模块.md(WinDetectionFactory部分)
|
||||
└─ 10-快速入门指南.md(任务5: 添加新牌型检测)
|
||||
预计时间: 3小时
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 按问题查找文档
|
||||
|
||||
### 问题: 客户端请求如何处理?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [03-RPC处理机制.md](framework/03-RPC处理机制.md) - 完整RPC处理流程
|
||||
- 📖 [04-游戏核心服务.md](core/04-游戏核心服务.md#rpchandler) - RpcHandler详解
|
||||
|
||||
**关键代码**: `rpc/RpcHandler.js`
|
||||
|
||||
---
|
||||
|
||||
### 问题: 精牌系统是如何实现的?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [05-共享代码模块.md](core/05-共享代码模块.md#jingalgorithm-精牌算法) - 精牌算法详解
|
||||
- 📖 [08-游戏流程概述.md](architecture/08-游戏流程概述.md#开精流程) - 精牌确定流程
|
||||
|
||||
**关键代码**: `shared/algorithms/JingAlgorithm.js`(5166行)
|
||||
|
||||
---
|
||||
|
||||
### 问题: 如何判断能否胡牌?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [05-共享代码模块.md](core/05-共享代码模块.md#windetectionfactory-胡牌检测工厂) - 胡牌检测算法
|
||||
- 📖 [04-游戏核心服务.md](core/04-游戏核心服务.md#mahjonggameservice) - 胡牌服务
|
||||
|
||||
**关键代码**: `shared/algorithms/WinDetectionFactory.js`
|
||||
|
||||
---
|
||||
|
||||
### 问题: 分数是如何计算的?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [05-共享代码模块.md](core/05-共享代码模块.md#scorecalculation-计分系统) - 计分算法详解
|
||||
- 📖 [08-游戏流程概述.md](architecture/08-游戏流程概述.md#胡牌结算) - 结算流程
|
||||
|
||||
**关键代码**: `shared/algorithms/ScoreCalculation.js`(917行)
|
||||
|
||||
---
|
||||
|
||||
### 问题: 如何添加日志和调试?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [07-工具模块.md](development/07-工具模块.md#logger-日志管理器) - Logger详细说明
|
||||
- 📖 [10-快速入门指南.md](development/10-快速入门指南.md#任务4-添加日志和调试信息) - 日志使用示例
|
||||
|
||||
**关键代码**: `utils/Logger.js`(606行)
|
||||
|
||||
---
|
||||
|
||||
### 问题: 游戏状态如何管理?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [04-游戏核心服务.md](core/04-游戏核心服务.md#gamestate-游戏状态对象) - gameState详解
|
||||
- 📖 [08-游戏流程概述.md](architecture/08-游戏流程概述.md#游戏状态机) - 状态转换
|
||||
|
||||
**关键代码**: `shared/dataStructures/GameStateManager.js`
|
||||
|
||||
---
|
||||
|
||||
### 问题: 房间配置如何解析?
|
||||
|
||||
**答案位置**:
|
||||
- 📖 [06-规则配置系统.md](core/06-规则配置系统.md) - 完整配置系统说明
|
||||
- 📖 [01-Export接口说明.md](framework/01-Export接口说明.md#roomtype配置) - roomtype格式
|
||||
|
||||
**关键代码**: `shared/config/RoomConfigUtils.js`(1222行)
|
||||
|
||||
---
|
||||
|
||||
## 📖 文档特色内容
|
||||
|
||||
### 🏆 最详细:05-共享代码模块.md
|
||||
|
||||
- **35,000字** 深度分析
|
||||
- 涵盖 **5大核心算法** 详解
|
||||
- **JingAlgorithm.js** 5166行完整分析
|
||||
- **ScoreCalculation.js** 917行计分逻辑
|
||||
- **MahjongCard.js** 2461行牌对象系统
|
||||
|
||||
**适合**: 想深入理解算法实现的开发者
|
||||
|
||||
---
|
||||
|
||||
### 🔄 最全面:08-游戏流程概述.md
|
||||
|
||||
- **完整游戏流程** 从开始到结束
|
||||
- **7个游戏阶段** 详细说明
|
||||
- **状态机设计** 和转换规则
|
||||
- **时序图** 展示交互流程
|
||||
- **操作优先级** 处理机制
|
||||
|
||||
**适合**: 想理解整体流程的开发者
|
||||
|
||||
---
|
||||
|
||||
### 🛠️ 最实用:10-快速入门指南.md
|
||||
|
||||
- **10分钟** 快速理解核心概念
|
||||
- **5个常见开发任务** 详细步骤
|
||||
- **10个FAQ** 解答高频问题
|
||||
- **3个实战练习** 从易到难
|
||||
- **代码导航技巧** 快速定位
|
||||
|
||||
**适合**: 想快速上手的新开发者
|
||||
|
||||
---
|
||||
|
||||
### 🏗️ 最系统:09-代码框架总结.md
|
||||
|
||||
- **三层架构** 详细说明
|
||||
- **完整依赖关系图** (6层依赖)
|
||||
- **6大设计模式** 实战应用
|
||||
- **4个扩展指南** 详细步骤
|
||||
- **5个常见问题** 解决方案
|
||||
|
||||
**适合**: 想理解架构设计的开发者
|
||||
|
||||
---
|
||||
|
||||
## 📊 文档统计
|
||||
|
||||
### 文档数量与字数
|
||||
|
||||
| 分类 | 文档数 | 总字数 | 占比 |
|
||||
|------|--------|--------|------|
|
||||
| 框架基础 | 4篇 | 70,000字 | 29% |
|
||||
| 核心服务 | 3篇 | 90,000字 | 38% |
|
||||
| 架构设计 | 2篇 | 45,000字 | 19% |
|
||||
| 开发指南 | 2篇 | 35,000字 | 14% |
|
||||
| **总计** | **13篇** | **240,000字** | **100%** |
|
||||
|
||||
### 难度分布
|
||||
|
||||
- ⭐ 入门级:2篇(快速理解)
|
||||
- ⭐⭐ 初级:3篇(基础理解)
|
||||
- ⭐⭐⭐ 中级:5篇(深入理解)
|
||||
- ⭐⭐⭐⭐ 高级:2篇(架构设计)
|
||||
- ⭐⭐⭐⭐⭐ 专家级:1篇(算法深度)
|
||||
|
||||
### 预计学习时间
|
||||
|
||||
- **快速浏览**: 2小时(理解基础架构)
|
||||
- **系统学习**: 2天(完整阅读所有文档)
|
||||
- **深入研究**: 1周(理解所有算法细节)
|
||||
- **精通掌握**: 2周(能独立开发和架构)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技术栈
|
||||
|
||||
### 编程语言
|
||||
- **JavaScript ES5** - 严格遵循ES5规范,确保浏览器兼容性
|
||||
|
||||
### 运行环境
|
||||
- **Node.js** (服务端) - 游戏服务器
|
||||
- **浏览器** (客户端) - Chrome/Firefox/Safari等
|
||||
|
||||
### 框架平台
|
||||
- **友乐游戏平台** - 自研游戏框架
|
||||
- **三文件架构** - mod.js/export.js/import.js
|
||||
|
||||
### 核心技术
|
||||
- **RPC通信** - WebSocket/HTTP协议
|
||||
- **状态机** - 7个游戏阶段管理
|
||||
- **精牌算法** - 5166行核心算法
|
||||
- **胡牌检测** - 5种牌型检测
|
||||
- **计分系统** - 917行计分逻辑
|
||||
|
||||
---
|
||||
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
server/games2/jinxianmahjong/
|
||||
├── mod.js # 模块入口(加载所有文件)
|
||||
├── export.js # 输出接口(框架→游戏,14个接口)
|
||||
├── import.js # 输入接口(游戏→框架,13个接口)
|
||||
│
|
||||
├── rpc/ # RPC处理器
|
||||
│ ├── RpcHandler.js # 标准RPC处理(34个方法)
|
||||
│ ├── AIRpcHandler.js # AI玩家RPC处理
|
||||
│ └── OperationEnumerator.js # 操作枚举器
|
||||
│
|
||||
├── game/ # 游戏核心服务
|
||||
│ ├── GameController.js # 游戏流程控制器
|
||||
│ ├── MahjongGameService.js # 麻将游戏服务
|
||||
│ ├── OperationManager.js # 操作管理器
|
||||
│ ├── AIManager.js # AI管理器
|
||||
│ └── RoomAdapter.js # 房间适配器
|
||||
│
|
||||
├── shared/ # 前后端共享代码
|
||||
│ ├── algorithms/ # 核心算法
|
||||
│ │ ├── JingAlgorithm.js # 精牌算法(5166行)
|
||||
│ │ ├── WinDetectionFactory.js # 胡牌检测
|
||||
│ │ ├── ScoreCalculation.js # 计分系统(917行)
|
||||
│ │ └── PatternFactory.js # 牌型分析
|
||||
│ ├── dataStructures/ # 数据结构
|
||||
│ │ ├── GameStateManager.js # 游戏状态管理
|
||||
│ │ └── MahjongCard.js # 麻将牌对象(2461行)
|
||||
│ ├── config/ # 配置系统
|
||||
│ │ ├── RoomConfigUtils.js # 配置工具(1222行)
|
||||
│ │ └── RuleConfigParser.js # 规则解析器
|
||||
│ ├── constants/ # 常量定义(12个模块)
|
||||
│ │ └── index.js # 常量统一导出
|
||||
│ └── utils/ # 共享工具
|
||||
│
|
||||
└── utils/ # 工具模块
|
||||
├── Logger.js # 日志管理器(606行)
|
||||
└── ErrorHandler.js # 错误处理器(659行)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌟 核心特性
|
||||
|
||||
### 1. 精牌系统(独特玩法)
|
||||
|
||||
进贤麻将最核心的特色系统,由 **5166行** 代码实现。
|
||||
|
||||
**功能**:
|
||||
- ✅ 掷骰子确定精牌(正精、副精)
|
||||
- ✅ 精牌可作为万能牌使用
|
||||
- ✅ 精牌计分(正精2分、副精1分)
|
||||
- ✅ 比精算法(比较精牌数量和价值)
|
||||
- ✅ 冲关机制(精分达到10分翻倍)
|
||||
|
||||
**文档**: [05-共享代码模块.md - JingAlgorithm](core/05-共享代码模块.md#jingalgorithm-精牌算法)
|
||||
|
||||
---
|
||||
|
||||
### 2. 5种胡牌牌型
|
||||
|
||||
支持多种胡牌牌型,满足不同玩法需求。
|
||||
|
||||
**牌型**:
|
||||
1. **平胡** - 标准3-3-3-3-2组合
|
||||
2. **七对** - 7个对子
|
||||
3. **四碰** - 4个刻子+1个对子
|
||||
4. **十三烂** - 特殊散牌组合
|
||||
5. **七星十三烂** - 最高级别牌型
|
||||
|
||||
**文档**: [05-共享代码模块.md - WinDetectionFactory](core/05-共享代码模块.md#windetectionfactory-胡牌检测工厂)
|
||||
|
||||
---
|
||||
|
||||
### 3. 灵活的规则配置
|
||||
|
||||
13位roomtype编码,支持丰富的规则组合。
|
||||
|
||||
**配置项**:
|
||||
- 局数(8/16/24局)
|
||||
- 精牌(带精/不带精)
|
||||
- 吃碰杠(允许/禁止)
|
||||
- 特殊规则(上下翻、买雷雷等)
|
||||
|
||||
**文档**: [06-规则配置系统.md](core/06-规则配置系统.md)
|
||||
|
||||
---
|
||||
|
||||
### 4. 完善的日志系统
|
||||
|
||||
6级日志,支持历史记录和统计分析。
|
||||
|
||||
**级别**: TRACE → DEBUG → INFO → WARN → ERROR → FATAL
|
||||
|
||||
**文档**: [07-工具模块.md - Logger](development/07-工具模块.md#logger-日志管理器)
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 性能优化
|
||||
|
||||
### 1. 配置缓存机制
|
||||
|
||||
使用LRU缓存策略,避免重复解析roomtype配置。
|
||||
|
||||
**效果**:
|
||||
- ✅ 缓存命中率 > 95%
|
||||
- ✅ 配置解析时间 < 1ms
|
||||
|
||||
**文档**: [06-规则配置系统.md - 缓存机制](core/06-规则配置系统.md#缓存机制)
|
||||
|
||||
---
|
||||
|
||||
### 2. 对象池模式
|
||||
|
||||
复用MahjongCard对象,减少GC压力。
|
||||
|
||||
**效果**:
|
||||
- ✅ 减少对象创建 80%
|
||||
- ✅ 内存占用降低 30%
|
||||
|
||||
**文档**: [09-代码框架总结.md - 性能优化](architecture/09-代码框架总结.md#性能优化建议)
|
||||
|
||||
---
|
||||
|
||||
### 3. 预计算策略
|
||||
|
||||
预先计算常用数据,提高运行时性能。
|
||||
|
||||
**应用**:
|
||||
- ✅ 牌型组合预计算
|
||||
- ✅ 精牌列表缓存
|
||||
- ✅ 规则模板预加载
|
||||
|
||||
---
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
||||
### 文档改进
|
||||
|
||||
如果你发现文档中的错误或需要改进的地方:
|
||||
|
||||
1. 在对应文档中记录问题
|
||||
2. 提出改进建议
|
||||
3. 更新文档内容
|
||||
4. 同步更新相关交叉引用
|
||||
|
||||
### 代码贡献
|
||||
|
||||
如果你开发了新功能或修复了bug:
|
||||
|
||||
1. 更新相关技术文档
|
||||
2. 添加代码示例
|
||||
3. 更新常见问题解答
|
||||
4. 更新本README的快速链接
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
### 遇到问题?
|
||||
|
||||
1. **查看文档** - 在本README中按问题查找相关文档
|
||||
2. **查看FAQ** - [10-快速入门指南.md](development/10-快速入门指南.md#常见问题解答-faq)
|
||||
3. **搜索代码** - 使用文档中的代码导航技巧
|
||||
4. **查看日志** - 使用Logger追踪程序执行
|
||||
|
||||
### 学习建议
|
||||
|
||||
- 📖 **先框架后细节** - 从框架基础开始,逐步深入
|
||||
- 💻 **理论结合实践** - 边学习边尝试修改代码
|
||||
- 🔍 **善用搜索** - 在文档中搜索关键词
|
||||
- 📝 **做好笔记** - 记录重要概念和代码位置
|
||||
|
||||
---
|
||||
|
||||
## 📜 更新日志
|
||||
|
||||
### v1.0 (2025年10月15日)
|
||||
|
||||
**完成的文档**:
|
||||
- ✅ 框架基础文档(4篇,70,000字)
|
||||
- ✅ 核心服务文档(3篇,90,000字)
|
||||
- ✅ 架构设计文档(2篇,45,000字)
|
||||
- ✅ 开发指南文档(2篇,35,000字)
|
||||
- ✅ 文档导航(README.md)
|
||||
|
||||
**文档特点**:
|
||||
- 📚 13篇技术文档,总计约240,000字
|
||||
- 🔍 深度分析核心算法(JingAlgorithm 5166行)
|
||||
- 💡 丰富的代码示例和最佳实践
|
||||
- 🎯 多种学习路径,适合不同角色
|
||||
|
||||
**重要里程碑**:
|
||||
- ✅ 完成所有计划文档
|
||||
- ✅ 建立完整文档体系
|
||||
- ✅ 提供多角色学习路径
|
||||
- ✅ 创建文档导航和快速索引
|
||||
|
||||
---
|
||||
|
||||
## 🎉 开始你的学习之旅!
|
||||
|
||||
选择一个适合你的学习路径,开始探索进贤麻将的技术世界吧!
|
||||
|
||||
**推荐起点**:
|
||||
- 🌟 **新手**: [10-快速入门指南.md](development/10-快速入门指南.md)
|
||||
- 🔬 **算法**: [05-共享代码模块.md](core/05-共享代码模块.md)
|
||||
- 🏗️ **架构**: [09-代码框架总结.md](architecture/09-代码框架总结.md)
|
||||
|
||||
**记住**:
|
||||
- 📖 遇到问题先查文档
|
||||
- 🔍 善用本README的快速导航
|
||||
- 💻 理论结合实践
|
||||
- 🧪 多写代码多测试
|
||||
|
||||
---
|
||||
|
||||
**Happy Coding! 🚀**
|
||||
|
||||
---
|
||||
|
||||
**维护团队**: 进贤麻将开发团队
|
||||
**文档版本**: v1.0
|
||||
**最后更新**: 2025年10月15日
|
||||
1205
codes/games/server/docs/guides/architecture/08-游戏流程概述.md
Normal file
1205
codes/games/server/docs/guides/architecture/08-游戏流程概述.md
Normal file
File diff suppressed because it is too large
Load Diff
1378
codes/games/server/docs/guides/architecture/09-代码框架总结.md
Normal file
1378
codes/games/server/docs/guides/architecture/09-代码框架总结.md
Normal file
File diff suppressed because it is too large
Load Diff
1388
codes/games/server/docs/guides/core/04-游戏核心服务.md
Normal file
1388
codes/games/server/docs/guides/core/04-游戏核心服务.md
Normal file
File diff suppressed because it is too large
Load Diff
1261
codes/games/server/docs/guides/core/05-共享代码模块.md
Normal file
1261
codes/games/server/docs/guides/core/05-共享代码模块.md
Normal file
File diff suppressed because it is too large
Load Diff
1542
codes/games/server/docs/guides/core/06-规则配置系统.md
Normal file
1542
codes/games/server/docs/guides/core/06-规则配置系统.md
Normal file
File diff suppressed because it is too large
Load Diff
1519
codes/games/server/docs/guides/development/07-工具模块.md
Normal file
1519
codes/games/server/docs/guides/development/07-工具模块.md
Normal file
File diff suppressed because it is too large
Load Diff
872
codes/games/server/docs/guides/development/10-快速入门指南.md
Normal file
872
codes/games/server/docs/guides/development/10-快速入门指南.md
Normal file
@@ -0,0 +1,872 @@
|
||||
# 快速入门指南
|
||||
|
||||
## 📋 文档概述
|
||||
|
||||
本文档为进贤麻将子游戏提供快速入门指南,帮助开发者:
|
||||
- **快速理解** - 10分钟理解项目核心结构
|
||||
- **快速定位** - 知道去哪里找需要的代码
|
||||
- **快速上手** - 掌握常见开发任务的实现方法
|
||||
- **快速解决** - 查找常见问题的解决方案
|
||||
|
||||
**文档目标**: 让新开发者能在**2小时内**理解项目结构并完成第一个功能修改。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 10分钟快速理解
|
||||
|
||||
### 核心概念速览
|
||||
|
||||
#### 1️⃣ 三文件架构 (最重要!)
|
||||
|
||||
```
|
||||
mod.js → 模块入口,加载所有文件
|
||||
export.js → 框架调用游戏的14个接口
|
||||
import.js → 游戏调用框架的13个接口
|
||||
```
|
||||
|
||||
**记住**:
|
||||
- 框架要执行游戏逻辑 → 调用 `export` 接口
|
||||
- 游戏要通知客户端 → 调用 `import` 接口
|
||||
|
||||
#### 2️⃣ 请求处理流程
|
||||
|
||||
```
|
||||
客户端发送操作
|
||||
↓
|
||||
packet.js 路由到 mod.js
|
||||
↓
|
||||
RpcHandler 处理请求
|
||||
↓
|
||||
GameController 执行逻辑
|
||||
↓
|
||||
import 发送响应给客户端
|
||||
```
|
||||
|
||||
#### 3️⃣ 核心目录结构
|
||||
|
||||
```javascript
|
||||
games2/jinxianmahjong/
|
||||
├── mod.js, export.js, import.js // 三文件架构
|
||||
├── rpc/RpcHandler.js // 客户端请求处理(34个RPC方法)
|
||||
├── game/
|
||||
│ ├── GameController.js // 游戏流程控制(开始、发牌、结算)
|
||||
│ ├── OperationManager.js // 操作管理(吃碰杠胡验证)
|
||||
│ └── MahjongGameService.js // 胡牌检测和计分
|
||||
├── shared/
|
||||
│ ├── algorithms/ // 算法(精牌、胡牌检测、计分)
|
||||
│ ├── dataStructures/ // 数据结构(牌对象、状态管理)
|
||||
│ ├── config/ // 配置解析
|
||||
│ └── constants/ // 常量定义(12个模块)
|
||||
└── utils/ // 工具(Logger、ErrorHandler)
|
||||
```
|
||||
|
||||
### 关键文件速查表
|
||||
|
||||
| 需求 | 去哪里找 | 核心文件 |
|
||||
|------|---------|----------|
|
||||
| **客户端请求如何处理?** | `rpc/` | RpcHandler.js |
|
||||
| **游戏怎么开始的?** | `game/` | GameController.js |
|
||||
| **怎么判断能否胡牌?** | `shared/algorithms/` | WinDetectionFactory.js |
|
||||
| **精牌怎么计算的?** | `shared/algorithms/` | JingAlgorithm.js |
|
||||
| **分数怎么算的?** | `shared/algorithms/` | ScoreCalculation.js |
|
||||
| **游戏状态怎么管理?** | `shared/dataStructures/` | GameStateManager.js |
|
||||
| **房间配置怎么解析?** | `shared/config/` | RoomConfigUtils.js |
|
||||
| **如何发送消息给客户端?** | 根目录 | import.js |
|
||||
| **框架如何调用游戏?** | 根目录 | export.js |
|
||||
|
||||
---
|
||||
|
||||
## 📖 学习路径
|
||||
|
||||
### 路径1: 新手入门 (推荐顺序)
|
||||
|
||||
```
|
||||
第1步: 理解架构
|
||||
↓
|
||||
阅读 00-框架基础概述.md
|
||||
理解三文件架构和RPC机制
|
||||
预计时间: 30分钟
|
||||
|
||||
第2步: 理解接口
|
||||
↓
|
||||
阅读 01-Export接口说明.md
|
||||
阅读 02-Import接口说明.md
|
||||
理解框架与游戏的交互
|
||||
预计时间: 30分钟
|
||||
|
||||
第3步: 理解流程
|
||||
↓
|
||||
阅读 08-游戏流程概述.md
|
||||
理解游戏从开始到结束的完整流程
|
||||
预计时间: 40分钟
|
||||
|
||||
第4步: 动手实践
|
||||
↓
|
||||
完成一个简单的功能修改
|
||||
(例如: 添加日志、修改分数)
|
||||
预计时间: 20分钟
|
||||
```
|
||||
|
||||
**总计**: 2小时入门
|
||||
|
||||
### 路径2: 算法研究 (进阶开发者)
|
||||
|
||||
```
|
||||
1. 阅读 05-共享代码模块.md (核心算法详解)
|
||||
2. 研究 JingAlgorithm.js (精牌系统)
|
||||
3. 研究 WinDetectionFactory.js (胡牌检测)
|
||||
4. 研究 ScoreCalculation.js (计分系统)
|
||||
```
|
||||
|
||||
### 路径3: 功能开发 (实战导向)
|
||||
|
||||
```
|
||||
1. 阅读 03-RPC处理机制.md (理解请求处理)
|
||||
2. 阅读 04-游戏核心服务.md (理解服务层)
|
||||
3. 阅读 09-代码框架总结.md (理解架构设计)
|
||||
4. 开始功能开发
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 常见开发任务
|
||||
|
||||
### 任务1: 添加新的RPC方法
|
||||
|
||||
**场景**: 需要处理客户端的新操作请求
|
||||
|
||||
**步骤**:
|
||||
|
||||
```javascript
|
||||
// 1. 在 rpc/RpcHandler.js 中添加方法
|
||||
RpcHandler.prototype.player_new_operation = function(pack, room, callback) {
|
||||
var playerId = pack.playerid;
|
||||
var data = pack.data;
|
||||
|
||||
// 验证操作
|
||||
var validation = this._validateOperation(room.gameState, playerId, data);
|
||||
if (!validation.valid) {
|
||||
return callback({ error: validation.error });
|
||||
}
|
||||
|
||||
// 执行操作
|
||||
var result = this._performOperation(room.gameState, playerId, data);
|
||||
|
||||
// 广播消息
|
||||
room.import.broadcast(room, {
|
||||
type: 'new_operation',
|
||||
playerId: playerId,
|
||||
data: result
|
||||
});
|
||||
|
||||
callback({ success: true, data: result });
|
||||
};
|
||||
|
||||
// 2. 在 mod.js 中注册RPC方法
|
||||
mod_jinxianmahjong.player_new_operation = function(pack) {
|
||||
var room = this.getRoom(pack.roomcode);
|
||||
return this.rpcHandler.player_new_operation(pack, room, function(result) {
|
||||
return result;
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
**相关文档**: [03-RPC处理机制.md](../framework/03-RPC处理机制.md)
|
||||
|
||||
---
|
||||
|
||||
### 任务2: 修改计分规则
|
||||
|
||||
**场景**: 需要调整某种牌型的分数
|
||||
|
||||
**步骤**:
|
||||
|
||||
```javascript
|
||||
// 在 shared/algorithms/ScoreCalculation.js 中修改
|
||||
ScoreCalculation.calculateWinScore = function(winResult, gameState) {
|
||||
var scores = {
|
||||
baseScore: 0,
|
||||
bonusScore: 0,
|
||||
jingScore: 0,
|
||||
totalScore: 0
|
||||
};
|
||||
|
||||
// 修改牌型分数
|
||||
var pattern = winResult.bestPattern;
|
||||
switch (pattern.type) {
|
||||
case 'pinghu':
|
||||
scores.baseScore = pattern.hasJing ? 4 : 8;
|
||||
break;
|
||||
case 'qidui':
|
||||
scores.baseScore = pattern.hasJing ? 8 : 64;
|
||||
break;
|
||||
case 'custom_pattern': // 新增牌型
|
||||
scores.baseScore = 16;
|
||||
break;
|
||||
// ...
|
||||
}
|
||||
|
||||
// 计算精分
|
||||
scores.jingScore = JingAlgorithm.calculateJingScore(
|
||||
gameState.players[winResult.winnerId].handCards,
|
||||
gameState.jingInfo
|
||||
);
|
||||
|
||||
// 总分
|
||||
scores.totalScore = scores.baseScore + scores.bonusScore + scores.jingScore;
|
||||
|
||||
return scores;
|
||||
};
|
||||
```
|
||||
|
||||
**相关文档**: [05-共享代码模块.md](../core/05-共享代码模块.md#scorecalculation-计分系统)
|
||||
|
||||
---
|
||||
|
||||
### 任务3: 添加新的游戏规则
|
||||
|
||||
**场景**: 需要支持新的房间配置选项
|
||||
|
||||
**步骤**:
|
||||
|
||||
```javascript
|
||||
// 1. 在 shared/config/RoomConfigUtils.js 中添加解析
|
||||
RoomConfigUtils.parse = function(roomtype) {
|
||||
// ...现有解析逻辑
|
||||
|
||||
// 新增规则位解析(假设使用第14位)
|
||||
var enableNewRule = roomtype.charAt(13) === '1';
|
||||
|
||||
return {
|
||||
// ...现有配置
|
||||
specialRules: {
|
||||
enableNewRule: enableNewRule, // 新规则
|
||||
// ...其他规则
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 2. 在游戏逻辑中使用规则
|
||||
// game/OperationManager.js
|
||||
OperationManager.validateOperation = function(gameState, operation) {
|
||||
// 检查新规则
|
||||
if (gameState.rules.specialRules.enableNewRule) {
|
||||
// 执行特殊验证逻辑
|
||||
}
|
||||
|
||||
// ...其他验证
|
||||
};
|
||||
```
|
||||
|
||||
**相关文档**: [06-规则配置系统.md](../core/06-规则配置系统.md)
|
||||
|
||||
---
|
||||
|
||||
### 任务4: 添加日志和调试信息
|
||||
|
||||
**场景**: 需要追踪代码执行流程
|
||||
|
||||
**步骤**:
|
||||
|
||||
```javascript
|
||||
var Logger = require('./utils/Logger.js');
|
||||
|
||||
// 在任何需要调试的地方添加日志
|
||||
function someFunction(param) {
|
||||
Logger.info('函数开始执行', { param: param });
|
||||
|
||||
try {
|
||||
// 业务逻辑
|
||||
Logger.debug('中间状态', { state: currentState });
|
||||
|
||||
// 更多逻辑
|
||||
Logger.info('操作成功', { result: result });
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
Logger.error('操作失败', {
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 查看日志历史
|
||||
var history = Logger.getHistory();
|
||||
console.log('最近100条日志:', history.slice(-100));
|
||||
|
||||
// 查看日志统计
|
||||
var stats = Logger.getStatistics();
|
||||
console.log('错误数量:', stats.ERROR);
|
||||
```
|
||||
|
||||
**相关文档**: [07-工具模块.md](07-工具模块.md#logger-日志管理器)
|
||||
|
||||
---
|
||||
|
||||
### 任务5: 添加新的牌型检测
|
||||
|
||||
**场景**: 需要支持新的胡牌牌型
|
||||
|
||||
**步骤**:
|
||||
|
||||
```javascript
|
||||
// 在 shared/algorithms/WinDetectionFactory.js 中添加
|
||||
WinDetectionFactory.detectWin = function(handTiles, jingInfo, gameState) {
|
||||
var patterns = [];
|
||||
|
||||
// ...现有牌型检测
|
||||
|
||||
// 添加新牌型检测
|
||||
var customPatternResult = this._checkCustomPattern(handTiles, jingInfo);
|
||||
if (customPatternResult.canWin) {
|
||||
patterns.push({
|
||||
type: 'custom_pattern',
|
||||
name: '自定义牌型',
|
||||
hasJing: customPatternResult.hasJing,
|
||||
baseScore: 32,
|
||||
description: '特殊组合牌型',
|
||||
combinations: customPatternResult.combinations
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
canWin: patterns.length > 0,
|
||||
patterns: patterns,
|
||||
bestPattern: this._selectBestPattern(patterns)
|
||||
};
|
||||
};
|
||||
|
||||
// 实现检测逻辑
|
||||
WinDetectionFactory._checkCustomPattern = function(handTiles, jingInfo) {
|
||||
// 实现牌型检测算法
|
||||
// 返回 { canWin: boolean, hasJing: boolean, combinations: [...] }
|
||||
};
|
||||
```
|
||||
|
||||
**相关文档**: [05-共享代码模块.md](../core/05-共享代码模块.md#windetectionfactory-胡牌检测工厂)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 代码导航技巧
|
||||
|
||||
### 技巧1: 快速查找功能入口
|
||||
|
||||
```javascript
|
||||
// 想知道某个操作是如何处理的?
|
||||
// 1. 找到客户端发送的RPC方法名,例如: "player_discard"
|
||||
// 2. 在 rpc/RpcHandler.js 中搜索该方法
|
||||
// 3. 阅读该方法的实现
|
||||
|
||||
// 示例: 查找出牌操作
|
||||
// → 搜索 "player_discard"
|
||||
// → 找到 RpcHandler.prototype.player_discard
|
||||
// → 理解处理流程
|
||||
```
|
||||
|
||||
### 技巧2: 追踪数据流
|
||||
|
||||
```javascript
|
||||
// 数据流追踪顺序:
|
||||
// 1. 客户端发送 → packet.js
|
||||
// 2. 路由到模块 → mod.js
|
||||
// 3. RPC处理 → rpc/RpcHandler.js
|
||||
// 4. 业务逻辑 → game/GameController.js 或其他服务
|
||||
// 5. 状态更新 → shared/dataStructures/GameStateManager.js
|
||||
// 6. 响应发送 → import.js → 客户端接收
|
||||
```
|
||||
|
||||
### 技巧3: 查找算法实现
|
||||
|
||||
```javascript
|
||||
// 想知道某个算法是如何实现的?
|
||||
// 1. 确定算法类型(精牌/胡牌检测/计分等)
|
||||
// 2. 到 shared/algorithms/ 目录查找
|
||||
// 3. 查看对应的算法文件
|
||||
|
||||
// 示例算法文件:
|
||||
// - JingAlgorithm.js → 精牌相关算法
|
||||
// - WinDetectionFactory.js → 胡牌检测
|
||||
// - ScoreCalculation.js → 计分计算
|
||||
// - PatternFactory.js → 牌型分析
|
||||
```
|
||||
|
||||
### 技巧4: 理解配置选项
|
||||
|
||||
```javascript
|
||||
// 想知道某个规则位的含义?
|
||||
// 1. 打开 shared/config/RoomConfigUtils.js
|
||||
// 2. 查看 parse() 方法
|
||||
// 3. 找到对应位的解析代码
|
||||
|
||||
// 或者查看 shared/constants/RoomConstants.js
|
||||
// 查看所有规则的定义和说明
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❓ 常见问题解答 (FAQ)
|
||||
|
||||
### Q1: 如何查看游戏当前状态?
|
||||
|
||||
**A**: 游戏状态保存在 `room.gameState` 对象中
|
||||
|
||||
```javascript
|
||||
// 在任何有 room 对象的地方
|
||||
console.log('当前阶段:', room.gameState.phase);
|
||||
console.log('当前玩家:', room.gameState.currentPlayer);
|
||||
console.log('庄家:', room.gameState.dealer);
|
||||
console.log('精牌信息:', room.gameState.jingInfo);
|
||||
|
||||
// 查看玩家手牌
|
||||
var player = room.gameState.players[0];
|
||||
console.log('玩家0手牌:', player.handCards);
|
||||
console.log('玩家0分数:', player.score);
|
||||
```
|
||||
|
||||
**相关文档**: [04-游戏核心服务.md](../core/04-游戏核心服务.md#gamestate-游戏状态对象)
|
||||
|
||||
---
|
||||
|
||||
### Q2: 如何判断一个操作是否合法?
|
||||
|
||||
**A**: 使用 `OperationManager` 进行验证
|
||||
|
||||
```javascript
|
||||
var OperationManager = require('./game/OperationManager.js');
|
||||
|
||||
// 验证出牌操作
|
||||
var validation = OperationManager.validateDiscard(
|
||||
gameState,
|
||||
playerId,
|
||||
tileCode
|
||||
);
|
||||
|
||||
if (!validation.valid) {
|
||||
console.error('操作不合法:', validation.error);
|
||||
return { error: validation.error };
|
||||
}
|
||||
|
||||
// 验证吃牌操作
|
||||
var validation = OperationManager.validateChow(
|
||||
gameState,
|
||||
playerId,
|
||||
tiles
|
||||
);
|
||||
```
|
||||
|
||||
**相关文档**: [04-游戏核心服务.md](../core/04-游戏核心服务.md#operationmanager-操作管理器)
|
||||
|
||||
---
|
||||
|
||||
### Q3: 精牌系统是如何工作的?
|
||||
|
||||
**A**: 精牌系统由 `JingAlgorithm.js` 实现
|
||||
|
||||
```javascript
|
||||
var JingAlgorithm = require('./shared/algorithms/JingAlgorithm.js');
|
||||
|
||||
// 1. 确定精牌
|
||||
var jingInfo = JingAlgorithm.determineJingCards(
|
||||
flippedCard, // 翻开的牌
|
||||
diceResult // 骰子结果
|
||||
);
|
||||
// 返回: { zhengJing: '5m', fuJing: '6m' }
|
||||
|
||||
// 2. 计算精分
|
||||
var jingScore = JingAlgorithm.calculateJingScore(
|
||||
handCards,
|
||||
jingInfo
|
||||
);
|
||||
|
||||
// 3. 检查是否比精
|
||||
var biJingResult = JingAlgorithm.checkBiJing(
|
||||
winnerCards,
|
||||
loserCards,
|
||||
jingInfo
|
||||
);
|
||||
```
|
||||
|
||||
**相关文档**: [05-共享代码模块.md](../core/05-共享代码模块.md#jingalgorithm-精牌算法)
|
||||
|
||||
---
|
||||
|
||||
### Q4: 如何发送消息给客户端?
|
||||
|
||||
**A**: 使用 `import` 接口
|
||||
|
||||
```javascript
|
||||
// 1. 发送给单个玩家
|
||||
room.import.sendToPlayer(playerId, {
|
||||
cmd: 'game_update',
|
||||
data: { /* ... */ }
|
||||
});
|
||||
|
||||
// 2. 广播给所有玩家
|
||||
room.import.broadcast(room, {
|
||||
cmd: 'player_operation',
|
||||
data: { /* ... */ }
|
||||
});
|
||||
|
||||
// 3. 广播给除某玩家外的其他玩家
|
||||
room.import.broadcastExcept(room, excludePlayerId, {
|
||||
cmd: 'player_discard',
|
||||
data: { /* ... */ }
|
||||
});
|
||||
```
|
||||
|
||||
**相关文档**: [02-Import接口说明.md](../framework/02-Import接口说明.md)
|
||||
|
||||
---
|
||||
|
||||
### Q5: gameState 和 room 有什么区别?
|
||||
|
||||
**A**:
|
||||
- **room**: 框架层的房间对象,包含玩家列表、房间配置等
|
||||
- **gameState**: 游戏层的状态对象,包含游戏逻辑相关的数据
|
||||
|
||||
```javascript
|
||||
// room 对象(框架层)
|
||||
room.roomcode // 房间号
|
||||
room.roomtype // 房间配置
|
||||
room.players // 玩家列表(框架格式)
|
||||
|
||||
// gameState 对象(游戏层)
|
||||
room.gameState.phase // 游戏阶段
|
||||
room.gameState.players // 玩家状态(游戏格式)
|
||||
room.gameState.jingInfo // 精牌信息
|
||||
room.gameState.currentPlayer // 当前玩家
|
||||
|
||||
// gameState 保存在 room 对象中
|
||||
// 通过 room.gameState 访问
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Q6: 如何添加错误处理?
|
||||
|
||||
**A**: 使用 `ErrorHandler` 统一处理
|
||||
|
||||
```javascript
|
||||
var ErrorHandler = require('./utils/ErrorHandler.js');
|
||||
|
||||
try {
|
||||
// 可能出错的代码
|
||||
someRiskyOperation();
|
||||
} catch (error) {
|
||||
// 记录错误
|
||||
ErrorHandler.handle(error, {
|
||||
context: 'someRiskyOperation',
|
||||
severity: 'high',
|
||||
playerId: playerId,
|
||||
roomcode: roomcode
|
||||
});
|
||||
|
||||
// 返回错误信息
|
||||
return {
|
||||
success: false,
|
||||
error: 'OPERATION_FAILED',
|
||||
message: error.message
|
||||
};
|
||||
}
|
||||
|
||||
// 查看错误统计
|
||||
var stats = ErrorHandler.getStatistics();
|
||||
console.log('错误分类统计:', stats.byCategory);
|
||||
```
|
||||
|
||||
**相关文档**: [07-工具模块.md](07-工具模块.md#errorhandler-错误处理器)
|
||||
|
||||
---
|
||||
|
||||
### Q7: 如何理解游戏阶段(phase)?
|
||||
|
||||
**A**: 游戏有7个主要阶段
|
||||
|
||||
```javascript
|
||||
// 游戏阶段常量
|
||||
GAME_PHASES = {
|
||||
WAITING: 'waiting', // 等待玩家准备
|
||||
DEALING: 'dealing', // 发牌阶段
|
||||
JING_DETERMINING: 'jing_determining', // 确定精牌
|
||||
PLAYING: 'playing', // 游戏进行中
|
||||
RESPONDING: 'responding', // 等待玩家响应
|
||||
ROUND_END: 'round_end', // 单局结束
|
||||
GAME_END: 'game_end' // 游戏结束
|
||||
};
|
||||
|
||||
// 状态转换示例
|
||||
// WAITING → DEALING → JING_DETERMINING → PLAYING → ROUND_END
|
||||
```
|
||||
|
||||
**相关文档**: [08-游戏流程概述.md](../architecture/08-游戏流程概述.md#游戏状态机)
|
||||
|
||||
---
|
||||
|
||||
### Q8: 如何修改房间配置解析?
|
||||
|
||||
**A**: 修改 `RoomConfigUtils.parse()` 方法
|
||||
|
||||
```javascript
|
||||
// shared/config/RoomConfigUtils.js
|
||||
RoomConfigUtils.parse = function(roomtype) {
|
||||
// roomtype 是13位字符串,例如: "1311111110000"
|
||||
|
||||
// 解析各位配置
|
||||
var config = {
|
||||
roundCount: this._parseRoundCount(roomtype[0]),
|
||||
useJing: roomtype[1] === '1',
|
||||
allowChiPengGang: roomtype[2] === '1',
|
||||
// ...更多配置
|
||||
};
|
||||
|
||||
return config;
|
||||
};
|
||||
```
|
||||
|
||||
**相关文档**: [06-规则配置系统.md](../core/06-规则配置系统.md)
|
||||
|
||||
---
|
||||
|
||||
### Q9: 如何追踪某个牌的来源?
|
||||
|
||||
**A**: 使用 `MahjongCard` 的 `sourceInfo` 属性
|
||||
|
||||
```javascript
|
||||
// 每张牌都有来源信息
|
||||
var card = {
|
||||
code: '3m',
|
||||
uniqueId: 'card_1234567890',
|
||||
sourceInfo: {
|
||||
sourceType: 'dealt', // dealt/drawn/discarded等
|
||||
playerId: 'player1',
|
||||
timestamp: 1234567890,
|
||||
round: 1
|
||||
}
|
||||
};
|
||||
|
||||
// 检查牌的来源
|
||||
if (card.sourceInfo.sourceType === 'dealt') {
|
||||
console.log('这张牌是发牌时获得的');
|
||||
} else if (card.sourceInfo.sourceType === 'drawn') {
|
||||
console.log('这张牌是摸牌时获得的');
|
||||
}
|
||||
```
|
||||
|
||||
**相关文档**: [05-共享代码模块.md](../core/05-共享代码模块.md#mahjongcard-麻将牌对象)
|
||||
|
||||
---
|
||||
|
||||
### Q10: 如何查看所有可用的常量?
|
||||
|
||||
**A**: 查看 `shared/constants/index.js`
|
||||
|
||||
```javascript
|
||||
var Constants = require('./shared/constants/index.js');
|
||||
|
||||
// 12个常量模块
|
||||
console.log(Constants.GameConstants); // 游戏常量
|
||||
console.log(Constants.OperationTypes); // 操作类型
|
||||
console.log(Constants.ErrorMessages); // 错误消息
|
||||
console.log(Constants.RoomConstants); // 房间常量
|
||||
console.log(Constants.ScoreConstants); // 分数常量
|
||||
console.log(Constants.TimeoutConstants); // 超时常量
|
||||
// ... 更多常量模块
|
||||
|
||||
// 使用常量
|
||||
var GAME_PHASES = Constants.GameConstants.GAME_PHASES;
|
||||
var ERROR_INVALID_OPERATION = Constants.ErrorMessages.INVALID_OPERATION;
|
||||
```
|
||||
|
||||
**相关文档**: [06-规则配置系统.md](../core/06-规则配置系统.md#常量系统)
|
||||
|
||||
---
|
||||
|
||||
## 📚 进阶学习资源
|
||||
|
||||
### 完整文档列表
|
||||
|
||||
#### 框架基础
|
||||
1. [00-框架基础概述.md](../framework/00-框架基础概述.md) - 友乐平台架构和ES5规范
|
||||
2. [01-Export接口说明.md](../framework/01-Export接口说明.md) - 框架调用游戏的14个接口
|
||||
3. [02-Import接口说明.md](../framework/02-Import接口说明.md) - 游戏调用框架的13个接口
|
||||
4. [03-RPC处理机制.md](../framework/03-RPC处理机制.md) - 客户端请求处理流程
|
||||
|
||||
#### 核心服务
|
||||
5. [04-游戏核心服务.md](../core/04-游戏核心服务.md) - GameController等5大核心服务
|
||||
6. [05-共享代码模块.md](../core/05-共享代码模块.md) - 精牌算法等核心算法详解
|
||||
7. [06-规则配置系统.md](../core/06-规则配置系统.md) - 房间配置和规则解析
|
||||
|
||||
#### 架构设计
|
||||
8. [08-游戏流程概述.md](../architecture/08-游戏流程概述.md) - 完整游戏流程和状态机
|
||||
9. [09-代码框架总结.md](../architecture/09-代码框架总结.md) - 架构设计和设计模式
|
||||
|
||||
#### 开发工具
|
||||
10. [07-工具模块.md](07-工具模块.md) - Logger和ErrorHandler使用指南
|
||||
|
||||
### 外部参考资料
|
||||
|
||||
- `docs/important/game/进贤麻将规则手册.md` - 完整游戏规则
|
||||
- `docs/important/game/进贤麻将技术设计要点.md` - 技术设计细节
|
||||
- `docs/important/server/服务器子游戏开发要求.md` - 开发规范
|
||||
- `docs/analysis/JingAlgorithm核心算法分析.md` - 精牌算法深度分析
|
||||
|
||||
---
|
||||
|
||||
## 🎯 学习检查清单
|
||||
|
||||
完成以下检查项,确保你已经掌握了基础知识:
|
||||
|
||||
### 基础理解 ✅
|
||||
- [ ] 理解三文件架构(mod.js/export.js/import.js)
|
||||
- [ ] 知道RPC请求的处理流程
|
||||
- [ ] 了解游戏的7个阶段
|
||||
- [ ] 知道gameState对象的结构
|
||||
- [ ] 理解精牌系统的基本概念
|
||||
|
||||
### 代码定位 ✅
|
||||
- [ ] 能快速找到RPC方法的实现位置
|
||||
- [ ] 知道算法文件在哪个目录
|
||||
- [ ] 知道如何查看游戏配置的解析
|
||||
- [ ] 能找到日志和错误处理的工具类
|
||||
|
||||
### 实践能力 ✅
|
||||
- [ ] 能添加一条日志语句
|
||||
- [ ] 能修改一个计分规则
|
||||
- [ ] 能添加一个简单的RPC方法
|
||||
- [ ] 能查看和理解gameState的内容
|
||||
|
||||
### 问题解决 ✅
|
||||
- [ ] 遇到错误知道如何查看日志
|
||||
- [ ] 知道如何验证操作是否合法
|
||||
- [ ] 知道如何发送消息给客户端
|
||||
- [ ] 知道去哪里查找算法实现
|
||||
|
||||
---
|
||||
|
||||
## 💪 实战练习
|
||||
|
||||
### 练习1: 添加一条日志 (难度: ⭐)
|
||||
|
||||
**任务**: 在玩家出牌时添加日志记录
|
||||
|
||||
```javascript
|
||||
// 在 rpc/RpcHandler.js 的 player_discard 方法中
|
||||
RpcHandler.prototype.player_discard = function(pack, room, callback) {
|
||||
var Logger = require('../utils/Logger.js');
|
||||
|
||||
// 添加这行日志
|
||||
Logger.info('玩家出牌', {
|
||||
playerId: pack.playerid,
|
||||
tile: pack.data.tile,
|
||||
roomcode: room.roomcode
|
||||
});
|
||||
|
||||
// ...原有代码
|
||||
};
|
||||
```
|
||||
|
||||
### 练习2: 修改七对分数 (难度: ⭐⭐)
|
||||
|
||||
**任务**: 将有精七对的分数从8分改为10分
|
||||
|
||||
```javascript
|
||||
// 在 shared/algorithms/ScoreCalculation.js 中找到
|
||||
case 'qidui':
|
||||
scores.baseScore = pattern.hasJing ? 8 : 64; // 原来
|
||||
|
||||
// 修改为
|
||||
case 'qidui':
|
||||
scores.baseScore = pattern.hasJing ? 10 : 64; // 修改后
|
||||
```
|
||||
|
||||
### 练习3: 添加操作验证 (难度: ⭐⭐⭐)
|
||||
|
||||
**任务**: 添加一个验证,禁止玩家在特定情况下出某张牌
|
||||
|
||||
```javascript
|
||||
// 在 game/OperationManager.js 中
|
||||
OperationManager.validateDiscard = function(gameState, playerId, tileCode) {
|
||||
// 原有验证...
|
||||
|
||||
// 添加自定义验证
|
||||
if (gameState.rules.specialRules.forbidSpecialCard) {
|
||||
if (tileCode === '1m') { // 禁止出1万
|
||||
return {
|
||||
valid: false,
|
||||
error: 'FORBIDDEN_CARD',
|
||||
message: '当前规则禁止出这张牌'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 快速链接
|
||||
|
||||
### 核心文件直达
|
||||
- [mod.js](../../games2/jinxianmahjong/mod.js) - 模块入口
|
||||
- [export.js](../../games2/jinxianmahjong/export.js) - Export接口
|
||||
- [import.js](../../games2/jinxianmahjong/import.js) - Import接口
|
||||
- [RpcHandler.js](../../games2/jinxianmahjong/rpc/RpcHandler.js) - RPC处理器
|
||||
- [GameController.js](../../games2/jinxianmahjong/game/GameController.js) - 游戏控制器
|
||||
|
||||
### 算法文件直达
|
||||
- [JingAlgorithm.js](../../games2/jinxianmahjong/shared/algorithms/JingAlgorithm.js) - 精牌算法
|
||||
- [WinDetectionFactory.js](../../games2/jinxianmahjong/shared/algorithms/WinDetectionFactory.js) - 胡牌检测
|
||||
- [ScoreCalculation.js](../../games2/jinxianmahjong/shared/algorithms/ScoreCalculation.js) - 计分系统
|
||||
|
||||
### 工具文件直达
|
||||
- [Logger.js](../../games2/jinxianmahjong/utils/Logger.js) - 日志工具
|
||||
- [ErrorHandler.js](../../games2/jinxianmahjong/utils/ErrorHandler.js) - 错误处理
|
||||
|
||||
---
|
||||
|
||||
## 📞 获取帮助
|
||||
|
||||
### 遇到问题时的步骤
|
||||
|
||||
1. **查看日志**: 检查Logger输出,了解程序执行流程
|
||||
2. **查看文档**: 在对应的文档中查找相关说明
|
||||
3. **搜索代码**: 在项目中搜索相关关键词
|
||||
4. **查看示例**: 参考其他类似功能的实现
|
||||
5. **调试代码**: 添加日志语句追踪执行流程
|
||||
|
||||
### 文档导航
|
||||
|
||||
- **概念不清楚** → 查看框架基础文档(00-03)
|
||||
- **不知道怎么实现** → 查看核心服务文档(04-06)
|
||||
- **不理解流程** → 查看游戏流程文档(08)
|
||||
- **想了解设计** → 查看架构总结文档(09)
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**最后更新**: 2025年10月15日
|
||||
**维护者**: 进贤麻将开发团队
|
||||
|
||||
---
|
||||
|
||||
## 🎉 开始你的开发之旅!
|
||||
|
||||
现在你已经掌握了快速入门的所有知识,可以开始实际开发了!
|
||||
|
||||
**建议的第一步**:
|
||||
1. 选择一个感兴趣的功能
|
||||
2. 找到对应的代码位置
|
||||
3. 添加一些日志了解执行流程
|
||||
4. 尝试做一个小修改
|
||||
5. 测试验证你的修改
|
||||
|
||||
**记住**:
|
||||
- 📖 遇到问题先查文档
|
||||
- 🔍 善用搜索找代码
|
||||
- 📝 多写日志帮助理解
|
||||
- 🧪 改完代码记得测试
|
||||
|
||||
祝你开发愉快! 🚀
|
||||
606
codes/games/server/docs/guides/framework/00-框架基础概述.md
Normal file
606
codes/games/server/docs/guides/framework/00-框架基础概述.md
Normal file
@@ -0,0 +1,606 @@
|
||||
# 友乐游戏框架基础概述
|
||||
|
||||
> **文档目标**:帮助开发者理解友乐游戏平台的整体架构、前后端分离机制、模块化设计和基础开发规范。
|
||||
|
||||
## 📚 目录
|
||||
|
||||
1. [友乐游戏平台架构](#1-友乐游戏平台架构)
|
||||
2. [前后端分离部署](#2-前后端分离部署)
|
||||
3. [三文件架构规范](#3-三文件架构规范)
|
||||
4. [模块加载机制](#4-模块加载机制)
|
||||
5. [数据包协议基础](#5-数据包协议基础)
|
||||
6. [开发环境与兼容性](#6-开发环境与兼容性)
|
||||
|
||||
---
|
||||
|
||||
## 1. 友乐游戏平台架构
|
||||
|
||||
### 1.1 整体架构
|
||||
|
||||
友乐游戏平台采用**模块化、可扩展**的架构设计,支持多个子游戏的独立开发和部署。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ 友乐游戏平台(Node.js) │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ 应用层(youle_app) │
|
||||
│ ├─ 房间管理(youle_room) │
|
||||
│ ├─ 玩家管理(youle_player) │
|
||||
│ ├─ 通信服务(youle_socket) │
|
||||
│ └─ 数据存储(youle_database) │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ 游戏模块层(mod_*) │
|
||||
│ ├─ mod_jinxianmahjong(进贤麻将) │
|
||||
│ ├─ mod_other_game1(其他游戏1) │
|
||||
│ └─ mod_other_game2(其他游戏2) │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ 网络层(packet.js) │
|
||||
│ ├─ WebSocket通信 │
|
||||
│ ├─ HTTP通信 │
|
||||
│ └─ RPC路由分发 │
|
||||
└─────────────────────────────────────────────────┘
|
||||
↕ WebSocket/HTTP
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ 客户端(浏览器环境) │
|
||||
│ ├─ 游戏界面渲染 │
|
||||
│ ├─ 用户交互处理 │
|
||||
│ ├─ 本地状态管理 │
|
||||
│ └─ 网络通信封装 │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.2 核心组件
|
||||
|
||||
| 组件名称 | 职责说明 | 部署位置 |
|
||||
|---------|---------|---------|
|
||||
| **youle_app** | 应用级服务提供者,管理所有游戏模块 | 服务端 |
|
||||
| **youle_room** | 房间管理服务,处理房间创建、加入、解散 | 服务端 |
|
||||
| **packet.js** | 数据包路由分发器,实现RPC调用 | 服务端 |
|
||||
| **mod_*(游戏模块)** | 子游戏具体实现,独立封装游戏逻辑 | 服务端 |
|
||||
| **客户端界面** | 游戏前端界面和交互逻辑 | 浏览器 |
|
||||
|
||||
### 1.3 关键设计理念
|
||||
|
||||
1. **模块独立性**:每个游戏模块独立开发、测试、部署
|
||||
2. **接口标准化**:所有游戏模块遵循统一的接口规范
|
||||
3. **双向解耦**:框架和游戏通过export/import接口解耦
|
||||
4. **状态同步**:服务端为权威状态源,客户端被动接收
|
||||
|
||||
---
|
||||
|
||||
## 2. 前后端分离部署
|
||||
|
||||
### 2.1 部署架构
|
||||
|
||||
> ⚠️ **重要**:友乐游戏采用**真正的前后端物理分离**,而非同进程模块调用。
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ 用户浏览器(客户端) │
|
||||
│ 环境:Chrome/Firefox/Safari等浏览器 │
|
||||
│ 语言:JavaScript ES5(不使用Node.js) │
|
||||
│ 部署:静态HTML/JS/CSS文件 │
|
||||
│ 运行:浏览器JavaScript引擎 │
|
||||
└──────────────────────────────────────────────┘
|
||||
↕
|
||||
WebSocket/HTTP协议通信
|
||||
↕
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ 游戏服务器(服务端) │
|
||||
│ 环境:Node.js运行时 │
|
||||
│ 语言:JavaScript ES5 │
|
||||
│ 部署:服务器进程(pm2/systemd等) │
|
||||
│ 运行:Node.js引擎 │
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 前后端通信特点
|
||||
|
||||
#### 客户端特点(浏览器环境)
|
||||
- **运行环境**:运行在用户浏览器中(Chrome、Firefox、Safari等)
|
||||
- **语言规范**:使用原生JavaScript ES5标准,不使用Node.js特性
|
||||
- **部署方式**:作为静态资源部署(HTML、JS、CSS文件)
|
||||
- **模块系统**:不使用npm包管理,不使用require/import
|
||||
- **依赖管理**:通过`<script>`标签按顺序加载
|
||||
|
||||
#### 服务端特点(Node.js环境)
|
||||
- **运行环境**:运行在服务器Node.js进程中
|
||||
- **语言规范**:使用JavaScript ES5,遵循Node.js模块规范
|
||||
- **部署方式**:作为Node.js应用部署
|
||||
- **模块系统**:使用Node.js的`require()`进行模块加载
|
||||
- **依赖管理**:使用npm管理依赖包
|
||||
|
||||
#### 通信机制
|
||||
|
||||
| 特性 | 说明 | 影响 |
|
||||
|-----|------|------|
|
||||
| **物理分离** | 客户端和服务端是完全独立的进程 | 不能直接调用函数,必须通过网络通信 |
|
||||
| **网络通信** | 使用WebSocket/HTTP协议 | 存在网络延迟,需要异步处理 |
|
||||
| **数据序列化** | 所有数据必须JSON序列化 | 不能传递函数、对象引用等 |
|
||||
| **异步交互** | 所有请求都是异步的 | 需要回调或事件机制处理响应 |
|
||||
| **状态同步** | 服务端主动推送状态变化 | 客户端需要维护本地状态副本 |
|
||||
|
||||
### 2.3 代码共享机制
|
||||
|
||||
由于前后端部署环境不同,代码共享通过**文件复制**方式实现:
|
||||
|
||||
```
|
||||
server/games2/jinxianmahjong/shared/
|
||||
├── core/ # 核心算法(前后端共享)
|
||||
│ ├── JingAlgorithm.js # 精牌算法
|
||||
│ ├── HandEvaluator.js # 牌型评估
|
||||
│ └── ScoringEngine.js # 计分引擎
|
||||
├── constants/ # 常量定义(前后端共享)
|
||||
├── dataStructures/ # 数据结构(前后端共享)
|
||||
└── utils/ # 工具函数(前后端共享)
|
||||
|
||||
↓ 文件复制(构建时)↓
|
||||
|
||||
client/js/shared/ # 复制到客户端目录
|
||||
├── core/
|
||||
├── constants/
|
||||
├── dataStructures/
|
||||
└── utils/
|
||||
```
|
||||
|
||||
**共享代码编写要求**:
|
||||
1. **ES5语法**:不使用任何ES6+特性(箭头函数、class、let/const等)
|
||||
2. **无副作用**:纯函数设计,不依赖全局状态
|
||||
3. **环境兼容**:同时兼容浏览器和Node.js环境
|
||||
4. **无依赖**:不依赖Node.js特定API或浏览器特定API
|
||||
|
||||
---
|
||||
|
||||
## 3. 三文件架构规范
|
||||
|
||||
每个子游戏必须遵循**三文件架构规范**:
|
||||
|
||||
### 3.1 架构概览
|
||||
|
||||
```
|
||||
server/games2/jinxianmahjong/
|
||||
├── mod.js # 【1】模块主入口
|
||||
├── export.js # 【2】输出接口(框架→子游戏)
|
||||
└── import.js # 【3】输入接口(子游戏→框架)
|
||||
```
|
||||
|
||||
### 3.2 三个核心文件
|
||||
|
||||
#### 1️⃣ mod.js - 模块主入口
|
||||
|
||||
**职责**:
|
||||
- 创建游戏模块实例
|
||||
- 按顺序加载依赖文件
|
||||
- 初始化模块状态
|
||||
- 定义RPC方法
|
||||
|
||||
**关键代码**:
|
||||
```javascript
|
||||
// 创建模块实例
|
||||
var mod_jinxianmahjong = cls_mod.new(
|
||||
"mod_jinxianmahjong", // 模块名称
|
||||
"jinxianmahjong", // 游戏ID
|
||||
youle_app // 父级应用
|
||||
);
|
||||
|
||||
// 加载依赖(按顺序)
|
||||
require('./export.js'); // 输出接口
|
||||
require('./import.js'); // 输入接口
|
||||
require('./rpc/RpcHandler.js'); // RPC处理器
|
||||
// ... 其他依赖
|
||||
|
||||
// 定义RPC方法
|
||||
mod_jinxianmahjong.player_draw = function(pack) {
|
||||
// 处理玩家摸牌请求
|
||||
};
|
||||
```
|
||||
|
||||
#### 2️⃣ export.js - 输出接口
|
||||
|
||||
**职责**:框架调用子游戏的标准接口
|
||||
|
||||
**必需的8个接口**:
|
||||
1. `get_needroomcard` - 创建房间所需房卡
|
||||
2. `get_asetcount` - 游戏局数
|
||||
3. `get_needroomcard_joinroom` - 加入房间所需房卡
|
||||
4. `makewar` - 开战(游戏开始)
|
||||
5. `get_deskinfo` - 获取牌桌信息(断线重连)
|
||||
6. `get_disbandRoom` - 解散房间
|
||||
7. `player_enter` - 玩家进入
|
||||
8. `player_leave` - 玩家离开
|
||||
|
||||
**实现模式**:
|
||||
```javascript
|
||||
var cls_jinxianmahjong_export = {
|
||||
new: function() {
|
||||
var exp = {};
|
||||
|
||||
exp.get_needroomcard = function(roomtype, o_game_config) {
|
||||
// 根据roomtype返回所需房卡数
|
||||
return 1; // 示例
|
||||
};
|
||||
|
||||
exp.makewar = function(o_room, o_game_config) {
|
||||
// 创建游戏桌对象
|
||||
var o_desk = createDesk(o_room);
|
||||
o_room.o_desk = o_desk;
|
||||
o_desk.o_room = o_room;
|
||||
|
||||
// 返回开战数据包
|
||||
return {
|
||||
app: "youle",
|
||||
route: "jinxianmahjong",
|
||||
rpc: "makewar",
|
||||
data: { /* 开战数据 */ }
|
||||
};
|
||||
};
|
||||
|
||||
// ... 其他6个接口
|
||||
|
||||
return exp;
|
||||
}
|
||||
};
|
||||
|
||||
// 挂载到模块
|
||||
mod_jinxianmahjong.export = cls_jinxianmahjong_export.new();
|
||||
```
|
||||
|
||||
#### 3️⃣ import.js - 输入接口
|
||||
|
||||
**职责**:子游戏调用框架服务
|
||||
|
||||
**核心的4个接口**:
|
||||
1. `check_player` - 验证玩家身份和位置
|
||||
2. `deduct_roomcard` - 扣除房卡
|
||||
3. `save_grade` - 保存游戏成绩
|
||||
4. `finish_gametask` - 完成游戏任务
|
||||
|
||||
**实现模式**:
|
||||
```javascript
|
||||
var cls_jinxianmahjong_import = {
|
||||
new: function() {
|
||||
var imp = {};
|
||||
|
||||
imp.check_player = function(agentid, gameid, roomcode, seat, playerid, conmode, fromid) {
|
||||
// 调用框架验证服务
|
||||
return mod_jinxianmahjong.app.youle_room.export.check_player(
|
||||
agentid, gameid, roomcode, seat, playerid, conmode, fromid
|
||||
);
|
||||
};
|
||||
|
||||
imp.deduct_roomcard = function(o_room) {
|
||||
// ⚠️ 必须在第一小局结算时调用
|
||||
return mod_jinxianmahjong.app.youle_room.export.deduct_roomcard(o_room);
|
||||
};
|
||||
|
||||
imp.save_grade = function(o_room, o_gameinfo1, o_gameinfo2, freeroomflag) {
|
||||
// ⚠️ 必须在大局结束时调用
|
||||
mod_jinxianmahjong.app.youle_room.export.save_grade(
|
||||
o_room, o_gameinfo1, o_gameinfo2, freeroomflag
|
||||
);
|
||||
};
|
||||
|
||||
// ... 其他接口
|
||||
|
||||
return imp;
|
||||
}
|
||||
};
|
||||
|
||||
// 挂载到模块
|
||||
mod_jinxianmahjong.import = cls_jinxianmahjong_import.new();
|
||||
```
|
||||
|
||||
### 3.3 文件加载顺序
|
||||
|
||||
**严格的加载顺序**(不可变更):
|
||||
|
||||
```
|
||||
1. mod.js # 首先加载,创建模块实例
|
||||
↓
|
||||
2. export.js # 加载输出接口
|
||||
↓
|
||||
3. import.js # 加载输入接口
|
||||
↓
|
||||
4. RpcHandler.js # 加载RPC处理器
|
||||
↓
|
||||
5. 其他业务文件 # 加载游戏逻辑
|
||||
```
|
||||
|
||||
**为什么顺序重要**:
|
||||
- `export.js`和`import.js`在模块初始化时就需要
|
||||
- 后续文件可能依赖这两个接口
|
||||
- 错误的顺序会导致`undefined`错误
|
||||
|
||||
---
|
||||
|
||||
## 4. 模块加载机制
|
||||
|
||||
### 4.1 双环境加载支持
|
||||
|
||||
友乐游戏框架支持两种运行环境:
|
||||
|
||||
#### Node.js环境(服务器/测试)
|
||||
```javascript
|
||||
if (typeof require !== 'undefined' && typeof module !== 'undefined') {
|
||||
// Node.js环境:使用require同步加载
|
||||
require('./export.js');
|
||||
require('./import.js');
|
||||
require('./rpc/RpcHandler.js');
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### 友乐平台环境(生产服务器)
|
||||
```javascript
|
||||
else if (typeof min_loadJsFile !== 'undefined') {
|
||||
// 友乐平台:使用min_loadJsFile异步加载
|
||||
min_loadJsFile("games2/jinxianmahjong/export.js", function() {
|
||||
min_loadJsFile("games2/jinxianmahjong/import.js", function() {
|
||||
min_loadJsFile("games2/jinxianmahjong/rpc/RpcHandler.js", function() {
|
||||
// 嵌套回调加载
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 模块初始化
|
||||
|
||||
```javascript
|
||||
function initializeModule() {
|
||||
console.log("[mod_jinxianmahjong] 模块初始化开始");
|
||||
|
||||
// 1. 验证必需接口
|
||||
if (!mod_jinxianmahjong.export) {
|
||||
throw new Error("export接口未加载");
|
||||
}
|
||||
if (!mod_jinxianmahjong.import) {
|
||||
throw new Error("import接口未加载");
|
||||
}
|
||||
|
||||
// 2. 设置就绪状态
|
||||
mod_jinxianmahjong.isReady = true;
|
||||
mod_jinxianmahjong.loadTime = new Date();
|
||||
|
||||
console.log("[mod_jinxianmahjong] ✅ 模块加载完成");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据包协议基础
|
||||
|
||||
### 5.1 统一包结构
|
||||
|
||||
所有数据包必须遵循以下结构:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"app": "youle", // 应用标识(固定为"youle")
|
||||
"route": "jinxianmahjong", // 路由模块名(游戏ID)
|
||||
"rpc": "player_draw", // RPC方法名
|
||||
"data": { // 业务数据
|
||||
"agentid": "agent001",
|
||||
"playerid": 12345,
|
||||
"gameid": "jinxianmahjong",
|
||||
"roomcode": 100001,
|
||||
"seat": 0,
|
||||
// ... 其他业务参数
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 三层路由机制
|
||||
|
||||
```
|
||||
客户端发送数据包
|
||||
↓
|
||||
【1】packet.js(网络层)
|
||||
↓ 根据app字段路由
|
||||
【2】youle_app(应用层)
|
||||
↓ 根据route字段路由
|
||||
【3】mod_jinxianmahjong(模块层)
|
||||
↓ 根据rpc字段调用
|
||||
【4】mod_jinxianmahjong.player_draw(pack)
|
||||
↓
|
||||
执行游戏逻辑
|
||||
```
|
||||
|
||||
**路由过程**:
|
||||
1. **packet.js**:接收网络数据包,解析app字段
|
||||
2. **youle_app**:根据route字段找到对应游戏模块
|
||||
3. **mod_jinxianmahjong**:根据rpc字段调用对应方法
|
||||
4. **RPC方法**:执行具体游戏逻辑
|
||||
|
||||
### 5.3 RPC方法标准模板
|
||||
|
||||
```javascript
|
||||
mod_jinxianmahjong.player_draw = function(pack) {
|
||||
// 1. 提取参数
|
||||
var agentid = pack.data.agentid;
|
||||
var playerid = parseInt(pack.data.playerid);
|
||||
var gameid = pack.data.gameid;
|
||||
var roomcode = parseInt(pack.data.roomcode);
|
||||
var seat = parseInt(pack.data.seat);
|
||||
|
||||
// 2. 验证玩家(必须)
|
||||
var o_room = mod_jinxianmahjong.import.check_player(
|
||||
agentid, gameid, roomcode, seat, playerid,
|
||||
pack.conmode, pack.fromid
|
||||
);
|
||||
if (!o_room) {
|
||||
return; // 验证失败
|
||||
}
|
||||
|
||||
// 3. 获取游戏桌对象
|
||||
var o_desk = o_room.o_desk;
|
||||
|
||||
// 4. 执行业务逻辑
|
||||
var result = o_desk.gameService.playerDraw(seat);
|
||||
|
||||
// 5. 构造响应包
|
||||
var msg = {
|
||||
app: "youle",
|
||||
route: "jinxianmahjong",
|
||||
rpc: "player_draw_result",
|
||||
data: {
|
||||
seat: seat,
|
||||
card: result.card,
|
||||
// ...
|
||||
}
|
||||
};
|
||||
|
||||
// 6. 发送响应
|
||||
o_room.method.sendpack_toall(msg);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 开发环境与兼容性
|
||||
|
||||
### 6.1 ES5语法规范
|
||||
|
||||
**必须遵循ES5语法**,不使用任何ES6+特性:
|
||||
|
||||
✅ **允许使用**:
|
||||
```javascript
|
||||
// 函数声明
|
||||
function myFunction() { }
|
||||
|
||||
// 变量声明
|
||||
var myVar = 123;
|
||||
|
||||
// 对象字面量
|
||||
var obj = {
|
||||
key: 'value',
|
||||
method: function() { }
|
||||
};
|
||||
|
||||
// 数组操作
|
||||
var arr = [1, 2, 3];
|
||||
arr.push(4);
|
||||
arr.forEach(function(item) { });
|
||||
|
||||
// 原型继承
|
||||
function MyClass() { }
|
||||
MyClass.prototype.method = function() { };
|
||||
```
|
||||
|
||||
❌ **禁止使用**:
|
||||
```javascript
|
||||
// 箭头函数(ES6)
|
||||
const func = () => { };
|
||||
|
||||
// let/const(ES6)
|
||||
let myVar = 123;
|
||||
const MY_CONST = 456;
|
||||
|
||||
// 类语法(ES6)
|
||||
class MyClass { }
|
||||
|
||||
// 模板字符串(ES6)
|
||||
var str = `Hello ${name}`;
|
||||
|
||||
// 解构赋值(ES6)
|
||||
var {x, y} = point;
|
||||
|
||||
// async/await(ES7)
|
||||
async function func() { }
|
||||
```
|
||||
|
||||
### 6.2 环境检测
|
||||
|
||||
```javascript
|
||||
// 检测Node.js环境
|
||||
if (typeof require !== 'undefined' && typeof module !== 'undefined') {
|
||||
// Node.js环境
|
||||
}
|
||||
|
||||
// 检测浏览器环境
|
||||
if (typeof window !== 'undefined') {
|
||||
// 浏览器环境
|
||||
}
|
||||
|
||||
// 检测友乐平台环境
|
||||
if (typeof min_loadJsFile !== 'undefined') {
|
||||
// 友乐平台环境
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 兼容性要求
|
||||
|
||||
| 特性 | Node.js环境 | 浏览器环境 | 要求 |
|
||||
|-----|------------|-----------|------|
|
||||
| **语法** | ES5 | ES5 | 不使用ES6+特性 |
|
||||
| **模块系统** | require() | `<script>`标签 | 双环境兼容 |
|
||||
| **全局对象** | global | window | 使用条件判断 |
|
||||
| **文件系统** | fs模块 | ❌ 不可用 | 共享代码不能依赖 |
|
||||
| **DOM API** | ❌ 不可用 | document等 | 共享代码不能依赖 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 关键概念总结
|
||||
|
||||
### 7.1 核心术语
|
||||
|
||||
| 术语 | 含义 | 重要性 |
|
||||
|-----|------|-------|
|
||||
| **mod** | 游戏模块实例(如mod_jinxianmahjong) | ⭐⭐⭐⭐⭐ |
|
||||
| **export** | 框架调用子游戏的接口集合 | ⭐⭐⭐⭐⭐ |
|
||||
| **import** | 子游戏调用框架的接口集合 | ⭐⭐⭐⭐⭐ |
|
||||
| **RPC** | 远程过程调用,客户端调用服务端方法 | ⭐⭐⭐⭐⭐ |
|
||||
| **o_room** | 房间对象,管理房间状态和玩家 | ⭐⭐⭐⭐ |
|
||||
| **o_desk** | 游戏桌对象,管理具体游戏状态 | ⭐⭐⭐⭐ |
|
||||
| **roomtype** | 房间类型配置数组(局数、玩法等) | ⭐⭐⭐ |
|
||||
| **pack** | 数据包对象,包含app、route、rpc、data | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
### 7.2 开发要点
|
||||
|
||||
1. **严格遵循三文件架构**:mod.js、export.js、import.js
|
||||
2. **加载顺序不可变更**:export → import → 其他文件
|
||||
3. **使用ES5语法**:确保浏览器和Node.js双环境兼容
|
||||
4. **理解前后端分离**:通过网络通信,不是函数调用
|
||||
5. **掌握RPC机制**:packet.js → app → mod → RPC方法
|
||||
6. **注意调用时机**:deduct_roomcard(第一局结算)、save_grade(大局结束)
|
||||
|
||||
---
|
||||
|
||||
## 8. 相关文档
|
||||
|
||||
- [01-Export接口说明](./01-Export接口说明.md) - 详细的8个必需接口说明
|
||||
- [02-Import接口说明](./02-Import接口说明.md) - 详细的4个框架服务接口
|
||||
- [03-RPC处理机制](./03-RPC处理机制.md) - RPC路由和处理流程
|
||||
- [08-游戏流程概述](../architecture/08-游戏流程概述.md) - 完整游戏流程说明
|
||||
|
||||
---
|
||||
|
||||
## 9. 快速上手
|
||||
|
||||
### 9.1 创建新游戏模块的步骤
|
||||
|
||||
1. **创建游戏目录**:`server/games2/yourgame/`
|
||||
2. **创建mod.js**:定义模块实例和RPC方法
|
||||
3. **创建export.js**:实现8个必需接口
|
||||
4. **创建import.js**:封装4个框架接口
|
||||
5. **创建RPC处理器**:处理客户端请求
|
||||
6. **创建游戏逻辑**:实现具体游戏功能
|
||||
7. **测试验证**:确保接口正确调用
|
||||
|
||||
### 9.2 常见问题
|
||||
|
||||
**Q: export和import的区别?**
|
||||
A: export是框架调用子游戏(框架→游戏),import是子游戏调用框架(游戏→框架)。
|
||||
|
||||
**Q: 为什么必须使用ES5语法?**
|
||||
A: 客户端部署在浏览器中,需要兼容老版本浏览器。ES5语法兼容性最好。
|
||||
|
||||
**Q: 什么时候调用deduct_roomcard?**
|
||||
A: 必须在第一小局结算时调用,不是开战时。
|
||||
|
||||
**Q: o_room和o_desk的关系?**
|
||||
A: o_room是房间对象(框架管理),o_desk是游戏桌对象(子游戏管理),通过`o_room.o_desk`关联。
|
||||
|
||||
---
|
||||
|
||||
**下一步**:阅读[01-Export接口说明](./01-Export接口说明.md)了解8个必需接口的详细实现。
|
||||
1097
codes/games/server/docs/guides/framework/01-Export接口说明.md
Normal file
1097
codes/games/server/docs/guides/framework/01-Export接口说明.md
Normal file
File diff suppressed because it is too large
Load Diff
1160
codes/games/server/docs/guides/framework/02-Import接口说明.md
Normal file
1160
codes/games/server/docs/guides/framework/02-Import接口说明.md
Normal file
File diff suppressed because it is too large
Load Diff
894
codes/games/server/docs/guides/framework/03-RPC处理机制.md
Normal file
894
codes/games/server/docs/guides/framework/03-RPC处理机制.md
Normal file
@@ -0,0 +1,894 @@
|
||||
# RPC处理机制详解
|
||||
|
||||
> **文档目标**:详细说明进贤麻将的RPC请求处理流程,包括RpcHandler、OperationEnumerator、AIRpcHandler的功能和使用方法。
|
||||
|
||||
## 📚 目录
|
||||
|
||||
1. [RPC机制概述](#1-rpc机制概述)
|
||||
2. [RpcHandler - RPC请求处理器](#2-rpchandler---rpc请求处理器)
|
||||
3. [OperationEnumerator - 操作列举器](#3-operationenumerator---操作列举器)
|
||||
4. [AIRpcHandler - AI玩家处理器](#4-airpchandler---ai玩家处理器)
|
||||
5. [RPC处理标准流程](#5-rpc处理标准流程)
|
||||
6. [数据包构建规范](#6-数据包构建规范)
|
||||
7. [实现示例](#7-实现示例)
|
||||
|
||||
---
|
||||
|
||||
## 1. RPC机制概述
|
||||
|
||||
### 1.1 什么是RPC
|
||||
|
||||
**RPC (Remote Procedure Call)** 是远程过程调用,允许客户端通过网络调用服务端的方法。
|
||||
|
||||
在友乐游戏框架中:
|
||||
```
|
||||
客户端(浏览器) 服务端(Node.js)
|
||||
│ │
|
||||
│ WebSocket/HTTP │
|
||||
│ ────────────────────────> │
|
||||
│ {app, route, rpc, data} │
|
||||
│ │
|
||||
│ packet.js
|
||||
│ ↓
|
||||
│ youle_app
|
||||
│ ↓
|
||||
│ mod_jinxianmahjong
|
||||
│ ↓
|
||||
│ mod_jinxianmahjong.player_discard(pack)
|
||||
│ ↓
|
||||
│ 处理业务逻辑
|
||||
│ ↓
|
||||
│ <────────────────────────│
|
||||
│ 响应数据包 │
|
||||
```
|
||||
|
||||
### 1.2 三层路由机制
|
||||
|
||||
```
|
||||
【第1层】packet.js - 网络层
|
||||
↓ 根据app字段路由
|
||||
【第2层】youle_app - 应用层
|
||||
↓ 根据route字段路由
|
||||
【第3层】mod_jinxianmahjong - 模块层
|
||||
↓ 根据rpc字段调用
|
||||
【执行】RPC方法执行
|
||||
```
|
||||
|
||||
**示例数据包**:
|
||||
```javascript
|
||||
{
|
||||
"app": "youle", // 应用标识 → 路由到youle_app
|
||||
"route": "jinxianmahjong", // 模块标识 → 路由到mod_jinxianmahjong
|
||||
"rpc": "player_discard", // 方法名 → 调用mod_jinxianmahjong.player_discard()
|
||||
"data": { // 业务数据
|
||||
"agentid": "agent001",
|
||||
"playerid": 12345,
|
||||
"gameid": "jinxianmahjong",
|
||||
"roomcode": 100001,
|
||||
"seat": 0,
|
||||
"cardUniqueId": 45
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 进贤麻将RPC架构
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ mod.js (RPC定义) │
|
||||
│ - 定义所有RPC方法 │
|
||||
│ - mod_jinxianmahjong.player_discard │
|
||||
│ - mod_jinxianmahjong.player_peng │
|
||||
│ - mod_jinxianmahjong.player_gang │
|
||||
│ - ... │
|
||||
└───────────────┬────────────────────────┘
|
||||
│ 调用
|
||||
┌───────────────▼────────────────────────┐
|
||||
│ RpcHandler.js │
|
||||
│ - 处理RPC请求 │
|
||||
│ - 参数提取和验证 │
|
||||
│ - 调用业戏控制器 │
|
||||
│ - 构建响应数据包 │
|
||||
└───────────────┬────────────────────────┘
|
||||
│ 委托
|
||||
┌───────────────▼────────────────────────┐
|
||||
│ GameController / OperationManager │
|
||||
│ - 游戏逻辑控制 │
|
||||
│ - 状态管理 │
|
||||
│ - 操作验证 │
|
||||
└───────────────┬────────────────────────┘
|
||||
│ 发包
|
||||
┌───────────────▼────────────────────────┐
|
||||
│ o_room.method.sendpack_* │
|
||||
│ - sendpack_toall() │
|
||||
│ - sendpack_toseat() │
|
||||
│ - sendpack_toother() │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. RpcHandler - RPC请求处理器
|
||||
|
||||
### 2.1 RpcHandler的职责
|
||||
|
||||
RpcHandler是进贤麻将的**核心RPC处理模块**,负责:
|
||||
|
||||
1. **接收和解析RPC请求**:提取参数、验证格式
|
||||
2. **玩家身份验证**:调用`check_player`验证玩家
|
||||
3. **委托业务逻辑**:调用GameController或OperationManager
|
||||
4. **构建响应数据**:按"一包多信息"原则构建响应
|
||||
5. **发送响应**:调用发包接口推送给客户端
|
||||
6. **错误处理**:统一的错误处理和日志记录
|
||||
|
||||
### 2.2 主要RPC方法
|
||||
|
||||
进贤麻将实现的核心RPC方法:
|
||||
|
||||
| RPC方法 | 对应操作 | 说明 |
|
||||
|--------|---------|------|
|
||||
| `handlePlayCard` | 出牌 | 玩家打出一张手牌 |
|
||||
| `handleDeclarePeng` | 碰牌 | 玩家碰别人打出的牌 |
|
||||
| `handleDeclareGang` | 杠牌 | 玩家杠牌(明杠/暗杠/加杠) |
|
||||
| `handleDeclareHu` | 胡牌 | 玩家胡牌(自摸/点炮) |
|
||||
| `handlePass` | 过牌 | 玩家放弃吃碰杠胡机会 |
|
||||
| `handleReady` | 准备 | 玩家准备开始游戏 |
|
||||
| `getGameState` | 获取状态 | 获取当前游戏状态 |
|
||||
|
||||
### 2.3 RPC方法标准结构
|
||||
|
||||
每个RPC方法遵循统一的处理流程:
|
||||
|
||||
```javascript
|
||||
handlePlayCard: function(pack) {
|
||||
try {
|
||||
// ===== 第1步:提取参数 =====
|
||||
var agentid = pack.data.agentid;
|
||||
var playerid = parseInt(pack.data.playerid);
|
||||
var gameid = pack.data.gameid;
|
||||
var roomcode = pack.data.roomcode;
|
||||
var seat = parseInt(pack.data.seat);
|
||||
var cardUniqueId = parseInt(pack.data.cardUniqueId);
|
||||
|
||||
console.log('[RpcHandler.playCard] 开始处理出牌请求:', {
|
||||
playerid, seat, cardUniqueId
|
||||
});
|
||||
|
||||
// ===== 第2步:验证玩家 =====
|
||||
var o_room = mod_jinxianmahjong.import.check_player(
|
||||
agentid, gameid, roomcode, seat, playerid,
|
||||
pack.conmode, pack.fromid
|
||||
);
|
||||
|
||||
if (!o_room) {
|
||||
console.error('[RpcHandler.playCard] 玩家验证失败');
|
||||
return { success: false, error: "玩家验证失败" };
|
||||
}
|
||||
|
||||
// ===== 第3步:获取游戏对象 =====
|
||||
var o_desk = o_room.o_desk;
|
||||
if (!o_desk) {
|
||||
console.error('[RpcHandler.playCard] 游戏桌不存在');
|
||||
this.sendErrorResponse(o_room, seat, 500, "游戏桌不存在");
|
||||
return { success: false, error: "游戏桌不存在" };
|
||||
}
|
||||
|
||||
// ===== 第4步:记录收包(调试) =====
|
||||
if (o_desk.debug && typeof o_desk.debug.save_receivepack === 'function') {
|
||||
o_desk.debug.save_receivepack(pack, seat, playerid);
|
||||
}
|
||||
|
||||
// ===== 第5步:委托业务逻辑 =====
|
||||
var operationRequest = {
|
||||
operation: "discard_card",
|
||||
playerSeat: seat,
|
||||
uniqueId: cardUniqueId,
|
||||
requestId: this._generateRequestId(),
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
var operationResult = OperationManager.handleOperation(o_room, operationRequest);
|
||||
|
||||
// ===== 第6步:处理结果 =====
|
||||
if (operationResult.success) {
|
||||
// 构建响应数据包
|
||||
var responseData = this._buildPlayCardResponse(o_room, seat, cardUniqueId, operationResult);
|
||||
|
||||
// 发送响应
|
||||
this._sendResponse(o_room, seat, responseData);
|
||||
|
||||
return { success: true };
|
||||
} else {
|
||||
// 操作失败,发送错误
|
||||
this.sendErrorResponse(o_room, seat, 400, operationResult.error);
|
||||
return { success: false, error: operationResult.error };
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[RpcHandler.playCard] 处理失败:', error);
|
||||
this.sendErrorResponse(o_room, seat, 500, "服务器内部错误");
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 "一包多信息"原则
|
||||
|
||||
RpcHandler遵循友乐平台的**"一包多信息"设计原则**:
|
||||
|
||||
**原则说明**:
|
||||
- 单个响应包包含**完整的状态更新信息**
|
||||
- 减少网络请求次数
|
||||
- 确保客户端状态同步
|
||||
|
||||
**示例**:出牌响应包包含
|
||||
```javascript
|
||||
{
|
||||
status: 200,
|
||||
seat: 0, // 出牌玩家
|
||||
discardedCard: {...}, // 打出的牌
|
||||
gameState: { // 游戏状态更新
|
||||
currentPlayer: 1,
|
||||
remainingCards: 52,
|
||||
phase: "playing"
|
||||
},
|
||||
playerActions: { // 其他玩家可执行操作
|
||||
1: {
|
||||
availableActions: ["peng", "gang", "hu"],
|
||||
pengResult: {...}, // 碰牌详情
|
||||
gangResult: {...}, // 杠牌详情
|
||||
huResult: {...}, // 胡牌详情
|
||||
timeout: 10000
|
||||
},
|
||||
2: {
|
||||
availableActions: ["hu"],
|
||||
huResult: {...},
|
||||
timeout: 10000
|
||||
}
|
||||
},
|
||||
autoDrawCard: null, // 是否自动摸牌
|
||||
waitingForResponse: true // 是否等待响应
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 分层推送机制
|
||||
|
||||
RpcHandler实现**分层推送**,为不同玩家定制不同的信息:
|
||||
|
||||
```javascript
|
||||
// 1. 给操作玩家:包含完整信息
|
||||
var dataForPlayer = {
|
||||
status: 200,
|
||||
seat: 0,
|
||||
myHandCards: [...], // 我的手牌(完整)
|
||||
discardedCard: {...},
|
||||
gameState: {...}
|
||||
};
|
||||
o_room.method.sendpack_toseat(dataForPlayer, 0);
|
||||
|
||||
// 2. 给其他玩家:隐藏私密信息
|
||||
var dataForOthers = {
|
||||
status: 200,
|
||||
seat: 0,
|
||||
handCardCount: 13, // 只显示数量,不显示具体牌
|
||||
discardedCard: {...},
|
||||
gameState: {...}
|
||||
};
|
||||
o_room.method.sendpack_toother(dataForOthers, 0);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. OperationEnumerator - 操作列举器
|
||||
|
||||
### 3.1 OperationEnumerator的职责
|
||||
|
||||
OperationEnumerator负责**生成玩家可执行的所有操作选项**:
|
||||
|
||||
1. **枚举所有可能操作**:出牌、吃、碰、杠、胡、过
|
||||
2. **计算操作参数**:每个操作需要的牌、组合等
|
||||
3. **生成choiceIndex**:为每个操作分配索引
|
||||
4. **验证操作合法性**:确保操作符合规则
|
||||
|
||||
### 3.2 操作类型
|
||||
|
||||
```javascript
|
||||
var operationTypes = {
|
||||
discard: [], // 出牌操作
|
||||
chi: [], // 吃牌操作
|
||||
peng: [], // 碰牌操作
|
||||
gang: [], // 杠牌操作(明杠、暗杠、加杠)
|
||||
hu: [], // 胡牌操作
|
||||
pass: [] // 过牌操作
|
||||
};
|
||||
```
|
||||
|
||||
### 3.3 核心方法
|
||||
|
||||
#### generateAvailableOperations
|
||||
|
||||
生成完整的可执行操作列表:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 为指定玩家生成完整的可执行操作列表
|
||||
* @param {Object} gameState - 当前游戏状态
|
||||
* @param {number} seat - 玩家座位号
|
||||
* @param {Object} context - 上下文信息
|
||||
* @returns {Object} 完整的操作列表
|
||||
*/
|
||||
generateAvailableOperations(gameState, seat, context = {}) {
|
||||
var operations = {
|
||||
discard: [],
|
||||
chi: [],
|
||||
peng: [],
|
||||
gang: [],
|
||||
hu: [],
|
||||
pass: []
|
||||
};
|
||||
|
||||
try {
|
||||
// 1. 生成出牌操作
|
||||
operations.discard = this.generateDiscardActions(gameState, seat);
|
||||
|
||||
// 2. 如果有刚出的牌,检查吃碰杠胡操作
|
||||
if (context.lastDiscardCard) {
|
||||
operations.chi = this.generateChiActions(gameState, seat, context.lastDiscardCard);
|
||||
operations.peng = this.generatePengActions(gameState, seat, context.lastDiscardCard);
|
||||
operations.gang = this.generateMingGangActions(gameState, seat, context.lastDiscardCard);
|
||||
operations.hu = this.generateHuActions(gameState, seat, context.lastDiscardCard, "discard");
|
||||
}
|
||||
|
||||
// 3. 检查自摸杠牌和胡牌
|
||||
if (context.justDrawCard) {
|
||||
operations.gang = operations.gang.concat(this.generateAnGangActions(gameState, seat));
|
||||
operations.gang = operations.gang.concat(this.generateJiaGangActions(gameState, seat));
|
||||
operations.hu = operations.hu.concat(this.generateHuActions(gameState, seat, context.justDrawCard, "draw"));
|
||||
}
|
||||
|
||||
// 4. 生成过牌操作
|
||||
if (this.hasNonDiscardOperations(operations)) {
|
||||
operations.pass = this.generatePassAction();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[OperationEnumerator] 生成操作列表时出错:', error);
|
||||
}
|
||||
|
||||
return operations;
|
||||
}
|
||||
```
|
||||
|
||||
#### generateDiscardActions
|
||||
|
||||
生成出牌操作:
|
||||
|
||||
```javascript
|
||||
generateDiscardActions(gameState, seat) {
|
||||
if (!gameState.playerHands || !gameState.playerHands[seat]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var handCards = gameState.playerHands[seat];
|
||||
var allowedCards = [];
|
||||
|
||||
// 获取所有手牌的uniqueId
|
||||
for (var i = 0; i < handCards.length; i++) {
|
||||
if (handCards[i] && handCards[i].uniqueId) {
|
||||
allowedCards.push(handCards[i].uniqueId);
|
||||
}
|
||||
}
|
||||
|
||||
return [{
|
||||
choiceIndex: 0,
|
||||
operationType: "discard",
|
||||
allowedCards: allowedCards,
|
||||
description: "出牌操作"
|
||||
}];
|
||||
}
|
||||
```
|
||||
|
||||
#### generatePengActions
|
||||
|
||||
生成碰牌操作:
|
||||
|
||||
```javascript
|
||||
generatePengActions(gameState, seat, sourceCard, fromSeat) {
|
||||
var pengActions = [];
|
||||
|
||||
if (!gameState.playerHands || !gameState.playerHands[seat] || !sourceCard) {
|
||||
return pengActions;
|
||||
}
|
||||
|
||||
var handCards = gameState.playerHands[seat];
|
||||
var sourceCode = sourceCard.code || sourceCard;
|
||||
|
||||
// 检查手牌中是否有至少2张相同的牌
|
||||
var sameCards = this.findSameCards(handCards, sourceCode, 2);
|
||||
|
||||
if (sameCards.length >= 2) {
|
||||
pengActions.push({
|
||||
choiceIndex: 0,
|
||||
operationType: "peng",
|
||||
sourceCard: {
|
||||
uniqueId: sourceCard.uniqueId,
|
||||
code: sourceCode,
|
||||
fromSeat: fromSeat
|
||||
},
|
||||
requiredCards: sameCards.slice(0, 2),
|
||||
description: "碰" + this.getCardName(sourceCode)
|
||||
});
|
||||
}
|
||||
|
||||
return pengActions;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 choiceIndex机制
|
||||
|
||||
**choiceIndex**是操作选择的索引,用于客户端选择和服务端执行:
|
||||
|
||||
```javascript
|
||||
// 服务端生成操作列表
|
||||
var operations = OperationEnumerator.generateAvailableOperations(gameState, seat, context);
|
||||
|
||||
// 示例输出
|
||||
{
|
||||
peng: [
|
||||
{ choiceIndex: 0, operationType: "peng", ... }, // 碰1万
|
||||
],
|
||||
gang: [
|
||||
{ choiceIndex: 0, operationType: "gang", gangType: "angang", ... }, // 暗杠2万
|
||||
{ choiceIndex: 1, operationType: "gang", gangType: "jiagang", ... } // 加杠3万
|
||||
],
|
||||
hu: [
|
||||
{ choiceIndex: 0, operationType: "hu", huType: "zimo", ... }
|
||||
]
|
||||
}
|
||||
|
||||
// 客户端选择操作,发送choiceIndex
|
||||
// 例如:选择加杠操作(choiceIndex=1)
|
||||
var request = {
|
||||
operation: "gang",
|
||||
choiceIndex: 1, // 选择第2个杠牌操作
|
||||
// ...
|
||||
};
|
||||
|
||||
// 服务端根据choiceIndex执行对应操作
|
||||
var selectedOperation = operations.gang[choiceIndex];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. AIRpcHandler - AI玩家处理器
|
||||
|
||||
### 4.1 AIRpcHandler的职责
|
||||
|
||||
AIRpcHandler处理**AI玩家的自动操作**:
|
||||
|
||||
1. **AI决策**:根据游戏状态做出决策
|
||||
2. **自动操作**:自动出牌、吃碰杠胡
|
||||
3. **延时模拟**:模拟人类玩家的思考时间
|
||||
4. **策略选择**:根据难度选择不同策略
|
||||
|
||||
### 4.2 AI决策流程
|
||||
|
||||
```javascript
|
||||
// AI玩家轮到操作
|
||||
AIRpcHandler.handleAITurn(o_room, aiSeat) {
|
||||
// 1. 获取可执行操作
|
||||
var operations = OperationEnumerator.generateAvailableOperations(
|
||||
gameState, aiSeat, context
|
||||
);
|
||||
|
||||
// 2. AI决策
|
||||
var decision = AIStrategy.makeDecision(gameState, aiSeat, operations);
|
||||
|
||||
// 3. 延时模拟思考
|
||||
setTimeout(function() {
|
||||
// 4. 执行AI操作
|
||||
if (decision.operation === "discard") {
|
||||
AIRpcHandler.executeAIDiscard(o_room, aiSeat, decision.cardUniqueId);
|
||||
} else if (decision.operation === "peng") {
|
||||
AIRpcHandler.executeAIPeng(o_room, aiSeat, decision);
|
||||
}
|
||||
// ...
|
||||
}, decision.thinkingTime);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 AI策略
|
||||
|
||||
```javascript
|
||||
// 简单策略示例
|
||||
AIStrategy.makeDecision = function(gameState, seat, operations) {
|
||||
// 优先级:胡 > 杠 > 碰 > 吃 > 出牌
|
||||
|
||||
if (operations.hu.length > 0) {
|
||||
return { operation: "hu", choiceIndex: 0 };
|
||||
}
|
||||
|
||||
if (operations.gang.length > 0) {
|
||||
return { operation: "gang", choiceIndex: 0 };
|
||||
}
|
||||
|
||||
if (operations.peng.length > 0) {
|
||||
return { operation: "peng", choiceIndex: 0 };
|
||||
}
|
||||
|
||||
// 默认出牌:出最不需要的牌
|
||||
var cardToDiscard = this.selectCardToDiscard(gameState, seat);
|
||||
return {
|
||||
operation: "discard",
|
||||
cardUniqueId: cardToDiscard.uniqueId
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. RPC处理标准流程
|
||||
|
||||
### 5.1 完整RPC处理流程图
|
||||
|
||||
```
|
||||
客户端发送请求
|
||||
↓
|
||||
【1】packet.js接收
|
||||
↓
|
||||
【2】youle_app路由
|
||||
↓
|
||||
【3】mod_jinxianmahjong路由
|
||||
↓
|
||||
【4】RPC方法(如player_discard)
|
||||
↓
|
||||
【5】RpcHandler.handlePlayCard
|
||||
├─ 提取参数
|
||||
├─ check_player验证
|
||||
├─ 记录收包
|
||||
└─ 委托OperationManager
|
||||
↓
|
||||
【6】OperationManager.handleOperation
|
||||
├─ 验证操作合法性
|
||||
├─ 执行游戏逻辑
|
||||
├─ 更新游戏状态
|
||||
└─ 返回结果
|
||||
↓
|
||||
【7】RpcHandler构建响应
|
||||
├─ 基础响应数据
|
||||
├─ 检查其他玩家操作机会
|
||||
├─ 添加操作提示
|
||||
└─ 构建完整响应包
|
||||
↓
|
||||
【8】发送响应
|
||||
├─ sendpack_toseat(给操作玩家)
|
||||
├─ sendpack_toother(给其他玩家)
|
||||
└─ sendpack_toall(广播给所有人)
|
||||
↓
|
||||
客户端接收响应
|
||||
├─ 更新本地状态
|
||||
├─ 播放动画
|
||||
└─ 显示界面
|
||||
```
|
||||
|
||||
### 5.2 标准RPC方法实现模板
|
||||
|
||||
```javascript
|
||||
// 在mod.js中定义RPC方法
|
||||
mod_jinxianmahjong.player_discard = function(pack) {
|
||||
return RpcHandler.handlePlayCard(pack);
|
||||
};
|
||||
|
||||
mod_jinxianmahjong.player_peng = function(pack) {
|
||||
return RpcHandler.handleDeclarePeng(pack);
|
||||
};
|
||||
|
||||
mod_jinxianmahjong.player_gang = function(pack) {
|
||||
return RpcHandler.handleDeclareGang(pack);
|
||||
};
|
||||
|
||||
mod_jinxianmahjong.player_hu = function(pack) {
|
||||
return RpcHandler.handleDeclareHu(pack);
|
||||
};
|
||||
|
||||
mod_jinxianmahjong.player_pass = function(pack) {
|
||||
return RpcHandler.handlePass(pack);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 数据包构建规范
|
||||
|
||||
### 6.1 响应包标准结构
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 200, // HTTP状态码风格
|
||||
message: "操作成功", // 消息说明
|
||||
data: { // 业务数据
|
||||
// 具体业务数据
|
||||
},
|
||||
timestamp: 1234567890 // 时间戳
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 错误响应结构
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 400, // 错误状态码
|
||||
error: "操作失败", // 错误消息
|
||||
code: "INVALID_OPERATION", // 错误码
|
||||
details: "详细错误信息", // 详细说明
|
||||
timestamp: 1234567890
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 状态码规范
|
||||
|
||||
| 状态码 | 含义 | 使用场景 |
|
||||
|-------|------|---------|
|
||||
| 200 | 成功 | 操作执行成功 |
|
||||
| 400 | 请求错误 | 参数错误、操作不合法 |
|
||||
| 401 | 未授权 | 玩家验证失败 |
|
||||
| 403 | 禁止操作 | 不是当前玩家的回合 |
|
||||
| 404 | 未找到 | 房间或玩家不存在 |
|
||||
| 500 | 服务器错误 | 内部错误 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 实现示例
|
||||
|
||||
### 7.1 完整的出牌RPC实现
|
||||
|
||||
```javascript
|
||||
// mod.js - 定义RPC方法
|
||||
mod_jinxianmahjong.player_discard = function(pack) {
|
||||
return RpcHandler.handlePlayCard(pack);
|
||||
};
|
||||
|
||||
// RpcHandler.js - 实现处理逻辑
|
||||
RpcHandler.handlePlayCard = function(pack) {
|
||||
try {
|
||||
// 1. 提取和验证参数
|
||||
var params = this._extractParams(pack);
|
||||
if (!params.valid) {
|
||||
return { success: false, error: params.error };
|
||||
}
|
||||
|
||||
// 2. 验证玩家
|
||||
var o_room = mod_jinxianmahjong.import.check_player(
|
||||
params.agentid, params.gameid, params.roomcode,
|
||||
params.seat, params.playerid, pack.conmode, pack.fromid
|
||||
);
|
||||
|
||||
if (!o_room) {
|
||||
return { success: false, error: "玩家验证失败" };
|
||||
}
|
||||
|
||||
// 3. 执行出牌操作
|
||||
var result = OperationManager.handleOperation(o_room, {
|
||||
operation: "discard_card",
|
||||
playerSeat: params.seat,
|
||||
uniqueId: params.cardUniqueId
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
this.sendErrorResponse(o_room, params.seat, 400, result.error);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 4. 构建响应数据
|
||||
var responseData = this._buildPlayCardResponse(o_room, params.seat, result);
|
||||
|
||||
// 5. 发送响应
|
||||
this._sendLayeredResponse(o_room, params.seat, responseData);
|
||||
|
||||
return { success: true };
|
||||
|
||||
} catch (error) {
|
||||
console.error('[RpcHandler.playCard] 错误:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
};
|
||||
|
||||
// 辅助方法:构建响应数据
|
||||
RpcHandler._buildPlayCardResponse = function(o_room, seat, result) {
|
||||
var gameState = o_room.o_desk.gameState;
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
seat: seat,
|
||||
discardedCard: this._serializeCard(result.discardedCard),
|
||||
gameState: {
|
||||
phase: gameState.phase,
|
||||
currentPlayer: gameState.currentPlayer,
|
||||
remainingCards: gameState.gameData.deck.length
|
||||
},
|
||||
playerActions: this._buildPlayerActions(o_room, result),
|
||||
waitingForResponse: result.hasResponse,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
};
|
||||
|
||||
// 辅助方法:分层发送响应
|
||||
RpcHandler._sendLayeredResponse = function(o_room, seat, responseData) {
|
||||
// 给操作玩家:包含完整信息
|
||||
var dataForPlayer = Object.assign({}, responseData, {
|
||||
myHandCards: this._serializeHandCards(o_room, seat)
|
||||
});
|
||||
o_room.method.sendpack_toseat(dataForPlayer, seat);
|
||||
|
||||
// 给其他玩家:隐藏私密信息
|
||||
var dataForOthers = Object.assign({}, responseData, {
|
||||
handCardCount: this._getHandCardCount(o_room, seat)
|
||||
});
|
||||
o_room.method.sendpack_toother(dataForOthers, seat);
|
||||
};
|
||||
```
|
||||
|
||||
### 7.2 操作枚举示例
|
||||
|
||||
```javascript
|
||||
// 使用OperationEnumerator
|
||||
var operations = OperationEnumerator.generateAvailableOperations(
|
||||
gameState,
|
||||
seat,
|
||||
{
|
||||
lastDiscardCard: { uniqueId: 45, code: 13 }, // 刚出的3万
|
||||
fromSeat: 1
|
||||
}
|
||||
);
|
||||
|
||||
// 输出示例
|
||||
{
|
||||
discard: [],
|
||||
chi: [],
|
||||
peng: [
|
||||
{
|
||||
choiceIndex: 0,
|
||||
operationType: "peng",
|
||||
sourceCard: { uniqueId: 45, code: 13, fromSeat: 1 },
|
||||
requiredCards: [
|
||||
{ uniqueId: 12, code: 13 },
|
||||
{ uniqueId: 78, code: 13 }
|
||||
],
|
||||
description: "碰3万"
|
||||
}
|
||||
],
|
||||
gang: [],
|
||||
hu: [
|
||||
{
|
||||
choiceIndex: 0,
|
||||
operationType: "hu",
|
||||
huType: "dianpao",
|
||||
winCards: [...],
|
||||
score: 8,
|
||||
description: "胡牌 - 8分"
|
||||
}
|
||||
],
|
||||
pass: [
|
||||
{
|
||||
choiceIndex: 0,
|
||||
operationType: "pass",
|
||||
description: "过"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 最佳实践
|
||||
|
||||
### 8.1 参数提取
|
||||
|
||||
```javascript
|
||||
// ✅ 统一的参数提取方法
|
||||
_extractParams: function(pack) {
|
||||
try {
|
||||
return {
|
||||
valid: true,
|
||||
agentid: pack.data.agentid,
|
||||
playerid: parseInt(pack.data.playerid),
|
||||
gameid: pack.data.gameid,
|
||||
roomcode: pack.data.roomcode,
|
||||
seat: parseInt(pack.data.seat),
|
||||
cardUniqueId: parseInt(pack.data.cardUniqueId)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
error: "参数解析失败: " + error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 错误处理
|
||||
|
||||
```javascript
|
||||
// ✅ 统一的错误响应
|
||||
sendErrorResponse: function(o_room, seat, statusCode, message) {
|
||||
var errorMsg = {
|
||||
app: "youle",
|
||||
route: "jinxianmahjong",
|
||||
rpc: "error",
|
||||
data: {
|
||||
status: statusCode,
|
||||
error: message,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
};
|
||||
o_room.method.sendpack_toseat(errorMsg, seat);
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 日志记录
|
||||
|
||||
```javascript
|
||||
// ✅ 详细的日志记录
|
||||
console.log('[RpcHandler.playCard] 开始处理:', {
|
||||
playerid: params.playerid,
|
||||
seat: params.seat,
|
||||
cardUniqueId: params.cardUniqueId
|
||||
});
|
||||
|
||||
console.log('[RpcHandler.playCard] 操作结果:', {
|
||||
success: result.success,
|
||||
error: result.error
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 常见问题
|
||||
|
||||
### Q1: RpcHandler和OperationManager的区别?
|
||||
|
||||
A:
|
||||
- **RpcHandler**:处理RPC请求,负责参数提取、验证、响应构建
|
||||
- **OperationManager**:执行游戏逻辑,负责状态管理、规则验证
|
||||
|
||||
### Q2: 为什么需要OperationEnumerator?
|
||||
|
||||
A: 因为需要提前告诉客户端有哪些操作可以执行,客户端根据choiceIndex选择操作。
|
||||
|
||||
### Q3: choiceIndex有什么用?
|
||||
|
||||
A: choiceIndex是操作选择的索引:
|
||||
- 服务端生成所有可能操作并分配索引
|
||||
- 客户端选择后发送choiceIndex
|
||||
- 服务端根据索引执行对应操作
|
||||
|
||||
### Q4: 如何实现分层推送?
|
||||
|
||||
A: 使用不同的发包接口:
|
||||
- `sendpack_toseat`:发给操作玩家(完整信息)
|
||||
- `sendpack_toother`:发给其他玩家(隐藏私密信息)
|
||||
|
||||
### Q5: AI玩家如何处理?
|
||||
|
||||
A: AI玩家通过AIRpcHandler自动处理:
|
||||
- 监听游戏状态变化
|
||||
- 自动调用AI决策
|
||||
- 模拟延时后执行操作
|
||||
|
||||
---
|
||||
|
||||
## 10. 下一步
|
||||
|
||||
阅读以下文档继续学习:
|
||||
|
||||
- [04-游戏核心服务](../core/04-游戏核心服务.md) - GameController和OperationManager详解
|
||||
- [05-共享代码模块](../core/05-共享代码模块.md) - 核心算法实现
|
||||
- [08-游戏流程概述](../architecture/08-游戏流程概述.md) - 完整游戏流程
|
||||
|
||||
---
|
||||
|
||||
**相关代码文件**:
|
||||
- `server/games2/jinxianmahjong/mod.js` - RPC方法定义
|
||||
- `server/games2/jinxianmahjong/rpc/RpcHandler.js` - RPC处理器
|
||||
- `server/games2/jinxianmahjong/rpc/OperationEnumerator.js` - 操作列举器
|
||||
- `server/games2/jinxianmahjong/rpc/AIRpcHandler.js` - AI处理器
|
||||
Reference in New Issue
Block a user