| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- <?php
- namespace App\Module\GameItems\Services;
- use App\Module\GameItems\Logics\Recipe as RecipeLogic;
- use App\Module\GameItems\Models\ItemRecipe;
- use App\Module\GameItems\Models\ItemRecipeMaterial;
- use App\Module\GameItems\Models\ItemCraftLog;
- use App\Module\GameItems\Models\ItemUserRecipe;
- use Exception;
- use Illuminate\Database\Eloquent\Collection;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- /**
- * 物品合成服务类
- *
- * 提供物品合成相关的服务,包括合成物品、获取用户可合成配方列表、解锁配方等功能。
- * 该类是物品合成模块对外提供服务的主要入口,封装了物品合成的复杂逻辑。
- *
- * 所有方法均为静态方法,可直接通过类名调用。
- */
- class CraftService
- {
- /**
- * 合成物品
- *
- * @param int $userId 用户ID
- * @param int $recipeId 配方ID
- * @param array $options 选项
- * @return array|bool 合成结果或失败标志
- */
- public static function craftItem(int $userId, int $recipeId, array $options = [])
- {
- try {
- // 获取配方信息
- $recipe = ItemRecipe::findOrFail($recipeId);
-
- // 检查配方是否激活
- if (!$recipe->is_active) {
- throw new Exception("配方未激活");
- }
-
- // 检查用户是否可以合成该配方
- $canCraft = $recipe->canCraftByUser($userId);
- if (!$canCraft['can_craft']) {
- throw new Exception($canCraft['reason']);
- }
-
- // 获取配方材料
- $materials = ItemRecipeMaterial::where('recipe_id', $recipeId)->get();
- if ($materials->isEmpty()) {
- throw new Exception("配方材料不存在");
- }
-
- // 获取合成数量
- $quantity = $options['quantity'] ?? 1;
-
- // 开启事务
- DB::beginTransaction();
-
- // 消耗材料
- $materialsUsed = [];
- foreach ($materials as $material) {
- $materialItemId = $material->material_item_id;
- $materialQuantity = $material->quantity * $quantity;
-
- // 检查用户是否有足够的材料
- $userItems = ItemService::getUserItems($userId, ['item_id' => $materialItemId]);
- $totalQuantity = $userItems->sum('quantity');
-
- if ($totalQuantity < $materialQuantity) {
- throw new Exception("材料不足:" . $material->materialItem->name);
- }
-
- // 消耗材料
- ItemService::consumeItem($userId, $materialItemId, null, $materialQuantity, [
- 'source_type' => 'craft',
- 'source_id' => $recipeId,
- 'details' => [
- 'recipe_id' => $recipeId,
- 'recipe_name' => $recipe->name
- ]
- ]);
-
- $materialsUsed[] = [
- 'item_id' => $materialItemId,
- 'item_name' => $material->materialItem->name,
- 'quantity' => $materialQuantity
- ];
- }
-
- // 计算成功率
- $isSuccess = true;
- if ($recipe->success_rate < 1.0) {
- $isSuccess = (mt_rand(1, 10000) <= $recipe->success_rate * 10000);
- }
-
- // 如果成功,添加结果物品到用户背包
- $resultData = null;
- if ($isSuccess) {
- // 计算结果数量
- $resultQuantity = $recipe->result_min_quantity * $quantity;
- if ($recipe->result_max_quantity > $recipe->result_min_quantity) {
- $resultQuantity = mt_rand($recipe->result_min_quantity, $recipe->result_max_quantity) * $quantity;
- }
-
- // 添加物品到用户背包
- $resultData = ItemService::addItem($userId, $recipe->result_item_id, $resultQuantity, [
- 'source_type' => 'craft',
- 'source_id' => $recipeId,
- 'details' => [
- 'recipe_id' => $recipeId,
- 'recipe_name' => $recipe->name
- ]
- ]);
- }
-
- // 更新用户配方使用记录
- $userRecipe = ItemUserRecipe::firstOrCreate(
- ['user_id' => $userId, 'recipe_id' => $recipeId],
- ['is_unlocked' => true, 'unlock_time' => now(), 'craft_count' => 0]
- );
- $userRecipe->incrementCraftCount($quantity);
-
- // 创建合成记录
- $craftLog = new ItemCraftLog([
- 'user_id' => $userId,
- 'recipe_id' => $recipeId,
- 'materials' => $materialsUsed,
- 'result_item_id' => $isSuccess ? $recipe->result_item_id : null,
- 'result_instance_id' => $isSuccess && isset($resultData['instance_id']) ? $resultData['instance_id'] : null,
- 'result_quantity' => $isSuccess ? $resultQuantity : 0,
- 'is_success' => $isSuccess,
- 'craft_time' => now(),
- 'ip_address' => $options['ip_address'] ?? request()->ip(),
- 'device_info' => $options['device_info'] ?? request()->userAgent(),
- ]);
- $craftLog->save();
-
- // 提交事务
- DB::commit();
-
- // 返回结果
- return [
- 'success' => $isSuccess,
- 'materials_used' => $materialsUsed,
- 'result' => $isSuccess ? [
- 'item_id' => $recipe->result_item_id,
- 'item_name' => $recipe->resultItem->name,
- 'quantity' => $resultQuantity,
- 'instance_id' => $resultData['instance_id'] ?? null
- ] : null
- ];
-
- } catch (Exception $e) {
- // 回滚事务
- if (DB::transactionLevel() > 0) {
- DB::rollBack();
- }
-
- Log::error('合成物品失败', [
- 'user_id' => $userId,
- 'recipe_id' => $recipeId,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
-
- return false;
- }
- }
-
- /**
- * 获取用户可合成配方列表
- *
- * @param int $userId 用户ID
- * @param array $filters 过滤条件
- * @return Collection 配方列表
- */
- public static function getUserAvailableRecipes(int $userId, array $filters = []): Collection
- {
- $query = ItemRecipe::where('is_active', true)
- ->where(function ($q) use ($userId) {
- $q->where('is_default_unlocked', true)
- ->orWhereHas('userRecipes', function ($q) use ($userId) {
- $q->where('user_id', $userId)
- ->where('is_unlocked', true);
- });
- });
-
- // 应用过滤条件
- if (isset($filters['category_id'])) {
- $query->where('category_id', $filters['category_id']);
- }
-
- return $query->orderBy('sort_order', 'asc')->get();
- }
-
- /**
- * 解锁用户配方
- *
- * @param int $userId 用户ID
- * @param int $recipeId 配方ID
- * @return bool 是否成功
- */
- public static function unlockRecipe(int $userId, int $recipeId): bool
- {
- try {
- $recipe = ItemRecipe::findOrFail($recipeId);
-
- // 检查配方是否激活
- if (!$recipe->is_active) {
- return false;
- }
-
- // 检查是否已解锁
- $userRecipe = ItemUserRecipe::where('user_id', $userId)
- ->where('recipe_id', $recipeId)
- ->first();
-
- if ($userRecipe && $userRecipe->is_unlocked) {
- return true; // 已经解锁
- }
-
- // 创建或更新用户配方记录
- if (!$userRecipe) {
- $userRecipe = new ItemUserRecipe([
- 'user_id' => $userId,
- 'recipe_id' => $recipeId,
- 'is_unlocked' => true,
- 'unlock_time' => now(),
- 'craft_count' => 0
- ]);
- $userRecipe->save();
- } else {
- $userRecipe->is_unlocked = true;
- $userRecipe->unlock_time = now();
- $userRecipe->save();
- }
-
- return true;
- } catch (Exception $e) {
- Log::error('解锁配方失败', [
- 'user_id' => $userId,
- 'recipe_id' => $recipeId,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
-
- return false;
- }
- }
- }
|