Skip to content

Commit 6a1a6f1

Browse files
alexp8Sneer-ra2TF338claudedependabot[bot]
authored
Develop (#507)
* add more logs and update secondsInQueue (#456) Co-authored-by: Sneer-ra2 <116219243+Sneer-ra2@users.noreply.github.com> * set AutoSaveInterval to 0 * update secondsInQueue to use updated_at * fix secondsInQueue bug * update player name fix * account-settings updates * Fix: Cooldown should start on connect (#452) (#461) * Fix: Cooldown should start on connect (#452) * Fix: Cooldown should start on connect * Fix: Cooldown should start on connect * housekeeping --------- Co-authored-by: TF338 <211804947+TF338@users.noreply.github.com> * fix cooldown * Do not prevent YvY any longer. (#468) * create migration (#470) * refactor(player-detail): optimize queries and refactor controller following SOLID principles (#472) Achieved 95.5% query reduction (1,563 → 70 queries) and improved code quality by refactoring the getLadderPlayer method from a 172-line "God Method" into a clean, maintainable architecture. Performance Improvements: - Eliminated N+1 query issues in service methods using SQL aggregation - Added eager loading to prevent duplicate queries in views - Optimized game data transformation with pre-computed URLs - Reduced service method queries from ~708 to ~5 - Reduced view queries from ~216 to 0 Query Optimizations: - getPlayerMatchups: 200+ queries → 1 with eager loading - getFactionResults: 27 queries → 1 with SQL aggregation (SUM/CASE) - getMapWinLossByPlayer: 121+ queries → 1 with aggregation + join - getPlayerGamesPlayedByMonth: 60 queries → 1 with DATE grouping - getTeamMatchups: 300+ queries → 1 with eager loading Code Quality Improvements (Fixed 10 Issues): - Applied Single Responsibility Principle - extracted Action class - Eliminated variable shadowing ($user vs $authenticatedUser vs $playerUser) - Removed redundant database queries (duplicate User::where calls) - Replaced json_encode/decode anti-pattern with clean object cast - Introduced constants for magic numbers (GAMES_PER_PAGE, etc.) - Added full type hints to all method signatures - Extracted data transformation logic to GameTransformer service - Fixed inconsistent null checks (strict comparison) - Removed duplicate view data (playerGamesLast24Hours) - Fixed undefined variable bug in SiteHelper::getMapPreviewUrl Architecture Changes: - Created GetPlayerDetailAction (Action pattern) - 230 lines - Created GameTransformer service - 95 lines - Created PlayerDetailData DTO (example) - 45 lines - Reduced controller method from 172 to 22 lines (87% reduction) New Files: - app/Actions/Player/GetPlayerDetailAction.php - app/DataTransferObjects/PlayerDetailData.php - app/Http/Services/GameTransformer.php Modified Files: - app/Http/Controllers/LadderController.php (refactored getLadderPlayer) - app/Http/Services/StatsService.php (SQL aggregation for stats) - app/Http/Services/ChartService.php (optimized date grouping) - app/Helpers/SiteHelper.php (fixed undefined variable) - resources/views/ladders/player/_games-table.blade.php (use eager-loaded data) - resources/views/ladders/components/_games-player-row.blade.php (pre-computed URLs) Developer Experience: - Added .vscode/ to .gitignore for IDE configuration - Added .specs/ to .gitignore for local technical documentation Benefits: ✅ 95.5% query reduction (1,563 → 70 queries) ✅ 87% controller code reduction (172 → 22 lines) ✅ SOLID principles applied ✅ Improved testability ✅ Enhanced maintainability ✅ No breaking changes (100% backward compatible) ✅ No performance regression 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> * Performance Optimization: Game & Player Detail Pages (#473) * refactor(player-detail): optimize queries and refactor controller following SOLID principles Achieved 95.5% query reduction (1,563 → 70 queries) and improved code quality by refactoring the getLadderPlayer method from a 172-line "God Method" into a clean, maintainable architecture. Performance Improvements: - Eliminated N+1 query issues in service methods using SQL aggregation - Added eager loading to prevent duplicate queries in views - Optimized game data transformation with pre-computed URLs - Reduced service method queries from ~708 to ~5 - Reduced view queries from ~216 to 0 Query Optimizations: - getPlayerMatchups: 200+ queries → 1 with eager loading - getFactionResults: 27 queries → 1 with SQL aggregation (SUM/CASE) - getMapWinLossByPlayer: 121+ queries → 1 with aggregation + join - getPlayerGamesPlayedByMonth: 60 queries → 1 with DATE grouping - getTeamMatchups: 300+ queries → 1 with eager loading Code Quality Improvements (Fixed 10 Issues): - Applied Single Responsibility Principle - extracted Action class - Eliminated variable shadowing ($user vs $authenticatedUser vs $playerUser) - Removed redundant database queries (duplicate User::where calls) - Replaced json_encode/decode anti-pattern with clean object cast - Introduced constants for magic numbers (GAMES_PER_PAGE, etc.) - Added full type hints to all method signatures - Extracted data transformation logic to GameTransformer service - Fixed inconsistent null checks (strict comparison) - Removed duplicate view data (playerGamesLast24Hours) - Fixed undefined variable bug in SiteHelper::getMapPreviewUrl Architecture Changes: - Created GetPlayerDetailAction (Action pattern) - 230 lines - Created GameTransformer service - 95 lines - Created PlayerDetailData DTO (example) - 45 lines - Reduced controller method from 172 to 22 lines (87% reduction) New Files: - app/Actions/Player/GetPlayerDetailAction.php - app/DataTransferObjects/PlayerDetailData.php - app/Http/Services/GameTransformer.php Modified Files: - app/Http/Controllers/LadderController.php (refactored getLadderPlayer) - app/Http/Services/StatsService.php (SQL aggregation for stats) - app/Http/Services/ChartService.php (optimized date grouping) - app/Helpers/SiteHelper.php (fixed undefined variable) - resources/views/ladders/player/_games-table.blade.php (use eager-loaded data) - resources/views/ladders/components/_games-player-row.blade.php (pre-computed URLs) Developer Experience: - Added .vscode/ to .gitignore for IDE configuration - Added .specs/ to .gitignore for local technical documentation Benefits: ✅ 95.5% query reduction (1,563 → 70 queries) ✅ 87% controller code reduction (172 → 22 lines) ✅ SOLID principles applied ✅ Improved testability ✅ Enhanced maintainability ✅ No breaking changes (100% backward compatible) ✅ No performance regression 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor * feat(game-detail): add comprehensive eager loading to eliminate N+1 queries Enhanced GameReportService with complete relationship eager loading: **Added eager loads:** - player.user.userSettings (for user preferences) - player.clanPlayer.clan (for clan games) - player.playerCaches (constrained by history ID) - map.mapHeaders (for map preview data) - stats (Stats2 relationship) - clan (for clan identification) - gameReport (for clan logic in views) - qmMatch.map (for map preview) **Query optimization:** - Consolidated player eager loads into single closure - Added constrained eager loading for playerCaches - Separate eager loads for mod vs non-mod users - All relationships used in views are now eager loaded **Known limitation:** Views currently call relationship methods (->player()->first()) instead of properties (->player), which bypasses eager loading. This is documented in game-detail-view-optimization-followup.md for future optimization. Current state: 260 → 248 queries (~5% reduction) Potential with view fixes: 260 → 5-10 queries (95-98% reduction) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(game-detail): remove non-existent playerCaches relationship from eager loading Removed attempted eager loading of 'playerCaches' relationship which does not exist on the Player model. The Player model has a playerCache($historyId) method that makes queries, but no playerCaches() relationship is defined. Attempting to eager load a non-existent relationship causes a runtime error. **Issue:** Call to undefined relationship [playerCaches] on model [App\Models\Player] **Fix:** Removed playerCaches from eager loading in GameReportService. The views still call the playerCache() method which makes queries - this is documented in game-detail-view-optimization-followup.md for future fix. **To properly optimize playerCache queries:** 1. Add playerCaches() relationship to Player model 2. Update views to use relationship collection 3. OR add memoization to the existing method 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * perf(game-detail): pre-compute player data and fix relationship access in views Moved query-heavy computations from views to controller to eliminate N+1 queries. **Action Layer Changes:** - Added attachPlayerCacheData() method to pre-compute player cache info - Attached playerCache, playerRank, playerPoints, playerTier to each PlayerGameReport - Added 'map' and 'gameAbbreviation' to view data (already eager-loaded) **View Layer Changes:** - Fixed relationship access: ->player()->first() → ->player (use property) - Fixed relationship access: ->clan()->first() → ->clan (use property) - Fixed relationship access: ->ladder()->first() → ->ladder (use property) - Removed direct Map query: Map::where('hash', '=', $game->hash) (use passed $map) - Use pre-computed $pgr->playerRank instead of $playerCache->rank() - Use pre-computed $pgr->playerPoints instead of $playerCache->points - Use pre-computed $pgr->playerTier instead of getCachedPlayerTierByLadderHistory() **Files Updated:** - app/Actions/Game/GetGameDetailAction.php - resources/views/ladders/game-detail.blade.php - resources/views/ladders/clan-game-detail.blade.php - resources/views/ladders/game/_player-card.blade.php - resources/views/ladders/game/_map-preview-with-players.blade.php **Query Reduction:** Before: 249 queries Expected after: ~10-20 queries (90-95% reduction) All queries that were in views are now executed once in the action layer and the results are passed to the view as pre-computed data. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * perf(game-detail): eliminate N+1 queries for countableGameObject and admin tools Fixed massive N+1 query issue in game cameo stats and admin game tools. **Critical Fix - countableGameObject N+1:** The view was iterating over gameObjectCounts (30-50 per player) and for EACH one, lazy-loading the countableGameObject relationship. For a 4-player game, this caused 120-200 queries! **Changes Made:** 1. GameReportService - Added eager loading: - stats.gameObjectCounts.countableGameObject (CRITICAL) - player.gameClips (for game clip display) 2. GetGameDetailAction - Pre-compute game clips: - Added playerGameClip to attachPlayerCacheData() - Uses eager-loaded gameClips collection instead of query 3. _game-cameo-stats.blade.php: - Fixed: $pgr->player()->first() → $pgr->player - Fixed: $player->gameClip($pgr->game_id) → $pgr->playerGameClip - Removed: $player->playerCache() query (use pre-computed data) - Now uses eager-loaded countableGameObject relationship 4. _admin-game-tools.blade.php (mod-only): - Fixed: $thisGameReport->playerGameReports()->get() → $thisGameReport->playerGameReports - Fixed: $pgr->player()->first() → $pgr->player - Uses already eager-loaded data instead of new queries **Query Impact:** Before: 222 queries Expected: ~10-20 queries (90-95% reduction) The countableGameObject fix alone eliminates 100-200 queries depending on the number of players and game objects in the match. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(game-detail): add missing gameClips relationship to Player model Added gameClips() hasMany relationship to Player model to support eager loading. **Issue:** Call to undefined relationship [gameClips] on model [App\Models\Player] **Root Cause:** The Player model had a gameClip($gameId) method but no gameClips() relationship. GameReportService was attempting to eager load 'player.gameClips' which failed. **Fix:** Added relationship to Player model: ```php public function gameClips() { return $this->hasMany(GameClip::class); } ``` The GameClip model already had belongsTo(Player::class), so this completes the bidirectional relationship. **Impact:** - Enables eager loading of game clips - Eliminates N+1 queries when accessing player game clips - Existing gameClip($gameId) method still works for backward compatibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * perf(game-detail): eliminate queries in map preview and player card views Fixed redundant Stats2 queries and pre-computed faction/point report data. **Issues Fixed:** 1. **Redundant Stats2 Query (2 occurrences):** - _map-preview-with-players.blade.php line 111 - _player-card.blade.php line 10 Problem: ```php ❌ $playerStats2 = Stats2::where("id", $pgr->stats->id)->first(); ``` This was querying for a Stats2 model that was already loaded as $pgr->stats! Solution: Pre-compute faction in action: $pgr->playerFaction = $pgr->stats->faction(...) Views now use: $pgr->playerFaction (no query) 2. **Point Report Method Calls:** - _map-preview-with-players.blade.php line 41 Problem: ```php ❌ $pointReport = $pgr->gameReport->getPointReportByClan($pgr->clan_id); ``` This method call could trigger additional queries. Solution: Pre-compute in action: $pgr->pointReport = $gameReport->getPointReportByClan(...) Views now use: $pgr->pointReport ?? $pgr 3. **Map Waypoints Eager Loading:** Added 'map.mapHeaders.waypoints' to eager loading for player spawn positions. **Changes Made:** - GameReportService: Added waypoints eager loading - GetGameDetailAction: - Added attachPointReports() method - Pre-compute playerFaction in attachPlayerCacheData() - Views: Use pre-computed data instead of making queries **Query Impact:** Before: ~2-4 queries per player for faction + point reports After: 0 queries (all pre-computed) For 4-player game: Eliminates 8-16 additional queries 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * remove stale file --------- Co-authored-by: Claude <noreply@anthropic.com> * bug fix * update gitignore * add script to download backup * check if player is streaming (#477) * fix: exclude observers from Quick Match ready-check player count (#476) Critical bug fix where observers were incorrectly counted toward required player count in Quick Match ready validation, causing two failure modes: 1. 1v1 matches: AFK observers could prevent matches from starting 2. 2v2+ matches: Incomplete teams (e.g., 3 players + 1 observer) would incorrectly satisfy the 4-player requirement, starting unfair matches Changes: - Split player count validation into two queries in MatchUpController - Query 1: Validate only actual players (exclude is_observer) for ready-check - Query 2: Include all players (with observers) for spawn configuration - Add comprehensive logging for actual vs total player counts - Improve error messages with structured context The match creation logic already correctly excludes observers; this fix brings the ready-check logic into alignment with that behavior. Fixes unfair team compositions while preserving observer functionality. Ready observers are still included in spawn.ini when they poll in time. * Track Canceled & Failed Quick Match Games (#479) * track aborted games * refactor: improve production readiness and code quality - Replace doctrine/dbal-dependent migration with raw SQL - Add database indexes for query performance (ladder_id, created_at, qm_match_id, reason) - Fix Blade template null handling for PHP 8+ compatibility - Extract player colors to config for reusability - Add username validation and proper logging - Standardize Laravel output conventions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * Bump vite from 6.3.5 to 6.4.2 in /cncnet-api (#484) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.5 to 6.4.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.4.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.4.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.4.2 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump follow-redirects from 1.15.9 to 1.16.0 in /cncnet-api (#485) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.9 to 1.16.0. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](follow-redirects/follow-redirects@v1.15.9...v1.16.0) --- updated-dependencies: - dependency-name: follow-redirects dependency-version: 1.16.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump postcss from 8.5.6 to 8.5.13 in /cncnet-api (#483) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.13. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.6...8.5.13) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump axios from 1.10.0 to 1.15.0 in /cncnet-api (#482) Bumps [axios](https://github.com/axios/axios) from 1.10.0 to 1.15.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.10.0...v1.15.0) --- updated-dependencies: - dependency-name: axios dependency-version: 1.15.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump symfony/process from 7.3.0 to 7.4.8 in /cncnet-api (#465) Bumps [symfony/process](https://github.com/symfony/process) from 7.3.0 to 7.4.8. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/8.1/CHANGELOG.md) - [Commits](symfony/process@v7.3.0...v7.4.8) --- updated-dependencies: - dependency-name: symfony/process dependency-version: 7.4.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump phpunit/phpunit from 11.5.34 to 11.5.50 in /cncnet-api (#464) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 11.5.34 to 11.5.50. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/11.5.50/ChangeLog-11.5.md) - [Commits](sebastianbergmann/phpunit@11.5.34...11.5.50) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-version: 11.5.50 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump symfony/http-foundation from 7.3.2 to 7.4.8 in /cncnet-api (#443) Bumps [symfony/http-foundation](https://github.com/symfony/http-foundation) from 7.3.2 to 7.4.8. - [Release notes](https://github.com/symfony/http-foundation/releases) - [Changelog](https://github.com/symfony/http-foundation/blob/8.1/CHANGELOG.md) - [Commits](symfony/http-foundation@v7.3.2...v7.4.8) --- updated-dependencies: - dependency-name: symfony/http-foundation dependency-version: 7.3.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * laravel fix * canceled matches housekeeping * move import script * canceled matches fix * filter out rows with no player data * canceled matches fixes * adjust css * reduce log spam * Optimize failed game launch detection for performance and accuracy - Increase detection threshold from 15 to 45 minutes to avoid flagging long games in progress - Reduce scan window from 24 hours to 2 hours (runs every 30 mins vs 5 mins) - Fix N+1 query issue by batch loading already-logged match IDs - Change schedule from every 5 minutes to every 30 minutes Reduces CPU load by ~85% while preventing false positives on competitive matches that exceed 30+ minutes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add auto-cleanup for false-positive failed launches and improve detection timing - Reduce detection threshold from 45 to 20 minutes for faster failure detection - Add auto-cleanup in saveLadderResult to delete canceled match when report arrives - Change schedule from every 30 minutes to every 10 minutes for better responsiveness - Add QmCanceledMatch import to ApiLadderController This creates a self-healing system: games flagged at 20min as failed get auto-cleaned if reports arrive late. Detection window now 10-30 mins instead of 30-60 mins with negligible CPU impact. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * correct won flag for team games (#457) * correct won flag for team games * Fix critical bugs in 2v2 dispute resolution and point calculation - Prevent OOS/unfinished reports from overriding valid finished reports in dispute resolution - Add division-by-zero protection when calculating team averages - Improve getWinningTeamFromReports() to detect ambiguous cases (multiple teams with non-defeated players) - Move won flag normalization to handleGameDispute() to fix race condition where promoted reports had unnormalized data - Add OOS validation to duration-based report selection Fixes issue where reconnection errors caused incorrect team to win (e.g., game 1134554 where Palacio's OOS report with duration=163 overrode three finished reports with duration=157). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix --------- Co-authored-by: Claude <noreply@anthropic.com> * fix migration * Add play_and_observe observer mode (#497) * Add play_and_observe observer mode and fix SiteHelper logging spam ## Observer Mode Enhancements ### New Feature: Play & Observe Mode - Added `observer_mode` enum field to replace boolean `is_observer` - Three modes: `null` (play only), `observe_only`, `play_and_observe` - `play_and_observe` users join as players, but become observers if excluded from match - Migration converts existing data: `is_observer=1` → `observe_only` ### Implementation - **Migration**: 2026_05_02_195634_convert_is_observer_to_observer_mode_in_user_settings.php - Converts `user_settings.is_observer` boolean → `observer_mode` enum - Includes rollback support - **UserSettings Model**: - Added constants for enum values - Helper methods: `wantsToObserveOnly()`, `canPlayAndObserve()`, `hasObserverModeEnabled()` - **QuickMatchService**: - Updated `handleObserver()` to only set observer flag for `observe_only` mode - Allows `play_and_observe` users to participate in normal matchmaking - **TeamMatchupHandler**: - After teams formed, finds `play_and_observe` users excluded from match - Validates Twitch live status for them (unless admin) - Adds them to observer pool with priority after `observe_only` users - **UI Changes**: - Radio buttons replace checkbox in account settings - Three options: Play Only, Play & Observe, Observe Only ### SiteHelper Logging Fix - Fixed null-safe operator usage in `getMapPreviewUrl()` to prevent 392k+ daily log spam - Removed unhelpful error logs (logged empty values on exception) - Added early returns for missing data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Refactor: Extract Twitch observer validation to shared helper Extract duplicated Twitch validation logic from TeamMatchupHandler and QuickMatchService::handleObserver() into reusable helper method. Changes: - Add QuickMatchService::canPlayerObserve() - centralizes Twitch validation for observers (admin bypass, username check, live status) - Refactor handleObserver() to use new helper (70 lines → 18 lines) - Extract TeamMatchupHandler inline closure to findPlayAndObservePlayers() private method for better readability - Use shared helper in TeamMatchupHandler instead of duplicating logic Benefits: - DRY: Twitch validation in one place instead of two - Maintainability: Future Twitch requirement changes need single edit - Testability: Can unit test canPlayerObserve() independently - Readability: Main matchup() flow cleaner (41-line closure → 1-line call) Related to PR #497 (play_and_observe observer mode) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * include showRealNames * Feature/teammatchup add logging (#503) * logging * optimize * fix bug * housekeeping * fix validation * validation fixes --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Sneer-ra2 <116219243+Sneer-ra2@users.noreply.github.com> Co-authored-by: TF338 <211804947+TF338@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 21ee144 commit 6a1a6f1

2 files changed

Lines changed: 11 additions & 8 deletions

File tree

cncnet-api/app/Http/Services/QuickMatchService.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,6 +1523,8 @@ private function validateMatchConfiguration(QmMatch $qmMatch): void
15231523
}
15241524

15251525
// Validate players
1526+
$isTeamGame = $players->count() > 2;
1527+
15261528
foreach ($players as $player) {
15271529
$playerName = $player->player?->username ?? 'Unknown';
15281530

@@ -1533,15 +1535,16 @@ private function validateMatchConfiguration(QmMatch $qmMatch): void
15331535
if ($player->location < -1) {
15341536
$errors[] = "Player {$playerName} has invalid location={$player->location} (should be >= -1)";
15351537
} else {
1536-
// Check for duplicate spawn locations
1537-
if (isset($spawnLocations[$player->location])) {
1538+
// Check for duplicate spawn locations (skip -1 as multiple players can have random spawn)
1539+
if ($player->location !== -1 && isset($spawnLocations[$player->location])) {
15381540
$errors[] = "Duplicate spawn location {$player->location}: {$spawnLocations[$player->location]} and {$playerName}";
15391541
} else {
15401542
$spawnLocations[$player->location] = $playerName;
15411543
}
15421544
}
15431545

1544-
if (!in_array($player->team, ['A', 'B'])) {
1546+
// Only validate teams for team games (2v2+), not 1v1
1547+
if ($isTeamGame && !in_array($player->team, ['A', 'B'])) {
15451548
$errors[] = "Player {$playerName} has invalid team={$player->team} (should be 'A' or 'B')";
15461549
}
15471550
}

cncnet-api/resources/views/components/ladder/listing/player-row.blade.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
$username = $playerCache->player_name . ($playerOfTheDay ? ' ' . \App\Helpers\SiteHelper::getEmojiByMonth() : '');
88
$url = \App\Models\URLHelper::getPlayerProfileUrl($history, $playerCache->player_name);
99
$mostPlayedFaction = $mostUsedFactions[$playerCache->id] ?? '';
10-
$avatar = $playerCache->player->user->getUserAvatar();
11-
$emoji = $playerCache->player->user->getEmoji();
12-
$twitch = $playerCache->player->user->getTwitchProfile();
13-
$youtube = $playerCache->player->user->getYouTubeProfile();
14-
$discord = $playerCache->player->user->getDiscordProfile();
10+
$avatar = $playerCache->player?->user?->getUserAvatar() ?? '';
11+
$emoji = $playerCache->player?->user?->getEmoji() ?? '';
12+
$twitch = $playerCache->player?->user?->getTwitchProfile() ?? '';
13+
$youtube = $playerCache->player?->user?->getYouTubeProfile() ?? '';
14+
$discord = $playerCache->player?->user?->getDiscordProfile() ?? '';
1515
$ladderHasEnded = $history->hasEnded();
1616
1717
$rank = $ranks[$playerCache->id] ?? 9999;

0 commit comments

Comments
 (0)