From d31f9eb2cc35eec3b48cb1af567949d0cf7a3298 Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sun, 3 Dec 2023 13:01:08 -0500 Subject: [PATCH 1/2] feat: add 'missable' type (#2065) --- app/Helpers/database/achievement.php | 7 +- app/Helpers/database/game.php | 10 +- app/Platform/AppServiceProvider.php | 4 + .../MigrateMissableAchievementsToType.php | 55 +++++++++ app/Platform/Enums/AchievementType.php | 3 + app/Platform/Models/Achievement.php | 9 ++ app/Platform/Models/Game.php | 2 +- database/factories/AchievementFactory.php | 7 ++ lang/en/achievement-type.php | 1 + public/achievementInfo.php | 36 +++--- public/achievementinspector.php | 12 +- public/gameInfo.php | 4 - public/reportissue.php | 2 - public/request/achievement/update-type.php | 11 +- public/ticketmanager.php | 3 +- .../views/components/icon/missable.blade.php | 3 + .../views/components/modal-trigger.blade.php | 6 +- .../components/achievement/title.blade.php | 12 -- .../developer/inspector-toolbox.blade.php | 32 +++-- .../achievements-list-item.blade.php | 6 - .../game/achievements-list/root.blade.php | 10 -- .../type-indicator.blade.php | 111 +++++++++++------- .../Feature/Connect/UploadAchievementTest.php | 4 +- 23 files changed, 226 insertions(+), 124 deletions(-) create mode 100644 app/Platform/Commands/MigrateMissableAchievementsToType.php create mode 100644 resources/views/components/icon/missable.blade.php diff --git a/app/Helpers/database/achievement.php b/app/Helpers/database/achievement.php index ba3f5738f6..0a121d7fc3 100644 --- a/app/Helpers/database/achievement.php +++ b/app/Helpers/database/achievement.php @@ -210,8 +210,11 @@ function UploadNewAchievement( ); $isEventGame = $gameData['ConsoleID'] == 101; - if ($isForSubsetOrTestKit || $isEventGame) { - $errorOut = "Cannot set type on achievement in subset, test kit, or event."; + if ( + ($isForSubsetOrTestKit || $isEventGame) + && ($type === AchievementType::Progression || $type === AchievementType::WinCondition) + ) { + $errorOut = "Cannot set progression or win condition type on achievement in subset, test kit, or event."; return false; } diff --git a/app/Helpers/database/game.php b/app/Helpers/database/game.php index 65cbedf260..7add6f7f15 100644 --- a/app/Helpers/database/game.php +++ b/app/Helpers/database/game.php @@ -65,8 +65,9 @@ function getGameMetadata( CASE WHEN ach.type = 'progression' THEN 0 WHEN ach.type = 'win_condition' THEN 1 - WHEN ach.type IS NULL THEN 2 - ELSE 3 + WHEN ach.type = 'missable' THEN 2 + WHEN ach.type IS NULL THEN 3 + ELSE 4 END, ach.DisplayOrder, ach.ID ASC ", @@ -75,8 +76,9 @@ function getGameMetadata( CASE WHEN ach.type = 'progression' THEN 0 WHEN ach.type = 'win_condition' THEN 1 - WHEN ach.type IS NULL THEN 2 - ELSE 3 + WHEN ach.type = 'missable' THEN 2 + WHEN ach.type IS NULL THEN 3 + ELSE 4 END DESC, ach.DisplayOrder DESC, ach.ID DESC ", diff --git a/app/Platform/AppServiceProvider.php b/app/Platform/AppServiceProvider.php index 71b692c558..c97b080b1e 100644 --- a/app/Platform/AppServiceProvider.php +++ b/app/Platform/AppServiceProvider.php @@ -5,6 +5,7 @@ namespace App\Platform; use App\Platform\Commands\DeleteOrphanedLeaderboardEntries; +use App\Platform\Commands\MigrateMissableAchievementsToType; use App\Platform\Commands\NoIntroImport; use App\Platform\Commands\ResetPlayerAchievement; use App\Platform\Commands\SyncAchievements; @@ -68,6 +69,9 @@ public function boot(): void // Game Hashes NoIntroImport::class, + // Achievements + MigrateMissableAchievementsToType::class, + // Leaderboards UpdateLeaderboardMetrics::class, DeleteOrphanedLeaderboardEntries::class, diff --git a/app/Platform/Commands/MigrateMissableAchievementsToType.php b/app/Platform/Commands/MigrateMissableAchievementsToType.php new file mode 100644 index 0000000000..89cc5fb4f2 --- /dev/null +++ b/app/Platform/Commands/MigrateMissableAchievementsToType.php @@ -0,0 +1,55 @@ +argument('achievementId'); + + if ($achievementId !== null) { + $achievement = Achievement::findOrFail($achievementId); + + $this->info('Updating missable type for achievement [' . $achievement->id . ']'); + + $this->syncMissableTypeForAchievement($achievement); + } else { + $allTaggedMissables = Achievement::where('Title', 'like', '%[m]%')->get(); + + $this->info('Updating missable types for ' . $allTaggedMissables->count() . ' achievements.'); + + foreach ($allTaggedMissables as $achievement) { + $this->syncMissableTypeForAchievement($achievement); + } + + $this->info('All achievements have been updated.'); + } + } + + private function syncMissableTypeForAchievement(Achievement $achievement): void + { + $usesLegacyMissableTag = mb_strpos($achievement->Title, '[m]'); + + // Is this achievement eligible for syncing? It must contain the legacy + // missable tag and must not already have a type. + if ($usesLegacyMissableTag && !$achievement->type) { + $achievement->type = AchievementType::Missable; + + // Remove the [m] tag and trim whitespace + $achievement->Title = trim(str_replace('[m]', '', $achievement->Title)); + } + + $achievement->save(); + } +} diff --git a/app/Platform/Enums/AchievementType.php b/app/Platform/Enums/AchievementType.php index a228dea74a..01b6b176e8 100644 --- a/app/Platform/Enums/AchievementType.php +++ b/app/Platform/Enums/AchievementType.php @@ -10,11 +10,14 @@ abstract class AchievementType public const WinCondition = 'win_condition'; + public const Missable = 'missable'; + public static function cases(): array { return [ self::Progression, self::WinCondition, + self::Missable, ]; } diff --git a/app/Platform/Models/Achievement.php b/app/Platform/Models/Achievement.php index c9c1b5ed59..376748f2cb 100644 --- a/app/Platform/Models/Achievement.php +++ b/app/Platform/Models/Achievement.php @@ -304,6 +304,15 @@ public function scopeWinCondition(Builder $query): Builder return $this->scopeType($query, AchievementType::WinCondition); } + /** + * @param Builder $query + * @return Builder + */ + public function scopeMissable(Builder $query): Builder + { + return $this->scopeType($query, AchievementType::Missable); + } + /** * @param Builder $query * @return Builder diff --git a/app/Platform/Models/Game.php b/app/Platform/Models/Game.php index 96137bb8cc..278ca2188b 100644 --- a/app/Platform/Models/Game.php +++ b/app/Platform/Models/Game.php @@ -165,7 +165,7 @@ public function shouldBeSearchable(): bool // == accessors - public function getCanHaveTypes(): bool + public function getCanHaveBeatenTypes(): bool { $isSubsetOrTestKit = ( mb_strpos($this->Title, "[Subset") !== false diff --git a/database/factories/AchievementFactory.php b/database/factories/AchievementFactory.php index ce1fd33e78..95ada5f5be 100644 --- a/database/factories/AchievementFactory.php +++ b/database/factories/AchievementFactory.php @@ -62,4 +62,11 @@ public function winCondition(): static 'type' => AchievementType::WinCondition, ]); } + + public function missable(): static + { + return $this->state(fn (array $attributes) => [ + 'type' => AchievementType::Missable, + ]); + } } diff --git a/lang/en/achievement-type.php b/lang/en/achievement-type.php index b1087183e3..81c5a096a4 100644 --- a/lang/en/achievement-type.php +++ b/lang/en/achievement-type.php @@ -3,6 +3,7 @@ use App\Platform\Enums\AchievementType; return [ + AchievementType::Missable => __('Missable'), AchievementType::Progression => __('Progression'), AchievementType::WinCondition => __('Win Condition'), ]; diff --git a/public/achievementInfo.php b/public/achievementInfo.php index 26f6cbe6cc..a48bfe52f1 100644 --- a/public/achievementInfo.php +++ b/public/achievementInfo.php @@ -122,7 +122,7 @@ function generateAchievementMetaDescription( ?> = Permissions::Developer || ($permissions >= Permissions::JuniorDeveloper && $isAuthor)): ?> ', [ 'rawTitle' => $achievementTitle, - 'isDisplayingTags' => false, ]); echo "