|
@@ -1,22 +1,17 @@
|
|
|
-# GameItems模块
|
|
|
|
|
|
|
+# GameItems 游戏物品模块
|
|
|
|
|
|
|
|
> 游戏物品系统 - 综合管理游戏内所有物品的生命周期
|
|
> 游戏物品系统 - 综合管理游戏内所有物品的生命周期
|
|
|
|
|
|
|
|
## 目录
|
|
## 目录
|
|
|
|
|
|
|
|
1. [模块概述](#1-模块概述)
|
|
1. [模块概述](#1-模块概述)
|
|
|
-2. [数据结构设计](#2-数据结构设计)
|
|
|
|
|
-3. [核心功能](#3-核心功能)
|
|
|
|
|
-4. [物品过期机制](#4-物品过期机制)
|
|
|
|
|
-5. [宝箱系统](#5-宝箱系统)
|
|
|
|
|
-6. [物品获取与堆叠](#6-物品获取与堆叠)
|
|
|
|
|
-7. [物品产出限制](#7-物品产出限制)
|
|
|
|
|
-8. [日志记录系统](#8-日志记录系统)
|
|
|
|
|
-9. [物品合成系统](#9-物品合成系统)
|
|
|
|
|
-10. [物品分解系统](#10-物品分解系统)
|
|
|
|
|
-11. [物品绑定机制](#11-物品绑定机制)
|
|
|
|
|
-12. [系统交互](#12-系统交互)
|
|
|
|
|
-13. [最佳实践与注意事项](#13-最佳实践与注意事项)
|
|
|
|
|
|
|
+2. [目录结构](#2-目录结构)
|
|
|
|
|
+3. [架构设计](#3-架构设计)
|
|
|
|
|
+4. [核心服务](#4-核心服务)
|
|
|
|
|
+5. [数据模型](#5-数据模型)
|
|
|
|
|
+6. [业务逻辑](#6-业务逻辑)
|
|
|
|
|
+7. [使用示例](#7-使用示例)
|
|
|
|
|
+8. [最佳实践](#8-最佳实践)
|
|
|
|
|
|
|
|
## 1. 模块概述
|
|
## 1. 模块概述
|
|
|
|
|
|
|
@@ -39,58 +34,128 @@ GameItems模块是游戏核心系统之一,负责管理游戏内所有物品
|
|
|
|
|
|
|
|
### 1.3 核心特点
|
|
### 1.3 核心特点
|
|
|
|
|
|
|
|
-1. **多物品宝箱系统**:支持一个宝箱同时掉落多个物品,可配置数量范围和概率
|
|
|
|
|
-2. **灵活的过期机制**:支持全局过期时间和用户特定过期时间
|
|
|
|
|
-3. **完善的属性系统**:通过JSON格式存储物品属性,支持复杂物品效果
|
|
|
|
|
-4. **单独属性物品**:支持每个物品实例拥有独特属性(如装备)
|
|
|
|
|
-5. **物品绑定机制**:限制物品流通,保持游戏经济平衡
|
|
|
|
|
-6. **物品产出限制**:控制稀有物品的产出数量和频率
|
|
|
|
|
-7. **全面的日志系统**:记录所有物品相关操作,支持数据分析和问题排查
|
|
|
|
|
-
|
|
|
|
|
-## 2. 数据结构设计
|
|
|
|
|
-
|
|
|
|
|
-### 2.1 设计原则
|
|
|
|
|
-
|
|
|
|
|
-游戏物品模块采用关系型数据库设计,通过多个相互关联的数据表实现物品管理。数据结构设计遵循以下原则:
|
|
|
|
|
-
|
|
|
|
|
-1. **模块化**:各个表结构清晰,职责单一
|
|
|
|
|
-2. **扩展性**:支持通过属性表扩展物品特性,无需修改数据库结构
|
|
|
|
|
-3. **性能优化**:合理的索引设计和关联关系
|
|
|
|
|
-4. **数据完整性**:使用外键和事务确保数据一致性
|
|
|
|
|
-
|
|
|
|
|
-### 2.2 核心数据表
|
|
|
|
|
-
|
|
|
|
|
-#### 2.2.1 物品基础表
|
|
|
|
|
|
|
+- **多物品宝箱系统**:支持一个宝箱同时掉落多种物品,可配置数量范围和概率
|
|
|
|
|
+- **保底机制**:支持在开启一定次数后必定获得指定物品
|
|
|
|
|
+- **灵活的过期机制**:支持全局过期和用户特定过期
|
|
|
|
|
+- **物品属性扩展**:支持通过JSON格式存储的键值对属性,实现复杂效果
|
|
|
|
|
+- **物品分类与组**:支持物品分类和物品组,便于管理和配置
|
|
|
|
|
+
|
|
|
|
|
+## 2. 目录结构
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+app/Module/GameItems/
|
|
|
|
|
+├── AdminControllers/ # 后台管理控制器
|
|
|
|
|
+│ ├── Helper/ # 控制器辅助类
|
|
|
|
|
+│ ├── Actions/ # 控制器动作类
|
|
|
|
|
+│ └── LazyRenderable/ # 懒加载渲染类
|
|
|
|
|
+├── Commands/ # 命令行工具
|
|
|
|
|
+├── Casts/ # 自定义类型转换器
|
|
|
|
|
+├── Databases/ # 数据库相关文件
|
|
|
|
|
+│ └── create.sql # 数据库创建脚本
|
|
|
|
|
+├── Enums/ # 枚举类型定义
|
|
|
|
|
+├── Events/ # 事件类
|
|
|
|
|
+├── Exceptions/ # 异常类
|
|
|
|
|
+├── Logics/ # 业务逻辑类
|
|
|
|
|
+├── Models/ # 数据模型
|
|
|
|
|
+├── Providers/ # 服务提供者
|
|
|
|
|
+├── Repositorys/ # 数据仓库
|
|
|
|
|
+├── Services/ # 服务类
|
|
|
|
|
+└── README.md # 模块文档
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2.1 主要目录说明
|
|
|
|
|
+
|
|
|
|
|
+- **AdminControllers/**: 包含所有后台管理界面的控制器,用于物品、宝箱、配方等的管理
|
|
|
|
|
+ - **Helper/**: 控制器辅助类,如表单、表格、筛选器等帮助类
|
|
|
|
|
+ - **Actions/**: 控制器动作类,如复制、导出等操作
|
|
|
|
|
+ - **LazyRenderable/**: 懒加载渲染类,用于异步加载数据
|
|
|
|
|
+- **Commands/**: 命令行工具,如数据导入导出、配置生成等
|
|
|
|
|
+- **Casts/**: 自定义类型转换器,用于处理JSON属性等特殊字段
|
|
|
|
|
+- **Enums/**: 定义模块中使用的所有枚举类型,如物品类型、交易类型等
|
|
|
|
|
+- **Events/**: 定义模块触发的事件,用于模块间的松耦合通信
|
|
|
|
|
+- **Exceptions/**: 自定义异常类,用于处理业务异常
|
|
|
|
|
+- **Logics/**: 业务逻辑类,处理具体的业务规则,内部使用
|
|
|
|
|
+- **Models/**: 数据模型,定义数据结构和关系
|
|
|
|
|
+- **Providers/**: 服务提供者,用于注册服务和事件
|
|
|
|
|
+- **Repositorys/**: 数据仓库,封装数据库操作
|
|
|
|
|
+- **Services/**: 服务类,对外提供功能接口
|
|
|
|
|
+
|
|
|
|
|
+## 3. 架构设计
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 模块架构
|
|
|
|
|
+
|
|
|
|
|
+GameItems模块采用分层架构设计,遵循"服务是对外的,Logic是内部的"原则:
|
|
|
|
|
+
|
|
|
|
|
+- **Models层**:数据模型,定义数据结构和关系
|
|
|
|
|
+- **Logics层**:业务逻辑,处理具体的业务规则
|
|
|
|
|
+- **Services层**:服务接口,对外提供功能,调用Logics层处理业务
|
|
|
|
|
+- **Controllers层**:控制器,处理HTTP请求,调用Services层
|
|
|
|
|
+- **Repositories层**:数据访问层,封装数据库操作
|
|
|
|
|
+
|
|
|
|
|
+### 2.2 核心类关系
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+Services
|
|
|
|
|
+ ├── ItemService - 物品基础服务
|
|
|
|
|
+ ├── ChestService - 宝箱服务
|
|
|
|
|
+ ├── CraftService - 合成服务
|
|
|
|
|
+ └── DismantleService - 分解服务
|
|
|
|
|
+
|
|
|
|
|
+Logics
|
|
|
|
|
+ ├── Item - 物品逻辑
|
|
|
|
|
+ ├── ChestContent - 宝箱内容逻辑
|
|
|
|
|
+ ├── PityTime - 保底计数逻辑
|
|
|
|
|
+ ├── ItemInstance - 物品实例逻辑
|
|
|
|
|
+ ├── UserRecipe - 用户配方逻辑
|
|
|
|
|
+ ├── Recipe - 配方逻辑
|
|
|
|
|
+ ├── UserOutputCounter - 用户产出计数逻辑
|
|
|
|
|
+ └── Group - 物品组逻辑
|
|
|
|
|
+
|
|
|
|
|
+Models
|
|
|
|
|
+ ├── Item - 物品基础信息
|
|
|
|
|
+ ├── ItemCategory - 物品分类
|
|
|
|
|
+ ├── ItemInstance - 物品实例(单独属性物品)
|
|
|
|
|
+ ├── ItemUser - 用户物品关联
|
|
|
|
|
+ ├── ItemGroup - 物品组
|
|
|
|
|
+ ├── ItemGroupItem - 物品组内容
|
|
|
|
|
+ ├── ItemChestContent - 宝箱内容配置
|
|
|
|
|
+ ├── ItemPityTime - 宝箱保底计数
|
|
|
|
|
+ ├── ItemChestOpenLog - 宝箱开启记录
|
|
|
|
|
+ ├── ItemRecipe - 物品合成配方
|
|
|
|
|
+ ├── ItemRecipeMaterial - 合成配方材料
|
|
|
|
|
+ ├── ItemUserRecipe - 用户配方解锁状态
|
|
|
|
|
+ ├── ItemCraftLog - 物品合成记录
|
|
|
|
|
+ ├── ItemDismantleRule - 物品分解规则
|
|
|
|
|
+ ├── ItemDismantleResult - 分解结果配置
|
|
|
|
|
+ ├── ItemDismantleLog - 物品分解记录
|
|
|
|
|
+ ├── ItemOutputLimit - 物品产出限制
|
|
|
|
|
+ ├── ItemUserOutputCounter - 用户产出计数
|
|
|
|
|
+ └── ItemTransactionLog - 物品交易记录
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2.3 设计原则
|
|
|
|
|
+
|
|
|
|
|
+1. **单一职责原则**:每个类只负责一个功能领域
|
|
|
|
|
+2. **关注点分离**:模型只负责数据结构,业务逻辑由Logic类处理
|
|
|
|
|
+3. **依赖注入**:通过构造函数注入依赖,提高可测试性
|
|
|
|
|
+4. **事务完整性**:所有涉及多个操作的功能都使用数据库事务确保原子性
|
|
|
|
|
+5. **日志记录**:关键操作都有详细的日志记录,便于追踪和分析
|
|
|
|
|
+
|
|
|
|
|
+## 3. 数据结构
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 核心表结构
|
|
|
|
|
|
|
|
| 表名 | 主要功能 | 关键字段 |
|
|
| 表名 | 主要功能 | 关键字段 |
|
|
|
|------|---------|---------|
|
|
|------|---------|---------|
|
|
|
-| item_categories | 物品分类管理 | id, name, code, parent_id |
|
|
|
|
|
| item_items | 统一属性物品定义 | id, name, type, is_unique, attributes |
|
|
| item_items | 统一属性物品定义 | id, name, type, is_unique, attributes |
|
|
|
|
|
+| item_categories | 物品分类管理 | id, name, code, parent_id |
|
|
|
| item_instances | 单独属性物品实例 | id, item_id, attributes, is_bound |
|
|
| item_instances | 单独属性物品实例 | id, item_id, attributes, is_bound |
|
|
|
| item_users | 用户物品关联 | user_id, item_id, instance_id, quantity |
|
|
| item_users | 用户物品关联 | user_id, item_id, instance_id, quantity |
|
|
|
| item_groups | 物品组定义 | id, name, code |
|
|
| item_groups | 物品组定义 | id, name, code |
|
|
|
| item_group_items | 物品组内容 | group_id, item_id, weight |
|
|
| item_group_items | 物品组内容 | group_id, item_id, weight |
|
|
|
-
|
|
|
|
|
-#### 2.2.2 宝箱系统表
|
|
|
|
|
-
|
|
|
|
|
-| 表名 | 主要功能 | 关键字段 |
|
|
|
|
|
-|------|---------|---------|
|
|
|
|
|
| item_chest_contents | 宝箱内容配置 | chest_id, item_id/group_id, weight |
|
|
| item_chest_contents | 宝箱内容配置 | chest_id, item_id/group_id, weight |
|
|
|
| item_pity_times | 用户宝箱保底计数 | user_id, chest_id, chest_content_id, current_count |
|
|
| item_pity_times | 用户宝箱保底计数 | user_id, chest_id, chest_content_id, current_count |
|
|
|
| item_chest_open_logs | 宝箱开启记录 | user_id, chest_id, result_items, pity_triggered |
|
|
| item_chest_open_logs | 宝箱开启记录 | user_id, chest_id, result_items, pity_triggered |
|
|
|
-
|
|
|
|
|
-#### 2.2.3 物品限制与日志表
|
|
|
|
|
-
|
|
|
|
|
-| 表名 | 主要功能 | 关键字段 |
|
|
|
|
|
-|------|---------|---------|
|
|
|
|
|
-| item_output_limits | 物品产出限制 | item_id, limit_type, max_quantity |
|
|
|
|
|
-| item_user_output_counters | 用户产出限制计数 | user_id, limit_id, current_count |
|
|
|
|
|
-| item_transaction_logs | 物品交易记录 | user_id, item_id, quantity, transaction_type |
|
|
|
|
|
-
|
|
|
|
|
-#### 2.2.4 物品合成与分解表
|
|
|
|
|
-
|
|
|
|
|
-| 表名 | 主要功能 | 关键字段 |
|
|
|
|
|
-|------|---------|---------|
|
|
|
|
|
| item_recipes | 合成配方定义 | id, result_item_id, success_rate |
|
|
| item_recipes | 合成配方定义 | id, result_item_id, success_rate |
|
|
|
| item_recipe_materials | 配方材料需求 | recipe_id, item_id, quantity |
|
|
| item_recipe_materials | 配方材料需求 | recipe_id, item_id, quantity |
|
|
|
| item_user_recipes | 用户配方解锁状态 | user_id, recipe_id, is_unlocked |
|
|
| item_user_recipes | 用户配方解锁状态 | user_id, recipe_id, is_unlocked |
|
|
@@ -98,2748 +163,734 @@ GameItems模块是游戏核心系统之一,负责管理游戏内所有物品
|
|
|
| item_dismantle_rules | 物品分解规则 | item_id/category_id, priority |
|
|
| item_dismantle_rules | 物品分解规则 | item_id/category_id, priority |
|
|
|
| item_dismantle_results | 分解结果配置 | rule_id, result_item_id, chance |
|
|
| item_dismantle_results | 分解结果配置 | rule_id, result_item_id, chance |
|
|
|
| item_dismantle_logs | 物品分解记录 | user_id, item_id, results |
|
|
| item_dismantle_logs | 物品分解记录 | user_id, item_id, results |
|
|
|
|
|
+| item_output_limits | 物品产出限制 | item_id, limit_type, max_quantity |
|
|
|
|
|
+| item_user_output_counters | 用户产出计数 | user_id, limit_id, current_count |
|
|
|
|
|
+| item_transaction_logs | 物品交易记录 | user_id, item_id, quantity, transaction_type |
|
|
|
|
|
|
|
|
-### 2.3 详细表结构
|
|
|
|
|
-
|
|
|
|
|
-#### 2.3.1 item_categories 表(物品分类)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 分类ID,主键 |
|
|
|
|
|
-| name | varchar | 分类名称 |
|
|
|
|
|
-| code | varchar | 分类编码(唯一) |
|
|
|
|
|
-| icon | varchar | 分类图标 |
|
|
|
|
|
-| sort | int | 排序权重 |
|
|
|
|
|
-| parent_id | int | 父分类ID(可为空,用于实现分类层级) |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 2.3.2 item_items 表(统一属性物品)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 物品ID,主键 |
|
|
|
|
|
-| name | varchar | 物品名称 |
|
|
|
|
|
-| description | text | 物品描述 |
|
|
|
|
|
-| category_id | int | 物品分类ID,外键关联item_categories表 |
|
|
|
|
|
-| type | tinyint | 物品类型(1:可使用, 2:可装备, 3:可合成, 4:可交任务, 5:可开启...) |
|
|
|
|
|
-| is_unique | tinyint | 是否是单独属性物品(0:否,默认, 1:是) |
|
|
|
|
|
-| icon | varchar | 物品图标路径 |
|
|
|
|
|
-| max_stack | int | 最大堆叠数量 |
|
|
|
|
|
-| sell_price | int | 出售价格 |
|
|
|
|
|
-| tradable | tinyint | 是否可交易(0:不可交易, 1:可交易,默认) |
|
|
|
|
|
-| dismantlable | tinyint | 是否可分解(0:不可分解, 1:可分解,默认) |
|
|
|
|
|
-| default_expire_seconds | int | 玩家获取物品后的默认有效秒数(0表示永久有效) |
|
|
|
|
|
-| display_attributes | json | 展示属性,以JSON格式存储键值对,用于界面展示和描述的属性 |
|
|
|
|
|
-| numeric_attributes | json | 数值属性,以JSON格式存储键值对,用于计算和游戏逻辑的属性 |
|
|
|
|
|
-| global_expire_at | timestamp | 物品全局过期时间(可为空) |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 2.3.3 item_instances 表(单独属性物品)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 唯一物品ID,主键 |
|
|
|
|
|
-| item_id | int | 关联的基础物品ID,外键关联item_items表 |
|
|
|
|
|
-| name | varchar | 物品名称(可以与基础物品不同,如"锐利的钢刀") |
|
|
|
|
|
-| display_attributes | json | 展示属性,以JSON格式存储键值对,用于界面展示和描述的属性 |
|
|
|
|
|
-| numeric_attributes | json | 数值属性,以JSON格式存储键值对,用于计算和游戏逻辑的属性 |
|
|
|
|
|
-| tradable | tinyint | 是否可交易(0:不可交易, 1:可交易,默认) |
|
|
|
|
|
-| is_bound | tinyint | 是否已绑定(0:未绑定, 1:已绑定) |
|
|
|
|
|
-| bound_to | varchar | 绑定对象(账号ID或角色ID) |
|
|
|
|
|
-| bind_exp_time | timestamp | 绑定过期时间(为空表示永久绑定) |
|
|
|
|
|
-| expire_at | timestamp | 物品过期时间(可为空) |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 2.3.4 item_users 表(用户物品关联)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 记录ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID,外键 |
|
|
|
|
|
-| item_id | int | 统一属性物品ID,外键关联item_items表(始终有值) |
|
|
|
|
|
-| instance_id | int | 单独属性物品ID,外键关联item_instances表(可为空) |
|
|
|
|
|
-| quantity | int | 数量(对于单独属性物品,该值始终为1) |
|
|
|
|
|
-| expire_at | timestamp | 用户物品过期时间(可为空) |
|
|
|
|
|
-| created_at | timestamp | 获取时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
-
|
|
|
|
|
-### 2.4 数据库索引设计
|
|
|
|
|
-
|
|
|
|
|
-为确保系统高性能运行,对关键字段进行了索引设计:
|
|
|
|
|
-
|
|
|
|
|
-#### 2.4.1 物品基础表索引
|
|
|
|
|
-
|
|
|
|
|
-| 表名 | 索引字段 | 索引类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- | --- |
|
|
|
|
|
-| item_items | id | 主键 | 物品ID主键索引 |
|
|
|
|
|
-| item_items | category_id | 普通索引 | 加速按物品分类查询 |
|
|
|
|
|
-| item_items | type | 普通索引 | 加速按物品类型查询 |
|
|
|
|
|
-| item_items | is_unique | 普通索引 | 加速查询单独属性物品 |
|
|
|
|
|
-| item_items | tradable | 普通索引 | 加速查询可交易/不可交易物品 |
|
|
|
|
|
-| item_items | dismantlable | 普通索引 | 加速查询可分解/不可分解物品 |
|
|
|
|
|
-| item_items | global_expire_at | 普通索引 | 加速过期物品查询 |
|
|
|
|
|
-| item_categories | id | 主键 | 分类ID主键索引 |
|
|
|
|
|
-| item_categories | parent_id | 普通索引 | 加速查询子分类 |
|
|
|
|
|
-| item_categories | code | 唯一索引 | 确保分类编码唯一性 |
|
|
|
|
|
-| item_instances | id | 主键 | 唯一物品ID主键索引 |
|
|
|
|
|
-| item_instances | item_id | 普通索引 | 加速根据基础物品查询唯一物品 |
|
|
|
|
|
-| item_instances | tradable | 普通索引 | 加速查询可交易/不可交易的单独属性物品 |
|
|
|
|
|
-| item_instances | is_bound | 普通索引 | 加速查询已绑定的单独属性物品 |
|
|
|
|
|
-| item_instances | bound_to | 普通索引 | 加速查询绑定到特定对象的单独属性物品 |
|
|
|
|
|
-| item_instances | bind_exp_time | 普通索引 | 加速查询需要解绑的单独属性物品 |
|
|
|
|
|
-| item_instances | expire_at | 普通索引 | 加速过期物品查询 |
|
|
|
|
|
-| item_users | user_id, item_id | 复合索引 | 加速用户统一属性物品查询 |
|
|
|
|
|
-| item_users | user_id, instance_id | 复合索引 | 加速用户单独属性物品查询 |
|
|
|
|
|
-| item_users | expire_at | 普通索引 | 加速过期物品查询 |
|
|
|
|
|
-
|
|
|
|
|
-#### 2.4.2 宝箱系统表索引
|
|
|
|
|
-
|
|
|
|
|
-| 表名 | 索引字段 | 索引类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- | --- |
|
|
|
|
|
-| item_chest_contents | chest_id | 普通索引 | 加速宝箱内容查询 |
|
|
|
|
|
-| item_chest_contents | item_id | 普通索引 | 加速物品在宝箱中的查询 |
|
|
|
|
|
-| item_chest_contents | group_id | 普通索引 | 加速查询物品组在宝箱中的配置 |
|
|
|
|
|
-| item_chest_contents | pity_count | 普通索引 | 加速查询启用保底的宝箱内容 |
|
|
|
|
|
-| item_pity_times | user_id, chest_id, chest_content_id | 复合索引 | 加速查询用户对特定宝箱内容的保底计数 |
|
|
|
|
|
-| item_chest_open_logs | user_id, open_time | 复合索引 | 加速查询用户的宝箱开启历史 |
|
|
|
|
|
-| item_chest_open_logs | chest_id | 普通索引 | 加速查询特定宝箱的开启记录 |
|
|
|
|
|
-
|
|
|
|
|
-### 2.5 数据模型关联关系
|
|
|
|
|
-
|
|
|
|
|
-以下是主要数据模型之间的关联关系:
|
|
|
|
|
-
|
|
|
|
|
-1. **用户与物品关系**
|
|
|
|
|
- - 用户可以拥有统一属性物品和单独属性物品,通过 item_users 表关联
|
|
|
|
|
- - 对于统一属性物品,直接关联 item_items 表
|
|
|
|
|
- - 对于单独属性物品,通过 item_instances 表间接关联 item_items 表
|
|
|
|
|
-
|
|
|
|
|
-2. **物品分类层级**
|
|
|
|
|
- - item_categories 表通过 parent_id 字段实现自关联,形成分类层级结构
|
|
|
|
|
- - item_items 表通过 category_id 字段关联到 item_categories 表
|
|
|
|
|
-
|
|
|
|
|
-3. **物品组与物品**
|
|
|
|
|
- - item_groups 表定义物品组
|
|
|
|
|
- - item_group_items 表建立物品组与物品的多对多关系
|
|
|
|
|
-
|
|
|
|
|
-4. **宝箱与内容关系**
|
|
|
|
|
- - 宝箱是 item_items 表中 type=5 的特殊物品
|
|
|
|
|
- - item_chest_contents 表定义宝箱可能掉落的内容
|
|
|
|
|
- - 宝箱内容可以是具体物品(item_id)或物品组(group_id)
|
|
|
|
|
-
|
|
|
|
|
-5. **物品合成关系**
|
|
|
|
|
- - item_recipes 表定义合成配方
|
|
|
|
|
- - item_recipe_materials 表定义配方所需材料
|
|
|
|
|
- - 用户通过 item_user_recipes 表记录已解锁的配方
|
|
|
|
|
-
|
|
|
|
|
-6. **物品分解关系**
|
|
|
|
|
- - item_dismantle_rules 表定义分解规则
|
|
|
|
|
- - item_dismantle_results 表定义分解可能的结果
|
|
|
|
|
- - 分解规则可以针对特定物品或整个分类
|
|
|
|
|
-
|
|
|
|
|
-### 2.6 单独属性物品实现
|
|
|
|
|
-
|
|
|
|
|
-为支持"每个用户拥有的同类物品可以有不同属性"的需求(如不同的武器有不同的属性),系统采用了统一属性物品和单独属性物品两种设计:
|
|
|
|
|
-
|
|
|
|
|
-#### 2.6.1 实现方式
|
|
|
|
|
-
|
|
|
|
|
-1. **物品类型区分**
|
|
|
|
|
- - item_items 表中的 is_unique 字段标记该物品是否为单独属性物品
|
|
|
|
|
- - 单独属性物品(如装备)在 item_instances 表中创建独立记录
|
|
|
|
|
- - 统一属性物品(如消耗品)直接使用 item_items 表的属性
|
|
|
|
|
-
|
|
|
|
|
-2. **属性存储方式**
|
|
|
|
|
- - 基础属性存储在 item_items 表中
|
|
|
|
|
- - 单独属性物品的特殊属性存储在 item_instances 表中
|
|
|
|
|
- - 属性使用 JSON 格式存储,分为展示属性和数值属性
|
|
|
|
|
-
|
|
|
|
|
-3. **用户物品关联**
|
|
|
|
|
- - item_users 表通过 item_id 和 instance_id 字段关联两种物品
|
|
|
|
|
- - 对于统一属性物品,instance_id 为空,quantity 可以大于1
|
|
|
|
|
- - 对于单独属性物品,instance_id 有值,quantity 始终为1
|
|
|
|
|
-
|
|
|
|
|
-## 3. 核心功能
|
|
|
|
|
-
|
|
|
|
|
-### 3.1 物品管理接口
|
|
|
|
|
-
|
|
|
|
|
-系统提供以下核心接口用于物品管理:
|
|
|
|
|
-
|
|
|
|
|
-#### 3.1.1 获取用户物品
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:获取用户拥有的所有物品或特定类型的物品
|
|
|
|
|
-- **参数**:用户ID,物品类型(可选),分页参数
|
|
|
|
|
-- **返回**:物品列表,包含数量、属性等信息
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 查询用户在 item_users 表中的记录
|
|
|
|
|
- 2. 关联 item_items 表获取物品基础信息
|
|
|
|
|
- 3. 对于单独属性物品,关联 item_instances 表获取特殊属性
|
|
|
|
|
- 4. 过滤掉已过期的物品(检查全局过期和用户物品过期)
|
|
|
|
|
- 5. 按类型、分类等条件筛选
|
|
|
|
|
-
|
|
|
|
|
-#### 3.1.2 添加物品到用户背包
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:向用户背包添加指定物品
|
|
|
|
|
-- **参数**:用户ID、物品ID、数量、过期时间(可选)、属性参数(可选)
|
|
|
|
|
-- **返回**:添加结果、当前数量
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查物品是否存在
|
|
|
|
|
- 2. 检查物品是否有全局过期时间
|
|
|
|
|
- 3. 对于统一属性物品:
|
|
|
|
|
- - 检查用户是否已有该物品且过期时间相同
|
|
|
|
|
- - 如果已有,增加数量(注意最大堆叠限制)
|
|
|
|
|
- - 如果没有,创建新记录
|
|
|
|
|
- 4. 对于单独属性物品:
|
|
|
|
|
- - 创建 item_instances 记录
|
|
|
|
|
- - 关联到用户
|
|
|
|
|
- 5. 记录物品获取日志
|
|
|
|
|
-
|
|
|
|
|
-#### 3.1.3 使用物品
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:消耗指定数量的物品并触发效果
|
|
|
|
|
-- **参数**:用户ID、物品ID/实例ID、数量、使用参数
|
|
|
|
|
-- **返回**:使用结果、剩余数量、触发效果
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查用户是否拥有足够数量的物品
|
|
|
|
|
- 2. 检查物品是否已过期
|
|
|
|
|
- 3. 根据物品类型执行不同的使用逻辑
|
|
|
|
|
- 4. 扣除物品数量
|
|
|
|
|
- 5. 记录物品消耗日志
|
|
|
|
|
- 6. 返回使用效果
|
|
|
|
|
-
|
|
|
|
|
-#### 3.1.4 删除用户物品
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:从用户背包中删除指定物品
|
|
|
|
|
-- **参数**:用户ID、物品ID/实例ID、数量、删除原因
|
|
|
|
|
-- **返回**:删除结果、剩余数量
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查用户是否拥有足够数量的物品
|
|
|
|
|
- 2. 扣除物品数量
|
|
|
|
|
- 3. 如果数量为0,删除记录
|
|
|
|
|
- 4. 对于单独属性物品,可选择是否删除 item_instances 记录
|
|
|
|
|
- 5. 记录物品删除日志
|
|
|
|
|
-
|
|
|
|
|
-### 3.2 物品交易接口
|
|
|
|
|
-
|
|
|
|
|
-系统支持玩家间物品交易和与NPC的交易:
|
|
|
|
|
-
|
|
|
|
|
-#### 3.2.1 玩家间交易
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:将物品从一个玩家转移到另一个玩家
|
|
|
|
|
-- **参数**:发送方ID、接收方ID、物品ID/实例ID、数量
|
|
|
|
|
-- **返回**:交易结果
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查物品是否可交易(tradable=1)
|
|
|
|
|
- 2. 检查物品是否已绑定(is_bound=0)
|
|
|
|
|
- 3. 检查发送方是否拥有足够数量的物品
|
|
|
|
|
- 4. 从发送方扣除物品
|
|
|
|
|
- 5. 向接收方添加物品
|
|
|
|
|
- 6. 记录交易日志
|
|
|
|
|
-
|
|
|
|
|
-#### 3.2.2 商店购买
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:玩家使用游戏货币购买物品
|
|
|
|
|
-- **参数**:用户ID、物品ID、数量
|
|
|
|
|
-- **返回**:购买结果、剩余货币
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查物品价格和玩家货币是否足够
|
|
|
|
|
- 2. 扣除玩家货币
|
|
|
|
|
- 3. 添加物品到玩家背包
|
|
|
|
|
- 4. 记录购买日志
|
|
|
|
|
-
|
|
|
|
|
-#### 3.2.3 商店出售
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:玩家将物品出售给商店获得货币
|
|
|
|
|
-- **参数**:用户ID、物品ID/实例ID、数量
|
|
|
|
|
-- **返回**:出售结果、获得货币
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查玩家是否拥有足够数量的物品
|
|
|
|
|
- 2. 计算出售价格(可能受物品品质、耐久度等影响)
|
|
|
|
|
- 3. 从玩家背包中扣除物品
|
|
|
|
|
- 4. 增加玩家货币
|
|
|
|
|
- 5. 记录出售日志
|
|
|
|
|
-
|
|
|
|
|
-### 3.3 单独属性物品接口
|
|
|
|
|
-
|
|
|
|
|
-系统提供以下接口用于管理单独属性物品:
|
|
|
|
|
-
|
|
|
|
|
-#### 3.3.1 创建单独属性物品
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:为用户创建具有独特属性的物品
|
|
|
|
|
-- **参数**:用户ID、基础物品ID、属性参数
|
|
|
|
|
-- **返回**:创建的单独属性物品信息
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查基础物品是否存在且 is_unique=1
|
|
|
|
|
- 2. 生成物品属性(可能包含随机因素)
|
|
|
|
|
- 3. 创建 item_instances 记录
|
|
|
|
|
- 4. 关联到用户
|
|
|
|
|
- 5. 记录物品创建日志
|
|
|
|
|
-
|
|
|
|
|
-#### 3.3.2 修改单独属性物品
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:修改单独属性物品的属性(如强化、附魔)
|
|
|
|
|
-- **参数**:用户ID、实例ID、属性变更
|
|
|
|
|
-- **返回**:修改后的物品信息
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查用户是否拥有该物品
|
|
|
|
|
- 2. 验证属性变更的合法性
|
|
|
|
|
- 3. 更新 item_instances 记录
|
|
|
|
|
- 4. 记录物品修改日志
|
|
|
|
|
-
|
|
|
|
|
-#### 3.3.3 获取单独属性物品详情
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:获取单独属性物品的详细信息
|
|
|
|
|
-- **参数**:实例ID
|
|
|
|
|
-- **返回**:物品详细信息,包括基础属性和特殊属性
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 查询 item_instances 表获取物品实例
|
|
|
|
|
- 2. 关联 item_items 表获取基础信息
|
|
|
|
|
- 3. 合并基础属性和特殊属性
|
|
|
|
|
- 4. 返回完整的物品信息
|
|
|
|
|
-
|
|
|
|
|
-## 4. 物品过期机制
|
|
|
|
|
-
|
|
|
|
|
-物品模块支持两种过期时间机制,用于实现物品的时效性管理。
|
|
|
|
|
-
|
|
|
|
|
-### 4.1 全局过期时间
|
|
|
|
|
-
|
|
|
|
|
-全局过期时间定义在 `item_items` 表的 `global_expire_at` 字段中,表示该物品在所有用户中的绝对过期时间。当超过这个时间点后,所有用户的该物品均失效。
|
|
|
|
|
-
|
|
|
|
|
-#### 4.1.1 应用场景
|
|
|
|
|
-
|
|
|
|
|
-- **限时活动物品**:活动结束后自动失效
|
|
|
|
|
-- **赠送的体验物品**:在特定日期后全部失效
|
|
|
|
|
-- **版本更新物品**:新版本发布后旧版本物品自动失效
|
|
|
|
|
-
|
|
|
|
|
-#### 4.1.2 实现方式
|
|
|
|
|
-
|
|
|
|
|
-1. 在物品定义时设置 `global_expire_at` 字段
|
|
|
|
|
-2. 在获取用户物品时,检查物品的全局过期时间
|
|
|
|
|
-3. 定期运行任务,清理全局过期的物品
|
|
|
|
|
-
|
|
|
|
|
-### 4.2 用户物品过期时间
|
|
|
|
|
-
|
|
|
|
|
-用户物品过期时间定义在 `item_users` 表的 `expire_at` 字段中,表示特定用户的特定物品的过期时间。这允许每个用户的同一物品有不同的过期时间。
|
|
|
|
|
-
|
|
|
|
|
-#### 4.2.1 应用场景
|
|
|
|
|
-
|
|
|
|
|
-- **限时使用的装备或道具**:从获取开始计时
|
|
|
|
|
-- **会员特权物品**:与会员有效期绑定
|
|
|
|
|
-- **租借物品**:租借期结束后自动失效
|
|
|
|
|
-- **试用物品**:试用期结束后自动失效
|
|
|
|
|
-
|
|
|
|
|
-#### 4.2.2 实现方式
|
|
|
|
|
-
|
|
|
|
|
-1. 在添加物品到用户背包时,根据物品的 `default_expire_seconds` 计算过期时间
|
|
|
|
|
-2. 如果 `default_expire_seconds` 为0,则物品永久有效
|
|
|
|
|
-3. 在获取用户物品时,检查用户物品的过期时间
|
|
|
|
|
-4. 定期运行任务,清理用户过期物品
|
|
|
|
|
-
|
|
|
|
|
-### 4.3 过期处理机制
|
|
|
|
|
-
|
|
|
|
|
-系统定期运行任务检查并处理过期物品,确保游戏内物品的时效性。
|
|
|
|
|
-
|
|
|
|
|
-#### 4.3.1 全局过期物品处理
|
|
|
|
|
-
|
|
|
|
|
-1. **查询全局过期物品**
|
|
|
|
|
- ```sql
|
|
|
|
|
- SELECT id FROM item_items WHERE global_expire_at IS NOT NULL AND global_expire_at < NOW()
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-2. **删除用户物品记录**
|
|
|
|
|
- ```sql
|
|
|
|
|
- DELETE FROM item_users WHERE item_id IN (已过期物品ID列表)
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-3. **记录日志**
|
|
|
|
|
- - 在 item_transaction_logs 表中记录物品过期删除日志
|
|
|
|
|
- - 交易类型设置为 "过期失效"
|
|
|
|
|
-
|
|
|
|
|
-4. **可选操作**
|
|
|
|
|
- - 发送通知给用户
|
|
|
|
|
- - 提供过期物品的替代品
|
|
|
|
|
-
|
|
|
|
|
-#### 4.3.2 用户物品过期处理
|
|
|
|
|
-
|
|
|
|
|
-1. **查询用户过期物品**
|
|
|
|
|
- ```sql
|
|
|
|
|
- SELECT id, user_id, item_id, instance_id FROM item_users
|
|
|
|
|
- WHERE expire_at IS NOT NULL AND expire_at < NOW()
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-2. **删除用户物品记录**
|
|
|
|
|
- ```sql
|
|
|
|
|
- DELETE FROM item_users WHERE id IN (已过期记录ID列表)
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-3. **处理单独属性物品**
|
|
|
|
|
- - 对于单独属性物品,可以选择删除或保留 item_instances 记录
|
|
|
|
|
- - 如果删除,需要确保没有其他用户关联到该实例
|
|
|
|
|
-
|
|
|
|
|
-4. **记录日志**
|
|
|
|
|
- - 在 item_transaction_logs 表中记录物品过期删除日志
|
|
|
|
|
- - 记录用户ID、物品ID、过期时间等信息
|
|
|
|
|
-
|
|
|
|
|
-### 4.4 过期时间的优先级
|
|
|
|
|
-
|
|
|
|
|
-当同时存在全局过期时间和用户物品过期时间时,系统采用以下优先级规则:
|
|
|
|
|
-
|
|
|
|
|
-1. **最早到期优先**:系统使用两个过期时间中较早的一个作为实际过期时间
|
|
|
|
|
-2. **全局过期强制执行**:即使用户物品过期时间晚于全局过期时间,全局过期时间到达后物品仍会失效
|
|
|
|
|
-3. **用户物品过期独立执行**:用户物品过期不影响其他用户的同类物品
|
|
|
|
|
-
|
|
|
|
|
-## 5. 宝箱系统
|
|
|
|
|
-
|
|
|
|
|
-宝箱系统是游戏物品系统的重要组成部分,允许玩家通过开启宝箱获得随机物品,增加游戏的随机性和乐趣。
|
|
|
|
|
-
|
|
|
|
|
-### 5.1 宝箱类型
|
|
|
|
|
-
|
|
|
|
|
-系统支持多种类型的宝箱,可以根据游戏需求进行配置:
|
|
|
|
|
-
|
|
|
|
|
-#### 5.1.1 按稀有度分类
|
|
|
|
|
-
|
|
|
|
|
-1. **普通宝箱**:包含基础消耗品和少量资源,开出稀有物品的概率较低
|
|
|
|
|
-2. **稀有宝箱**:有较高机会获得稀有装备和较多资源
|
|
|
|
|
-3. **史诗宝箱**:包含高价值物品,有较高概率获得史诗级物品
|
|
|
|
|
-4. **传说宝箱**:最高级别宝箱,有机会获得传说级物品
|
|
|
|
|
-
|
|
|
|
|
-#### 5.1.2 按获取方式分类
|
|
|
|
|
-
|
|
|
|
|
-1. **任务宝箱**:完成任务获得的宝箱,内容通常与任务相关
|
|
|
|
|
-2. **活动宝箱**:特定活动期间可获得的宝箱,包含活动限定物品
|
|
|
|
|
-3. **商店宝箱**:通过游戏货币或真实货币购买的宝箱
|
|
|
|
|
-4. **成就宝箱**:达成特定成就后获得的宝箱
|
|
|
|
|
-5. **副本宝箱**:在游戏副本中获得的宝箱,内容通常与副本主题相关
|
|
|
|
|
-
|
|
|
|
|
-### 5.2 宝箱配置
|
|
|
|
|
-
|
|
|
|
|
-宝箱的内容和概率通过 `item_chest_contents` 表进行配置:
|
|
|
|
|
-
|
|
|
|
|
-#### 5.2.1 基本配置
|
|
|
|
|
-
|
|
|
|
|
-1. **宝箱定义**:宝箱本身是 `item_items` 表中 `type=5` 的特殊物品
|
|
|
|
|
-2. **内容配置**:通过 `item_chest_contents` 表定义宝箱可能掉落的内容
|
|
|
|
|
-3. **物品组支持**:宝箱内容可以是具体物品(item_id)或物品组(group_id)
|
|
|
|
|
-4. **数量范围**:每个内容可以设置最小和最大掉落数量
|
|
|
|
|
-5. **概率控制**:通过 weight 字段控制每个内容的掉落概率
|
|
|
|
|
-
|
|
|
|
|
-#### 5.2.2 多物品掉落
|
|
|
|
|
-
|
|
|
|
|
-宝箱系统支持一个宝箱同时掉落多个物品:
|
|
|
|
|
-
|
|
|
|
|
-1. **掉落数量控制**:
|
|
|
|
|
- - 宝箱物品在 `numeric_attributes` 字段中定义 `min_drop_count` 和 `max_drop_count` 属性
|
|
|
|
|
- - 系统在开启宝箱时随机决定实际掉落的物品数量
|
|
|
|
|
-
|
|
|
|
|
-2. **重复控制**:
|
|
|
|
|
- - 通过 `allow_duplicate` 字段控制物品是否可以在同一宝箱中重复掉落
|
|
|
|
|
- - 当设置为0时,同一内容在一次开启中最多出现一次
|
|
|
|
|
-
|
|
|
|
|
-3. **物品组随机**:
|
|
|
|
|
- - 当内容配置为物品组时,系统会根据物品组中的权重随机选择一个物品
|
|
|
|
|
- - 物品组可以包含多个物品,增加宝箱内容的多样性
|
|
|
|
|
-
|
|
|
|
|
-### 5.3 概率机制
|
|
|
|
|
-
|
|
|
|
|
-宝箱内容的概率由 `item_chest_contents` 表中的 `weight` 字段决定:
|
|
|
|
|
-
|
|
|
|
|
-#### 5.3.1 基础概率计算
|
|
|
|
|
-
|
|
|
|
|
-1. **权重定义**:
|
|
|
|
|
- - 每个宝箱内容的权重为三位小数
|
|
|
|
|
- - 同一宝箱的所有内容权重总和为100
|
|
|
|
|
- - 每个内容的概率直接等于其权重值(百分比)
|
|
|
|
|
-
|
|
|
|
|
-2. **概率计算公式**:
|
|
|
|
|
- ```
|
|
|
|
|
- 内容获取概率 = 内容权重 / 宝箱内容权重总和 * 100%
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-3. **多物品抽取**:
|
|
|
|
|
- - 当宝箱配置为掉落多个物品时,系统会进行多次抽取
|
|
|
|
|
- - 每次抽取都会根据权重进行随机选择
|
|
|
|
|
- - 如果不允许重复,已选中的内容会从后续抽取中排除
|
|
|
|
|
-
|
|
|
|
|
-### 5.4 保底机制
|
|
|
|
|
-
|
|
|
|
|
-为了确保玩家在多次开启宝箱后能获得稀有物品,系统实现了保底机制:
|
|
|
|
|
-
|
|
|
|
|
-#### 5.4.1 保底机制设计
|
|
|
|
|
-
|
|
|
|
|
-保底机制直接集成在宝箱内容配置中,具有以下特点:
|
|
|
|
|
-
|
|
|
|
|
-1. **内容级别保底**:
|
|
|
|
|
- - 每个宝箱内容可以设置自己的保底次数(`pity_count`字段)
|
|
|
|
|
- - 当玩家连续未获得该内容达到指定次数后,必定获得该内容
|
|
|
|
|
-
|
|
|
|
|
-2. **灵活的概率调整**:
|
|
|
|
|
- - 通过 `pity_weight_factor` 字段控制递增概率的幅度
|
|
|
|
|
- - 可以为不同内容设置不同的递增策略
|
|
|
|
|
-
|
|
|
|
|
-3. **保底计数记录**:
|
|
|
|
|
- - 在 `item_pity_times` 表中记录用户对每个宝箱内容的尝试次数
|
|
|
|
|
- - 当获得内容后,相应的计数会重置
|
|
|
|
|
-
|
|
|
|
|
-#### 5.4.2 保底实现方式
|
|
|
|
|
-
|
|
|
|
|
-系统支持两种保底实现方式:
|
|
|
|
|
-
|
|
|
|
|
-1. **确定保底**:
|
|
|
|
|
- - 当玩家开启次数达到 `pity_count` 时,100%获得该内容
|
|
|
|
|
- - 适用于重要的稀有物品
|
|
|
|
|
-
|
|
|
|
|
-2. **递增概率**:
|
|
|
|
|
- - 每次未获得目标内容时,增加下次获得的概率
|
|
|
|
|
- - 概率增加公式:
|
|
|
|
|
- ```
|
|
|
|
|
- 调整后概率 = 基础概率 * (1 + (当前计数 / pity_count) * pity_weight_factor)
|
|
|
|
|
- ```
|
|
|
|
|
- - 当计数达到 `pity_count` 时,概率变为100%
|
|
|
|
|
-
|
|
|
|
|
-#### 5.4.3 保底机制实现流程
|
|
|
|
|
-
|
|
|
|
|
-1. **获取宝箱内容配置**
|
|
|
|
|
- - 从 `item_chest_contents` 表查询宝箱的所有内容配置
|
|
|
|
|
- - 过滤出 `pity_count > 0` 的内容,这些是启用了保底的内容
|
|
|
|
|
-
|
|
|
|
|
-2. **获取用户保底计数**
|
|
|
|
|
- - 从 `item_pity_times` 表查询用户对各宝箱内容的当前计数
|
|
|
|
|
- - 如果不存在,创建新记录并初始化计数
|
|
|
|
|
-
|
|
|
|
|
-3. **调整掉落概率**
|
|
|
|
|
- - 根据保底计数调整各内容的掉落概率
|
|
|
|
|
- - 如果有内容的计数达到保底次数,直接选择该内容
|
|
|
|
|
-
|
|
|
|
|
-4. **更新保底计数**
|
|
|
|
|
- - 对于未获得的内容,增加保底计数
|
|
|
|
|
- - 对于已获得的内容,重置保底计数
|
|
|
|
|
|
|
+### 3.2 关键字段说明
|
|
|
|
|
|
|
|
-### 5.5 宝箱开启接口
|
|
|
|
|
|
|
+#### 3.2.1 物品类型 (item_items.type)
|
|
|
|
|
|
|
|
-系统提供以下接口用于宝箱开启:
|
|
|
|
|
|
|
+物品类型决定了物品的基本行为和使用方式:
|
|
|
|
|
|
|
|
-#### 5.5.1 开启宝箱
|
|
|
|
|
|
|
+- 1: 可使用物品 - 直接消耗获得效果
|
|
|
|
|
+- 2: 可装备物品 - 装备后提供属性加成
|
|
|
|
|
+- 3: 可合成物品 - 可用于合成其他物品
|
|
|
|
|
+- 4: 任务物品 - 用于完成任务
|
|
|
|
|
+- 5: 宝箱物品 - 可开启获得其他物品
|
|
|
|
|
+- 6: 货币物品 - 用于交易和购买
|
|
|
|
|
|
|
|
-- **功能**:消耗宝箱并获取随机物品
|
|
|
|
|
-- **参数**:用户ID、宝箱ID、数量
|
|
|
|
|
-- **返回**:获得的物品列表、剩余宝箱数量
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查用户是否拥有足够数量的宝箱
|
|
|
|
|
- 2. 获取宝箱配置和用户保底计数
|
|
|
|
|
- 3. 计算实际掉落物品数量
|
|
|
|
|
- 4. 根据概率和保底机制选择掉落内容
|
|
|
|
|
- 5. 从用户背包中扣除宝箱
|
|
|
|
|
- 6. 向用户背包添加获得的物品
|
|
|
|
|
- 7. 更新保底计数
|
|
|
|
|
- 8. 记录宝箱开启日志
|
|
|
|
|
|
|
+#### 3.2.2 物品属性 (display_attributes, numeric_attributes)
|
|
|
|
|
|
|
|
-#### 5.5.2 获取宝箱内容预览
|
|
|
|
|
|
|
+物品属性以JSON格式存储,分为两类:
|
|
|
|
|
|
|
|
-- **功能**:预览宝箱可能获得的物品及概率
|
|
|
|
|
-- **参数**:宝箱ID
|
|
|
|
|
-- **返回**:可能获得的物品列表及概率
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 获取宝箱配置
|
|
|
|
|
- 2. 计算各内容的实际概率
|
|
|
|
|
- 3. 对于物品组,展开显示组内物品
|
|
|
|
|
- 4. 返回完整的可能获得物品列表及概率
|
|
|
|
|
|
|
+- **display_attributes**: 用于界面展示的属性,如图标、描述、外观等
|
|
|
|
|
+- **numeric_attributes**: 用于游戏逻辑计算的属性,如攻击力、防御力、使用效果等
|
|
|
|
|
|
|
|
-### 5.6 宝箱日志记录
|
|
|
|
|
|
|
+#### 3.2.3 交易类型 (item_transaction_logs.transaction_type)
|
|
|
|
|
|
|
|
-每次宝箱开启都会记录详细日志,用于数据分析和问题排查:
|
|
|
|
|
|
|
+记录物品流转的类型:
|
|
|
|
|
|
|
|
-#### 5.6.1 日志内容
|
|
|
|
|
|
|
+- 1: 获取 - 玩家获得物品
|
|
|
|
|
+- 2: 消耗 - 玩家消耗物品
|
|
|
|
|
+- 3: 交易获得 - 通过交易获得物品
|
|
|
|
|
+- 4: 交易失去 - 通过交易失去物品
|
|
|
|
|
+- 5: 过期失效 - 物品过期被移除
|
|
|
|
|
|
|
|
-在 `item_chest_open_logs` 表中记录以下信息:
|
|
|
|
|
|
|
+## 4. 核心功能
|
|
|
|
|
|
|
|
-1. **用户信息**:开启宝箱的用户ID
|
|
|
|
|
-2. **宝箱信息**:宝箱ID、开启数量
|
|
|
|
|
-3. **开启时间**:宝箱开启的时间戳
|
|
|
|
|
-4. **获得物品**:以JSON格式记录获得的所有物品ID和数量
|
|
|
|
|
-5. **保底触发**:是否触发保底机制,触发的内容ID
|
|
|
|
|
-6. **安全信息**:IP地址、设备信息等
|
|
|
|
|
|
|
+### 4.1 物品管理
|
|
|
|
|
|
|
|
-#### 5.6.2 日志用途
|
|
|
|
|
|
|
+#### 4.1.1 添加物品到用户背包
|
|
|
|
|
|
|
|
-1. **数据分析**:分析宝箱开启模式和物品掉落分布
|
|
|
|
|
-2. **概率验证**:验证实际掉落概率是否符合配置
|
|
|
|
|
-3. **用户支持**:解决用户关于宝箱开启的问题
|
|
|
|
|
-4. **异常检测**:发现可能的作弊或异常行为
|
|
|
|
|
-
|
|
|
|
|
-## 6. 物品获取与堆叠
|
|
|
|
|
-
|
|
|
|
|
-当玩家多次获得同一物品时,系统需要根据物品类型和过期时间进行不同的处理,以确保物品管理的合理性和高效性。
|
|
|
|
|
-
|
|
|
|
|
-### 6.1 统一属性物品的处理
|
|
|
|
|
-
|
|
|
|
|
-对于统一属性物品(如消耗品、材料等),系统采用以下处理策略:
|
|
|
|
|
-
|
|
|
|
|
-#### 6.1.1 基本堆叠规则
|
|
|
|
|
-
|
|
|
|
|
-1. **数量累加**:
|
|
|
|
|
- - 当玩家获得已拥有的统一属性物品时,系统会增加物品数量
|
|
|
|
|
- - 在 `item_users` 表中更新 `quantity` 字段
|
|
|
|
|
-
|
|
|
|
|
-2. **最大堆叠限制**:
|
|
|
|
|
- - 每种物品都有最大堆叠数量限制,定义在 `item_items` 表的 `max_stack` 字段
|
|
|
|
|
- - 当数量超过最大堆叠限制时,系统会创建新的堆叠
|
|
|
|
|
-
|
|
|
|
|
-3. **堆叠创建逻辑**:
|
|
|
|
|
- ```php
|
|
|
|
|
- // 伪代码示例
|
|
|
|
|
- $currentQuantity = $userItem->quantity;
|
|
|
|
|
- $maxStack = $item->max_stack;
|
|
|
|
|
- $newQuantity = $currentQuantity + $addQuantity;
|
|
|
|
|
-
|
|
|
|
|
- if ($newQuantity <= $maxStack) {
|
|
|
|
|
- // 直接增加数量
|
|
|
|
|
- $userItem->quantity = $newQuantity;
|
|
|
|
|
- $userItem->save();
|
|
|
|
|
- } else {
|
|
|
|
|
- // 先填满当前堆叠
|
|
|
|
|
- $userItem->quantity = $maxStack;
|
|
|
|
|
- $userItem->save();
|
|
|
|
|
-
|
|
|
|
|
- // 创建新堆叠
|
|
|
|
|
- $remainingQuantity = $newQuantity - $maxStack;
|
|
|
|
|
- $this->addNewStack($userId, $itemId, $remainingQuantity);
|
|
|
|
|
- }
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-#### 6.1.2 过期时间分组策略
|
|
|
|
|
-
|
|
|
|
|
-对于有过期时间的统一属性物品,系统按照过期时间分组存储:
|
|
|
|
|
-
|
|
|
|
|
-1. **过期时间匹配**:
|
|
|
|
|
- - 相同物品但过期时间不同,创建不同的记录
|
|
|
|
|
- - 相同物品且过期时间相同,数量累加
|
|
|
|
|
-
|
|
|
|
|
-2. **过期时间查找逻辑**:
|
|
|
|
|
- ```php
|
|
|
|
|
- // 伪代码示例
|
|
|
|
|
- $userItem = UserItem::where('user_id', $userId)
|
|
|
|
|
- ->where('item_id', $itemId)
|
|
|
|
|
- ->where('expire_at', $expireAt)
|
|
|
|
|
- ->first();
|
|
|
|
|
-
|
|
|
|
|
- if ($userItem) {
|
|
|
|
|
- // 找到相同过期时间的记录,增加数量
|
|
|
|
|
- $userItem->quantity += $quantity;
|
|
|
|
|
- $userItem->save();
|
|
|
|
|
- } else {
|
|
|
|
|
- // 创建新记录
|
|
|
|
|
- UserItem::create([
|
|
|
|
|
- 'user_id' => $userId,
|
|
|
|
|
- 'item_id' => $itemId,
|
|
|
|
|
- 'quantity' => $quantity,
|
|
|
|
|
- 'expire_at' => $expireAt
|
|
|
|
|
- ]);
|
|
|
|
|
- }
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-3. **使用优先级**:
|
|
|
|
|
- - 在使用物品时,优先使用即将过期的物品
|
|
|
|
|
- - 系统按过期时间升序排序,先使用最早过期的物品
|
|
|
|
|
-
|
|
|
|
|
-### 6.2 单独属性物品的处理
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+// 添加统一属性物品
|
|
|
|
|
+$result = $itemService->addItem($userId, $itemId, $quantity, [
|
|
|
|
|
+ 'source_type' => 'quest_reward',
|
|
|
|
|
+ 'source_id' => $questId,
|
|
|
|
|
+]);
|
|
|
|
|
|
|
|
-对于单独属性物品(如装备、宠物等),每次获取都创建新记录,即使是相同物品:
|
|
|
|
|
-
|
|
|
|
|
-#### 6.2.1 单独属性物品创建
|
|
|
|
|
-
|
|
|
|
|
-1. **实例创建**:
|
|
|
|
|
- - 每个单独属性物品都在 `item_instances` 表中创建一条记录
|
|
|
|
|
- - 生成独特的属性(可能包含随机因素)
|
|
|
|
|
-
|
|
|
|
|
-2. **用户关联**:
|
|
|
|
|
- - 在 `item_users` 表中创建记录,关联用户和物品实例
|
|
|
|
|
- - `quantity` 字段始终为1
|
|
|
|
|
-
|
|
|
|
|
-3. **创建流程**:
|
|
|
|
|
- ```php
|
|
|
|
|
- // 伪代码示例
|
|
|
|
|
- // 1. 创建物品实例
|
|
|
|
|
- $instance = ItemInstance::create([
|
|
|
|
|
- 'item_id' => $itemId,
|
|
|
|
|
- 'name' => $generatedName,
|
|
|
|
|
- 'display_attributes' => $displayAttributes,
|
|
|
|
|
- 'numeric_attributes' => $numericAttributes,
|
|
|
|
|
- 'expire_at' => $expireAt
|
|
|
|
|
- ]);
|
|
|
|
|
-
|
|
|
|
|
- // 2. 关联到用户
|
|
|
|
|
- UserItem::create([
|
|
|
|
|
- 'user_id' => $userId,
|
|
|
|
|
- 'item_id' => $itemId,
|
|
|
|
|
- 'instance_id' => $instance->id,
|
|
|
|
|
- 'quantity' => 1,
|
|
|
|
|
- 'expire_at' => $expireAt
|
|
|
|
|
- ]);
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-#### 6.2.2 属性差异化
|
|
|
|
|
-
|
|
|
|
|
-单独属性物品可以通过多种方式实现属性差异化:
|
|
|
|
|
-
|
|
|
|
|
-1. **随机属性生成**:
|
|
|
|
|
- - 在创建物品实例时生成随机属性
|
|
|
|
|
- - 属性范围可以根据物品基础属性和品质定义
|
|
|
|
|
-
|
|
|
|
|
-2. **命名差异化**:
|
|
|
|
|
- - 可以根据属性生成不同的物品名称
|
|
|
|
|
- - 例如:"锐利的钢刀"、"坚固的钢刀"等
|
|
|
|
|
-
|
|
|
|
|
-3. **属性继承与变异**:
|
|
|
|
|
- - 从基础物品继承部分属性
|
|
|
|
|
- - 添加随机变异或特殊效果
|
|
|
|
|
-
|
|
|
|
|
-### 6.3 物品获取来源记录
|
|
|
|
|
-
|
|
|
|
|
-系统记录物品的获取来源,便于数据分析和问题排查:
|
|
|
|
|
-
|
|
|
|
|
-#### 6.3.1 来源类型
|
|
|
|
|
-
|
|
|
|
|
-在 `item_transaction_logs` 表中记录物品获取来源:
|
|
|
|
|
-
|
|
|
|
|
-1. **任务奖励**:完成任务获得的物品
|
|
|
|
|
-2. **商店购买**:通过游戏商店购买的物品
|
|
|
|
|
-3. **宝箱开启**:通过开启宝箱获得的物品
|
|
|
|
|
-4. **怪物掉落**:击败怪物获得的物品
|
|
|
|
|
-5. **玩家交易**:通过与其他玩家交易获得的物品
|
|
|
|
|
-6. **系统赠送**:系统活动或补偿赠送的物品
|
|
|
|
|
-7. **合成获得**:通过物品合成获得的物品
|
|
|
|
|
-8. **分解获得**:通过物品分解获得的物品
|
|
|
|
|
-
|
|
|
|
|
-#### 6.3.2 来源记录格式
|
|
|
|
|
-
|
|
|
|
|
-```json
|
|
|
|
|
-{
|
|
|
|
|
- "source_type": "chest_open",
|
|
|
|
|
- "source_id": 12345,
|
|
|
|
|
- "details": {
|
|
|
|
|
- "chest_id": 101,
|
|
|
|
|
- "open_time": "2023-05-01 12:34:56",
|
|
|
|
|
- "is_pity": false
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 添加单独属性物品
|
|
|
|
|
+$result = $itemService->addItem($userId, $itemId, 1, [
|
|
|
|
|
+ 'source_type' => 'chest_open',
|
|
|
|
|
+ 'source_id' => $chestId,
|
|
|
|
|
+ 'display_attributes' => ['color' => 'red', 'size' => 'large'],
|
|
|
|
|
+ 'numeric_attributes' => ['attack' => 100, 'defense' => 50],
|
|
|
|
|
+]);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 6.4 物品获取限制
|
|
|
|
|
-
|
|
|
|
|
-系统支持对物品获取进行限制,防止物品过度产出:
|
|
|
|
|
-
|
|
|
|
|
-#### 6.4.1 背包容量限制
|
|
|
|
|
-
|
|
|
|
|
-1. **背包容量检查**:
|
|
|
|
|
- - 在添加物品前检查用户背包是否有足够空间
|
|
|
|
|
- - 背包容量可以根据用户等级或VIP等级动态调整
|
|
|
|
|
-
|
|
|
|
|
-2. **超出处理策略**:
|
|
|
|
|
- - 拒绝添加:当背包已满时拒绝添加新物品
|
|
|
|
|
- - 邮件发送:将无法添加的物品通过邮件发送给用户
|
|
|
|
|
- - 临时扩容:临时扩大背包容量,但用户需要尽快清理
|
|
|
|
|
-
|
|
|
|
|
-#### 6.4.2 物品数量限制
|
|
|
|
|
-
|
|
|
|
|
-1. **单个物品限制**:
|
|
|
|
|
- - 某些特殊物品可以设置最大持有数量
|
|
|
|
|
- - 当达到限制时,无法再获取该物品
|
|
|
|
|
-
|
|
|
|
|
-2. **物品组限制**:
|
|
|
|
|
- - 可以对一组相关物品设置总数限制
|
|
|
|
|
- - 例如,限制所有任务道具的总数量
|
|
|
|
|
-
|
|
|
|
|
-## 7. 物品产出限制
|
|
|
|
|
-
|
|
|
|
|
-为了防止某些物品产出超过预期,影响游戏平衡,系统实现了物品产出限制机制。
|
|
|
|
|
-
|
|
|
|
|
-### 7.1 限制类型
|
|
|
|
|
-
|
|
|
|
|
-系统支持多种限制类型,可以根据游戏需求灵活配置:
|
|
|
|
|
-
|
|
|
|
|
-#### 7.1.1 全局总量限制
|
|
|
|
|
-
|
|
|
|
|
-- **定义**:限制物品在整个游戏中的总产出数量
|
|
|
|
|
-- **应用场景**:限量版物品、稀有收藏品
|
|
|
|
|
-- **实现方式**:
|
|
|
|
|
- - 在 `item_output_limits` 表中设置 `limit_type=1`
|
|
|
|
|
- - 使用 `current_quantity` 字段记录当前已产出数量
|
|
|
|
|
- - 每次产出前检查是否超过 `max_quantity`
|
|
|
|
|
-
|
|
|
|
|
-#### 7.1.2 单个用户限制
|
|
|
|
|
-
|
|
|
|
|
-- **定义**:限制每个用户可获得的物品总数量
|
|
|
|
|
-- **应用场景**:防止单个用户囤积稀有物品、控制关键物品分配
|
|
|
|
|
-- **实现方式**:
|
|
|
|
|
- - 在 `item_output_limits` 表中设置 `limit_type=2`
|
|
|
|
|
- - 在 `item_user_output_counters` 表中记录每个用户的获取数量
|
|
|
|
|
- - 每次产出前检查用户是否超过限制
|
|
|
|
|
-
|
|
|
|
|
-#### 7.1.3 单日全局限制
|
|
|
|
|
-
|
|
|
|
|
-- **定义**:限制每天在整个游戏中的产出数量
|
|
|
|
|
-- **应用场景**:控制物品流通速度、防止市场泛滥
|
|
|
|
|
-- **实现方式**:
|
|
|
|
|
- - 在 `item_output_limits` 表中设置 `limit_type=3`
|
|
|
|
|
- - 使用 `current_quantity` 字段记录当日已产出数量
|
|
|
|
|
- - 每天重置计数
|
|
|
|
|
-
|
|
|
|
|
-#### 7.1.4 单日用户限制
|
|
|
|
|
-
|
|
|
|
|
-- **定义**:限制每个用户每天可获得的物品数量
|
|
|
|
|
-- **应用场景**:日常活动物品、防止刷取行为
|
|
|
|
|
-- **实现方式**:
|
|
|
|
|
- - 在 `item_output_limits` 表中设置 `limit_type=4`
|
|
|
|
|
- - 在 `item_user_output_counters` 表中记录用户当日获取数量
|
|
|
|
|
- - 每天重置计数
|
|
|
|
|
-
|
|
|
|
|
-### 7.2 重置机制
|
|
|
|
|
-
|
|
|
|
|
-不同类型的限制可以设置不同的重置周期,满足多样化的游戏需求:
|
|
|
|
|
-
|
|
|
|
|
-#### 7.2.1 重置类型
|
|
|
|
|
-
|
|
|
|
|
-1. **不重置**(`reset_type=0`):
|
|
|
|
|
- - 永久限制,适用于限量物品
|
|
|
|
|
- - 一旦达到限制,永远不会重置
|
|
|
|
|
-
|
|
|
|
|
-2. **每日重置**(`reset_type=1`):
|
|
|
|
|
- - 每天重置限制计数
|
|
|
|
|
- - 适用于日常活动物品
|
|
|
|
|
- - 重置时间通常为凌晨0点
|
|
|
|
|
-
|
|
|
|
|
-3. **每周重置**(`reset_type=2`):
|
|
|
|
|
- - 每周重置限制计数
|
|
|
|
|
- - 适用于周常活动物品
|
|
|
|
|
- - 重置时间通常为每周一凌晨0点
|
|
|
|
|
-
|
|
|
|
|
-4. **每月重置**(`reset_type=3`):
|
|
|
|
|
- - 每月重置限制计数
|
|
|
|
|
- - 适用于月度活动物品
|
|
|
|
|
- - 重置时间通常为每月1日凌晨0点
|
|
|
|
|
-
|
|
|
|
|
-#### 7.2.2 重置实现
|
|
|
|
|
-
|
|
|
|
|
-系统通过定时任务实现自动重置:
|
|
|
|
|
|
|
+#### 4.1.2 消耗用户物品
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function resetLimits()
|
|
|
|
|
-{
|
|
|
|
|
- $now = new DateTime();
|
|
|
|
|
|
|
+// 消耗统一属性物品
|
|
|
|
|
+$result = $itemService->consumeItem($userId, $itemId, null, $quantity, [
|
|
|
|
|
+ 'source_type' => 'item_use',
|
|
|
|
|
+ 'details' => ['effect_id' => 123],
|
|
|
|
|
+]);
|
|
|
|
|
|
|
|
- // 重置每日限制
|
|
|
|
|
- $dailyLimits = OutputLimit::where('reset_type', 1)
|
|
|
|
|
- ->where('last_reset_time', '<', $now->format('Y-m-d 00:00:00'))
|
|
|
|
|
- ->get();
|
|
|
|
|
|
|
+// 消耗单独属性物品
|
|
|
|
|
+$result = $itemService->consumeItem($userId, $itemId, $instanceId, 1, [
|
|
|
|
|
+ 'source_type' => 'equipment_upgrade',
|
|
|
|
|
+ 'details' => ['upgrade_id' => 456],
|
|
|
|
|
+]);
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
- foreach ($dailyLimits as $limit) {
|
|
|
|
|
- $limit->current_quantity = 0;
|
|
|
|
|
- $limit->last_reset_time = $now;
|
|
|
|
|
- $limit->save();
|
|
|
|
|
|
|
+#### 4.1.3 获取用户物品列表
|
|
|
|
|
|
|
|
- // 重置用户计数
|
|
|
|
|
- UserOutputCounter::where('limit_id', $limit->id)
|
|
|
|
|
- ->update(['current_count' => 0]);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+// 获取所有物品
|
|
|
|
|
+$items = $itemService->getUserItems($userId);
|
|
|
|
|
|
|
|
- // 类似地处理每周和每月重置
|
|
|
|
|
- // ...
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 获取特定类型的物品
|
|
|
|
|
+$items = $itemService->getUserItems($userId, [
|
|
|
|
|
+ 'type' => 2, // 装备类物品
|
|
|
|
|
+ 'category_id' => 5, // 特定分类
|
|
|
|
|
+]);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 7.3 关联物品限制
|
|
|
|
|
-
|
|
|
|
|
-系统支持将多个相关物品关联到同一个限制规则下,防止通过不同渠道绕过限制:
|
|
|
|
|
|
|
+### 4.2 宝箱系统
|
|
|
|
|
|
|
|
-#### 7.3.1 共享限制额度
|
|
|
|
|
|
|
+#### 4.2.1 开启宝箱
|
|
|
|
|
|
|
|
-- **定义**:多个物品共享同一个限制额度
|
|
|
|
|
-- **应用场景**:不同渠道获取的相同物品、功能相似的物品
|
|
|
|
|
-- **实现方式**:
|
|
|
|
|
- - 在 `item_output_limits` 表的 `related_items` 字段中存储关联物品ID列表
|
|
|
|
|
- - 检查限制时,同时考虑所有关联物品的产出数量
|
|
|
|
|
-
|
|
|
|
|
-#### 7.3.2 关联物品配置
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+// 开启宝箱
|
|
|
|
|
+$result = $chestService->openChest($userId, $chestId, $quantity, [
|
|
|
|
|
+ 'ip_address' => $request->ip(),
|
|
|
|
|
+ 'device_info' => $request->userAgent(),
|
|
|
|
|
+]);
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
-// related_items字段示例
|
|
|
|
|
-{
|
|
|
|
|
- "items": [1001, 1002, 1003],
|
|
|
|
|
- "relation_type": "shared_limit"
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 结果示例
|
|
|
|
|
+[
|
|
|
|
|
+ 'success' => true,
|
|
|
|
|
+ 'chest_id' => 123,
|
|
|
|
|
+ 'quantity' => 1,
|
|
|
|
|
+ 'results' => [
|
|
|
|
|
+ [
|
|
|
|
|
+ [
|
|
|
|
|
+ 'item_id' => 456,
|
|
|
|
|
+ 'quantity' => 2,
|
|
|
|
|
+ 'is_pity' => false,
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ 'item_id' => 789,
|
|
|
|
|
+ 'quantity' => 1,
|
|
|
|
|
+ 'is_pity' => true,
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'pity_triggered' => true,
|
|
|
|
|
+ 'log_id' => 10001,
|
|
|
|
|
+]
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 7.4 限制检查流程
|
|
|
|
|
-
|
|
|
|
|
-在物品产出前,系统会执行以下检查流程,确保不超过设定的限制:
|
|
|
|
|
-
|
|
|
|
|
-#### 7.4.1 检查步骤
|
|
|
|
|
-
|
|
|
|
|
-1. **查询物品限制**:
|
|
|
|
|
- ```php
|
|
|
|
|
- $limit = OutputLimit::where('item_id', $itemId)->first();
|
|
|
|
|
- if (!$limit) {
|
|
|
|
|
- // 没有限制,直接允许产出
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-2. **检查限制类型**:
|
|
|
|
|
- ```php
|
|
|
|
|
- switch ($limit->limit_type) {
|
|
|
|
|
- case 1: // 全局总量限制
|
|
|
|
|
- return $this->checkGlobalTotalLimit($limit, $quantity);
|
|
|
|
|
- case 2: // 单个用户限制
|
|
|
|
|
- return $this->checkUserTotalLimit($limit, $userId, $quantity);
|
|
|
|
|
- case 3: // 单日全局限制
|
|
|
|
|
- return $this->checkDailyGlobalLimit($limit, $quantity);
|
|
|
|
|
- case 4: // 单日用户限制
|
|
|
|
|
- return $this->checkDailyUserLimit($limit, $userId, $quantity);
|
|
|
|
|
- }
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-3. **检查关联物品**:
|
|
|
|
|
- ```php
|
|
|
|
|
- if (!empty($limit->related_items)) {
|
|
|
|
|
- $relatedItems = json_decode($limit->related_items, true);
|
|
|
|
|
- foreach ($relatedItems['items'] as $relatedItemId) {
|
|
|
|
|
- // 检查关联物品的产出记录
|
|
|
|
|
- // ...
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-4. **更新计数**:
|
|
|
|
|
- ```php
|
|
|
|
|
- if ($isGlobalLimit) {
|
|
|
|
|
- $limit->current_quantity += $quantity;
|
|
|
|
|
- $limit->save();
|
|
|
|
|
- } else {
|
|
|
|
|
- $counter = UserOutputCounter::firstOrCreate([
|
|
|
|
|
- 'user_id' => $userId,
|
|
|
|
|
- 'limit_id' => $limit->id
|
|
|
|
|
- ]);
|
|
|
|
|
- $counter->current_count += $quantity;
|
|
|
|
|
- $counter->save();
|
|
|
|
|
- }
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-#### 7.4.2 超限处理
|
|
|
|
|
-
|
|
|
|
|
-当检测到物品产出将超过限制时,系统可以采取以下处理方式:
|
|
|
|
|
-
|
|
|
|
|
-1. **拒绝产出**:直接拒绝物品产出,返回错误信息
|
|
|
|
|
-2. **部分产出**:产出不超过限制的部分数量
|
|
|
|
|
-3. **替代产出**:提供替代物品作为补偿
|
|
|
|
|
-4. **等待队列**:将超出部分放入等待队列,等待下次重置后产出
|
|
|
|
|
-
|
|
|
|
|
-### 7.5 监控与预警
|
|
|
|
|
-
|
|
|
|
|
-系统提供监控和预警机制,帮助游戏运营团队及时了解物品产出情况:
|
|
|
|
|
-
|
|
|
|
|
-#### 7.5.1 接近限制预警
|
|
|
|
|
-
|
|
|
|
|
-当物品产出数量接近限制时(例如达到80%),系统可以发送预警通知:
|
|
|
|
|
|
|
+#### 4.2.2 获取宝箱内容预览
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-if ($currentQuantity >= $maxQuantity * 0.8 && $currentQuantity < $maxQuantity * 0.9) {
|
|
|
|
|
- // 发送80%预警
|
|
|
|
|
- $this->sendWarning($itemId, '80%');
|
|
|
|
|
-} elseif ($currentQuantity >= $maxQuantity * 0.9) {
|
|
|
|
|
- // 发送90%预警
|
|
|
|
|
- $this->sendWarning($itemId, '90%');
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 获取宝箱内容预览
|
|
|
|
|
+$preview = $chestService->getChestContentPreview($chestId);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 7.5.2 产出统计报告
|
|
|
|
|
-
|
|
|
|
|
-系统定期生成物品产出统计报告,包括:
|
|
|
|
|
-
|
|
|
|
|
-1. **总产出数量**:各物品的总产出数量
|
|
|
|
|
-2. **限制使用情况**:各限制规则的使用情况
|
|
|
|
|
-3. **用户获取分布**:物品在用户间的分布情况
|
|
|
|
|
-4. **时间分布**:物品产出的时间分布
|
|
|
|
|
-
|
|
|
|
|
-## 8. 日志记录系统
|
|
|
|
|
-
|
|
|
|
|
-物品系统的所有操作都会记录详细日志,用于数据分析、问题排查和安全审计。
|
|
|
|
|
-
|
|
|
|
|
-### 8.1 日志类型
|
|
|
|
|
-
|
|
|
|
|
-系统根据不同的操作类型记录多种日志:
|
|
|
|
|
-
|
|
|
|
|
-#### 8.1.1 物品交易日志
|
|
|
|
|
-
|
|
|
|
|
-在 `item_transaction_logs` 表中记录所有物品获取和消耗操作:
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 日志ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID |
|
|
|
|
|
-| item_id | int | 物品ID |
|
|
|
|
|
-| instance_id | int | 单独属性物品ID(可为空) |
|
|
|
|
|
-| quantity | int | 数量(正数表示获取,负数表示消耗) |
|
|
|
|
|
-| transaction_type | tinyint | 交易类型(1:获取, 2:使用, 3:交易, 4:出售, 5:过期, 6:删除...) |
|
|
|
|
|
-| source_type | varchar | 来源类型(任务、商店、宝箱等) |
|
|
|
|
|
-| source_id | int | 来源ID(任务ID、商店ID、宝箱ID等) |
|
|
|
|
|
-| details | json | 详细信息,以JSON格式存储 |
|
|
|
|
|
-| transaction_time | timestamp | 交易时间 |
|
|
|
|
|
-| ip_address | varchar | 操作的IP地址 |
|
|
|
|
|
-| device_info | varchar | 设备信息 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 8.1.2 宝箱开启日志
|
|
|
|
|
-
|
|
|
|
|
-在 `item_chest_open_logs` 表中记录宝箱开启操作:
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 日志ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID |
|
|
|
|
|
-| chest_id | int | 宝箱ID |
|
|
|
|
|
-| quantity | int | 开启数量 |
|
|
|
|
|
-| results | json | 获得的物品,以JSON格式存储 |
|
|
|
|
|
-| pity_triggered | tinyint | 是否触发保底机制(0:否, 1:是) |
|
|
|
|
|
-| pity_content_id | int | 触发保底的内容ID(可为空) |
|
|
|
|
|
-| open_time | timestamp | 开启时间 |
|
|
|
|
|
-| ip_address | varchar | 操作的IP地址 |
|
|
|
|
|
-| device_info | varchar | 设备信息 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 8.1.3 物品合成日志
|
|
|
|
|
-
|
|
|
|
|
-在 `item_craft_logs` 表中记录物品合成操作:
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 日志ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID |
|
|
|
|
|
-| recipe_id | int | 配方ID |
|
|
|
|
|
-| materials | json | 消耗的材料,以JSON格式存储 |
|
|
|
|
|
-| result_item_id | int | 获得的物品ID |
|
|
|
|
|
-| result_instance_id | int | 获得的单独属性物品ID(可为空) |
|
|
|
|
|
-| result_quantity | int | 获得的物品数量 |
|
|
|
|
|
-| is_success | tinyint | 是否成功(0:失败, 1:成功) |
|
|
|
|
|
-| craft_time | timestamp | 合成时间 |
|
|
|
|
|
-| ip_address | varchar | 操作的IP地址 |
|
|
|
|
|
-| device_info | varchar | 设备信息 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 8.1.4 物品分解日志
|
|
|
|
|
-
|
|
|
|
|
-在 `item_dismantle_logs` 表中记录物品分解操作:
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 记录ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID |
|
|
|
|
|
-| item_id | int | 被分解的物品ID |
|
|
|
|
|
-| instance_id | int | 被分解的单独属性物品ID(可为空) |
|
|
|
|
|
-| quantity | int | 分解数量 |
|
|
|
|
|
-| rule_id | int | 使用的分解规则ID |
|
|
|
|
|
-| results | json | 分解结果,包含获得的物品ID、数量等信息 |
|
|
|
|
|
-| dismantle_time | timestamp | 分解时间 |
|
|
|
|
|
-| ip_address | varchar | 操作的IP地址 |
|
|
|
|
|
-| device_info | varchar | 设备信息 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-
|
|
|
|
|
-### 8.2 日志记录策略
|
|
|
|
|
-
|
|
|
|
|
-系统采用以下策略记录日志,确保数据完整性和系统性能:
|
|
|
|
|
-
|
|
|
|
|
-#### 8.2.1 事务内记录
|
|
|
|
|
-
|
|
|
|
|
-日志记录应在数据库事务内进行,确保操作和日志的一致性:
|
|
|
|
|
|
|
+### 4.3 物品合成系统
|
|
|
|
|
+
|
|
|
|
|
+#### 4.3.1 合成物品
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-DB::beginTransaction();
|
|
|
|
|
-try {
|
|
|
|
|
- // 执行物品操作
|
|
|
|
|
- $this->addItemToUser($userId, $itemId, $quantity);
|
|
|
|
|
-
|
|
|
|
|
- // 记录日志
|
|
|
|
|
- $this->logTransaction($userId, $itemId, $quantity, 1, $sourceType, $sourceId);
|
|
|
|
|
-
|
|
|
|
|
- DB::commit();
|
|
|
|
|
-} catch (\Exception $e) {
|
|
|
|
|
- DB::rollBack();
|
|
|
|
|
- throw $e;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 合成物品
|
|
|
|
|
+$result = $craftService->craftItem($userId, $recipeId, [
|
|
|
|
|
+ 'ip_address' => $request->ip(),
|
|
|
|
|
+ 'device_info' => $request->userAgent(),
|
|
|
|
|
+]);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 8.2.2 异步日志记录
|
|
|
|
|
-
|
|
|
|
|
-对于高频操作,可以使用队列实现异步日志记录,减轻数据库压力:
|
|
|
|
|
|
|
+#### 4.3.2 获取用户可合成配方列表
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 将日志记录任务推送到队列
|
|
|
|
|
-Queue::push(new RecordItemTransactionLog($userId, $itemId, $quantity, $transactionType, $sourceType, $sourceId));
|
|
|
|
|
|
|
+// 获取用户可合成配方列表
|
|
|
|
|
+$recipes = $craftService->getUserAvailableRecipes($userId);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 8.2.3 批量日志记录
|
|
|
|
|
|
|
+### 4.4 物品分解系统
|
|
|
|
|
|
|
|
-对于批量操作,可以使用批量插入优化性能:
|
|
|
|
|
|
|
+#### 4.4.1 分解物品
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-$logs = [];
|
|
|
|
|
-foreach ($items as $item) {
|
|
|
|
|
- $logs[] = [
|
|
|
|
|
- 'user_id' => $userId,
|
|
|
|
|
- 'item_id' => $item['id'],
|
|
|
|
|
- 'quantity' => $item['quantity'],
|
|
|
|
|
- 'transaction_type' => $transactionType,
|
|
|
|
|
- 'transaction_time' => now(),
|
|
|
|
|
- // 其他字段...
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 批量插入日志
|
|
|
|
|
-DB::table('item_transaction_logs')->insert($logs);
|
|
|
|
|
|
|
+// 分解物品
|
|
|
|
|
+$result = $dismantleService->dismantleItem($userId, $itemId, $instanceId, $quantity, [
|
|
|
|
|
+ 'ip_address' => $request->ip(),
|
|
|
|
|
+ 'device_info' => $request->userAgent(),
|
|
|
|
|
+]);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 8.3 日志查询接口
|
|
|
|
|
-
|
|
|
|
|
-系统提供以下接口用于查询日志:
|
|
|
|
|
-
|
|
|
|
|
-#### 8.3.1 查询用户物品历史
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:查询用户的物品获取和消耗历史
|
|
|
|
|
-- **参数**:用户ID、物品ID(可选)、交易类型(可选)、时间范围(可选)、分页参数
|
|
|
|
|
-- **返回**:物品交易记录列表
|
|
|
|
|
-- **查询示例**:
|
|
|
|
|
- ```php
|
|
|
|
|
- $logs = TransactionLog::where('user_id', $userId)
|
|
|
|
|
- ->when($itemId, function ($query) use ($itemId) {
|
|
|
|
|
- return $query->where('item_id', $itemId);
|
|
|
|
|
- })
|
|
|
|
|
- ->when($transactionType, function ($query) use ($transactionType) {
|
|
|
|
|
- return $query->where('transaction_type', $transactionType);
|
|
|
|
|
- })
|
|
|
|
|
- ->when($startTime && $endTime, function ($query) use ($startTime, $endTime) {
|
|
|
|
|
- return $query->whereBetween('transaction_time', [$startTime, $endTime]);
|
|
|
|
|
- })
|
|
|
|
|
- ->orderBy('transaction_time', 'desc')
|
|
|
|
|
- ->paginate($perPage);
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-#### 8.3.2 查询宝箱开启历史
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:查询用户的宝箱开启历史
|
|
|
|
|
-- **参数**:用户ID、宝箱ID(可选)、时间范围(可选)、分页参数
|
|
|
|
|
-- **返回**:宝箱开启记录列表
|
|
|
|
|
-- **查询示例**:
|
|
|
|
|
- ```php
|
|
|
|
|
- $logs = ChestOpenLog::where('user_id', $userId)
|
|
|
|
|
- ->when($chestId, function ($query) use ($chestId) {
|
|
|
|
|
- return $query->where('chest_id', $chestId);
|
|
|
|
|
- })
|
|
|
|
|
- ->when($startTime && $endTime, function ($query) use ($startTime, $endTime) {
|
|
|
|
|
- return $query->whereBetween('open_time', [$startTime, $endTime]);
|
|
|
|
|
- })
|
|
|
|
|
- ->orderBy('open_time', 'desc')
|
|
|
|
|
- ->paginate($perPage);
|
|
|
|
|
- ```
|
|
|
|
|
-
|
|
|
|
|
-### 8.4 日志分析与应用
|
|
|
|
|
-
|
|
|
|
|
-系统日志可用于多种分析和应用场景:
|
|
|
|
|
-
|
|
|
|
|
-#### 8.4.1 数据分析
|
|
|
|
|
-
|
|
|
|
|
-1. **物品流通分析**:
|
|
|
|
|
- - 分析物品的获取和消耗渠道
|
|
|
|
|
- - 识别最受欢迎的物品和获取方式
|
|
|
|
|
- - 监控物品经济平衡
|
|
|
|
|
-
|
|
|
|
|
-2. **用户行为分析**:
|
|
|
|
|
- - 分析用户的物品使用模式
|
|
|
|
|
- - 识别高价值用户和活跃用户
|
|
|
|
|
- - 发现潜在的游戏优化点
|
|
|
|
|
-
|
|
|
|
|
-#### 8.4.2 问题排查
|
|
|
|
|
-
|
|
|
|
|
-1. **物品丢失排查**:
|
|
|
|
|
- - 通过日志追踪物品的完整生命周期
|
|
|
|
|
- - 确认物品是否正常获取和消耗
|
|
|
|
|
- - 识别可能的系统错误或漏洞
|
|
|
|
|
-
|
|
|
|
|
-2. **异常行为检测**:
|
|
|
|
|
- - 识别可能的作弊或滥用行为
|
|
|
|
|
- - 监控异常的物品获取模式
|
|
|
|
|
- - 发现潜在的系统漏洞
|
|
|
|
|
-
|
|
|
|
|
-#### 8.4.3 用户支持
|
|
|
|
|
-
|
|
|
|
|
-1. **物品恢复**:
|
|
|
|
|
- - 在系统错误导致物品丢失时,通过日志确认物品状态
|
|
|
|
|
- - 提供准确的物品恢复服务
|
|
|
|
|
-
|
|
|
|
|
-2. **用户查询**:
|
|
|
|
|
- - 回答用户关于物品获取和消耗的问题
|
|
|
|
|
- - 提供物品历史记录查询服务
|
|
|
|
|
-
|
|
|
|
|
-### 8.5 日志清理与归档
|
|
|
|
|
-
|
|
|
|
|
-为了管理日志数据量,系统实现了日志清理和归档机制:
|
|
|
|
|
-
|
|
|
|
|
-#### 8.5.1 日志保留策略
|
|
|
|
|
-
|
|
|
|
|
-1. **实时日志**:
|
|
|
|
|
- - 保留最近30天的日志在主数据库中
|
|
|
|
|
- - 用于实时查询和问题排查
|
|
|
|
|
-
|
|
|
|
|
-2. **归档日志**:
|
|
|
|
|
- - 30天以上的日志移动到归档数据库
|
|
|
|
|
- - 用于长期数据分析和审计
|
|
|
|
|
-
|
|
|
|
|
-3. **统计汇总**:
|
|
|
|
|
- - 对超过180天的日志进行统计汇总
|
|
|
|
|
- - 保留关键统计数据,删除详细记录
|
|
|
|
|
-
|
|
|
|
|
-#### 8.5.2 归档实现
|
|
|
|
|
|
|
+#### 4.4.2 获取物品分解预览
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function archiveLogs()
|
|
|
|
|
-{
|
|
|
|
|
- $cutoffDate = now()->subDays(30);
|
|
|
|
|
-
|
|
|
|
|
- // 查找需要归档的日志
|
|
|
|
|
- $logsToArchive = TransactionLog::where('transaction_time', '<', $cutoffDate)
|
|
|
|
|
- ->limit(1000)
|
|
|
|
|
- ->get();
|
|
|
|
|
-
|
|
|
|
|
- if ($logsToArchive->isEmpty()) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 插入到归档表
|
|
|
|
|
- DB::connection('archive')->table('archived_transaction_logs')->insert(
|
|
|
|
|
- $logsToArchive->toArray()
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 删除已归档的日志
|
|
|
|
|
- $ids = $logsToArchive->pluck('id')->toArray();
|
|
|
|
|
- TransactionLog::whereIn('id', $ids)->delete();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-## 9. 物品合成系统
|
|
|
|
|
-
|
|
|
|
|
-物品合成系统允许玩家使用已有物品合成新物品,增加游戏深度和物品获取途径。
|
|
|
|
|
-
|
|
|
|
|
-### 9.1 合成系统概述
|
|
|
|
|
-
|
|
|
|
|
-物品合成系统具有以下特点:
|
|
|
|
|
-
|
|
|
|
|
-#### 9.1.1 系统特点
|
|
|
|
|
-
|
|
|
|
|
-1. **多材料合成**:支持使用多种不同物品作为材料
|
|
|
|
|
-2. **概率成功**:合成可以设置成功率,增加游戏随机性
|
|
|
|
|
-3. **等级限制**:可以设置合成的等级或条件限制
|
|
|
|
|
-4. **配方解锁**:玩家需要先解锁配方才能进行合成
|
|
|
|
|
-5. **多币种成本**:支持消耗多种货币作为合成成本
|
|
|
|
|
-
|
|
|
|
|
-#### 9.1.2 合成流程
|
|
|
|
|
-
|
|
|
|
|
-1. **选择配方**:玩家从已解锁的配方中选择要合成的物品
|
|
|
|
|
-2. **检查材料**:系统检查玩家是否拥有足够的材料
|
|
|
|
|
-3. **支付成本**:扣除合成所需的货币成本
|
|
|
|
|
-4. **消耗材料**:从玩家背包中扣除材料
|
|
|
|
|
-5. **概率判定**:根据配方的成功率判定是否合成成功
|
|
|
|
|
-6. **发放物品**:合成成功时,向玩家发放合成物品
|
|
|
|
|
-7. **记录日志**:记录合成操作的详细信息
|
|
|
|
|
-
|
|
|
|
|
-### 9.2 数据库设计
|
|
|
|
|
|
|
+// 获取物品分解预览
|
|
|
|
|
+$preview = $dismantleService->getDismantlePreview($userId, $itemId, $instanceId);
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-合成系统涉及三个主要数据表:配方表、配方材料表和用户配方表。
|
|
|
|
|
|
|
+## 4. 核心服务
|
|
|
|
|
|
|
|
-#### 9.2.1 item_recipes 表(合成配方)
|
|
|
|
|
|
|
+### 4.1 ItemService
|
|
|
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 配方ID,主键 |
|
|
|
|
|
-| name | varchar | 配方名称 |
|
|
|
|
|
-| result_item_id | int | 产出物品ID,外键关联item_items表 |
|
|
|
|
|
-| result_min_quantity | int | 最小产出数量 |
|
|
|
|
|
-| result_max_quantity | int | 最大产出数量 |
|
|
|
|
|
-| success_rate | decimal(5,2) | 成功率(百分比,最大100) |
|
|
|
|
|
-| coin_cost | json | 货币成本,以JSON格式存储多种货币类型和数量 |
|
|
|
|
|
-| level_required | int | 所需等级 |
|
|
|
|
|
-| is_default_unlocked | tinyint | 是否默认解锁(0:否, 1:是) |
|
|
|
|
|
-| unlock_condition | json | 解锁条件,以JSON格式存储 |
|
|
|
|
|
-| cooldown_seconds | int | 冷却时间(秒) |
|
|
|
|
|
-| category_id | int | 配方分类ID |
|
|
|
|
|
-| sort_order | int | 排序权重 |
|
|
|
|
|
-| is_active | tinyint | 是否激活(0:否, 1:是) |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
|
|
+物品基础服务,负责物品的基本操作。
|
|
|
|
|
|
|
|
-#### 9.2.2 item_recipe_materials 表(配方材料)
|
|
|
|
|
|
|
+#### 主要方法
|
|
|
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 记录ID,主键 |
|
|
|
|
|
-| recipe_id | int | 配方ID,外键关联item_recipes表 |
|
|
|
|
|
-| item_id | int | 材料物品ID,外键关联item_items表 |
|
|
|
|
|
-| quantity | int | 所需数量 |
|
|
|
|
|
-| is_consumed | tinyint | 是否消耗(0:不消耗, 1:消耗) |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取用户物品列表
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param array $filters 过滤条件
|
|
|
|
|
+ * @param bool $includeExpired 是否包含已过期物品
|
|
|
|
|
+ * @return Collection
|
|
|
|
|
+ */
|
|
|
|
|
+public function getUserItems(int $userId, array $filters = [], bool $includeExpired = false): Collection;
|
|
|
|
|
|
|
|
-#### 9.2.3 item_user_recipes 表(用户配方)
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 添加物品到用户背包
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $itemId 物品ID
|
|
|
|
|
+ * @param int $quantity 数量
|
|
|
|
|
+ * @param array $options 选项
|
|
|
|
|
+ * @return array 添加结果
|
|
|
|
|
+ */
|
|
|
|
|
+public function addItem(int $userId, int $itemId, int $quantity, array $options = []): array;
|
|
|
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 记录ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID |
|
|
|
|
|
-| recipe_id | int | 配方ID,外键关联item_recipes表 |
|
|
|
|
|
-| is_unlocked | tinyint | 是否已解锁(0:否, 1:是) |
|
|
|
|
|
-| unlock_time | timestamp | 解锁时间 |
|
|
|
|
|
-| last_craft_time | timestamp | 最后合成时间 |
|
|
|
|
|
-| craft_count | int | 合成次数 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 消耗用户物品
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $itemId 物品ID
|
|
|
|
|
+ * @param int|null $instanceId 物品实例ID(单独属性物品)
|
|
|
|
|
+ * @param int $quantity 数量
|
|
|
|
|
+ * @param array $options 选项
|
|
|
|
|
+ * @return array 消耗结果
|
|
|
|
|
+ */
|
|
|
|
|
+public function consumeItem(int $userId, int $itemId, ?int $instanceId, int $quantity, array $options = []): array;
|
|
|
|
|
|
|
|
-### 9.3 多币种成本设计
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 检查用户物品数量
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $itemId 物品ID
|
|
|
|
|
+ * @param int|null $instanceId 物品实例ID(单独属性物品)
|
|
|
|
|
+ * @return int 物品数量
|
|
|
|
|
+ */
|
|
|
|
|
+public function getItemQuantity(int $userId, int $itemId, ?int $instanceId = null): int;
|
|
|
|
|
|
|
|
-系统支持使用多种货币作为合成成本,增加游戏经济的深度:
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 检查物品是否过期
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $itemId 物品ID
|
|
|
|
|
+ * @param int|null $instanceId 物品实例ID
|
|
|
|
|
+ * @return bool 是否过期
|
|
|
|
|
+ */
|
|
|
|
|
+public function isItemExpired(int $itemId, ?int $instanceId = null): bool;
|
|
|
|
|
+```
|
|
|
|
|
|
|
|
-#### 9.3.1 币种类型
|
|
|
|
|
|
|
+### 4.2 ChestService
|
|
|
|
|
|
|
|
-1. **游戏金币**:基础游戏货币
|
|
|
|
|
-2. **钻石**:高级游戏货币,通常与真实货币关联
|
|
|
|
|
-3. **声望**:特定阵营或活动的声望货币
|
|
|
|
|
-4. **活动代币**:限时活动专用货币
|
|
|
|
|
|
|
+宝箱服务,负责宝箱开启和内容管理。
|
|
|
|
|
|
|
|
-#### 9.3.2 成本存储格式
|
|
|
|
|
|
|
+#### 主要方法
|
|
|
|
|
|
|
|
-在 `item_recipes` 表的 `coin_cost` 字段中,使用JSON格式存储多币种成本:
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 开启宝箱
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $chestId 宝箱ID
|
|
|
|
|
+ * @param int $quantity 开启数量
|
|
|
|
|
+ * @param array $options 选项
|
|
|
|
|
+ * @return array 开启结果
|
|
|
|
|
+ */
|
|
|
|
|
+public function openChest(int $userId, int $chestId, int $quantity = 1, array $options = []): array;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取宝箱内容预览
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $chestId 宝箱ID
|
|
|
|
|
+ * @return array 宝箱内容预览
|
|
|
|
|
+ */
|
|
|
|
|
+public function getChestContentPreview(int $chestId): array;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4.3 CraftService
|
|
|
|
|
+
|
|
|
|
|
+合成服务,负责物品合成和配方管理。
|
|
|
|
|
+
|
|
|
|
|
+#### 主要方法
|
|
|
|
|
+
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 合成物品
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $recipeId 配方ID
|
|
|
|
|
+ * @param array $options 选项
|
|
|
|
|
+ * @return array 合成结果
|
|
|
|
|
+ */
|
|
|
|
|
+public function craftItem(int $userId, int $recipeId, array $options = []): array;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取用户可合成配方列表
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param array $filters 过滤条件
|
|
|
|
|
+ * @return Collection 配方列表
|
|
|
|
|
+ */
|
|
|
|
|
+public function getUserAvailableRecipes(int $userId, array $filters = []): Collection;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 解锁用户配方
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $recipeId 配方ID
|
|
|
|
|
+ * @return bool 是否成功
|
|
|
|
|
+ */
|
|
|
|
|
+public function unlockRecipe(int $userId, int $recipeId): bool;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4.4 DismantleService
|
|
|
|
|
+
|
|
|
|
|
+分解服务,负责物品分解和规则管理。
|
|
|
|
|
+
|
|
|
|
|
+#### 主要方法
|
|
|
|
|
+
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 分解物品
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $itemId 物品ID
|
|
|
|
|
+ * @param int|null $instanceId 物品实例ID
|
|
|
|
|
+ * @param int $quantity 数量
|
|
|
|
|
+ * @param array $options 选项
|
|
|
|
|
+ * @return array 分解结果
|
|
|
|
|
+ */
|
|
|
|
|
+public function dismantleItem(int $userId, int $itemId, ?int $instanceId, int $quantity, array $options = []): array;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取物品分解预览
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int $userId 用户ID
|
|
|
|
|
+ * @param int $itemId 物品ID
|
|
|
|
|
+ * @param int|null $instanceId 物品实例ID
|
|
|
|
|
+ * @return array 分解预览
|
|
|
|
|
+ */
|
|
|
|
|
+public function getDismantlePreview(int $userId, int $itemId, ?int $instanceId): array;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 5. 数据模型
|
|
|
|
|
+
|
|
|
|
|
+### 5.1 核心模型
|
|
|
|
|
+
|
|
|
|
|
+#### 5.1.1 Item
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
|
|
+物品基础信息模型,定义物品的基本属性。
|
|
|
|
|
+
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 物品基础信息
|
|
|
|
|
+ *
|
|
|
|
|
+ * field start
|
|
|
|
|
+ * @property int $id 物品ID,主键
|
|
|
|
|
+ * @property string $name 物品名称
|
|
|
|
|
+ * @property string $description 物品描述
|
|
|
|
|
+ * @property int $category_id 物品分类ID,外键关联kku_item_categories表
|
|
|
|
|
+ * @property int $type 物品类型(1:可使用, 2:可装备, 3:可合成, 4:可交任务, 5:可开启...)
|
|
|
|
|
+ * @property int $is_unique 是否是单独属性物品(0:否,默认, 1:是)
|
|
|
|
|
+ * @property int $max_stack 最大堆叠数量
|
|
|
|
|
+ * @property int $sell_price 出售价格
|
|
|
|
|
+ * @property int $tradable 是否可交易(0:不可交易, 1:可交易,默认)
|
|
|
|
|
+ * @property int $dismantlable 是否可分解(0:不可分解, 1:可分解,默认)
|
|
|
|
|
+ * @property int $default_expire_seconds 玩家获取物品后的默认有效秒数(0表示永久有效)
|
|
|
|
|
+ * @property object|array $display_attributes 展示属性,以JSON格式存储键值对,用于界面展示和描述的属性
|
|
|
|
|
+ * @property object|array $numeric_attributes 数值属性,以JSON格式存储键值对,用于计算和游戏逻辑的属性
|
|
|
|
|
+ * @property string $global_expire_at 物品全局过期时间(可为空)
|
|
|
|
|
+ * @property \Carbon\Carbon $created_at 创建时间
|
|
|
|
|
+ * @property \Carbon\Carbon $updated_at 更新时间
|
|
|
|
|
+ * field end
|
|
|
|
|
+ */
|
|
|
|
|
+class Item extends ModelCore
|
|
|
|
|
+{
|
|
|
|
|
+ // 模型实现...
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 5.1.2 ItemChestContent
|
|
|
|
|
+
|
|
|
|
|
+宝箱内容配置模型,定义宝箱可能掉落的物品。
|
|
|
|
|
+
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 宝箱内容配置
|
|
|
|
|
+ *
|
|
|
|
|
+ * field start
|
|
|
|
|
+ * @property int $id 记录ID,主键
|
|
|
|
|
+ * @property int $chest_id 宝箱物品ID,外键关联kku_item_items表
|
|
|
|
|
+ * @property int $item_id 可能获得的物品ID,外键关联kku_item_items表(与group_id二选一)
|
|
|
|
|
+ * @property int $group_id 物品组ID,外键关联kku_item_groups表(与item_id二选一)
|
|
|
|
|
+ * @property int $min_quantity 最小数量
|
|
|
|
|
+ * @property int $max_quantity 最大数量
|
|
|
|
|
+ * @property float $weight 权重,决定获取概率
|
|
|
|
|
+ * @property int $allow_duplicate 是否允许在同一宝箱中重复掉落(0:不允许, 1:允许)
|
|
|
|
|
+ * @property int $pity_count 保底次数,当玩家连续未获得该内容达到次数后必定获得(0表示不启用保底)
|
|
|
|
|
+ * @property float $pity_weight_factor 保底权重因子,用于递增概率计算(默认1.0)
|
|
|
|
|
+ * @property \Carbon\Carbon $created_at 创建时间
|
|
|
|
|
+ * @property \Carbon\Carbon $updated_at 更新时间
|
|
|
|
|
+ * field end
|
|
|
|
|
+ */
|
|
|
|
|
+class ItemChestContent extends ModelCore
|
|
|
{
|
|
{
|
|
|
- "gold": 1000,
|
|
|
|
|
- "diamond": 5,
|
|
|
|
|
- "reputation": {
|
|
|
|
|
- "faction_id": 2,
|
|
|
|
|
- "amount": 100
|
|
|
|
|
- },
|
|
|
|
|
- "event_token": {
|
|
|
|
|
- "token_id": 101,
|
|
|
|
|
- "amount": 20
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 模型实现...
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 9.3.3 成本检查逻辑
|
|
|
|
|
|
|
+#### 5.1.3 ItemUser
|
|
|
|
|
+
|
|
|
|
|
+用户物品关联模型,记录用户拥有的物品。
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function checkCraftCost($userId, $recipeId)
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 用户物品关联
|
|
|
|
|
+ *
|
|
|
|
|
+ * field start
|
|
|
|
|
+ * @property int $id 记录ID,主键
|
|
|
|
|
+ * @property int $user_id 用户ID
|
|
|
|
|
+ * @property int $item_id 统一属性物品ID,外键关联kku_item_items表
|
|
|
|
|
+ * @property int $instance_id 单独属性物品ID,外键关联kku_item_instances表(可为空)
|
|
|
|
|
+ * @property int $quantity 数量(对于单独属性物品,该值始终为1)
|
|
|
|
|
+ * @property string $expire_at 用户物品过期时间(可为空)
|
|
|
|
|
+ * @property \Carbon\Carbon $created_at 获取时间
|
|
|
|
|
+ * @property \Carbon\Carbon $updated_at 更新时间
|
|
|
|
|
+ * field end
|
|
|
|
|
+ */
|
|
|
|
|
+class ItemUser extends ModelCore
|
|
|
{
|
|
{
|
|
|
- $recipe = Recipe::find($recipeId);
|
|
|
|
|
- $coinCost = json_decode($recipe->coin_cost, true);
|
|
|
|
|
-
|
|
|
|
|
- // 检查各种货币是否足够
|
|
|
|
|
- foreach ($coinCost as $coinType => $amount) {
|
|
|
|
|
- if (is_array($amount)) {
|
|
|
|
|
- // 处理特殊货币(声望、活动代币等)
|
|
|
|
|
- $specialCoinId = $amount['faction_id'] ?? $amount['token_id'];
|
|
|
|
|
- $specialCoinAmount = $amount['amount'];
|
|
|
|
|
-
|
|
|
|
|
- if (!$this->hasEnoughSpecialCoin($userId, $coinType, $specialCoinId, $specialCoinAmount)) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // 处理基础货币(金币、钻石)
|
|
|
|
|
- if (!$this->hasEnoughCoin($userId, $coinType, $amount)) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ // 模型实现...
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 9.4 合成成功率机制
|
|
|
|
|
|
|
+### 5.2 模型关系
|
|
|
|
|
|
|
|
-系统支持概率性合成,增加游戏的随机性和挑战性:
|
|
|
|
|
|
|
+模型之间的关系定义如下:
|
|
|
|
|
|
|
|
-#### 9.4.1 基础成功率
|
|
|
|
|
|
|
+- **Item** 与 **ItemCategory** 是多对一关系
|
|
|
|
|
+- **Item** 与 **ItemInstance** 是一对多关系
|
|
|
|
|
+- **Item** 与 **ItemUser** 是一对多关系
|
|
|
|
|
+- **ItemInstance** 与 **ItemUser** 是一对多关系
|
|
|
|
|
+- **Item** 与 **ItemChestContent** 是一对多关系(作为宝箱)
|
|
|
|
|
+- **Item** 与 **ItemChestContent** 是一对多关系(作为内容)
|
|
|
|
|
+- **ItemGroup** 与 **ItemGroupItem** 是一对多关系
|
|
|
|
|
+- **ItemGroup** 与 **ItemChestContent** 是一对多关系
|
|
|
|
|
+- **ItemRecipe** 与 **ItemRecipeMaterial** 是一对多关系
|
|
|
|
|
+- **ItemRecipe** 与 **ItemUserRecipe** 是一对多关系
|
|
|
|
|
|
|
|
-每个配方都有一个基础成功率,定义在 `item_recipes` 表的 `success_rate` 字段中:
|
|
|
|
|
|
|
+## 6. 业务逻辑
|
|
|
|
|
|
|
|
-- 成功率范围:0-100(百分比)
|
|
|
|
|
-- 成功率为100表示必定成功
|
|
|
|
|
-- 成功率为0表示无法通过常规方式成功
|
|
|
|
|
|
|
+### 6.1 Logics层
|
|
|
|
|
|
|
|
-#### 9.4.2 成功率调整因素
|
|
|
|
|
|
|
+Logics层包含所有业务逻辑处理类,负责具体的业务规则实现。这些类不直接对外提供服务,而是由Services层调用。
|
|
|
|
|
|
|
|
-基础成功率可以受多种因素影响:
|
|
|
|
|
|
|
+#### 6.1.1 Item
|
|
|
|
|
|
|
|
-1. **玩家等级**:等级越高,成功率可能越高
|
|
|
|
|
-2. **技能加成**:特定技能可以提高成功率
|
|
|
|
|
-3. **道具加成**:使用特殊道具可以提高成功率
|
|
|
|
|
-4. **设备加成**:使用特殊设备进行合成可以提高成功率
|
|
|
|
|
-
|
|
|
|
|
-#### 9.4.3 成功率计算
|
|
|
|
|
|
|
+物品逻辑类,处理物品相关的业务逻辑。
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function calculateSuccessRate($userId, $recipeId)
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 物品逻辑类
|
|
|
|
|
+ */
|
|
|
|
|
+class Item
|
|
|
{
|
|
{
|
|
|
- $recipe = Recipe::find($recipeId);
|
|
|
|
|
- $baseRate = $recipe->success_rate;
|
|
|
|
|
-
|
|
|
|
|
- // 获取玩家等级加成
|
|
|
|
|
- $user = User::find($userId);
|
|
|
|
|
- $levelBonus = $this->getLevelSuccessBonus($user->level);
|
|
|
|
|
-
|
|
|
|
|
- // 获取技能加成
|
|
|
|
|
- $skillBonus = $this->getSkillSuccessBonus($userId);
|
|
|
|
|
-
|
|
|
|
|
- // 获取道具加成
|
|
|
|
|
- $itemBonus = $this->getItemSuccessBonus($userId);
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断物品是否为宝箱
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemModel $item 物品模型
|
|
|
|
|
+ * @return bool
|
|
|
|
|
+ */
|
|
|
|
|
+ public function isChest(ItemModel $item): bool;
|
|
|
|
|
|
|
|
- // 计算最终成功率
|
|
|
|
|
- $finalRate = $baseRate + $levelBonus + $skillBonus + $itemBonus;
|
|
|
|
|
-
|
|
|
|
|
- // 确保成功率在0-100范围内
|
|
|
|
|
- return max(0, min(100, $finalRate));
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检查物品是否已过期(全局过期)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemModel $item 物品模型
|
|
|
|
|
+ * @return bool
|
|
|
|
|
+ */
|
|
|
|
|
+ public function isExpired(ItemModel $item): bool;
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 9.5 合成接口
|
|
|
|
|
-
|
|
|
|
|
-系统提供以下接口用于物品合成:
|
|
|
|
|
-
|
|
|
|
|
-#### 9.5.1 获取可用配方
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:获取用户可用的合成配方列表
|
|
|
|
|
-- **参数**:用户ID、分类ID(可选)
|
|
|
|
|
-- **返回**:配方列表,包含名称、材料、成功率等信息
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 查询用户已解锁的配方
|
|
|
|
|
- 2. 检查配方是否激活
|
|
|
|
|
- 3. 关联配方材料信息
|
|
|
|
|
- 4. 检查用户是否拥有足够材料
|
|
|
|
|
- 5. 返回配方列表,标记可合成状态
|
|
|
|
|
-
|
|
|
|
|
-#### 9.5.2 执行合成
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:执行物品合成操作
|
|
|
|
|
-- **参数**:用户ID、配方ID
|
|
|
|
|
-- **返回**:合成结果、获得的物品
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查配方是否存在且已解锁
|
|
|
|
|
- 2. 检查冷却时间是否已过
|
|
|
|
|
- 3. 检查用户是否拥有足够材料和货币
|
|
|
|
|
- 4. 扣除材料和货币
|
|
|
|
|
- 5. 根据成功率判定是否成功
|
|
|
|
|
- 6. 发放合成物品或返回失败信息
|
|
|
|
|
- 7. 更新用户配方使用记录
|
|
|
|
|
- 8. 记录合成日志
|
|
|
|
|
-
|
|
|
|
|
-#### 9.5.3 解锁配方
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:解锁新的合成配方
|
|
|
|
|
-- **参数**:用户ID、配方ID
|
|
|
|
|
-- **返回**:解锁结果
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查配方是否存在
|
|
|
|
|
- 2. 检查用户是否已解锁该配方
|
|
|
|
|
- 3. 检查解锁条件是否满足
|
|
|
|
|
- 4. 解锁配方并记录解锁时间
|
|
|
|
|
- 5. 返回解锁结果
|
|
|
|
|
-
|
|
|
|
|
-### 9.6 配方解锁机制
|
|
|
|
|
-
|
|
|
|
|
-系统支持多种配方解锁机制,增加游戏的探索性和进度感:
|
|
|
|
|
-
|
|
|
|
|
-#### 9.6.1 解锁方式
|
|
|
|
|
-
|
|
|
|
|
-1. **默认解锁**:
|
|
|
|
|
- - 在 `item_recipes` 表中设置 `is_default_unlocked=1`
|
|
|
|
|
- - 玩家创建角色时自动解锁
|
|
|
|
|
-
|
|
|
|
|
-2. **等级解锁**:
|
|
|
|
|
- - 在 `unlock_condition` 中设置所需等级
|
|
|
|
|
- - 玩家达到指定等级时自动解锁
|
|
|
|
|
-
|
|
|
|
|
-3. **任务解锁**:
|
|
|
|
|
- - 在 `unlock_condition` 中设置关联任务
|
|
|
|
|
- - 完成指定任务后解锁
|
|
|
|
|
-
|
|
|
|
|
-4. **成就解锁**:
|
|
|
|
|
- - 在 `unlock_condition` 中设置关联成就
|
|
|
|
|
- - 达成指定成就后解锁
|
|
|
|
|
-
|
|
|
|
|
-5. **物品解锁**:
|
|
|
|
|
- - 使用特定物品(如配方书)解锁
|
|
|
|
|
- - 系统检测物品使用事件并解锁对应配方
|
|
|
|
|
|
|
+#### 6.1.2 ChestContent
|
|
|
|
|
|
|
|
-#### 9.6.2 解锁条件格式
|
|
|
|
|
|
|
+宝箱内容逻辑类,处理宝箱内容相关的业务逻辑。
|
|
|
|
|
|
|
|
-在 `item_recipes` 表的 `unlock_condition` 字段中,使用JSON格式存储解锁条件:
|
|
|
|
|
-
|
|
|
|
|
-```json
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+/**
|
|
|
|
|
+ * 宝箱内容逻辑类
|
|
|
|
|
+ */
|
|
|
|
|
+class ChestContent
|
|
|
{
|
|
{
|
|
|
- "type": "level",
|
|
|
|
|
- "value": 20
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断是否为物品组内容
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemChestContent $content 宝箱内容
|
|
|
|
|
+ * @return bool
|
|
|
|
|
+ */
|
|
|
|
|
+ public function isGroupContent(ItemChestContent $content): bool;
|
|
|
|
|
|
|
|
-或者更复杂的条件:
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取随机数量
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemChestContent $content 宝箱内容
|
|
|
|
|
+ * @return int
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getRandomQuantity(ItemChestContent $content): int;
|
|
|
|
|
|
|
|
-```json
|
|
|
|
|
-{
|
|
|
|
|
- "type": "multi",
|
|
|
|
|
- "conditions": [
|
|
|
|
|
- {
|
|
|
|
|
- "type": "level",
|
|
|
|
|
- "value": 15
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- "type": "quest",
|
|
|
|
|
- "quest_id": 1024,
|
|
|
|
|
- "status": "completed"
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- "type": "item",
|
|
|
|
|
- "item_id": 5001,
|
|
|
|
|
- "quantity": 1
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- "logic": "and"
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 计算调整后的权重(考虑保底机制)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemChestContent $content 宝箱内容
|
|
|
|
|
+ * @param int $currentPityCount 当前保底计数
|
|
|
|
|
+ * @return float
|
|
|
|
|
+ */
|
|
|
|
|
+ public function getAdjustedWeight(ItemChestContent $content, int $currentPityCount = 0): float;
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 9.7 合成结果计算
|
|
|
|
|
-
|
|
|
|
|
-系统支持多种合成结果计算方式,增加游戏的多样性:
|
|
|
|
|
-
|
|
|
|
|
-#### 9.7.1 固定结果
|
|
|
|
|
|
|
+#### 6.1.3 PityTime
|
|
|
|
|
|
|
|
-最简单的合成方式,成功后获得固定数量的物品:
|
|
|
|
|
|
|
+保底计数逻辑类,处理宝箱保底机制相关的业务逻辑。
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-if ($this->isSuccess($userId, $recipeId)) {
|
|
|
|
|
- $recipe = Recipe::find($recipeId);
|
|
|
|
|
- $resultItemId = $recipe->result_item_id;
|
|
|
|
|
- $quantity = $recipe->result_min_quantity; // 固定数量
|
|
|
|
|
-
|
|
|
|
|
- $this->addItemToUser($userId, $resultItemId, $quantity);
|
|
|
|
|
- return ['success' => true, 'item_id' => $resultItemId, 'quantity' => $quantity];
|
|
|
|
|
-} else {
|
|
|
|
|
- return ['success' => false];
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 宝箱保底计数逻辑类
|
|
|
|
|
+ */
|
|
|
|
|
+class PityTime
|
|
|
|
|
+{
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 增加保底计数
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemPityTime $pityTime 保底计数模型
|
|
|
|
|
+ * @param int $count 增加的数量,默认为1
|
|
|
|
|
+ * @return bool
|
|
|
|
|
+ */
|
|
|
|
|
+ public function incrementCount(ItemPityTime $pityTime, int $count = 1): bool;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 重置保底计数
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param ItemPityTime $pityTime 保底计数模型
|
|
|
|
|
+ * @return bool
|
|
|
|
|
+ */
|
|
|
|
|
+ public function resetCount(ItemPityTime $pityTime): bool;
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 9.7.2 随机数量
|
|
|
|
|
|
|
+### 6.2 业务流程
|
|
|
|
|
|
|
|
-成功后获得的物品数量在一个范围内随机:
|
|
|
|
|
|
|
+#### 6.2.1 宝箱开启流程
|
|
|
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-if ($this->isSuccess($userId, $recipeId)) {
|
|
|
|
|
- $recipe = Recipe::find($recipeId);
|
|
|
|
|
- $resultItemId = $recipe->result_item_id;
|
|
|
|
|
- $minQuantity = $recipe->result_min_quantity;
|
|
|
|
|
- $maxQuantity = $recipe->result_max_quantity;
|
|
|
|
|
-
|
|
|
|
|
- // 随机数量
|
|
|
|
|
- $quantity = rand($minQuantity, $maxQuantity);
|
|
|
|
|
-
|
|
|
|
|
- $this->addItemToUser($userId, $resultItemId, $quantity);
|
|
|
|
|
- return ['success' => true, 'item_id' => $resultItemId, 'quantity' => $quantity];
|
|
|
|
|
-} else {
|
|
|
|
|
- return ['success' => false];
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
|
|
+1. 用户请求开启宝箱
|
|
|
|
|
+2. 验证用户是否拥有足够数量的宝箱
|
|
|
|
|
+3. 获取宝箱内容配置
|
|
|
|
|
+4. 获取用户保底计数
|
|
|
|
|
+5. 计算每个内容的调整后权重
|
|
|
|
|
+6. 检查是否有达到保底次数的内容
|
|
|
|
|
+7. 随机选择掉落内容
|
|
|
|
|
+8. 消耗宝箱物品
|
|
|
|
|
+9. 添加获得的物品到用户背包
|
|
|
|
|
+10. 更新保底计数
|
|
|
|
|
+11. 记录宝箱开启日志
|
|
|
|
|
+12. 返回开启结果
|
|
|
|
|
+
|
|
|
|
|
+#### 6.2.2 物品合成流程
|
|
|
|
|
+
|
|
|
|
|
+1. 用户请求合成物品
|
|
|
|
|
+2. 验证用户是否已解锁该配方
|
|
|
|
|
+3. 检查用户是否在冷却时间内
|
|
|
|
|
+4. 获取配方所需材料
|
|
|
|
|
+5. 检查用户是否拥有足够的材料
|
|
|
|
|
+6. 消耗材料
|
|
|
|
|
+7. 计算合成成功率
|
|
|
|
|
+8. 随机决定是否成功
|
|
|
|
|
+9. 如果成功,添加产物到用户背包
|
|
|
|
|
+10. 更新用户配方使用记录
|
|
|
|
|
+11. 记录合成日志
|
|
|
|
|
+12. 返回合成结果
|
|
|
|
|
|
|
|
-#### 9.7.3 品质变化
|
|
|
|
|
|
|
+## 7. 使用示例
|
|
|
|
|
|
|
|
-对于单独属性物品,合成可能影响物品的品质:
|
|
|
|
|
|
|
+### 7.1 在其他模块中使用物品服务
|
|
|
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-if ($this->isSuccess($userId, $recipeId)) {
|
|
|
|
|
- $recipe = Recipe::find($recipeId);
|
|
|
|
|
- $resultItemId = $recipe->result_item_id;
|
|
|
|
|
-
|
|
|
|
|
- // 计算品质
|
|
|
|
|
- $baseQuality = 100;
|
|
|
|
|
- $qualityVariation = rand(-10, 20); // 品质随机变化
|
|
|
|
|
- $finalQuality = $baseQuality + $qualityVariation;
|
|
|
|
|
-
|
|
|
|
|
- // 创建单独属性物品
|
|
|
|
|
- $attributes = [
|
|
|
|
|
- 'quality' => $finalQuality,
|
|
|
|
|
- // 其他属性...
|
|
|
|
|
- ];
|
|
|
|
|
-
|
|
|
|
|
- $instanceId = $this->createItemInstance($resultItemId, $attributes);
|
|
|
|
|
- $this->addItemInstanceToUser($userId, $resultItemId, $instanceId);
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- 'success' => true,
|
|
|
|
|
- 'item_id' => $resultItemId,
|
|
|
|
|
- 'instance_id' => $instanceId,
|
|
|
|
|
- 'quality' => $finalQuality
|
|
|
|
|
- ];
|
|
|
|
|
-} else {
|
|
|
|
|
- return ['success' => false];
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
|
|
+```php
|
|
|
|
|
+// 在任务完成后添加奖励物品
|
|
|
|
|
+public function completeQuest(int $userId, int $questId)
|
|
|
|
|
+{
|
|
|
|
|
+ // 获取任务信息
|
|
|
|
|
+ $quest = $this->questRepository->find($questId);
|
|
|
|
|
+
|
|
|
|
|
+ // 验证任务是否可完成
|
|
|
|
|
+ if (!$this->questService->canComplete($userId, $questId)) {
|
|
|
|
|
+ throw new QuestCannotCompleteException("任务无法完成");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-## 10. 物品分解系统
|
|
|
|
|
-
|
|
|
|
|
-物品分解系统允许玩家将不需要的物品分解为基础材料或其他资源,增加物品循环利用的途径,丰富游戏经济系统。
|
|
|
|
|
-
|
|
|
|
|
-### 10.1 分解系统概述
|
|
|
|
|
-
|
|
|
|
|
-#### 10.1.1 系统特点
|
|
|
|
|
-
|
|
|
|
|
-1. **资源回收**:将不需要的物品转化为有用的材料或资源
|
|
|
|
|
-2. **经济平衡**:为过剩物品提供消耗渠道,维持游戏经济平衡
|
|
|
|
|
-3. **多样化奖励**:分解可以获得多种类型的材料和资源
|
|
|
|
|
-4. **随机性**:分解结果可以包含随机因素,增加游戏乐趣
|
|
|
|
|
-5. **品质影响**:物品品质影响分解获得的材料数量和种类
|
|
|
|
|
-
|
|
|
|
|
-#### 10.1.2 分解系统流程
|
|
|
|
|
-
|
|
|
|
|
-1. **物品选择**:玩家选择要分解的物品和数量
|
|
|
|
|
-2. **分解预览**:系统显示可能获得的材料及概率
|
|
|
|
|
-3. **确认分解**:玩家确认分解操作
|
|
|
|
|
-4. **规则匹配**:系统根据物品特性匹配适用的分解规则
|
|
|
|
|
-5. **结果计算**:根据规则计算分解结果
|
|
|
|
|
-6. **物品扣除**:从玩家背包中扣除被分解的物品
|
|
|
|
|
-7. **材料发放**:向玩家发放分解获得的材料
|
|
|
|
|
-8. **日志记录**:记录分解操作的详细信息
|
|
|
|
|
-
|
|
|
|
|
-### 10.2 数据库设计
|
|
|
|
|
-
|
|
|
|
|
-分解系统涉及三个主要数据表:分解规则表、分解结果配置表和分解日志表。
|
|
|
|
|
-
|
|
|
|
|
-#### 10.2.1 item_dismantle_rules 表(物品分解规则)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 规则ID,主键 |
|
|
|
|
|
-| item_id | int | 物品ID,外键关联item_items表 |
|
|
|
|
|
-| category_id | int | 分类ID,外键关联item_categories表(与item_id二选一,用于对整个分类设置规则) |
|
|
|
|
|
-| min_rarity | tinyint | 最小适用稀有度 |
|
|
|
|
|
-| max_rarity | tinyint | 最大适用稀有度 |
|
|
|
|
|
-| priority | int | 规则优先级,当多个规则适用时,使用优先级最高的规则 |
|
|
|
|
|
-| is_active | tinyint | 是否激活(0:否, 1:是) |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 10.2.2 item_dismantle_results 表(分解结果配置)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 记录ID,主键 |
|
|
|
|
|
-| rule_id | int | 分解规则ID,外键关联item_dismantle_rules表 |
|
|
|
|
|
-| result_item_id | int | 结果物品ID,外键关联item_items表 |
|
|
|
|
|
-| min_quantity | int | 最小数量 |
|
|
|
|
|
-| max_quantity | int | 最大数量 |
|
|
|
|
|
-| base_chance | decimal(5,2) | 基础获取概率(百分比,最大100) |
|
|
|
|
|
-| rarity_factor | decimal(5,2) | 稀有度影响因子,物品稀有度对数量的影响系数 |
|
|
|
|
|
-| quality_factor | decimal(5,2) | 品质影响因子,物品品质对数量的影响系数 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-| updated_at | timestamp | 更新时间 |
|
|
|
|
|
-
|
|
|
|
|
-#### 10.2.3 item_dismantle_logs 表(分解记录)
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| id | int | 记录ID,主键 |
|
|
|
|
|
-| user_id | int | 用户ID |
|
|
|
|
|
-| item_id | int | 被分解的物品ID |
|
|
|
|
|
-| instance_id | int | 被分解的单独属性物品ID(可为空) |
|
|
|
|
|
-| quantity | int | 分解数量 |
|
|
|
|
|
-| rule_id | int | 使用的分解规则ID |
|
|
|
|
|
-| results | json | 分解结果,包含获得的物品ID、数量等信息 |
|
|
|
|
|
-| dismantle_time | timestamp | 分解时间 |
|
|
|
|
|
-| ip_address | varchar | 操作的IP地址 |
|
|
|
|
|
-| device_info | varchar | 设备信息 |
|
|
|
|
|
-| created_at | timestamp | 创建时间 |
|
|
|
|
|
-
|
|
|
|
|
-### 10.3 分解规则和机制
|
|
|
|
|
-
|
|
|
|
|
-物品分解系统支持多种规则和机制,确保分解结果的合理性和游戏平衡。
|
|
|
|
|
-
|
|
|
|
|
-#### 10.3.1 规则匹配逻辑
|
|
|
|
|
-
|
|
|
|
|
-系统按照以下优先级顺序匹配分解规则:
|
|
|
|
|
-
|
|
|
|
|
-1. **精确匹配**:根据物品ID精确匹配分解规则
|
|
|
|
|
-2. **分类匹配**:当没有精确匹配规则时,根据物品分类匹配规则
|
|
|
|
|
-3. **稀有度范围**:规则可以设置适用的稀有度范围
|
|
|
|
|
-4. **优先级**:当多个规则都适用时,使用优先级最高的规则
|
|
|
|
|
|
|
+ // 开始事务
|
|
|
|
|
+ DB::beginTransaction();
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 标记任务完成
|
|
|
|
|
+ $this->questService->markAsCompleted($userId, $questId);
|
|
|
|
|
+
|
|
|
|
|
+ // 添加奖励物品
|
|
|
|
|
+ foreach ($quest->rewards as $reward) {
|
|
|
|
|
+ $this->itemService->addItem(
|
|
|
|
|
+ $userId,
|
|
|
|
|
+ $reward['item_id'],
|
|
|
|
|
+ $reward['quantity'],
|
|
|
|
|
+ [
|
|
|
|
|
+ 'source_type' => 'quest_reward',
|
|
|
|
|
+ 'source_id' => $questId,
|
|
|
|
|
+ 'details' => ['quest_name' => $quest->name],
|
|
|
|
|
+ ]
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function findDismantleRule($itemId, $rarity)
|
|
|
|
|
-{
|
|
|
|
|
- // 1. 尝试精确匹配
|
|
|
|
|
- $rule = DismantleRule::where('item_id', $itemId)
|
|
|
|
|
- ->where('is_active', 1)
|
|
|
|
|
- ->where('min_rarity', '<=', $rarity)
|
|
|
|
|
- ->where('max_rarity', '>=', $rarity)
|
|
|
|
|
- ->orderBy('priority', 'desc')
|
|
|
|
|
- ->first();
|
|
|
|
|
-
|
|
|
|
|
- if ($rule) {
|
|
|
|
|
- return $rule;
|
|
|
|
|
|
|
+ DB::commit();
|
|
|
|
|
+ return ['success' => true, 'message' => '任务完成,奖励已发放'];
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ DB::rollBack();
|
|
|
|
|
+ throw $e;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 2. 尝试分类匹配
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
- $rule = DismantleRule::where('category_id', $item->category_id)
|
|
|
|
|
- ->where('item_id', null)
|
|
|
|
|
- ->where('is_active', 1)
|
|
|
|
|
- ->where('min_rarity', '<=', $rarity)
|
|
|
|
|
- ->where('max_rarity', '>=', $rarity)
|
|
|
|
|
- ->orderBy('priority', 'desc')
|
|
|
|
|
- ->first();
|
|
|
|
|
-
|
|
|
|
|
- return $rule;
|
|
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 10.3.2 特殊物品处理
|
|
|
|
|
-
|
|
|
|
|
-不同类型的物品在分解时有特殊处理逻辑:
|
|
|
|
|
-
|
|
|
|
|
-1. **绑定物品**:绑定物品分解后,获得的材料也会继承绑定状态
|
|
|
|
|
-2. **不可分解物品**:通过item_items表中的dismantlable字段标记物品是否可分解
|
|
|
|
|
-3. **单独属性物品**:分解单独属性物品时,可以根据其特殊属性调整分解结果
|
|
|
|
|
|
|
+### 6.2 实现宝箱开启功能
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function canDismantle($itemId, $instanceId = null)
|
|
|
|
|
|
|
+// 在控制器中实现宝箱开启功能
|
|
|
|
|
+public function openChest(Request $request, int $chestId)
|
|
|
{
|
|
{
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
|
|
+ // 验证请求
|
|
|
|
|
+ $validated = $request->validate([
|
|
|
|
|
+ 'quantity' => 'required|integer|min:1|max:10',
|
|
|
|
|
+ ]);
|
|
|
|
|
|
|
|
- // 检查物品是否可分解
|
|
|
|
|
- if ($item->dismantlable == 0) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 获取当前用户ID
|
|
|
|
|
+ $userId = Auth::id();
|
|
|
|
|
+
|
|
|
|
|
+ // 开启宝箱
|
|
|
|
|
+ $result = $this->chestService->openChest(
|
|
|
|
|
+ $userId,
|
|
|
|
|
+ $chestId,
|
|
|
|
|
+ $validated['quantity'],
|
|
|
|
|
+ [
|
|
|
|
|
+ 'ip_address' => $request->ip(),
|
|
|
|
|
+ 'device_info' => $request->userAgent(),
|
|
|
|
|
+ ]
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- // 检查单独属性物品
|
|
|
|
|
- if ($instanceId) {
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
- // 可以添加特殊条件,如不允许分解特定品质以上的装备
|
|
|
|
|
- if ($instance->numeric_attributes->quality > 90) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'success' => true,
|
|
|
|
|
+ 'data' => $result,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'success' => false,
|
|
|
|
|
+ 'message' => $e->getMessage(),
|
|
|
|
|
+ ], 400);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### 10.3.3 批量分解功能
|
|
|
|
|
-
|
|
|
|
|
-系统支持多种批量分解方式,提高用户体验:
|
|
|
|
|
-
|
|
|
|
|
-1. **同类物品批量分解**:一次分解多个相同物品
|
|
|
|
|
-2. **多类物品批量分解**:一次分解多种不同物品
|
|
|
|
|
-3. **自动分解**:可以设置自动分解规则,如自动分解低品质物品
|
|
|
|
|
|
|
+### 6.3 实现物品合成功能
|
|
|
|
|
|
|
|
```php
|
|
```php
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function batchDismantle($userId, $items)
|
|
|
|
|
|
|
+// 在控制器中实现物品合成功能
|
|
|
|
|
+public function craftItem(Request $request, int $recipeId)
|
|
|
{
|
|
{
|
|
|
- $results = [];
|
|
|
|
|
- $totalResults = [];
|
|
|
|
|
-
|
|
|
|
|
- DB::beginTransaction();
|
|
|
|
|
try {
|
|
try {
|
|
|
- foreach ($items as $item) {
|
|
|
|
|
- $itemId = $item['item_id'];
|
|
|
|
|
- $instanceId = $item['instance_id'] ?? null;
|
|
|
|
|
- $quantity = $item['quantity'];
|
|
|
|
|
-
|
|
|
|
|
- // 检查是否可分解
|
|
|
|
|
- if (!$this->canDismantle($itemId, $instanceId)) {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 执行分解
|
|
|
|
|
- $dismantleResult = $this->dismantleItem($userId, $itemId, $instanceId, $quantity);
|
|
|
|
|
- $results[] = $dismantleResult;
|
|
|
|
|
-
|
|
|
|
|
- // 合并结果
|
|
|
|
|
- foreach ($dismantleResult['materials'] as $material) {
|
|
|
|
|
- if (isset($totalResults[$material['item_id']])) {
|
|
|
|
|
- $totalResults[$material['item_id']]['quantity'] += $material['quantity'];
|
|
|
|
|
- } else {
|
|
|
|
|
- $totalResults[$material['item_id']] = $material;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 获取当前用户ID
|
|
|
|
|
+ $userId = Auth::id();
|
|
|
|
|
+
|
|
|
|
|
+ // 合成物品
|
|
|
|
|
+ $result = $this->craftService->craftItem(
|
|
|
|
|
+ $userId,
|
|
|
|
|
+ $recipeId,
|
|
|
|
|
+ [
|
|
|
|
|
+ 'ip_address' => $request->ip(),
|
|
|
|
|
+ 'device_info' => $request->userAgent(),
|
|
|
|
|
+ ]
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- DB::commit();
|
|
|
|
|
- return [
|
|
|
|
|
|
|
+ return response()->json([
|
|
|
'success' => true,
|
|
'success' => true,
|
|
|
- 'detail_results' => $results,
|
|
|
|
|
- 'total_materials' => array_values($totalResults)
|
|
|
|
|
- ];
|
|
|
|
|
- } catch (\Exception $e) {
|
|
|
|
|
- DB::rollBack();
|
|
|
|
|
- return ['success' => false, 'message' => $e->getMessage()];
|
|
|
|
|
|
|
+ 'data' => $result,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ return response()->json([
|
|
|
|
|
+ 'success' => false,
|
|
|
|
|
+ 'message' => $e->getMessage(),
|
|
|
|
|
+ ], 400);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-### 10.4 分解结果计算
|
|
|
|
|
-
|
|
|
|
|
-分解结果的计算是一个多步骤的过程,考虑多种因素。
|
|
|
|
|
-
|
|
|
|
|
-#### 10.4.1 基础数量计算
|
|
|
|
|
-
|
|
|
|
|
-首先计算基础数量:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-$baseQuantity = rand($resultConfig->min_quantity, $resultConfig->max_quantity);
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 10.4.2 稀有度和品质影响
|
|
|
|
|
-
|
|
|
|
|
-物品的稀有度和品质会影响最终获得的数量:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-$rarityBonus = ($item->rarity - 1) * $resultConfig->rarity_factor;
|
|
|
|
|
-
|
|
|
|
|
-// 对于单独属性物品,考虑品质
|
|
|
|
|
-$qualityBonus = 0;
|
|
|
|
|
-if ($instanceId) {
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
- $quality = $instance->numeric_attributes->quality ?? 0;
|
|
|
|
|
- $qualityBonus = $quality * $resultConfig->quality_factor;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-$finalQuantity = ceil($baseQuantity * (1 + $rarityBonus) * (1 + $qualityBonus));
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 10.4.3 概率计算
|
|
|
|
|
-
|
|
|
|
|
-每个可能的分解结果都有一个获取概率,也受物品稀有度和品质影响:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-$baseChance = $resultConfig->base_chance;
|
|
|
|
|
-$rarityBonus = ($item->rarity - 1) * 5; // 每级稀有度增加5%概率
|
|
|
|
|
-
|
|
|
|
|
-// 对于单独属性物品,考虑品质
|
|
|
|
|
-$qualityBonus = 0;
|
|
|
|
|
-if ($instanceId) {
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
- $quality = $instance->numeric_attributes->quality ?? 0;
|
|
|
|
|
- $qualityBonus = $quality * 0.1; // 每点品质增加0.1%概率
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-$finalChance = $baseChance + $rarityBonus + $qualityBonus;
|
|
|
|
|
-$finalChance = min(100, $finalChance); // 最大100%
|
|
|
|
|
-
|
|
|
|
|
-// 判断是否获得该结果
|
|
|
|
|
-$isObtained = (mt_rand(1, 100) <= $finalChance);
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 10.4.4 特殊结果机制
|
|
|
|
|
-
|
|
|
|
|
-某些特殊情况下,分解可能有额外结果:
|
|
|
|
|
-
|
|
|
|
|
-1. **暴击分解**:有小概率获得双倍或三倍材料
|
|
|
|
|
-2. **稀有材料**:分解高品质物品有几率获得稀有材料
|
|
|
|
|
-3. **特殊道具**:某些物品分解可能获得特殊道具或货币
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-// 检查是否触发暴击
|
|
|
|
|
-$criticalChance = 5; // 5%暴击概率
|
|
|
|
|
-$isCritical = (mt_rand(1, 100) <= $criticalChance);
|
|
|
|
|
-
|
|
|
|
|
-if ($isCritical) {
|
|
|
|
|
- $criticalMultiplier = (mt_rand(1, 100) <= 30) ? 3 : 2; // 30%几率3倍,70%几率2倍
|
|
|
|
|
- $finalQuantity *= $criticalMultiplier;
|
|
|
|
|
- $results['is_critical'] = true;
|
|
|
|
|
- $results['critical_multiplier'] = $criticalMultiplier;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 检查是否获得稀有材料
|
|
|
|
|
-if ($item->rarity >= 3 && mt_rand(1, 100) <= 10) {
|
|
|
|
|
- $rareMaterials = $this->getRareMaterials($item->category_id);
|
|
|
|
|
- // 添加稀有材料到结果中
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 10.5 分解系统接口
|
|
|
|
|
-
|
|
|
|
|
-系统提供以下接口用于物品分解:
|
|
|
|
|
-
|
|
|
|
|
-#### 10.5.1 获取物品分解预览
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:预览物品分解可能获得的材料
|
|
|
|
|
-- **参数**:用户ID、物品ID、数量
|
|
|
|
|
-- **返回**:可能获得的材料列表及概率
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查物品是否可分解
|
|
|
|
|
- 2. 获取适用的分解规则
|
|
|
|
|
- 3. 获取可能的分解结果及概率
|
|
|
|
|
- 4. 返回预览信息
|
|
|
|
|
-
|
|
|
|
|
-#### 10.5.2 执行物品分解
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:分解指定物品并获得材料
|
|
|
|
|
-- **参数**:用户ID、物品ID、数量
|
|
|
|
|
-- **返回**:分解结果、获得的材料列表
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查用户是否拥有足够数量的物品
|
|
|
|
|
- 2. 检查物品是否可分解
|
|
|
|
|
- 3. 获取适用的分解规则
|
|
|
|
|
- 4. 计算分解结果
|
|
|
|
|
- 5. 从用户背包中扣除物品
|
|
|
|
|
- 6. 向用户背包添加获得的材料
|
|
|
|
|
- 7. 记录分解日志
|
|
|
|
|
-
|
|
|
|
|
-#### 10.5.3 批量分解物品
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:批量分解多个物品
|
|
|
|
|
-- **参数**:用户ID、物品ID列表及数量
|
|
|
|
|
-- **返回**:分解结果、获得的材料列表
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 检查用户是否拥有所有指定物品
|
|
|
|
|
- 2. 对每个物品执行分解操作
|
|
|
|
|
- 3. 合并分解结果
|
|
|
|
|
- 4. 返回总体分解结果
|
|
|
|
|
-
|
|
|
|
|
-#### 10.5.4 获取分解历史
|
|
|
|
|
-
|
|
|
|
|
-- **功能**:查询用户的物品分解历史
|
|
|
|
|
-- **参数**:用户ID、时间范围(可选)
|
|
|
|
|
-- **返回**:分解历史记录列表
|
|
|
|
|
-- **处理逻辑**:
|
|
|
|
|
- 1. 查询用户的分解日志记录
|
|
|
|
|
- 2. 按时间排序
|
|
|
|
|
- 3. 返回分解历史列表
|
|
|
|
|
-
|
|
|
|
|
-### 10.6 分解日志记录
|
|
|
|
|
-
|
|
|
|
|
-系统记录所有分解操作,确保可追溯性和数据分析需求:
|
|
|
|
|
-
|
|
|
|
|
-#### 10.6.1 日志内容
|
|
|
|
|
-
|
|
|
|
|
-在 `item_dismantle_logs` 表中记录以下信息:
|
|
|
|
|
-
|
|
|
|
|
-1. **用户信息**:执行分解的用户ID
|
|
|
|
|
-2. **物品信息**:被分解的物品ID、数量
|
|
|
|
|
-3. **分解结果**:获得的材料列表及数量
|
|
|
|
|
-4. **时间信息**:分解操作的时间
|
|
|
|
|
-5. **规则信息**:应用的分解规则ID
|
|
|
|
|
-6. **安全信息**:IP地址、设备信息等
|
|
|
|
|
-
|
|
|
|
|
-#### 10.6.2 日志用途
|
|
|
|
|
-
|
|
|
|
|
-1. **数据分析**:分析玩家分解行为和偏好
|
|
|
|
|
-2. **问题排查**:解决玩家关于分解结果的疑问
|
|
|
|
|
-3. **系统监控**:监控分解系统的运行状态
|
|
|
|
|
-4. **平衡调整**:为游戏平衡调整提供数据支持
|
|
|
|
|
-
|
|
|
|
|
-### 10.7 与其他系统的交互
|
|
|
|
|
-
|
|
|
|
|
-分解系统与游戏中的多个系统有紧密的交互关系:
|
|
|
|
|
-
|
|
|
|
|
-#### 10.7.1 与背包系统交互
|
|
|
|
|
-
|
|
|
|
|
-- 分解操作会减少背包中的物品,并添加新的材料
|
|
|
|
|
-- 需要检查背包容量是否足够存放分解获得的材料
|
|
|
|
|
-
|
|
|
|
|
-#### 10.7.2 与任务和成就系统交互
|
|
|
|
|
-
|
|
|
|
|
-- 分解特定物品或获得特定材料可能触发任务进度
|
|
|
|
|
-- 累计分解次数或特定物品分解可能触发成就
|
|
|
|
|
-
|
|
|
|
|
-#### 10.7.3 与合成系统交互
|
|
|
|
|
-
|
|
|
|
|
-- 分解获得的材料可用于物品合成
|
|
|
|
|
-- 分解和合成形成物品循环利用的闭环
|
|
|
|
|
-
|
|
|
|
|
-#### 10.7.4 与商店系统交互
|
|
|
|
|
-
|
|
|
|
|
-- 分解获得的材料可以在商店出售或用于购买其他物品
|
|
|
|
|
-- 商店可以提供分解服务,收取一定费用
|
|
|
|
|
-
|
|
|
|
|
-## 11. 物品绑定机制
|
|
|
|
|
-
|
|
|
|
|
-物品绑定机制用于限制物品的流通和交易,保持游戏经济平衡,并增加游戏内容的专属性。
|
|
|
|
|
-
|
|
|
|
|
-### 11.1 绑定机制概述
|
|
|
|
|
-
|
|
|
|
|
-#### 11.1.1 绑定机制目的
|
|
|
|
|
-
|
|
|
|
|
-物品绑定机制主要用于以下目的:
|
|
|
|
|
-
|
|
|
|
|
-1. **限制物品交易**:防止高价值物品在玩家间无限制流通
|
|
|
|
|
-2. **增加成就感**:使某些物品具有专属性,提高获取难度和价值感
|
|
|
|
|
-3. **控制游戏经济**:防止物品市场泛滥和通货膨胀
|
|
|
|
|
-4. **区分物品来源**:通过不同的绑定状态区分物品的获取途径
|
|
|
|
|
-5. **增加游戏深度**:为不同物品设计不同的绑定规则,增加游戏策略性
|
|
|
|
|
-
|
|
|
|
|
-#### 11.1.2 绑定与不可交易的区别
|
|
|
|
|
-
|
|
|
|
|
-物品绑定和物品不可交易是两个不同的概念,虽然它们都会限制物品的流通,但在实现方式、应用场景和用户体验上有明显区别:
|
|
|
|
|
-
|
|
|
|
|
-1. **概念区别**:
|
|
|
|
|
- - **物品绑定**:指物品与特定玩家或角色建立关联,限制物品只能被该玩家或角色使用
|
|
|
|
|
- - **物品不可交易**:指物品本身的一种固有属性,决定该物品是否可以参与玩家间的交易
|
|
|
|
|
-
|
|
|
|
|
-2. **状态变化**:
|
|
|
|
|
- - **物品绑定**:是一种状态变化,物品可以从未绑定变为已绑定
|
|
|
|
|
- - **物品不可交易**:是物品的固有特性,通常在物品创建时就已确定
|
|
|
|
|
-
|
|
|
|
|
-3. **触发条件**:
|
|
|
|
|
- - **物品绑定**:通常发生在特定触发条件下(获取、使用、装备等)
|
|
|
|
|
- - **物品不可交易**:不依赖于物品的使用状态或归属,始终保持不变
|
|
|
|
|
-
|
|
|
|
|
-### 11.2 绑定类型
|
|
|
|
|
-
|
|
|
|
|
-系统支持多种绑定类型,可以根据游戏需求灵活配置:
|
|
|
|
|
-
|
|
|
|
|
-#### 11.2.1 按绑定时机分类
|
|
|
|
|
-
|
|
|
|
|
-1. **不绑定**:物品可以自由交易和转移
|
|
|
|
|
-2. **获取绑定**:物品一旦被玩家获取后绑定到该玩家账号
|
|
|
|
|
-3. **使用绑定**:物品在首次使用后绑定到玩家账号
|
|
|
|
|
-4. **装备绑定**:装备类物品在首次装备后绑定
|
|
|
|
|
-
|
|
|
|
|
-#### 11.2.2 按绑定对象分类
|
|
|
|
|
-
|
|
|
|
|
-1. **角色绑定**:物品绑定到特定角色,不可在同一账号的不同角色间转移
|
|
|
|
|
-2. **账号绑定**:物品绑定到账号,可在同一账号的不同角色间转移
|
|
|
|
|
-
|
|
|
|
|
-#### 11.2.3 按绑定时长分类
|
|
|
|
|
-
|
|
|
|
|
-1. **永久绑定**:一旦绑定,永远不会解除
|
|
|
|
|
-2. **时间绑定**:物品在特定时间段内绑定,之后可以解除绑定
|
|
|
|
|
-
|
|
|
|
|
-### 11.3 数据库设计
|
|
|
|
|
-
|
|
|
|
|
-物品绑定机制主要针对单独属性物品(item_instances),因为这些物品具有独特性和个体差异。
|
|
|
|
|
-
|
|
|
|
|
-#### 11.3.1 item_instances 表中的绑定相关字段
|
|
|
|
|
-
|
|
|
|
|
-| 字段名 | 类型 | 说明 |
|
|
|
|
|
-| --- | --- | --- |
|
|
|
|
|
-| is_bound | tinyint | 是否已绑定(0:未绑定, 1:已绑定) |
|
|
|
|
|
-| bound_to | varchar | 绑定对象(账号ID或角色ID) |
|
|
|
|
|
-| bind_exp_time | timestamp | 绑定过期时间(为空表示永久绑定) |
|
|
|
|
|
-
|
|
|
|
|
-这种设计的优势:
|
|
|
|
|
-
|
|
|
|
|
-1. **与物品实例直接关联**:绑定状态直接与物品实例关联,而不是与用户物品关系关联
|
|
|
|
|
-2. **简化数据查询**:不需要跨表查询即可获取物品的绑定状态
|
|
|
|
|
-3. **更好的语义表达**:绑定是物品实例的属性,而不是用户与物品关系的属性
|
|
|
|
|
-4. **支持物品转移**:当物品在用户间转移时,绑定状态随物品实例一起转移
|
|
|
|
|
-
|
|
|
|
|
-### 11.4 绑定状态处理逻辑
|
|
|
|
|
-
|
|
|
|
|
-物品绑定状态的处理逻辑主要针对单独属性物品(item_instances):
|
|
|
|
|
-
|
|
|
|
|
-#### 11.4.1 获取绑定处理
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function handleAcquireBind($itemId, $instanceId, $userId)
|
|
|
|
|
-{
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否需要获取绑定
|
|
|
|
|
- if ($item->bind_type == 1) { // 获取绑定
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
- $instance->is_bound = 1;
|
|
|
|
|
- $instance->bound_to = $userId;
|
|
|
|
|
- $instance->bind_exp_time = null; // 永久绑定
|
|
|
|
|
- $instance->save();
|
|
|
|
|
-
|
|
|
|
|
- // 记录绑定日志
|
|
|
|
|
- $this->logItemBind($instanceId, $userId, 'acquire');
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.4.2 使用绑定处理
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function handleUseBind($itemId, $instanceId, $userId)
|
|
|
|
|
-{
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否需要使用绑定
|
|
|
|
|
- if ($item->bind_type == 2) { // 使用绑定
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
-
|
|
|
|
|
- // 只有未绑定的物品才需要处理
|
|
|
|
|
- if ($instance->is_bound == 0) {
|
|
|
|
|
- $instance->is_bound = 1;
|
|
|
|
|
- $instance->bound_to = $userId;
|
|
|
|
|
- $instance->bind_exp_time = null; // 永久绑定
|
|
|
|
|
- $instance->save();
|
|
|
|
|
-
|
|
|
|
|
- // 记录绑定日志
|
|
|
|
|
- $this->logItemBind($instanceId, $userId, 'use');
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.4.3 装备绑定处理
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function handleEquipBind($itemId, $instanceId, $userId)
|
|
|
|
|
-{
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否需要装备绑定
|
|
|
|
|
- if ($item->bind_type == 3) { // 装备绑定
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
-
|
|
|
|
|
- // 只有未绑定的物品才需要处理
|
|
|
|
|
- if ($instance->is_bound == 0) {
|
|
|
|
|
- $instance->is_bound = 1;
|
|
|
|
|
- $instance->bound_to = $userId;
|
|
|
|
|
- $instance->bind_exp_time = null; // 永久绑定
|
|
|
|
|
- $instance->save();
|
|
|
|
|
-
|
|
|
|
|
- // 记录绑定日志
|
|
|
|
|
- $this->logItemBind($instanceId, $userId, 'equip');
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.4.4 临时绑定处理
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function handleTimeBind($itemId, $instanceId, $userId, $bindDuration)
|
|
|
|
|
-{
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否需要时间绑定
|
|
|
|
|
- if ($item->bind_type == 6) { // 时间绑定
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
- $instance->is_bound = 1;
|
|
|
|
|
- $instance->bound_to = $userId;
|
|
|
|
|
-
|
|
|
|
|
- // 计算绑定过期时间
|
|
|
|
|
- $expTime = now()->addSeconds($bindDuration);
|
|
|
|
|
- $instance->bind_exp_time = $expTime;
|
|
|
|
|
- $instance->save();
|
|
|
|
|
-
|
|
|
|
|
- // 记录绑定日志
|
|
|
|
|
- $this->logItemBind($instanceId, $userId, 'time', $expTime);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 11.5 绑定物品的交易限制
|
|
|
|
|
-
|
|
|
|
|
-单独属性物品的交易限制由两个因素决定:物品的可交易性(tradable)和绑定状态(is_bound):
|
|
|
|
|
-
|
|
|
|
|
-#### 11.5.1 交易检查流程
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function canTrade($instanceId, $fromUserId, $toUserId)
|
|
|
|
|
-{
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否可交易
|
|
|
|
|
- if ($instance->tradable == 0) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_trade' => false,
|
|
|
|
|
- 'reason' => 'item_not_tradable'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否已绑定
|
|
|
|
|
- if ($instance->is_bound == 1) {
|
|
|
|
|
- // 检查绑定对象
|
|
|
|
|
- if ($instance->bound_to != $fromUserId) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_trade' => false,
|
|
|
|
|
- 'reason' => 'item_bound_to_another_user'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 检查绑定类型(账号绑定可以在同一账号的角色间转移)
|
|
|
|
|
- $fromUser = User::find($fromUserId);
|
|
|
|
|
- $toUser = User::find($toUserId);
|
|
|
|
|
-
|
|
|
|
|
- if ($fromUser->account_id != $toUser->account_id) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_trade' => false,
|
|
|
|
|
- 'reason' => 'item_bound_to_account'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_trade' => true
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.5.2 商店出售限制
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function canSellToShop($instanceId, $userId)
|
|
|
|
|
-{
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
-
|
|
|
|
|
- // 不可交易物品通常不能出售给NPC商店
|
|
|
|
|
- if ($instance->tradable == 0) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_sell' => false,
|
|
|
|
|
- 'reason' => 'item_not_tradable'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 已绑定物品只能由绑定的玩家出售
|
|
|
|
|
- if ($instance->is_bound == 1 && $instance->bound_to != $userId) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_sell' => false,
|
|
|
|
|
- 'reason' => 'item_bound_to_another_user'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- 'can_sell' => true,
|
|
|
|
|
- // 已绑定物品可能有价格折扣
|
|
|
|
|
- 'price_modifier' => $instance->is_bound ? 0.5 : 1.0
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.5.3 邮件发送限制
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function canSendByMail($instanceId, $fromUserId, $toUserId)
|
|
|
|
|
-{
|
|
|
|
|
- // 邮件发送限制与交易限制相同
|
|
|
|
|
- return $this->canTrade($instanceId, $fromUserId, $toUserId);
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 11.6 应用场景
|
|
|
|
|
-
|
|
|
|
|
-物品绑定机制适用于多种场景:
|
|
|
|
|
-
|
|
|
|
|
-#### 11.6.1 任务奖励
|
|
|
|
|
-
|
|
|
|
|
-重要任务奖励通常设置为获取绑定,确保玩家亲自完成任务:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function giveQuestReward($userId, $questId)
|
|
|
|
|
-{
|
|
|
|
|
- $quest = Quest::find($questId);
|
|
|
|
|
-
|
|
|
|
|
- foreach ($quest->rewards as $reward) {
|
|
|
|
|
- $itemId = $reward['item_id'];
|
|
|
|
|
- $quantity = $reward['quantity'];
|
|
|
|
|
-
|
|
|
|
|
- // 创建物品实例并设置为获取绑定
|
|
|
|
|
- $instanceId = $this->createItemInstance($itemId);
|
|
|
|
|
- $this->handleAcquireBind($itemId, $instanceId, $userId);
|
|
|
|
|
-
|
|
|
|
|
- // 添加到用户背包
|
|
|
|
|
- $this->addItemInstanceToUser($userId, $itemId, $instanceId);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.6.2 成就奖励
|
|
|
|
|
-
|
|
|
|
|
-成就奖励物品通常设置为账号绑定,表彰玩家的个人成就:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function giveAchievementReward($userId, $achievementId)
|
|
|
|
|
-{
|
|
|
|
|
- $achievement = Achievement::find($achievementId);
|
|
|
|
|
- $user = User::find($userId);
|
|
|
|
|
-
|
|
|
|
|
- foreach ($achievement->rewards as $reward) {
|
|
|
|
|
- $itemId = $reward['item_id'];
|
|
|
|
|
- $quantity = $reward['quantity'];
|
|
|
|
|
-
|
|
|
|
|
- // 创建物品实例并设置为账号绑定
|
|
|
|
|
- $instanceId = $this->createItemInstance($itemId);
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
- $instance->is_bound = 1;
|
|
|
|
|
- $instance->bound_to = $user->account_id; // 绑定到账号
|
|
|
|
|
- $instance->save();
|
|
|
|
|
-
|
|
|
|
|
- // 添加到用户背包
|
|
|
|
|
- $this->addItemInstanceToUser($userId, $itemId, $instanceId);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.6.3 活动物品
|
|
|
|
|
-
|
|
|
|
|
-活动限定物品通常设置为获取绑定,防止二次交易:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function giveEventItem($userId, $eventId, $itemId)
|
|
|
|
|
-{
|
|
|
|
|
- $event = Event::find($eventId);
|
|
|
|
|
-
|
|
|
|
|
- // 创建物品实例并设置为获取绑定
|
|
|
|
|
- $instanceId = $this->createItemInstance($itemId);
|
|
|
|
|
- $this->handleAcquireBind($itemId, $instanceId, $userId);
|
|
|
|
|
-
|
|
|
|
|
- // 添加到用户背包
|
|
|
|
|
- $this->addItemInstanceToUser($userId, $itemId, $instanceId);
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 11.7 绑定状态的显示
|
|
|
|
|
-
|
|
|
|
|
-在游戏界面中,应清晰显示物品的绑定状态:
|
|
|
|
|
-
|
|
|
|
|
-#### 11.7.1 物品图标标记
|
|
|
|
|
-
|
|
|
|
|
-已绑定物品在图标上添加特殊标记,区分不同的绑定类型:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function getItemIconWithBindMark($itemId, $instanceId)
|
|
|
|
|
-{
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
- $iconPath = $item->icon;
|
|
|
|
|
-
|
|
|
|
|
- if ($instanceId) {
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
-
|
|
|
|
|
- if ($instance->is_bound) {
|
|
|
|
|
- // 根据绑定类型添加不同的标记
|
|
|
|
|
- if ($instance->bind_exp_time) {
|
|
|
|
|
- return $iconPath . '?mark=time_bound';
|
|
|
|
|
- } else {
|
|
|
|
|
- return $iconPath . '?mark=bound';
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return $iconPath;
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.7.2 物品描述
|
|
|
|
|
-
|
|
|
|
|
-在物品描述中注明绑定类型和状态:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function getItemDescription($itemId, $instanceId)
|
|
|
|
|
-{
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
- $description = $item->description;
|
|
|
|
|
-
|
|
|
|
|
- if ($instanceId) {
|
|
|
|
|
- $instance = ItemInstance::find($instanceId);
|
|
|
|
|
-
|
|
|
|
|
- if ($instance->is_bound) {
|
|
|
|
|
- $description .= "\n已绑定到: " . $this->getBindTargetName($instance->bound_to);
|
|
|
|
|
-
|
|
|
|
|
- if ($instance->bind_exp_time) {
|
|
|
|
|
- $description .= "\n绑定解除时间: " . $instance->bind_exp_time;
|
|
|
|
|
- } else {
|
|
|
|
|
- $description .= "\n永久绑定";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return $description;
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 11.7.3 交易提示
|
|
|
|
|
-
|
|
|
|
|
-尝试交易绑定物品时,显示明确的错误提示:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function getTradeErrorMessage($result)
|
|
|
|
|
-{
|
|
|
|
|
- switch ($result['reason']) {
|
|
|
|
|
- case 'item_not_tradable':
|
|
|
|
|
- return "该物品不可交易";
|
|
|
|
|
- case 'item_bound_to_another_user':
|
|
|
|
|
- return "该物品已绑定到其他玩家,无法交易";
|
|
|
|
|
- case 'item_bound_to_account':
|
|
|
|
|
- return "该物品已绑定到账号,只能在同一账号的角色间转移";
|
|
|
|
|
- default:
|
|
|
|
|
- return "无法交易该物品";
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-## 12. 系统交互
|
|
|
|
|
-
|
|
|
|
|
-GameItems模块作为游戏的核心系统之一,与其他多个系统有紧密的交互关系。
|
|
|
|
|
-
|
|
|
|
|
-### 12.1 与其他系统的交互
|
|
|
|
|
-
|
|
|
|
|
-#### 12.1.1 与用户系统交互
|
|
|
|
|
-
|
|
|
|
|
-物品系统需要与用户系统交互,确保物品正确关联到用户:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function checkUserExists($userId)
|
|
|
|
|
-{
|
|
|
|
|
- $user = User::find($userId);
|
|
|
|
|
- if (!$user) {
|
|
|
|
|
- throw new UserNotFoundException("用户不存在: $userId");
|
|
|
|
|
- }
|
|
|
|
|
- return $user;
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 12.1.2 与任务系统交互
|
|
|
|
|
-
|
|
|
|
|
-物品系统与任务系统交互,支持任务相关的物品操作:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function checkQuestItemRequirement($userId, $questId)
|
|
|
|
|
-{
|
|
|
|
|
- $quest = Quest::find($questId);
|
|
|
|
|
- $requirements = $quest->item_requirements;
|
|
|
|
|
-
|
|
|
|
|
- foreach ($requirements as $req) {
|
|
|
|
|
- $itemId = $req['item_id'];
|
|
|
|
|
- $quantity = $req['quantity'];
|
|
|
|
|
-
|
|
|
|
|
- $userItem = UserItem::where('user_id', $userId)
|
|
|
|
|
- ->where('item_id', $itemId)
|
|
|
|
|
- ->first();
|
|
|
|
|
-
|
|
|
|
|
- if (!$userItem || $userItem->quantity < $quantity) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 12.1.3 与商店系统交互
|
|
|
|
|
-
|
|
|
|
|
-物品系统与商店系统交互,支持物品的购买和出售:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function buyItemFromShop($userId, $shopItemId, $quantity)
|
|
|
|
|
-{
|
|
|
|
|
- $shopItem = ShopItem::find($shopItemId);
|
|
|
|
|
- $itemId = $shopItem->item_id;
|
|
|
|
|
- $price = $shopItem->price * $quantity;
|
|
|
|
|
-
|
|
|
|
|
- // 检查用户余额
|
|
|
|
|
- $user = User::find($userId);
|
|
|
|
|
- if ($user->balance < $price) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'success' => false,
|
|
|
|
|
- 'message' => '余额不足'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 扣除余额
|
|
|
|
|
- $user->balance -= $price;
|
|
|
|
|
- $user->save();
|
|
|
|
|
-
|
|
|
|
|
- // 添加物品
|
|
|
|
|
- $this->addItemToUser($userId, $itemId, $quantity);
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- 'success' => true,
|
|
|
|
|
- 'item_id' => $itemId,
|
|
|
|
|
- 'quantity' => $quantity,
|
|
|
|
|
- 'price' => $price
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 12.1.4 与邮件系统交互
|
|
|
|
|
-
|
|
|
|
|
-物品系统与邮件系统交互,支持通过邮件发送物品:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function sendItemByMail($fromUserId, $toUserId, $itemId, $quantity, $message)
|
|
|
|
|
-{
|
|
|
|
|
- // 检查物品是否可以发送
|
|
|
|
|
- if (!$this->canSendItem($fromUserId, $itemId, $quantity)) {
|
|
|
|
|
- return [
|
|
|
|
|
- 'success' => false,
|
|
|
|
|
- 'message' => '物品不可发送'
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 从发送者背包中扣除物品
|
|
|
|
|
- $this->removeItemFromUser($fromUserId, $itemId, $quantity);
|
|
|
|
|
-
|
|
|
|
|
- // 创建邮件
|
|
|
|
|
- $mail = Mail::create([
|
|
|
|
|
- 'from_user_id' => $fromUserId,
|
|
|
|
|
- 'to_user_id' => $toUserId,
|
|
|
|
|
- 'subject' => '物品发送',
|
|
|
|
|
- 'message' => $message,
|
|
|
|
|
- 'has_attachment' => 1
|
|
|
|
|
- ]);
|
|
|
|
|
-
|
|
|
|
|
- // 添加邮件附件
|
|
|
|
|
- MailAttachment::create([
|
|
|
|
|
- 'mail_id' => $mail->id,
|
|
|
|
|
- 'item_id' => $itemId,
|
|
|
|
|
- 'quantity' => $quantity
|
|
|
|
|
- ]);
|
|
|
|
|
-
|
|
|
|
|
- return [
|
|
|
|
|
- 'success' => true,
|
|
|
|
|
- 'mail_id' => $mail->id
|
|
|
|
|
- ];
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 12.2 事件系统
|
|
|
|
|
-
|
|
|
|
|
-物品系统使用事件机制与其他系统进行松耦合交互:
|
|
|
|
|
-
|
|
|
|
|
-#### 12.2.1 物品相关事件
|
|
|
|
|
-
|
|
|
|
|
-系统定义了以下物品相关事件:
|
|
|
|
|
-
|
|
|
|
|
-1. **ItemAdded**:物品添加到用户背包时触发
|
|
|
|
|
-2. **ItemRemoved**:物品从用户背包移除时触发
|
|
|
|
|
-3. **ItemUsed**:物品被使用时触发
|
|
|
|
|
-4. **ItemTraded**:物品被交易时触发
|
|
|
|
|
-5. **ChestOpened**:宝箱被开启时触发
|
|
|
|
|
-6. **ItemCrafted**:物品被合成时触发
|
|
|
|
|
-7. **ItemDismantled**:物品被分解时触发
|
|
|
|
|
-8. **ItemBound**:物品被绑定时触发
|
|
|
|
|
-
|
|
|
|
|
-#### 12.2.2 事件监听
|
|
|
|
|
-
|
|
|
|
|
-其他系统可以监听这些事件并执行相应操作:
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-// 在服务提供者中注册事件监听
|
|
|
|
|
-public function boot()
|
|
|
|
|
-{
|
|
|
|
|
- Event::listen(ItemAdded::class, function ($event) {
|
|
|
|
|
- // 更新任务进度
|
|
|
|
|
- $this->questService->updateItemCollectionProgress(
|
|
|
|
|
- $event->userId,
|
|
|
|
|
- $event->itemId,
|
|
|
|
|
- $event->quantity
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 更新成就进度
|
|
|
|
|
- $this->achievementService->updateItemCollectionProgress(
|
|
|
|
|
- $event->userId,
|
|
|
|
|
- $event->itemId,
|
|
|
|
|
- $event->quantity
|
|
|
|
|
- );
|
|
|
|
|
- });
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-### 12.3 API接口
|
|
|
|
|
-
|
|
|
|
|
-物品系统提供以下API接口供其他系统调用:
|
|
|
|
|
-
|
|
|
|
|
-#### 12.3.1 物品查询接口
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function getUserItems($userId, $filters = [])
|
|
|
|
|
-{
|
|
|
|
|
- $query = UserItem::where('user_id', $userId);
|
|
|
|
|
-
|
|
|
|
|
- // 应用过滤条件
|
|
|
|
|
- if (isset($filters['item_id'])) {
|
|
|
|
|
- $query->where('item_id', $filters['item_id']);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isset($filters['category_id'])) {
|
|
|
|
|
- $query->whereHas('item', function ($q) use ($filters) {
|
|
|
|
|
- $q->where('category_id', $filters['category_id']);
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 排除过期物品
|
|
|
|
|
- $query->where(function ($q) {
|
|
|
|
|
- $q->whereNull('expire_at')
|
|
|
|
|
- ->orWhere('expire_at', '>', now());
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- return $query->get();
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-#### 12.3.2 物品操作接口
|
|
|
|
|
-
|
|
|
|
|
-```php
|
|
|
|
|
-// 伪代码示例
|
|
|
|
|
-public function addItem($userId, $itemId, $quantity, $options = [])
|
|
|
|
|
-{
|
|
|
|
|
- // 检查用户是否存在
|
|
|
|
|
- $this->checkUserExists($userId);
|
|
|
|
|
-
|
|
|
|
|
- // 检查物品是否存在
|
|
|
|
|
- $item = Item::find($itemId);
|
|
|
|
|
- if (!$item) {
|
|
|
|
|
- throw new ItemNotFoundException("物品不存在: $itemId");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 处理单独属性物品
|
|
|
|
|
- if ($item->is_unique) {
|
|
|
|
|
- return $this->addUniqueItem($userId, $itemId, $options);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 处理统一属性物品
|
|
|
|
|
- return $this->addNormalItem($userId, $itemId, $quantity, $options);
|
|
|
|
|
-}
|
|
|
|
|
-```
|
|
|
|
|
-
|
|
|
|
|
-## 13. 最佳实践与注意事项
|
|
|
|
|
-
|
|
|
|
|
-### 13.1 性能优化
|
|
|
|
|
-
|
|
|
|
|
-为确保物品系统的高性能运行,应遵循以下最佳实践:
|
|
|
|
|
-
|
|
|
|
|
-#### 13.1.1 数据库优化
|
|
|
|
|
-
|
|
|
|
|
-1. **合理使用索引**:
|
|
|
|
|
- - 为频繁查询的字段创建索引
|
|
|
|
|
- - 避免过多索引导致写入性能下降
|
|
|
|
|
- - 定期分析查询性能,优化索引设计
|
|
|
|
|
-
|
|
|
|
|
-2. **批量操作**:
|
|
|
|
|
- - 使用批量插入和更新减少数据库操作次数
|
|
|
|
|
- - 对于大量物品操作,使用事务确保原子性
|
|
|
|
|
-
|
|
|
|
|
-3. **分表策略**:
|
|
|
|
|
- - 对于高频访问的日志表,考虑按时间或用户ID分表
|
|
|
|
|
- - 历史数据可以归档到单独的表中
|
|
|
|
|
-
|
|
|
|
|
-#### 13.1.2 缓存策略
|
|
|
|
|
-
|
|
|
|
|
-1. **用户物品缓存**:
|
|
|
|
|
- - 缓存用户常用物品列表,减少数据库查询
|
|
|
|
|
- - 使用Redis等内存数据库存储临时数据
|
|
|
|
|
-
|
|
|
|
|
-2. **物品定义缓存**:
|
|
|
|
|
- - 缓存物品基础定义,避免重复查询
|
|
|
|
|
- - 使用缓存标签管理相关缓存
|
|
|
|
|
-
|
|
|
|
|
-3. **缓存失效策略**:
|
|
|
|
|
- - 在物品数据变更时主动清除相关缓存
|
|
|
|
|
- - 设置合理的缓存过期时间
|
|
|
|
|
-
|
|
|
|
|
-#### 13.1.3 异步处理
|
|
|
|
|
-
|
|
|
|
|
-1. **队列处理**:
|
|
|
|
|
- - 使用队列处理非即时性操作,如日志记录
|
|
|
|
|
- - 批量物品操作可以放入队列异步处理
|
|
|
|
|
|
|
+## 8. 最佳实践
|
|
|
|
|
|
|
|
-2. **定时任务**:
|
|
|
|
|
- - 使用定时任务处理物品过期、绑定解除等周期性操作
|
|
|
|
|
- - 将资源密集型操作安排在服务器负载较低的时间执行
|
|
|
|
|
|
|
+### 8.1 开发规范
|
|
|
|
|
|
|
|
-### 13.2 安全考虑
|
|
|
|
|
|
|
+1. **模型中不包含业务逻辑**:所有业务逻辑都应放在Logics层中
|
|
|
|
|
+2. **服务类是对外的门面**:其他模块只能通过Services层访问GameItems模块功能
|
|
|
|
|
+3. **使用依赖注入**:通过构造函数注入依赖,提高可测试性
|
|
|
|
|
+4. **使用事务确保数据一致性**:所有涉及多个操作的功能都应使用数据库事务
|
|
|
|
|
+5. **记录关键操作日志**:所有物品获取和消耗操作都应记录日志
|
|
|
|
|
|
|
|
-物品系统涉及游戏经济核心,需要特别注意安全性:
|
|
|
|
|
|
|
+### 8.2 扩展指南
|
|
|
|
|
|
|
|
-#### 13.2.1 防作弊措施
|
|
|
|
|
|
|
+#### 8.2.1 添加新的物品类型
|
|
|
|
|
|
|
|
-1. **操作验证**:
|
|
|
|
|
- - 所有物品操作都需要进行权限和合法性验证
|
|
|
|
|
- - 敏感操作(如删除物品)需要额外的验证步骤
|
|
|
|
|
|
|
+1. 在 `Enums/ITEM_TYPE.php` 中添加新的类型常量
|
|
|
|
|
+2. 在 `Models/Item.php` 中添加相关的关联方法(如果需要)
|
|
|
|
|
+3. 在 `Logics/Item.php` 中添加处理新类型的逻辑方法
|
|
|
|
|
+4. 在 `Services/ItemService.php` 中添加对外提供的服务方法
|
|
|
|
|
|
|
|
-2. **异常监控**:
|
|
|
|
|
- - 监控异常的物品获取和消耗模式
|
|
|
|
|
- - 设置物品操作的频率限制和阈值警报
|
|
|
|
|
|
|
+#### 8.2.2 添加新的宝箱机制
|
|
|
|
|
|
|
|
-3. **日志审计**:
|
|
|
|
|
- - 记录所有物品操作的详细日志
|
|
|
|
|
- - 定期审计物品流通情况,发现潜在问题
|
|
|
|
|
|
|
+1. 在 `Models/ItemChestContent.php` 中添加新的字段(如果需要)
|
|
|
|
|
+2. 在 `Logics/ChestContent.php` 中添加新机制的逻辑方法
|
|
|
|
|
+3. 在 `Services/ChestService.php` 中修改 `openChest` 方法以支持新机制
|
|
|
|
|
|
|
|
-#### 13.2.2 并发控制
|
|
|
|
|
|
|
+### 8.3 性能优化建议
|
|
|
|
|
|
|
|
-1. **乐观锁**:
|
|
|
|
|
- - 使用版本号或时间戳实现乐观锁
|
|
|
|
|
- - 在高并发场景下防止数据不一致
|
|
|
|
|
|
|
+1. **使用批量操作**:对于大量物品操作,使用批量插入和更新
|
|
|
|
|
+2. **合理使用索引**:为频繁查询的字段创建索引
|
|
|
|
|
+3. **缓存热点数据**:缓存物品基础信息、配方等不常变化的数据
|
|
|
|
|
+4. **分页加载**:用户物品列表使用分页加载,避免一次加载过多数据
|
|
|
|
|
+5. **延迟加载**:使用延迟加载关联数据,避免N+1查询问题
|
|
|
|
|
|
|
|
-2. **悲观锁**:
|
|
|
|
|
- - 对于关键操作,使用数据库行锁或表锁
|
|
|
|
|
- - 在事务中锁定相关记录,防止并发修改
|
|
|
|
|
|
|
+### 7.2 安全考虑
|
|
|
|
|
|
|
|
-3. **分布式锁**:
|
|
|
|
|
- - 在分布式环境中,使用Redis等实现分布式锁
|
|
|
|
|
- - 确保跨服务器的操作原子性
|
|
|
|
|
|
|
+1. **事务完整性**:所有涉及多个操作的功能都使用数据库事务
|
|
|
|
|
+2. **日志记录**:记录所有物品获取和消耗操作,便于追踪和审计
|
|
|
|
|
+3. **输入验证**:严格验证所有输入参数,防止恶意请求
|
|
|
|
|
+4. **并发控制**:使用锁机制防止并发操作导致的数据不一致
|
|
|
|
|
+5. **权限检查**:确保用户只能操作自己的物品
|
|
|
|
|
|
|
|
-### 13.3 通用注意事项
|
|
|
|
|
|
|
+### 7.3 代码规范
|
|
|
|
|
|
|
|
-在实现和维护物品系统时,应注意以下事项:
|
|
|
|
|
|
|
+1. **遵循单一职责原则**:每个类只负责一个功能领域
|
|
|
|
|
+2. **使用依赖注入**:通过构造函数注入依赖,提高可测试性
|
|
|
|
|
+3. **编写单元测试**:为核心功能编写单元测试,确保代码质量
|
|
|
|
|
+4. **使用类型提示**:使用PHP类型提示增强代码可读性和安全性
|
|
|
|
|
+5. **编写详细注释**:为公共方法编写详细的PHPDoc注释
|
|
|
|
|
|
|
|
-1. **物品使用逻辑**应根据物品类型进行不同处理
|
|
|
|
|
-2. **需要考虑物品数量上限和背包容量限制**
|
|
|
|
|
-3. **稀有物品获取应有日志记录**
|
|
|
|
|
-4. **物品交易需考虑并发安全问题,建议使用数据库事务**
|
|
|
|
|
-5. **敏感操作(如删除物品)需要有权限验证**
|
|
|
|
|
-6. **在获取用户物品时,始终检查过期时间,不展示已过期物品**
|
|
|
|
|
-7. **在添加物品到用户背包时,需要检查全局过期时间**
|
|
|
|
|
-8. **宝箱开启操作应使用事务确保原子性**
|
|
|
|
|
-9. **宝箱配置应由管理员仔细调整和测试,确保概率合理**
|
|
|
|
|
-10. **当物品数量超过最大堆叠数量时,应自动创建新的堆叠**
|
|
|
|
|
-11. **在物品产出前应检查产出限制,防止超过预期产出**
|
|
|
|
|
-12. **对于关联物品限制,需要同时检查所有相关物品的产出记录**
|
|
|
|
|
-13. **定期检查并重置限制计数,确保重置机制正常运行**
|
|
|
|
|
-14. **对于限量物品,应设置监控机制,在接近限制时发出警告**
|
|
|
|
|
-15. **所有物品获取和消耗操作应记录到交易日志表中**
|
|
|
|
|
-16. **宝箱开启操作应同时记录到宝箱开启日志和物品交易日志**
|
|
|
|
|
-17. **定期清理和归档旧日志,防止日志表过大影响系统性能**
|
|
|
|
|
-18. **对于高频率的日志写入操作,考虑使用队列或批量写入方式提高性能**
|
|
|
|
|
-19. **物品合成操作应使用事务确保原子性,防止材料扣除后合成失败导致数据不一致**
|
|
|
|
|
-20. **合成配方的成功率和奖励应由管理员仔细调整和测试,确保游戏平衡**
|
|
|
|
|
-21. **对于高价值物品的合成,应考虑添加额外的验证和确认机制**
|
|
|
|
|
-22. **合成系统应考虑与物品产出限制系统集成,防止通过合成绕过产出限制**
|
|
|
|
|
-23. **处理多币种成本时,应确保在事务中同时检查和扣除所有必要的代币,防止部分扣除导致的数据不一致**
|
|
|
|
|
-24. **绑定物品的状态变更应在事务中处理,确保数据一致性**
|
|
|
|
|
-25. **对于时间绑定物品,需要定期检查并更新绑定状态**
|
|
|
|
|
-26. **在物品交易前,必须检查物品的绑定状态,防止绑定物品被交易**
|
|
|
|
|
-27. **物品分解操作应使用事务确保原子性,防止物品被扣除但未获得分解结果**
|
|
|
|
|
-28. **分解绑定物品时,获得的材料应继承绑定状态**
|
|
|
|
|
-29. **分解单独属性物品时,应考虑物品的特殊属性对分解结果的影响**
|
|
|
|
|
-30. **批量分解时,应注意性能优化,避免大量物品同时分解导致系统负担**
|
|
|
|
|
|
|
+### 7.4 常见问题解决
|
|
|
|
|
|
|
|
|
|
+1. **物品数量不足**:在消耗物品前先检查数量是否足够
|
|
|
|
|
+2. **宝箱概率问题**:使用权重系统而非直接概率,确保总和为100%
|
|
|
|
|
+3. **保底机制实现**:使用计数器记录未获得次数,达到阈值时强制获得
|
|
|
|
|
+4. **过期物品处理**:定期清理过期物品,避免数据库膨胀
|
|
|
|
|
+5. **并发操作冲突**:使用悲观锁或乐观锁解决并发操作问题
|