目录结构调整
This commit is contained in:
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. 测试验证你的修改
|
||||
|
||||
**记住**:
|
||||
- 📖 遇到问题先查文档
|
||||
- 🔍 善用搜索找代码
|
||||
- 📝 多写日志帮助理解
|
||||
- 🧪 改完代码记得测试
|
||||
|
||||
祝你开发愉快! 🚀
|
||||
Reference in New Issue
Block a user