README.md 91 KB

GameItems模块

游戏物品系统 - 综合管理游戏内所有物品的生命周期

目录

  1. 模块概述
  2. 数据结构设计
  3. 核心功能
  4. 物品过期机制
  5. 宝箱系统
  6. 物品获取与堆叠
  7. 物品产出限制
  8. 日志记录系统
  9. 物品合成系统
  10. 物品分解系统
  11. 物品绑定机制
  12. 系统交互
  13. 最佳实践与注意事项

1. 模块概述

1.1 功能与目的

GameItems模块是游戏核心系统之一,负责管理游戏内所有物品的完整生命周期,包括创建、获取、使用、交易、过期和销毁。该模块为游戏内经济系统和玩家进度提供基础支持,是连接多个游戏子系统的核心组件。

1.2 主要功能

  • 物品基础属性管理:名称、描述、图标、类型等
  • 物品获取与消耗逻辑:添加物品到用户背包、消耗物品
  • 物品库存管理:堆叠、数量限制、过期处理
  • 物品交易系统:玩家间交易、商店交易
  • 特殊物品效果:使用效果、装备效果
  • 宝箱系统:宝箱配置、开启机制、保底机制
  • 物品过期管理:全局过期和用户特定过期
  • 物品合成系统:配方、材料、成功率
  • 物品分解系统:分解规则、结果计算
  • 物品绑定机制:绑定类型、交易限制

1.3 核心特点

  1. 多物品宝箱系统:支持一个宝箱同时掉落多个物品,可配置数量范围和概率
  2. 灵活的过期机制:支持全局过期时间和用户特定过期时间
  3. 完善的属性系统:通过JSON格式存储物品属性,支持复杂物品效果
  4. 单独属性物品:支持每个物品实例拥有独特属性(如装备)
  5. 物品绑定机制:限制物品流通,保持游戏经济平衡
  6. 物品产出限制:控制稀有物品的产出数量和频率
  7. 全面的日志系统:记录所有物品相关操作,支持数据分析和问题排查

2. 数据结构设计

2.1 设计原则

游戏物品模块采用关系型数据库设计,通过多个相互关联的数据表实现物品管理。数据结构设计遵循以下原则:

  1. 模块化:各个表结构清晰,职责单一
  2. 扩展性:支持通过属性表扩展物品特性,无需修改数据库结构
  3. 性能优化:合理的索引设计和关联关系
  4. 数据完整性:使用外键和事务确保数据一致性

2.2 核心数据表

2.2.1 物品基础表

表名 主要功能 关键字段
item_categories 物品分类管理 id, name, code, parent_id
item_items 统一属性物品定义 id, name, type, is_unique, attributes
item_instances 单独属性物品实例 id, item_id, attributes, is_bound
item_users 用户物品关联 user_id, item_id, instance_id, quantity
item_groups 物品组定义 id, name, code
item_group_items 物品组内容 group_id, item_id, weight

2.2.2 宝箱系统表

表名 主要功能 关键字段
item_chest_contents 宝箱内容配置 chest_id, item_id/group_id, weight
item_pity_times 用户宝箱保底计数 user_id, chest_id, chest_content_id, current_count
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_recipe_materials 配方材料需求 recipe_id, item_id, quantity
item_user_recipes 用户配方解锁状态 user_id, recipe_id, is_unlocked
item_craft_logs 物品合成记录 user_id, recipe_id, is_success
item_dismantle_rules 物品分解规则 item_id/category_id, priority
item_dismantle_results 分解结果配置 rule_id, result_item_id, chance
item_dismantle_logs 物品分解记录 user_id, item_id, results

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. 查询全局过期物品

    SELECT id FROM item_items WHERE global_expire_at IS NOT NULL AND global_expire_at < NOW()
    
  2. 删除用户物品记录

    DELETE FROM item_users WHERE item_id IN (已过期物品ID列表)
    
  3. 记录日志

    • 在 item_transaction_logs 表中记录物品过期删除日志
    • 交易类型设置为 "过期失效"
  4. 可选操作

    • 发送通知给用户
    • 提供过期物品的替代品

4.3.2 用户物品过期处理

  1. 查询用户过期物品

    SELECT id, user_id, item_id, instance_id FROM item_users
    WHERE expire_at IS NOT NULL AND expire_at < NOW()
    
  2. 删除用户物品记录

    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_countmax_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. 更新保底计数

    • 对于未获得的内容,增加保底计数
    • 对于已获得的内容,重置保底计数

5.5 宝箱开启接口

系统提供以下接口用于宝箱开启:

5.5.1 开启宝箱

  • 功能:消耗宝箱并获取随机物品
  • 参数:用户ID、宝箱ID、数量
  • 返回:获得的物品列表、剩余宝箱数量
  • 处理逻辑
    1. 检查用户是否拥有足够数量的宝箱
    2. 获取宝箱配置和用户保底计数
    3. 计算实际掉落物品数量
    4. 根据概率和保底机制选择掉落内容
    5. 从用户背包中扣除宝箱
    6. 向用户背包添加获得的物品
    7. 更新保底计数
    8. 记录宝箱开启日志

5.5.2 获取宝箱内容预览

  • 功能:预览宝箱可能获得的物品及概率
  • 参数:宝箱ID
  • 返回:可能获得的物品列表及概率
  • 处理逻辑
    1. 获取宝箱配置
    2. 计算各内容的实际概率
    3. 对于物品组,展开显示组内物品
    4. 返回完整的可能获得物品列表及概率

5.6 宝箱日志记录

每次宝箱开启都会记录详细日志,用于数据分析和问题排查:

5.6.1 日志内容

item_chest_open_logs 表中记录以下信息:

  1. 用户信息:开启宝箱的用户ID
  2. 宝箱信息:宝箱ID、开启数量
  3. 开启时间:宝箱开启的时间戳
  4. 获得物品:以JSON格式记录获得的所有物品ID和数量
  5. 保底触发:是否触发保底机制,触发的内容ID
  6. 安全信息:IP地址、设备信息等

5.6.2 日志用途

  1. 数据分析:分析宝箱开启模式和物品掉落分布
  2. 概率验证:验证实际掉落概率是否符合配置
  3. 用户支持:解决用户关于宝箱开启的问题
  4. 异常检测:发现可能的作弊或异常行为

6. 物品获取与堆叠

当玩家多次获得同一物品时,系统需要根据物品类型和过期时间进行不同的处理,以确保物品管理的合理性和高效性。

6.1 统一属性物品的处理

对于统一属性物品(如消耗品、材料等),系统采用以下处理策略:

6.1.1 基本堆叠规则

  1. 数量累加

    • 当玩家获得已拥有的统一属性物品时,系统会增加物品数量
    • item_users 表中更新 quantity 字段
  2. 最大堆叠限制

    • 每种物品都有最大堆叠数量限制,定义在 item_items 表的 max_stack 字段
    • 当数量超过最大堆叠限制时,系统会创建新的堆叠
  3. 堆叠创建逻辑

    // 伪代码示例
    $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. 过期时间查找逻辑

    // 伪代码示例
    $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 单独属性物品的处理

对于单独属性物品(如装备、宠物等),每次获取都创建新记录,即使是相同物品:

6.2.1 单独属性物品创建

  1. 实例创建

    • 每个单独属性物品都在 item_instances 表中创建一条记录
    • 生成独特的属性(可能包含随机因素)
  2. 用户关联

    • item_users 表中创建记录,关联用户和物品实例
    • quantity 字段始终为1
  3. 创建流程

    // 伪代码示例
    // 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 来源记录格式

{
  "source_type": "chest_open",
  "source_id": 12345,
  "details": {
    "chest_id": 101,
    "open_time": "2023-05-01 12:34:56",
    "is_pity": false
  }
}

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 重置实现

系统通过定时任务实现自动重置:

// 伪代码示例
public function resetLimits()
{
    $now = new DateTime();

    // 重置每日限制
    $dailyLimits = OutputLimit::where('reset_type', 1)
        ->where('last_reset_time', '<', $now->format('Y-m-d 00:00:00'))
        ->get();

    foreach ($dailyLimits as $limit) {
        $limit->current_quantity = 0;
        $limit->last_reset_time = $now;
        $limit->save();

        // 重置用户计数
        UserOutputCounter::where('limit_id', $limit->id)
            ->update(['current_count' => 0]);
    }

    // 类似地处理每周和每月重置
    // ...
}

7.3 关联物品限制

系统支持将多个相关物品关联到同一个限制规则下,防止通过不同渠道绕过限制:

7.3.1 共享限制额度

  • 定义:多个物品共享同一个限制额度
  • 应用场景:不同渠道获取的相同物品、功能相似的物品
  • 实现方式
    • item_output_limits 表的 related_items 字段中存储关联物品ID列表
    • 检查限制时,同时考虑所有关联物品的产出数量

7.3.2 关联物品配置

// related_items字段示例
{
  "items": [1001, 1002, 1003],
  "relation_type": "shared_limit"
}

7.4 限制检查流程

在物品产出前,系统会执行以下检查流程,确保不超过设定的限制:

7.4.1 检查步骤

  1. 查询物品限制

    $limit = OutputLimit::where('item_id', $itemId)->first();
    if (!$limit) {
       // 没有限制,直接允许产出
       return true;
    }
    
  2. 检查限制类型

    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. 检查关联物品

    if (!empty($limit->related_items)) {
       $relatedItems = json_decode($limit->related_items, true);
       foreach ($relatedItems['items'] as $relatedItemId) {
           // 检查关联物品的产出记录
           // ...
       }
    }
    
  4. 更新计数

    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%),系统可以发送预警通知:

if ($currentQuantity >= $maxQuantity * 0.8 && $currentQuantity < $maxQuantity * 0.9) {
    // 发送80%预警
    $this->sendWarning($itemId, '80%');
} elseif ($currentQuantity >= $maxQuantity * 0.9) {
    // 发送90%预警
    $this->sendWarning($itemId, '90%');
}

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 事务内记录

日志记录应在数据库事务内进行,确保操作和日志的一致性:

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;
}

8.2.2 异步日志记录

对于高频操作,可以使用队列实现异步日志记录,减轻数据库压力:

// 将日志记录任务推送到队列
Queue::push(new RecordItemTransactionLog($userId, $itemId, $quantity, $transactionType, $sourceType, $sourceId));

8.2.3 批量日志记录

对于批量操作,可以使用批量插入优化性能:

$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);

8.3 日志查询接口

系统提供以下接口用于查询日志:

8.3.1 查询用户物品历史

  • 功能:查询用户的物品获取和消耗历史
  • 参数:用户ID、物品ID(可选)、交易类型(可选)、时间范围(可选)、分页参数
  • 返回:物品交易记录列表
  • 查询示例

    $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(可选)、时间范围(可选)、分页参数
  • 返回:宝箱开启记录列表
  • 查询示例

    $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 归档实现

// 伪代码示例
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 数据库设计

合成系统涉及三个主要数据表:配方表、配方材料表和用户配方表。

#### 9.2.1 item_recipes 表(合成配方)

| 字段名 | 类型 | 说明 |
| --- | --- | --- |
| 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 | 更新时间 |

#### 9.2.3 item_user_recipes 表(用户配方)

| 字段名 | 类型 | 说明 |
| --- | --- | --- |
| 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 | 更新时间 |

### 9.3 多币种成本设计

系统支持使用多种货币作为合成成本,增加游戏经济的深度:

#### 9.3.1 币种类型

1. **游戏金币**:基础游戏货币
2. **钻石**:高级游戏货币,通常与真实货币关联
3. **声望**:特定阵营或活动的声望货币
4. **活动代币**:限时活动专用货币

#### 9.3.2 成本存储格式

在 `item_recipes` 表的 `coin_cost` 字段中,使用JSON格式存储多币种成本:

json { "gold": 1000, "diamond": 5, "reputation": {

"faction_id": 2,
"amount": 100

}, "event_token": {

"token_id": 101,
"amount": 20

} }


#### 9.3.3 成本检查逻辑

php // 伪代码示例 public function checkCraftCost($userId, $recipeId) {

$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 合成成功率机制

系统支持概率性合成,增加游戏的随机性和挑战性:

#### 9.4.1 基础成功率

每个配方都有一个基础成功率,定义在 `item_recipes` 表的 `success_rate` 字段中:

- 成功率范围:0-100(百分比)
- 成功率为100表示必定成功
- 成功率为0表示无法通过常规方式成功

#### 9.4.2 成功率调整因素

基础成功率可以受多种因素影响:

1. **玩家等级**:等级越高,成功率可能越高
2. **技能加成**:特定技能可以提高成功率
3. **道具加成**:使用特殊道具可以提高成功率
4. **设备加成**:使用特殊设备进行合成可以提高成功率

#### 9.4.3 成功率计算

php // 伪代码示例 public function calculateSuccessRate($userId, $recipeId) {

$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);

// 计算最终成功率
$finalRate = $baseRate + $levelBonus + $skillBonus + $itemBonus;

// 确保成功率在0-100范围内
return max(0, min(100, $finalRate));

}


### 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. **物品解锁**:
   - 使用特定物品(如配方书)解锁
   - 系统检测物品使用事件并解锁对应配方

#### 9.6.2 解锁条件格式

在 `item_recipes` 表的 `unlock_condition` 字段中,使用JSON格式存储解锁条件:

json { "type": "level", "value": 20 }


或者更复杂的条件:

json { "type": "multi", "conditions": [

{
  "type": "level",
  "value": 15
},
{
  "type": "quest",
  "quest_id": 1024,
  "status": "completed"
},
{
  "type": "item",
  "item_id": 5001,
  "quantity": 1
}

], "logic": "and" }


### 9.7 合成结果计算

系统支持多种合成结果计算方式,增加游戏的多样性:

#### 9.7.1 固定结果

最简单的合成方式,成功后获得固定数量的物品:

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];

}


#### 9.7.2 随机数量

成功后获得的物品数量在一个范围内随机:

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];

}


#### 9.7.3 品质变化

对于单独属性物品,合成可能影响物品的品质:

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];

}


## 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. **优先级**:当多个规则都适用时,使用优先级最高的规则

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;
}

// 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. **单独属性物品**:分解单独属性物品时,可以根据其特殊属性调整分解结果

php // 伪代码示例 public function canDismantle($itemId, $instanceId = null) {

$item = Item::find($itemId);

// 检查物品是否可分解
if ($item->dismantlable == 0) {
    return false;
}

// 检查单独属性物品
if ($instanceId) {
    $instance = ItemInstance::find($instanceId);
    // 可以添加特殊条件,如不允许分解特定品质以上的装备
    if ($instance->numeric_attributes->quality > 90) {
        return false;
    }
}

return true;

}


#### 10.3.3 批量分解功能

系统支持多种批量分解方式,提高用户体验:

1. **同类物品批量分解**:一次分解多个相同物品
2. **多类物品批量分解**:一次分解多种不同物品
3. **自动分解**:可以设置自动分解规则,如自动分解低品质物品

php // 伪代码示例 public function batchDismantle($userId, $items) {

$results = [];
$totalResults = [];

DB::beginTransaction();
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;
            }
        }
    }

    DB::commit();
    return [
        'success' => true,
        'detail_results' => $results,
        'total_materials' => array_values($totalResults)
    ];
} catch (\Exception $e) {
    DB::rollBack();
    return ['success' => false, 'message' => $e->getMessage()];
}

}


### 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 与用户系统交互

物品系统需要与用户系统交互,确保物品正确关联到用户:

// 伪代码示例
public function checkUserExists($userId)
{
    $user = User::find($userId);
    if (!$user) {
        throw new UserNotFoundException("用户不存在: $userId");
    }
    return $user;
}

12.1.2 与任务系统交互

物品系统与任务系统交互,支持任务相关的物品操作:

// 伪代码示例
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 与商店系统交互

物品系统与商店系统交互,支持物品的购买和出售:

// 伪代码示例
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 与邮件系统交互

物品系统与邮件系统交互,支持通过邮件发送物品:

// 伪代码示例
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 事件监听

其他系统可以监听这些事件并执行相应操作:

// 伪代码示例
// 在服务提供者中注册事件监听
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 物品查询接口

// 伪代码示例
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 物品操作接口

// 伪代码示例
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. 队列处理

    • 使用队列处理非即时性操作,如日志记录
    • 批量物品操作可以放入队列异步处理
  2. 定时任务

    • 使用定时任务处理物品过期、绑定解除等周期性操作
    • 将资源密集型操作安排在服务器负载较低的时间执行

13.2 安全考虑

物品系统涉及游戏经济核心,需要特别注意安全性:

13.2.1 防作弊措施

  1. 操作验证

    • 所有物品操作都需要进行权限和合法性验证
    • 敏感操作(如删除物品)需要额外的验证步骤
  2. 异常监控

    • 监控异常的物品获取和消耗模式
    • 设置物品操作的频率限制和阈值警报
  3. 日志审计

    • 记录所有物品操作的详细日志
    • 定期审计物品流通情况,发现潜在问题

13.2.2 并发控制

  1. 乐观锁

    • 使用版本号或时间戳实现乐观锁
    • 在高并发场景下防止数据不一致
  2. 悲观锁

    • 对于关键操作,使用数据库行锁或表锁
    • 在事务中锁定相关记录,防止并发修改
  3. 分布式锁

    • 在分布式环境中,使用Redis等实现分布式锁
    • 确保跨服务器的操作原子性

13.3 通用注意事项

在实现和维护物品系统时,应注意以下事项:

  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. 批量分解时,应注意性能优化,避免大量物品同时分解导致系统负担