# 快速入门指南 ## 📋 文档概述 本文档为进贤麻将子游戏提供快速入门指南,帮助开发者: - **快速理解** - 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. 测试验证你的修改 **记住**: - 📖 遇到问题先查文档 - 🔍 善用搜索找代码 - 📝 多写日志帮助理解 - 🧪 改完代码记得测试 祝你开发愉快! 🚀