041014-宝箱保底机制实现.md 6.8 KB

宝箱保底机制实现

任务时间: 2025年06月04日 10:14
任务类型: 功能开发
优先级: 中等
状态: ✅ 已完成

任务概述

为新的宝箱系统实现保底机制,确保用户在多次开启宝箱后能够获得稀有奖励,提升用户体验和游戏公平性。

主要工作内容

1. 数据库设计

创建保底计数表

  • 表名: kku_game_reward_group_pity_counts
  • 功能: 记录用户对每个奖励项的保底计数
  • 字段:
    • user_id: 用户ID
    • reward_group_id: 奖励组ID
    • reward_item_id: 奖励项ID
    • count: 当前计数
    • pity_threshold: 保底阈值
    • last_attempt_at: 最后尝试时间
    • last_hit_at: 最后命中时间

扩展奖励项表

kku_game_reward_items 表添加保底相关字段:

  • pity_threshold: 保底阈值(0表示不启用保底)
  • pity_weight_factor: 保底权重因子(递增概率的倍数)
  • pity_enabled: 是否启用保底机制

2. 核心模型开发

GameRewardGroupPityCount 模型

  • 保底计数的数据模型
  • 提供保底状态检查方法
  • 支持计数增加和重置操作
  • 包含权重调整计算逻辑

更新 GameRewardItem 模型

  • 添加保底相关字段的支持
  • 更新 fillable 和 casts 配置
  • 保持向后兼容性

3. 保底服务层

PityService 服务类

提供完整的保底机制功能:

核心方法:

  • getUserPityCounts(): 获取用户保底计数
  • initializePityCounts(): 初始化保底计数
  • applyPityAdjustments(): 应用保底权重调整
  • updatePityCounts(): 更新保底计数
  • checkPityTriggers(): 检查保底触发
  • getPityStatus(): 获取保底状态信息
  • resetAllPityCounts(): 重置保底计数
  • cleanupOldPityCounts(): 清理过期记录

保底机制特点:

  • 支持多个奖励项的独立保底计数
  • 权重递增算法,接近保底时概率提升
  • 达到保底阈值时确保必中
  • 获得奖励后自动重置计数

4. 奖励系统集成

更新 RewardService

  • 添加 grantRewardWithPity() 方法
  • 提供保底状态查询接口
  • 支持保底计数重置功能

更新 RewardLogic

  • 实现 grantRewardWithPity() 逻辑
  • 集成保底权重调整算法
  • 支持独立概率和权重选择两种模式
  • 完整的事务处理和错误处理

更新 ChestService

  • 宝箱开启时默认启用保底机制
  • 调用新的保底奖励发放接口
  • 保持原有功能的完整性

5. 保底算法设计

权重调整算法

// 基础权重调整公式
$adjustedWeight = $baseWeight * (1 + $progressRatio * $weightFactor)

// 保底触发时
if ($count >= $threshold) {
    $adjustedWeight = 999999.0; // 确保必中
}

计数管理逻辑

  • 每次尝试时增加计数
  • 获得对应奖励时重置计数
  • 支持多个奖励项的独立计数
  • 自动清理过期记录

6. 功能特点

灵活配置

  • 每个奖励项可独立配置保底
  • 支持不同的保底阈值
  • 可调整权重递增因子
  • 支持启用/禁用控制

性能优化

  • 批量查询减少数据库访问
  • 智能初始化避免重复创建
  • 索引优化提升查询效率
  • 定期清理过期数据

数据完整性

  • 外键约束确保数据一致性
  • 唯一索引防止重复记录
  • 事务处理保证原子性
  • 完整的错误处理机制

技术实现细节

数据库脚本

-- 创建保底计数表
CREATE TABLE `kku_game_reward_group_pity_counts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `reward_group_id` int NOT NULL COMMENT '奖励组ID',
  `reward_item_id` int NOT NULL COMMENT '奖励项ID',
  `count` int NOT NULL DEFAULT '0' COMMENT '当前计数',
  `pity_threshold` int NOT NULL DEFAULT '0' COMMENT '保底阈值',
  `last_attempt_at` timestamp NULL DEFAULT NULL COMMENT '最后尝试时间',
  `last_hit_at` timestamp NULL DEFAULT NULL COMMENT '最后命中时间',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_user_reward_item` (`user_id`,`reward_group_id`,`reward_item_id`),
  -- 其他索引和外键约束...
);

-- 添加保底字段到奖励项表
ALTER TABLE `kku_game_reward_items` 
ADD COLUMN `pity_threshold` int NOT NULL DEFAULT '0' COMMENT '保底阈值(0表示不启用保底)',
ADD COLUMN `pity_weight_factor` decimal(8,4) NOT NULL DEFAULT '1.0000' COMMENT '保底权重因子(递增概率的倍数)',
ADD COLUMN `pity_enabled` tinyint NOT NULL DEFAULT '0' COMMENT '是否启用保底机制';

使用示例

use App\Module\Game\Enums\REWARD_SOURCE_TYPE;

// 发放奖励(启用保底机制)
$result = RewardService::grantRewardWithPity(
    $userId,
    $rewardGroupId,
    REWARD_SOURCE_TYPE::CHEST, // 使用枚举
    $chestId,
    true // 启用保底
);

// 查看用户保底状态
$pityStatus = RewardService::getUserPityStatus($userId, $rewardGroupId);

// 重置用户保底计数
RewardService::resetUserPity($userId, $rewardGroupId);

测试验证

功能测试

  • ✅ 保底计数正确初始化
  • ✅ 权重调整算法正确
  • ✅ 保底触发机制正常
  • ✅ 计数重置逻辑正确
  • ✅ 数据库约束有效

性能测试

  • ✅ 批量查询性能良好
  • ✅ 索引优化效果明显
  • ✅ 内存使用合理
  • ✅ 并发处理稳定

兼容性测试

  • ✅ 与现有宝箱系统兼容
  • ✅ 不影响其他奖励功能
  • ✅ 向后兼容性良好
  • ✅ 数据迁移无问题

后续优化建议

功能扩展

  1. 保底历史记录: 记录保底触发历史,便于数据分析
  2. 保底预告功能: 提前告知用户接近保底状态
  3. 保底配置界面: 后台管理界面配置保底参数
  4. 保底统计报表: 分析保底机制的效果和用户行为

性能优化

  1. 缓存机制: 缓存用户保底状态减少数据库查询
  2. 异步处理: 保底计数更新可考虑异步处理
  3. 数据归档: 定期归档历史保底数据
  4. 监控告警: 添加保底系统的监控和告警

业务扩展

  1. 多级保底: 支持多个保底阈值的递进式保底
  2. 保底共享: 同类型奖励组之间的保底计数共享
  3. 保底转移: 支持保底计数在不同奖励组间转移
  4. 保底补偿: 系统异常时的保底补偿机制

总结

成功实现了完整的宝箱保底机制系统,包括:

  1. 完整的数据模型: 保底计数表和相关字段
  2. 核心服务层: PityService 提供全面的保底功能
  3. 系统集成: 与现有奖励系统无缝集成
  4. 灵活配置: 支持多种保底策略和参数
  5. 性能优化: 高效的查询和计算算法
  6. 数据安全: 完整的约束和事务处理

该系统为游戏提供了公平、透明的保底机制,提升了用户体验,同时保持了系统的稳定性和可扩展性。