| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- <?php
- namespace App\Module\GameItems\Services;
- use App\Module\GameItems\Models\Item;
- use App\Module\GameItems\Models\ItemDismantleRule;
- use App\Module\GameItems\Models\ItemDismantleLog;
- use App\Module\GameItems\Models\ItemUser;
- use Exception;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- /**
- * 物品分解服务类
- *
- * 提供物品分解相关的服务,包括分解物品、获取分解预览等功能。
- * 该类是物品分解模块对外提供服务的主要入口,封装了物品分解的复杂逻辑。
- *
- * 所有方法均为静态方法,可直接通过类名调用。
- */
- class DismantleService
- {
- /**
- * 分解物品
- *
- * @param int $userId 用户ID
- * @param int $itemId 物品ID
- * @param int|null $instanceId 物品实例ID(单独属性物品)
- * @param int $quantity 数量
- * @param array $options 选项
- * @return array|bool 分解结果或失败标志
- */
- public static function dismantleItem(int $userId, int $itemId, ?int $instanceId, int $quantity, array $options = [])
- {
- try {
- // 获取物品信息
- $item = Item::findOrFail($itemId);
- // 检查物品是否可分解
- if (!$item->can_dismantle) {
- throw new Exception("该物品不可分解");
- }
- // 检查用户是否拥有该物品
- $userItem = ItemUser::where('user_id', $userId)
- ->where('item_id', $itemId);
- if ($instanceId) {
- $userItem->where('instance_id', $instanceId);
- }
- $userItem = $userItem->first();
- if (!$userItem || $userItem->quantity < $quantity) {
- throw new Exception("物品数量不足");
- }
- // 获取分解规则
- $rule = self::getDismantleRule($itemId);
- if (!$rule) {
- throw new Exception("没有找到适用的分解规则");
- }
- // 开启事务
- DB::beginTransaction();
- // 消耗物品
- ItemService::consumeItem($userId, $itemId, $instanceId, $quantity, [
- 'source_type' => 'dismantle',
- 'source_id' => $rule->id,
- 'details' => [
- 'rule_id' => $rule->id,
- 'rule_name' => $rule->name
- ]
- ]);
- // 获取分解结果
- $dismantleResults = [];
- for ($i = 0; $i < $quantity; $i++) {
- $results = $rule->getDismantleResults();
- foreach ($results as $result) {
- // 添加到分解结果
- if (isset($dismantleResults[$result['item_id']])) {
- $dismantleResults[$result['item_id']]['quantity'] += $result['quantity'];
- } else {
- $dismantleResults[$result['item_id']] = $result;
- }
- }
- }
- // 添加分解结果物品到用户背包
- $addedItems = [];
- foreach ($dismantleResults as $resultItemId => $resultData) {
- $resultQuantity = $resultData['quantity'];
- if ($resultQuantity > 0) {
- // 添加物品到用户背包
- $addResult = ItemService::addItem($userId, $resultItemId, $resultQuantity, [
- 'source_type' => 'dismantle',
- 'source_id' => $rule->id,
- 'details' => [
- 'rule_id' => $rule->id,
- 'rule_name' => $rule->name,
- 'original_item_id' => $itemId,
- 'original_item_name' => $item->name
- ]
- ]);
- $addedItems[] = [
- 'item_id' => $resultItemId,
- 'item_name' => $resultData['item_name'],
- 'quantity' => $resultQuantity,
- 'instance_id' => $addResult['instance_id'] ?? null
- ];
- }
- }
- // 计算返还金币
- $coinReturn = 0;
- if ($rule->coin_return_rate > 0 && $item->sell_price > 0) {
- $coinReturn = floor($item->sell_price * $rule->coin_return_rate * $quantity);
- if ($coinReturn > 0) {
- // TODO: 添加金币到用户账户
- // 这里需要调用Fund模块的服务来添加金币
- }
- }
- // 创建分解记录
- $dismantleLog = new ItemDismantleLog([
- 'user_id' => $userId,
- 'rule_id' => $rule->id,
- 'item_id' => $itemId,
- 'instance_id' => $instanceId,
- 'quantity' => $quantity,
- 'results' => $addedItems,
- 'coin_return' => $coinReturn,
- 'dismantle_time' => now(),
- 'ip_address' => $options['ip_address'] ?? request()->ip(),
- 'device_info' => $options['device_info'] ?? request()->userAgent(),
- ]);
- $dismantleLog->save();
- // 提交事务
- DB::commit();
- // 返回结果
- return [
- 'success' => true,
- 'dismantled_item' => [
- 'item_id' => $itemId,
- 'item_name' => $item->name,
- 'quantity' => $quantity,
- 'instance_id' => $instanceId
- ],
- 'results' => $addedItems,
- 'coin_return' => $coinReturn
- ];
- } catch (Exception $e) {
- // 回滚事务
- if (DB::transactionLevel() > 0) {
- DB::rollBack();
- }
- Log::error('分解物品失败', [
- 'user_id' => $userId,
- 'item_id' => $itemId,
- 'instance_id' => $instanceId,
- 'quantity' => $quantity,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- return false;
- }
- }
- /**
- * 获取物品分解预览
- *
- * @param int $userId 用户ID
- * @param int $itemId 物品ID
- * @param int|null $instanceId 物品实例ID(单独属性物品)
- * @return array 分解预览
- */
- public static function getDismantlePreview(int $userId, int $itemId, ?int $instanceId = null): array
- {
- try {
- // 获取物品信息
- $item = Item::findOrFail($itemId);
- // 检查物品是否可分解
- if (!$item->can_dismantle) {
- return [
- 'can_dismantle' => false,
- 'reason' => '该物品不可分解'
- ];
- }
- // 获取分解规则
- $rule = self::getDismantleRule($itemId);
- if (!$rule) {
- return [
- 'can_dismantle' => false,
- 'reason' => '没有找到适用的分解规则'
- ];
- }
- // 获取分解结果预览
- $results = $rule->results()->with('resultItem')->get()->map(function ($result) {
- return [
- 'item_id' => $result->result_item_id,
- 'item_name' => $result->resultItem->name,
- 'min_quantity' => $result->min_quantity,
- 'max_quantity' => $result->max_quantity,
- 'chance' => $result->chance
- ];
- })->toArray();
- // 计算返还金币
- $coinReturn = 0;
- if ($rule->coin_return_rate > 0 && $item->sell_price > 0) {
- $coinReturn = floor($item->sell_price * $rule->coin_return_rate);
- }
- return [
- 'can_dismantle' => true,
- 'item' => [
- 'item_id' => $itemId,
- 'item_name' => $item->name,
- 'instance_id' => $instanceId
- ],
- 'possible_results' => $results,
- 'coin_return' => $coinReturn
- ];
- } catch (Exception $e) {
- Log::error('获取分解预览失败', [
- 'user_id' => $userId,
- 'item_id' => $itemId,
- 'instance_id' => $instanceId,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- return [
- 'can_dismantle' => false,
- 'reason' => '系统错误'
- ];
- }
- }
- /**
- * 获取物品的分解规则
- *
- * @param int $itemId 物品ID
- * @return ItemDismantleRule|null 分解规则
- */
- private static function getDismantleRule(int $itemId): ?ItemDismantleRule
- {
- // 获取物品信息
- $item = Item::find($itemId);
- if (!$item) {
- return null;
- }
- // 获取物品稀有度(从numeric_attributes中获取,如果没有则默认为1)
- $rarity = 1;
- if ($item->numeric_attributes && isset($item->numeric_attributes['rarity'])) {
- $rarity = (int)$item->numeric_attributes['rarity'];
- }
- // 1. 优先查找针对特定物品的规则(包含稀有度匹配)
- $rule = ItemDismantleRule::where('item_id', $itemId)
- ->where('is_active', true)
- ->where('min_rarity', '<=', $rarity)
- ->where('max_rarity', '>=', $rarity)
- ->orderBy('priority', 'desc')
- ->first();
- if ($rule) {
- return $rule;
- }
- // 2. 查找针对物品分类的规则(包含稀有度匹配)
- $rule = ItemDismantleRule::where('category_id', $item->category_id)
- ->whereNull('item_id')
- ->where('is_active', true)
- ->where('min_rarity', '<=', $rarity)
- ->where('max_rarity', '>=', $rarity)
- ->orderBy('priority', 'desc')
- ->first();
- if ($rule) {
- return $rule;
- }
- // 3. 查找通用规则(包含稀有度匹配)
- $rule = ItemDismantleRule::whereNull('item_id')
- ->whereNull('category_id')
- ->where('is_active', true)
- ->where('min_rarity', '<=', $rarity)
- ->where('max_rarity', '>=', $rarity)
- ->orderBy('priority', 'desc')
- ->first();
- return $rule;
- }
- }
|