Skip to content

Commit 7c0b9cc

Browse files
alexp8Sneer-ra2
andauthored
Develop to Main (#386)
* Duplicate handling. * Added page of list with active duplicates. * Full IP-check for confirmed duplicates. * Simplification. * Removed comment. * Small update. * Added database migration. * Added unit test. * track observers * move comment * update image.php * fix null pointer (#379) * Develop (#380) (#381) * Duplicate handling. * Added page of list with active duplicates. * Full IP-check for confirmed duplicates. * Simplification. * Removed comment. * Small update. * Added database migration. * Added unit test. * track observers * move comment * update image.php * fix null pointer (#379) --------- Co-authored-by: Sneer <[email protected]> Co-authored-by: Sneer-ra2 <[email protected]> * add more logs (#382) * add more logs * update log * Fix for createPlayer. * fix bug where disconnect gave everyone minus points (#385) * fix bug where disconnect gave everyone minus points * fix ladder info map issue * Improved naming on elo page. * Improved description for duplicate reason. --------- Co-authored-by: Sneer <[email protected]> Co-authored-by: Sneer-ra2 <[email protected]>
1 parent 4c48896 commit 7c0b9cc

File tree

4 files changed

+96
-51
lines changed

4 files changed

+96
-51
lines changed

cncnet-api/app/Extensions/Qm/Matchup/BaseMatchupHandler.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,18 @@ public function __construct(QmQueueEntry $qmQueueEntry, int $gameType)
3333
public function createMatch(Collection $maps, Collection $otherQMQueueEntries)
3434
{
3535
// filter out placeholder maps
36-
$filteredMaps = $maps->filter(function ($map) {
37-
return
38-
!strpos($map->description, 'Map Info')
39-
&& !strpos($map->description, 'Map Guide')
40-
&& !strpos($map->description, 'Ladder Guide')
41-
&& !strpos($map->description, 'Ladder Info')
42-
&& !strpos($map->description, 'Ladder Rules');
36+
$filteredMaps = $maps->filter(function ($map)
37+
{
38+
return !(
39+
str_contains($map->description, 'Map Info') ||
40+
str_contains($map->description, 'Map Guide') ||
41+
str_contains($map->description, 'Ladder Guide') ||
42+
str_contains($map->description, 'Ladder Info') ||
43+
str_contains($map->description, 'Ladder Rules')
44+
);
4345
});
4446

47+
4548
$this->removeQueueEntry();
4649

4750
return $this->quickMatchService->createQmMatch(

cncnet-api/app/Http/Controllers/AdminController.php

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ private function buildDuplicateList(User $user, Collection $ipDuplicates, Collec
233233
{
234234
$allDupes->push([
235235
'user' => $dupe,
236-
'reason' => 'IP',
236+
'reason' => 'Recent IP',
237237
]);
238238
}
239239

@@ -273,7 +273,7 @@ private function buildDuplicateList(User $user, Collection $ipDuplicates, Collec
273273
{
274274
$allDupes->push([
275275
'user' => $relatedUser,
276-
'reason' => 'Manually',
276+
'reason' => 'Indirect or marked manually',
277277
]);
278278
}
279279
}
@@ -288,47 +288,48 @@ private function buildDuplicateList(User $user, Collection $ipDuplicates, Collec
288288
$dupeUser = $entry['user'];
289289
$reason = $entry['reason'];
290290

291-
if ($userPrimaryId === $dupeUser->primaryId())
291+
if (!str_contains($reason, 'IP'))
292292
{
293-
// This is a confirmed duplicates.
294-
$finalReason = $reason;
295-
296-
if (!str_contains($finalReason, 'IP'))
297-
{
298-
// Perform a full IP history comparison if 'IP' is not already part of the reason.
299-
// This helps preserve the IP-based link even if users no longer share a current IP.
300-
// Only accept IP-matches within a 1.5 year range.
301-
$userIpMap = IpAddressHistory::where('user_id', $user->id)->get()->groupBy('ip_address_id');
302-
$dupeIpMap = IpAddressHistory::where('user_id', $dupeUser->id)->get()->groupBy('ip_address_id');
293+
// Perform a full IP history comparison if 'IP' is not already part of the reason.
294+
// This helps preserve the IP-based link even if users no longer share a current IP.
295+
// Only accept IP-matches within a 1.5 year range.
296+
$userIpMap = IpAddressHistory::where('user_id', $user->id)->get()->groupBy('ip_address_id');
297+
$dupeIpMap = IpAddressHistory::where('user_id', $dupeUser->id)->get()->groupBy('ip_address_id');
303298

304-
$commonIpIds = array_intersect($userIpMap->keys()->all(), $dupeIpMap->keys()->all());
305-
$matched = false;
299+
$commonIpIds = array_intersect($userIpMap->keys()->all(), $dupeIpMap->keys()->all());
300+
$matched = false;
306301

307-
foreach ($commonIpIds as $ipId)
302+
foreach ($commonIpIds as $ipId)
303+
{
304+
foreach ($userIpMap[$ipId] as $uEntry)
308305
{
309-
foreach ($userIpMap[$ipId] as $uEntry)
306+
foreach ($dupeIpMap[$ipId] as $dEntry)
310307
{
311-
foreach ($dupeIpMap[$ipId] as $dEntry)
308+
$diffInDays = abs($uEntry->created_at->diffInDays($dEntry->created_at));
309+
if ($diffInDays <= 500)
312310
{
313-
$diffInDays = abs($uEntry->created_at->diffInDays($dEntry->created_at));
314-
if ($diffInDays <= 500)
315-
{
316-
$matched = true;
317-
break 3;
318-
}
311+
$matched = true;
312+
break 3;
319313
}
320314
}
321315
}
316+
}
322317

323-
if ($matched)
324-
{
325-
$finalReason .= ' & IP';
326-
}
318+
if ($matched && str_contains($reason, "manually"))
319+
{
320+
$reason = 'IP';
321+
}
322+
else if ($matched)
323+
{
324+
$reason .= ' & IP';
327325
}
326+
}
328327

328+
if ($userPrimaryId === $dupeUser->primaryId())
329+
{
329330
$confirmed->push([
330331
'user' => $dupeUser,
331-
'reason' => $finalReason,
332+
'reason' => $reason,
332333
]);
333334
}
334335
elseif ($user->isDuplicate() && $dupeUser->isConfirmedPrimary() && $userPrimaryId !== $dupeUser->primaryId())

cncnet-api/app/Http/Controllers/ApiLadderController.php

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,43 @@ public function awardClanPoints($gameReport, $history)
474474
return 200;
475475
}
476476

477+
478+
/**
479+
* Determine the winning team from a collection of player game reports.
480+
* Falls back to using a non-defeated player’s team if no player is marked as 'won'.
481+
*
482+
* @param \Illuminate\Support\Collection|\App\Models\PlayerGameReport[] $playerGameReports
483+
* @return int|null The winning team number, or null if none found.
484+
*/
485+
public function getWinningTeamFromReports($playerGameReports): ?int
486+
{
487+
foreach ($playerGameReports as $pgr)
488+
{
489+
if ($pgr->won)
490+
{
491+
return $pgr->team;
492+
}
493+
}
494+
495+
// Step 2: Fallback — no winner marked; use a non-defeated player (disconnected game case)
496+
foreach ($playerGameReports as $pgr)
497+
{
498+
if (!$pgr->defeated)
499+
{
500+
Log::info("Fallback to 'defeated' logic for disconnected game.", [
501+
'game_id' => $pgr->game_id,
502+
'player_id' => $pgr->player_id,
503+
'team' => $pgr->team,
504+
]);
505+
return $pgr->team;
506+
}
507+
}
508+
509+
// No winning team found
510+
return null;
511+
}
512+
513+
477514
/**
478515
*
479516
* @param GameReport $gameReport
@@ -506,17 +543,8 @@ public function awardTeamPoints(GameReport $gameReport, LadderHistory $history)
506543

507544
$disconnected = 0;
508545

509-
// String a or b.
510-
$winningTeam = null;
511-
512-
foreach ($playerGameReports as $pgr)
513-
{
514-
if ($pgr->won)
515-
{
516-
// grab the qm players that belong to this qm match, return the team of the current player
517-
$winningTeam = $pgr->team;
518-
}
519-
}
546+
// determine which team won
547+
$winningTeam = $this->getWinningTeamFromReports($playerGameReports);
520548

521549
foreach ($playerGameReports as $playerGR)
522550
{
@@ -567,17 +595,30 @@ public function awardTeamPoints(GameReport $gameReport, LadderHistory $history)
567595
$gvc = ceil(($base_rating * $enemy_average) / 230000);
568596
}
569597

570-
$wol_k = $history->ladder->qmLadderRules->wol_k;
571598
$diff = $enemy_points - $ally_points;
572599
$we = 1 / (pow(10, abs($diff) / 600) + 1);
573-
$we = $diff > 0 && $playerGRTeamWonTheGame ? 1 - $we : ($diff < 0 && !$playerGRTeamWonTheGame ? 1 - $we : $we);
600+
if (($diff > 0 && $playerGRTeamWonTheGame) || ($diff < 0 && !$playerGRTeamWonTheGame))
601+
{
602+
$we = 1 - $we;
603+
}
604+
605+
$wol_k = $history->ladder->qmLadderRules->wol_k;
574606
$wol = (int)($wol_k * $we);
575607

576608
$eloAdjust = 0;
577609

578-
if ($playerGR->draw)
610+
if ($playerGR->draw || $winningTeam === null) // draw or couldn't find a winner
579611
{
580612
$playerGR->points = 0;
613+
614+
Log::info("No points awarded due to draw or missing winning team.", [
615+
'game_id' => $playerGR->game_id,
616+
'player_id' => $playerGR->player_id,
617+
'username' => optional($playerGR->player)->username,
618+
'draw' => $playerGR->draw,
619+
'team' => $playerGR->team,
620+
'winning_team' => $winningTeam,
621+
]);
581622
}
582623
else if ($playerGRTeamWonTheGame)
583624
{

cncnet-api/app/Http/Controllers/RankingController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function getIndex(Request $request)
5151

5252
if (Storage::disk('rating')->exists($gameMode . "_best_teams.json"))
5353
{
54-
array_push($stats, "Best teams");
54+
array_push($stats, "Best Teammates");
5555
array_push($jsonFiles, "best_teams.json");
5656
}
5757

0 commit comments

Comments
 (0)